diff -r 000000000000 -r d0f3a028347a libtelepathy/src/tp-conn.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libtelepathy/src/tp-conn.c Tue Feb 02 01:10:06 2010 +0200 @@ -0,0 +1,734 @@ +/* tp-conn.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-conn.h" +#include "tp-helpers.h" +#include "tp-connmgr.h" +#include "tp-props-iface.h" + + + +#ifdef EMULATOR +#include "libtelepathy_wsd_solution.h" +#endif + +#ifdef EMULATOR + + GET_STATIC_VAR_FROM_TLS(parent_class,tp_conn,GObjectClass *) + #define parent_class (*GET_WSD_VAR_NAME(parent_class,tp_conn,s)()) + + GET_STATIC_VAR_FROM_TLS(type1,tp_conn,GType) + #define type1 (*GET_WSD_VAR_NAME(type1,tp_conn,s)()) + + GET_STATIC_VAR_FROM_TLS(ret1,tp_conn,GQuark) + #define ret1 (*GET_WSD_VAR_NAME(ret1,tp_conn,s)()) + + GET_STATIC_VAR_FROM_TLS(ret2,tp_conn,GQuark) + #define ret2 (*GET_WSD_VAR_NAME(ret2,tp_conn,s)()) + + GET_STATIC_VAR_FROM_TLS(ret3,tp_conn,GQuark) + #define ret3 (*GET_WSD_VAR_NAME(ret3,tp_conn,s)()) + + GET_STATIC_VAR_FROM_TLS(ret4,tp_conn,GQuark) + #define ret4 (*GET_WSD_VAR_NAME(ret4,tp_conn,s)()) + + GET_STATIC_VAR_FROM_TLS(ret5,tp_conn,GQuark) + #define ret5 (*GET_WSD_VAR_NAME(ret5,tp_conn,s)()) + + GET_STATIC_VAR_FROM_TLS(ret6,tp_conn,GQuark) + #define ret6 (*GET_WSD_VAR_NAME(ret6,tp_conn,s)()) + + GET_STATIC_VAR_FROM_TLS(ret7,tp_conn,GQuark) + #define ret7 (*GET_WSD_VAR_NAME(ret7,tp_conn,s)()) + + GET_STATIC_VAR_FROM_TLS(ret8,tp_conn,GQuark) + #define ret8 (*GET_WSD_VAR_NAME(ret8,tp_conn,s)()) + + GET_STATIC_VAR_FROM_TLS(ret9,tp_conn,GQuark) + #define ret9 (*GET_WSD_VAR_NAME(ret9,tp_conn,s)()) + +#else + static GObjectClass *parent_class = NULL; +#endif + + + +static gboolean tp_conn_status_change_handler(DBusGProxy *proxy, + guint status, guint reason, + gpointer user_data); + +static void _tp_conn_connect_req_handler(DBusGProxy *proxy, + GError *error, gpointer user_data); + +static void _tp_conn_register_signal_marshallers() +{ + /* Register marshaller for NewChannel signal */ + dbus_g_object_register_marshaller(tp_conn_signals_marshal_VOID__OBJECT_STRING_UINT_UINT_BOOLEAN, G_TYPE_NONE, DBUS_TYPE_G_OBJECT_PATH, G_TYPE_STRING, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_BOOLEAN, G_TYPE_INVALID); + /* Register marshaller for StatusChanged signal */ + dbus_g_object_register_marshaller(tp_conn_signals_marshal_VOID__UINT_UINT, G_TYPE_NONE, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_INVALID); +} + +static void _tp_conn_register_interface_signal_marshallers() +{ + /* Register marshaller for Aliasing interface signal AliasUpdate and + ContactInfo interface signal GotContactInfo*/ + dbus_g_object_register_marshaller(tp_ifaces_signals_marshal_VOID__UINT_STRING, G_TYPE_NONE, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_INVALID); + /* Register marshaller for Forwarding interface signal ForwardingChanged */ + dbus_g_object_register_marshaller(tp_ifaces_signals_marshal_VOID__UINT, G_TYPE_NONE, G_TYPE_UINT, G_TYPE_INVALID); + /* Register marshaller for Presence interface signal PresenceUpdate */ + dbus_g_object_register_marshaller(tp_ifaces_signals_marshal_VOID__BOXED, G_TYPE_NONE, G_TYPE_BOXED, G_TYPE_INVALID); + /* Register marshaller for Privacy interface signal PrivacyModeChanged */ + dbus_g_object_register_marshaller(tp_ifaces_signals_marshal_VOID__STRING, G_TYPE_NONE, G_TYPE_STRING, G_TYPE_INVALID); + /* Register marshaller for Renaming interface signal Renamed */ + dbus_g_object_register_marshaller(tp_ifaces_signals_marshal_VOID__UINT_UINT, G_TYPE_NONE, G_TYPE_UINT, G_TYPE_UINT, 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_conn_init_interface_signal_signatures(GData **signal_sigs) +{ + g_datalist_init(signal_sigs); + + /* Create and store aliasing iface signal signatures */ + g_datalist_id_set_data(signal_sigs, TELEPATHY_CONN_IFACE_ALIASING_QUARK, + (gpointer)&tp_conn_set_aliasing_signatures); + /* Create and store capabilities iface signal signatures */ + g_datalist_id_set_data(signal_sigs, TELEPATHY_CONN_IFACE_CAPABILITIES_QUARK, + (gpointer)&tp_conn_set_capabilities_signatures); + /* Create and store contactinfo iface signal signatures */ + g_datalist_id_set_data(signal_sigs, TELEPATHY_CONN_IFACE_CONTACTINFO_QUARK, + (gpointer)&tp_conn_set_contactinfo_signatures); + /* Create and store forwarding iface signal signatures */ + g_datalist_id_set_data(signal_sigs, TELEPATHY_CONN_IFACE_FORWARDING_QUARK, + (gpointer)&tp_conn_set_forwarding_signatures); + /* Create and store presence iface signal signatures */ + g_datalist_id_set_data(signal_sigs, TELEPATHY_CONN_IFACE_PRESENCE_QUARK, + (gpointer)&tp_conn_set_presence_signatures); + /* Create and store privacy iface signal signatures */ + g_datalist_id_set_data(signal_sigs, TELEPATHY_CONN_IFACE_PRIVACY_QUARK, + (gpointer)&tp_conn_set_privacy_signatures); + /* Create and store renaming iface signal signatures */ + g_datalist_id_set_data(signal_sigs, TELEPATHY_CONN_IFACE_RENAMING_QUARK, + (gpointer)&tp_conn_set_renaming_signatures); + g_datalist_id_set_data(signal_sigs, TELEPATHY_CONN_IFACE_AVATAR_QUARK, + (gpointer)&tp_conn_set_avatar_signatures); +} + +static void synthesize_status_changed(TpConn *conn); + +static void tp_conn_init(GTypeInstance *instance, gpointer g_class) +{ + TpConn *self = TELEPATHY_CONN(instance); + + self->first_run = TRUE; +} + + +static void tp_conn_dispose(GObject *obj) +{ + TpConn *self = TELEPATHY_CONN(obj); + + if (self->first_run == TRUE) + { + self->first_run = FALSE; + synthesize_status_changed(self); + g_datalist_clear(&(self->interface_list)); + } + + /* Call parent class dispose method */ + if (G_OBJECT_CLASS(parent_class)->dispose) + { + G_OBJECT_CLASS(parent_class)->dispose(obj); + } + +} + + +static void tp_conn_finalize(GObject *obj) +{ + if (G_OBJECT_CLASS(parent_class)->finalize) + { + G_OBJECT_CLASS(parent_class)->finalize(obj); + } + +} + + +static void tp_conn_class_init(TpConnClass *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_conn_dispose; + obj->finalize = tp_conn_finalize; + _tp_conn_register_signal_marshallers(); + _tp_conn_register_interface_signal_marshallers(); + _tp_conn_init_interface_signal_signatures(&(klass->iface_signal_sigs)); +} + +#ifdef SYMBIAN +EXPORT_C +#endif +GType tp_conn_get_type(void) +{ +#ifndef EMULATOR + static GType type1 = 0; +#endif + + if (type1 == 0) + { + static const GTypeInfo info = + { + sizeof(TpConnClass), + NULL, + NULL, + (GClassInitFunc)tp_conn_class_init, + NULL, + NULL, + sizeof(TpConn), + 0, + (GInstanceInitFunc)tp_conn_init + + }; + type1 = g_type_register_static(DBUS_TYPE_G_PROXY, + "TpConn", &info, 0); + } + return type1; +} + +/* The interface name getters */ + +GQuark tp_get_conn_interface() +{ +#ifndef EMULATOR + static GQuark ret1 = 0; +#endif + + if (ret1 == 0) + { + /* FIXME: The naming conventions should be unified */ + ret1 = g_quark_from_static_string(TP_IFACE_CONN_INTERFACE); + } + + return ret1; +} + +GQuark tp_get_conn_aliasing_interface() +{ +#ifndef EMULATOR + static GQuark ret2 = 0; +#endif + + if (ret2 == 0) + { + ret2 = g_quark_from_static_string(TP_IFACE_CONN_INTERFACE_ALIASING); + } + + return ret2; +} + +GQuark tp_get_conn_capabilities_interface() +{ +#ifndef EMULATOR + static GQuark ret3 = 0; +#endif + + if (ret3 == 0) + { + ret3 = g_quark_from_static_string(TP_IFACE_CONN_INTERFACE_CAPABILITIES); + } + + return ret3; +} + +GQuark tp_get_conn_contactinfo_interface() +{ +#ifndef EMULATOR + static GQuark ret4 = 0; +#endif + + if (ret4 == 0) + { + ret4 = g_quark_from_static_string(TP_IFACE_CONN_INTERFACE_CONTACT_INFO); + } + + return ret4; +} + +GQuark tp_get_conn_forwarding_interface() +{ +#ifndef EMULATOR + static GQuark ret5 = 0; +#endif + + if (ret5 == 0) + { + ret5 = g_quark_from_static_string(TP_IFACE_CONN_INTERFACE_FORWARDING); + } + + return ret5; +} + +#ifdef SYMBIAN +EXPORT_C +#endif +GQuark tp_get_conn_presence_interface() +{ +#ifndef EMULATOR + static GQuark ret6 = 0; +#endif + + if (ret6 == 0) + { + ret6 = g_quark_from_static_string(TP_IFACE_CONN_INTERFACE_PRESENCE); + } + + return ret6; +} + + +GQuark tp_get_conn_privacy_interface() +{ +#ifndef EMULATOR + static GQuark ret7 = 0; +#endif + + if (ret7 == 0) + { + ret7 = g_quark_from_static_string(TP_IFACE_CONN_INTERFACE_PRIVACY); + } + + return ret7; +} + + + +GQuark tp_get_conn_renaming_interface() +{ +#ifndef EMULATOR + static GQuark ret8 = 0; +#endif + + if (ret8 == 0) + { + ret8 = g_quark_from_static_string(TP_IFACE_CONN_INTERFACE_RENAMING); + } + + return ret8; +} + +#ifdef SYMBIAN +EXPORT_C +#endif +GQuark tp_get_conn_avatar_interface(void) + { +#ifndef EMULATOR + static GQuark ret9 = 0; +#endif + + if (ret9 == 0) + { + ret9 = g_quark_from_static_string(TP_IFACE_CONN_INTERFACE_AVATAR); + } + + return ret9; + } + +TpConn * +tp_conn_new_without_connect (DBusGConnection *connection, + const gchar *bus_name, + const gchar *object_path, + guint *status, + GError **error) +{ + gchar *unique_name; + gchar **interfaces; + guint conn_status = TP_CONN_STATUS_DISCONNECTED; + TpConn *obj; + GError *err = NULL; + + 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); + + /* Create the proxy object for this connection. It will be used to + perform the actual method calls over D-BUS. */ + + 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)) + { + return NULL; + } + + obj = g_object_new (TELEPATHY_CONN_TYPE, + "name", unique_name, + "path", object_path, + "interface", TP_IFACE_CONN_INTERFACE,//TP_IFACE_CONNECTION, + "connection", connection, + NULL); + g_free (unique_name); + + g_datalist_init (&(obj->interface_list)); + + //ADD_SIGNALS_FOR_CONNECTION (DBUS_G_PROXY (obj)); //commenting this bcoz header file not found + //equivalent of above stmt + dbus_g_proxy_add_signal (DBUS_G_PROXY (obj), "NewChannel",\ + DBUS_TYPE_G_OBJECT_PATH,\ + G_TYPE_STRING,\ + G_TYPE_UINT,\ + G_TYPE_UINT,\ + G_TYPE_BOOLEAN,\ + G_TYPE_INVALID);\ + dbus_g_proxy_add_signal (DBUS_G_PROXY (obj), "StatusChanged",\ + G_TYPE_UINT,\ + G_TYPE_UINT,\ + G_TYPE_INVALID); + + /* Check if the connection is already connected. If so, we can + * already perform GetInterfaces(). */ + + if (!tp_conn_get_status (DBUS_G_PROXY (obj), &conn_status, &err)) + { + if (err != NULL) + g_propagate_error (error, err); + + g_object_unref (obj); + return NULL; + } + + if (conn_status == TP_CONN_STATUS_CONNECTED) + { + if (!tp_conn_get_interfaces (DBUS_G_PROXY (obj), &interfaces, &err)) + { + if (err != NULL) + g_propagate_error (error, err); + + g_object_unref (obj); + return NULL; + } + + /* Initialize the interface objects for this TpConn object */ + tp_conn_local_set_interfaces (obj, interfaces); + + g_strfreev (interfaces); + } + else + { + /* Not connected yet, so this is really a new connection. Thus, we + have to hook up to StatusChanged signal to perform the + GetInterfaces when it goes Connected */ + + dbus_g_proxy_connect_signal (DBUS_G_PROXY (obj), "StatusChanged", + G_CALLBACK (tp_conn_status_change_handler), NULL, NULL); + } + + if (status != NULL) + *status = conn_status; + return obj; +} + + +TpConn * +tp_conn_new (DBusGConnection *connection, + const gchar *bus_name, + const gchar *object_path) +{ + GError *error = NULL; + guint status; + TpConn *obj; + + 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); + + obj = tp_conn_new_without_connect (connection, bus_name, object_path, + &status, &error); + + if (obj == NULL) + { + /* either GetNameOwner, GetStatus or GetInterfaces failed */ + if (error != NULL) + { + g_warning ("Failed to create connection for %s %s: %s", bus_name, + object_path, error->message); + g_error_free (error); + } + else + { + g_warning ("Failed to create connection for %s %s: error is NULL", + bus_name, object_path); + } + + return NULL; + } + + if (status != TP_CONN_STATUS_CONNECTED) + { + tp_conn_connect_async (DBUS_G_PROXY (obj), _tp_conn_connect_req_handler, + NULL); + } + + return obj; +} + +#ifdef SYMBIAN +EXPORT_C +#endif +TpChan *tp_conn_new_channel(DBusGConnection *connection, + TpConn *tp_conn, const gchar *bus_name, + gchar *type, guint handle_type, + guint handle, gboolean supress_handler) +{ + GError *error = NULL; + gchar *chan_object_path = NULL; + TpChan *new_chan = NULL; + + g_return_val_if_fail(connection, NULL); + g_return_val_if_fail(TELEPATHY_IS_CONN(tp_conn), NULL); + g_return_val_if_fail(bus_name, NULL); + g_return_val_if_fail(type, NULL); + + /* Request a new channel to be created by using the proxy object. + We also retrieve the object path for it here. */ + + if (!tp_conn_request_channel(DBUS_G_PROXY(tp_conn), + type, handle_type, handle, supress_handler, + &chan_object_path, &error)) + { + g_warning("RequestChannel() failed: %s\n", error -> message); + + g_error_free(error); + return NULL; + } + + + /* Create the object to represent the channel */ + + new_chan = tp_chan_new(connection, bus_name, chan_object_path, type, + handle_type, handle); + + + g_free(chan_object_path); + + + + return new_chan; +} + + +void tp_conn_local_set_interfaces(TpConn *self, gchar **interfaces) +{ + gchar **temp_ifaces = NULL; + const gchar *bus_name = dbus_g_proxy_get_bus_name(DBUS_G_PROXY(self)); + const gchar *object_path = dbus_g_proxy_get_path(DBUS_G_PROXY(self)); + + DBusGConnection *connection = tp_get_bus (); + + if (interfaces == NULL || connection == NULL) + { + return; + } + + /* Create and store the proxy objects for the connection interfaces. */ + for (temp_ifaces = interfaces; *temp_ifaces; temp_ifaces++) + { + DBusGProxy *if_proxy; + GQuark key = g_quark_from_string(*temp_ifaces); + + if (key == TELEPATHY_PROPS_IFACE_QUARK) + { + if_proxy = DBUS_G_PROXY (tp_props_iface_new (connection, + bus_name, object_path)); + } + else + { + if_proxy = dbus_g_proxy_new_for_name(connection, bus_name, object_path, + *temp_ifaces); + if (if_proxy != NULL) + { + GData *sig_list = TELEPATHY_CONN_GET_CLASS(self)->iface_signal_sigs; + void (*signature_setter_func)(); + + /* Does the interface have signals? If yes, add their signatures + for the interface instance */ + 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); + } + + } +} + +#ifdef SYMBIAN +EXPORT_C +#endif +DBusGProxy * +tp_conn_get_interface (TpConn *self, + GQuark iface_quark) +{ + DBusGProxy *iface_proxy = NULL; + + g_return_val_if_fail (self != NULL, NULL); + g_return_val_if_fail (iface_quark != 0, NULL); + + iface_proxy = (DBusGProxy *) g_datalist_id_get_data ( + &(self->interface_list), iface_quark); + + return iface_proxy; +} + +void +_tp_conn_connect_req_handler (DBusGProxy *proxy, + GError *error, + gpointer user_data) +{ + /* The interfaces for the TpConn are set on the StatusChanged + handler when we get connected. Just print errors (if any) + here. */ + + if (error) + { + g_warning ("Could not perform Connect() for the connection, because: %s", + error->message); + g_error_free (error); + return; + } + +} + +static gboolean +tp_conn_status_change_handler (DBusGProxy *proxy, + guint status, + guint reason, + gpointer user_data) +{ + gchar **interfaces = NULL; + GError *error = NULL; + TpConn *tp_conn = (TpConn *) proxy; + + /* If the connection is up, we can get the list of interfaces */ + /* FIXME: At some point, we should switch to doing this asynchronously */ + + if (status == TP_CONN_STATUS_CONNECTED) + { + if (!tp_conn_get_interfaces (DBUS_G_PROXY (proxy), &interfaces, &error)) + { + g_warning ("GetInterfaces failed: %s\n", error->message); + g_error_free (error); + return TRUE; + } + + /* Initialize the interface objects for this TpConn object */ + + tp_conn_local_set_interfaces (tp_conn, interfaces); + + g_strfreev (interfaces); + + dbus_g_proxy_disconnect_signal (proxy, "StatusChanged", + G_CALLBACK (tp_conn_status_change_handler), NULL); + } + + return TRUE; +} + + +static void synthesize_status_changed(TpConn *conn) +{ + + DBusMessageIter iter; + DBusMessage *msg = NULL; + guint value; + GType uint_type = G_TYPE_UINT; + GArray *statuschanged_signal_types = g_array_new(FALSE, FALSE, + sizeof(GType)); + + + if (!statuschanged_signal_types) + { + g_warning("%s: Could not allocate type array for StatusChanged", + G_STRFUNC); + return; + } + + msg = dbus_message_new_signal(dbus_g_proxy_get_path(DBUS_G_PROXY(conn)), + TP_IFACE_CONN_INTERFACE, "StatusChanged"); + + if (!msg) + { + g_warning("%s: Could not allocate message for StatusChanged signal", + G_STRFUNC); + g_array_free(statuschanged_signal_types, FALSE); + return; + } + + dbus_message_iter_init_append(msg, &iter); + value = TP_CONN_STATUS_DISCONNECTED; + dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT32, &value); + value = TP_CONN_STATUS_REASON_NONE_SPECIFIED; + dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT32, &value); + + /* TODO: It might be worth considering to setup/remove the array in + base_init/base_deinit to make it persist for the whole class */ + + if (statuschanged_signal_types) + { + g_array_insert_val(statuschanged_signal_types, 0, uint_type); + g_array_insert_val(statuschanged_signal_types, 1, uint_type); + } + else + { + g_warning("%s: Could not allocate array for StatusChanged types", + G_STRFUNC); + dbus_message_unref(msg); + return; + } + + g_signal_emit_by_name(DBUS_G_PROXY(conn), + TP_IFACE_CONN_SIGNAL_STATUSCHANGED_SYNTHESIZED, msg, + statuschanged_signal_types); + g_array_free(statuschanged_signal_types, TRUE); + dbus_message_unref(msg); +}