telepathy: fix crash in TpDBusPropertiesMixin
[siplcs.git] / src / telepathy / telepathy-connection.c
blob1069780de9d408ae271d10a95eea37489cacabea
1 /**
2 * @file telepathy-connection.c
4 * pidgin-sipe
6 * Copyright (C) 2012 SIPE Project <http://sipe.sourceforge.net/>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
27 #include <string.h>
29 #include <glib-object.h>
30 #include <telepathy-glib/base-connection.h>
31 #include <telepathy-glib/base-protocol.h>
32 #include <telepathy-glib/contacts-mixin.h>
33 #include <telepathy-glib/handle-repo-dynamic.h>
34 #include <telepathy-glib/presence-mixin.h>
35 #include <telepathy-glib/simple-password-manager.h>
36 #include <telepathy-glib/telepathy-glib.h>
38 #include "sipe-backend.h"
39 #include "sipe-common.h"
40 #include "sipe-core.h"
42 #include "telepathy-private.h"
44 G_BEGIN_DECLS
46 * Connection class - data structures
48 typedef struct _SipeConnectionClass {
49 TpBaseConnectionClass parent_class;
50 TpDBusPropertiesMixinClass properties_mixin;
51 TpContactsMixinClass contacts_mixin;
52 TpPresenceMixinClass presence_mixin;
53 } SipeConnectionClass;
55 typedef struct _SipeConnection {
56 TpBaseConnection parent;
57 TpContactsMixinClass contacts_mixin;
58 TpPresenceMixin presence_mixin;
60 /* channel managers */
61 TpSimplePasswordManager *password_manager;
62 struct _SipeContactList *contact_list;
64 struct sipe_backend_private private;
65 gchar *account;
66 gchar *login;
67 gchar *password;
68 gchar *server;
69 gchar *port;
70 guint transport;
71 gchar *user_agent;
72 gchar *authentication;
73 gboolean is_disconnecting;
75 GPtrArray *contact_info_fields;
76 } SipeConnection;
78 #define SIPE_PUBLIC_TO_CONNECTION sipe_public->backend_private->connection
81 * Connection class - type macros
83 static GType sipe_connection_get_type(void) G_GNUC_CONST;
84 #define SIPE_TYPE_CONNECTION \
85 (sipe_connection_get_type())
86 #define SIPE_CONNECTION(obj) \
87 (G_TYPE_CHECK_INSTANCE_CAST((obj), SIPE_TYPE_CONNECTION, \
88 SipeConnection))
89 G_END_DECLS
92 * Connection class - type definition
94 static void init_aliasing (gpointer, gpointer);
95 G_DEFINE_TYPE_WITH_CODE(SipeConnection,
96 sipe_connection,
97 TP_TYPE_BASE_CONNECTION,
98 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_ALIASING,
99 init_aliasing);
100 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACTS,
101 tp_contacts_mixin_iface_init);
102 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACT_GROUPS,
103 tp_base_contact_list_mixin_groups_iface_init);
104 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACT_INFO,
105 sipe_telepathy_contact_info_iface_init);
106 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACT_LIST,
107 tp_base_contact_list_mixin_list_iface_init);
108 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_PRESENCE,
109 tp_presence_mixin_iface_init);
110 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_SIMPLE_PRESENCE,
111 tp_presence_mixin_simple_presence_iface_init);
112 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_DBUS_PROPERTIES,
113 tp_dbus_properties_mixin_iface_init);
118 * Connection class - instance methods
120 static gchar *normalize_contact(SIPE_UNUSED_PARAMETER TpHandleRepoIface *repo,
121 const gchar *id,
122 SIPE_UNUSED_PARAMETER gpointer context,
123 GError **error)
125 return(sipe_telepathy_protocol_normalize_contact(NULL, id, error));
128 static void create_handle_repos(SIPE_UNUSED_PARAMETER TpBaseConnection *conn,
129 TpHandleRepoIface *repos[NUM_TP_HANDLE_TYPES])
131 repos[TP_HANDLE_TYPE_CONTACT] = tp_dynamic_handle_repo_new(TP_HANDLE_TYPE_CONTACT,
132 normalize_contact,
133 NULL);
136 static gboolean connect_to_core(SipeConnection *self,
137 GError **error)
139 gchar *login_domain = NULL;
140 gchar *login_account = NULL;
141 struct sipe_core_public *sipe_public;
142 const gchar *errmsg;
144 /* login name specified? */
145 if (self->login && strlen(self->login)) {
146 /* Allowed domain-account separators are / or \ */
147 gchar **domain_user = g_strsplit_set(self->login, "/\\", 2);
148 gboolean has_domain = domain_user[1] != NULL;
149 SIPE_DEBUG_INFO("connect_to_core: login '%s'", self->login);
150 login_domain = has_domain ? g_strdup(domain_user[0]) : NULL;
151 login_account = g_strdup(domain_user[has_domain ? 1 : 0]);
152 SIPE_DEBUG_INFO("connect_to_core: auth domain '%s' user '%s'",
153 login_domain ? login_domain : "",
154 login_account);
155 g_strfreev(domain_user);
158 sipe_public = sipe_core_allocate(self->account,
159 login_domain, login_account,
160 self->password,
161 NULL, /* @TODO: email */
162 NULL, /* @TODO: email_url */
163 &errmsg);
164 g_free(login_domain);
165 g_free(login_account);
167 SIPE_DEBUG_INFO("connect_to_core: created %p", sipe_public);
169 if (sipe_public) {
170 struct sipe_backend_private *telepathy_private = &self->private;
172 /* initialize backend private data */
173 sipe_public->backend_private = telepathy_private;
174 telepathy_private->public = sipe_public;
175 telepathy_private->contact_list = self->contact_list;
176 telepathy_private->connection = self;
177 telepathy_private->activity = SIPE_ACTIVITY_UNSET;
178 telepathy_private->message = NULL;
179 telepathy_private->transport = NULL;
180 telepathy_private->ipaddress = NULL;
182 /* map option list to flags - default is NTLM */
183 SIPE_CORE_FLAG_UNSET(KRB5);
184 SIPE_CORE_FLAG_UNSET(TLS_DSK);
185 #ifdef HAVE_LIBKRB5
186 if (sipe_strequal(self->authentication, "krb5")) {
187 SIPE_DEBUG_INFO_NOFORMAT("connect_to_core: KRB5 selected");
188 SIPE_CORE_FLAG_SET(KRB5);
189 } else
190 #endif
191 if (sipe_strequal(self->authentication, "tls-dsk")) {
192 SIPE_DEBUG_INFO_NOFORMAT("connect_to_core: TLS-DSK selected");
193 SIPE_CORE_FLAG_SET(TLS_DSK);
196 /* @TODO: add parameter for SSO */
197 SIPE_CORE_FLAG_UNSET(SSO);
199 sipe_core_transport_sip_connect(sipe_public,
200 self->transport,
201 self->server,
202 self->port);
204 return(TRUE);
205 } else {
206 g_set_error_literal(error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
207 errmsg);
208 return(FALSE);
212 static void password_manager_cb(GObject *source,
213 GAsyncResult *result,
214 gpointer data)
216 SipeConnection *self = data;
217 TpBaseConnection *base = TP_BASE_CONNECTION(self);
218 GError *error = NULL;
219 const GString *password = tp_simple_password_manager_prompt_finish(
220 TP_SIMPLE_PASSWORD_MANAGER(source),
221 result,
222 &error);
224 if (password == NULL) {
225 SIPE_DEBUG_ERROR("password_manager_cb: failed: %s",
226 error ? error->message : "UNKNOWN");
228 if (base->status != TP_CONNECTION_STATUS_DISCONNECTED) {
229 tp_base_connection_disconnect_with_dbus_error(base,
230 error ? tp_error_get_dbus_name(error->code) : "",
231 NULL,
232 TP_CONNECTION_STATUS_REASON_AUTHENTICATION_FAILED);
234 g_error_free(error);
235 } else {
237 g_free(self->password);
238 self->password = g_strdup(password->str);
240 if (!connect_to_core(self, &error)) {
241 if (base->status != TP_CONNECTION_STATUS_DISCONNECTED) {
242 tp_base_connection_disconnect_with_dbus_error(base,
243 tp_error_get_dbus_name(error->code),
244 NULL,
245 TP_CONNECTION_STATUS_REASON_AUTHENTICATION_FAILED);
247 g_error_free(error);
252 static gboolean start_connecting(TpBaseConnection *base,
253 GError **error)
255 SipeConnection *self = SIPE_CONNECTION(base);
256 gboolean rc = TRUE;
257 gchar *uri = sipe_telepathy_protocol_normalize_contact(NULL,
258 self->account,
259 error);
261 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::start_connecting");
263 /* set up mandatory self-handle */
264 if (uri) {
265 base->self_handle = tp_handle_ensure(tp_base_connection_get_handles(base,
266 TP_HANDLE_TYPE_CONTACT),
267 uri,
268 NULL,
269 error);
270 g_free(uri);
271 if (!base->self_handle) {
272 SIPE_DEBUG_ERROR("SipeConnection::start_connecting: self handle creation failed: %s",
273 (*error)->message);
274 return(FALSE);
276 } else {
277 SIPE_DEBUG_ERROR("SipeConnection::start_connecting: %s",
278 (*error)->message);
279 return(FALSE);
282 tp_base_connection_change_status(base, TP_CONNECTION_STATUS_CONNECTING,
283 TP_CONNECTION_STATUS_REASON_REQUESTED);
285 /* we need a password */
286 if (self->password)
287 rc = connect_to_core(self, error);
288 else {
289 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::start_connecting: requesting password from user");
290 tp_simple_password_manager_prompt_async(self->password_manager,
291 password_manager_cb,
292 self);
295 return(rc);
298 static gboolean disconnect_from_core(gpointer data)
300 TpBaseConnection *base = data;
301 SipeConnection *self = SIPE_CONNECTION(base);
302 struct sipe_backend_private *telepathy_private = &self->private;
303 struct sipe_core_public *sipe_public = telepathy_private->public;
305 SIPE_DEBUG_INFO("disconnect_from_core: %p", sipe_public);
307 if (sipe_public)
308 sipe_core_deallocate(sipe_public);
309 telepathy_private->public = NULL;
310 telepathy_private->transport = NULL;
312 g_free(telepathy_private->ipaddress);
313 telepathy_private->ipaddress = NULL;
315 g_free(telepathy_private->message);
316 telepathy_private->message = NULL;
318 SIPE_DEBUG_INFO_NOFORMAT("disconnect_from_core: core deallocated");
320 /* now it is OK to destroy the connection object */
321 tp_base_connection_finish_shutdown(base);
323 return(FALSE);
326 static void shut_down(TpBaseConnection *base)
328 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::shut_down");
330 /* this can be called synchronously, defer destruction */
331 g_idle_add(disconnect_from_core, base);
334 static GPtrArray *create_channel_managers(TpBaseConnection *base)
336 SipeConnection *self = SIPE_CONNECTION(base);
337 GPtrArray *channel_managers = g_ptr_array_new();
339 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::create_channel_managers");
341 self->contact_list = sipe_telepathy_contact_list_new(base);
342 g_ptr_array_add(channel_managers, self->contact_list);
344 self->password_manager = tp_simple_password_manager_new(base);
345 g_ptr_array_add(channel_managers, self->password_manager);
347 g_ptr_array_add(channel_managers, sipe_telepathy_search_new(base));
349 return(channel_managers);
352 static void aliasing_fill_contact_attributes(GObject *object,
353 const GArray *contacts,
354 GHashTable *attributes)
356 SipeConnection *self = SIPE_CONNECTION(object);
357 guint i;
359 for (i = 0; i < contacts->len; i++) {
360 TpHandle contact = g_array_index(contacts, guint, i);
362 tp_contacts_mixin_set_contact_attribute(attributes,
363 contact,
364 TP_TOKEN_CONNECTION_INTERFACE_ALIASING_ALIAS,
365 tp_g_value_slice_new_string(
366 sipe_telepathy_buddy_get_alias(self->contact_list,
367 contact)));
371 static void contact_info_properties_getter(GObject *object,
372 SIPE_UNUSED_PARAMETER GQuark interface,
373 GQuark name,
374 GValue *value,
375 gpointer getter_data)
377 GQuark fields = g_quark_from_static_string("SupportedFields");
379 if (name == fields)
380 g_value_set_boxed(value,
381 SIPE_CONNECTION(object)->contact_info_fields);
382 else
383 g_value_set_uint(value,
384 GPOINTER_TO_UINT(getter_data));
387 static void sipe_connection_constructed(GObject *object)
389 SipeConnection *self = SIPE_CONNECTION(object);
390 TpBaseConnection *base = TP_BASE_CONNECTION(object);
391 void (*chain_up)(GObject *) = G_OBJECT_CLASS(sipe_connection_parent_class)->constructed;
393 if (chain_up)
394 chain_up(object);
396 tp_contacts_mixin_init(object,
397 G_STRUCT_OFFSET(SipeConnection, contacts_mixin));
398 tp_base_connection_register_with_contacts_mixin(base);
400 tp_base_contact_list_mixin_register_with_contacts_mixin(base);
402 tp_contacts_mixin_add_contact_attributes_iface(object,
403 TP_IFACE_CONNECTION_INTERFACE_ALIASING,
404 aliasing_fill_contact_attributes);
406 tp_presence_mixin_init(object,
407 G_STRUCT_OFFSET(SipeConnection,
408 presence_mixin));
409 tp_presence_mixin_simple_presence_register_with_contacts_mixin(object);
411 self->contact_info_fields = sipe_telepathy_contact_info_fields();
414 static void sipe_connection_finalize(GObject *object)
416 SipeConnection *self = SIPE_CONNECTION(object);
418 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::finalize");
420 tp_contacts_mixin_finalize(object);
421 tp_presence_mixin_finalize(object);
422 g_boxed_free(TP_ARRAY_TYPE_FIELD_SPECS, self->contact_info_fields);
424 g_free(self->authentication);
425 g_free(self->user_agent);
426 g_free(self->port);
427 g_free(self->server);
428 g_free(self->password);
429 g_free(self->login);
430 g_free(self->account);
432 G_OBJECT_CLASS(sipe_connection_parent_class)->finalize(object);
436 * Connection class - type implementation
438 static const gchar *interfaces_always_present[] = {
439 /* @TODO */
440 TP_IFACE_CONNECTION_INTERFACE_ALIASING,
441 TP_IFACE_CONNECTION_INTERFACE_CONTACT_GROUPS,
442 TP_IFACE_CONNECTION_INTERFACE_CONTACT_INFO,
443 TP_IFACE_CONNECTION_INTERFACE_CONTACT_LIST,
444 TP_IFACE_CONNECTION_INTERFACE_CONTACTS,
445 TP_IFACE_CONNECTION_INTERFACE_PRESENCE,
446 TP_IFACE_CONNECTION_INTERFACE_REQUESTS,
447 TP_IFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE,
448 NULL
451 static void sipe_connection_class_init(SipeConnectionClass *klass)
453 GObjectClass *object_class = G_OBJECT_CLASS(klass);
454 TpBaseConnectionClass *base_class = TP_BASE_CONNECTION_CLASS(klass);
455 static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = {
457 /* 0 */
458 .name = TP_IFACE_CONNECTION_INTERFACE_CONTACT_INFO,
459 .getter = contact_info_properties_getter,
460 .setter = NULL,
463 /* LAST! */
464 .name = NULL,
468 /* initalize non-constant fields */
469 prop_interfaces[0].props = sipe_telepathy_contact_info_props();
471 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::class_init");
473 object_class->constructed = sipe_connection_constructed;
474 object_class->finalize = sipe_connection_finalize;
476 base_class->create_handle_repos = create_handle_repos;
477 base_class->start_connecting = start_connecting;
478 base_class->shut_down = shut_down;
479 base_class->create_channel_managers = create_channel_managers;
481 base_class->interfaces_always_present = interfaces_always_present;
483 klass->properties_mixin.interfaces = prop_interfaces;
484 tp_dbus_properties_mixin_class_init(object_class,
485 G_STRUCT_OFFSET(SipeConnectionClass,
486 properties_mixin));
487 tp_contacts_mixin_class_init(object_class,
488 G_STRUCT_OFFSET(SipeConnectionClass,
489 contacts_mixin));
490 sipe_telepathy_status_init(object_class,
491 G_STRUCT_OFFSET(SipeConnectionClass,
492 presence_mixin));
493 tp_presence_mixin_simple_presence_init_dbus_properties(object_class);
494 tp_base_contact_list_mixin_class_init(base_class);
497 static void sipe_connection_init(SIPE_UNUSED_PARAMETER SipeConnection *self)
499 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::init");
503 * Connection class - interface implementation
505 * Contact aliases
507 static void get_alias_flags(TpSvcConnectionInterfaceAliasing *aliasing,
508 DBusGMethodInvocation *context)
510 TpBaseConnection *base = TP_BASE_CONNECTION(aliasing);
512 TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED(base, context);
513 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::get_alias_flags called");
515 tp_svc_connection_interface_aliasing_return_from_get_alias_flags(context,
516 TP_CONNECTION_ALIAS_FLAG_USER_SET);
519 static void get_aliases(TpSvcConnectionInterfaceAliasing *aliasing,
520 const GArray *contacts,
521 DBusGMethodInvocation *context)
523 SipeConnection *self = SIPE_CONNECTION(aliasing);
524 TpBaseConnection *base = TP_BASE_CONNECTION(aliasing);
525 TpHandleRepoIface *contact_repo = tp_base_connection_get_handles(base,
526 TP_HANDLE_TYPE_CONTACT);
527 GError *error = NULL;
528 GHashTable *result;
529 guint i;
531 TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED(base, context);
532 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::get_aliases called");
534 if (!tp_handles_are_valid(contact_repo, contacts, FALSE, &error)) {
535 dbus_g_method_return_error(context, error);
536 g_error_free(error);
537 return;
540 result = g_hash_table_new(g_direct_hash, g_direct_equal);
542 for (i = 0; i < contacts->len; i++) {
543 TpHandle contact = g_array_index(contacts, TpHandle, i);
544 const gchar *alias = sipe_telepathy_buddy_get_alias(self->contact_list,
545 contact);
546 g_hash_table_insert(result,
547 GUINT_TO_POINTER(contact),
548 (gchar *) alias);
551 tp_svc_connection_interface_aliasing_return_from_get_aliases(context,
552 result);
553 g_hash_table_unref(result);
556 static void request_aliases(TpSvcConnectionInterfaceAliasing *aliasing,
557 const GArray *contacts,
558 DBusGMethodInvocation *context)
560 SipeConnection *self = SIPE_CONNECTION(aliasing);
561 TpBaseConnection *base = TP_BASE_CONNECTION(aliasing);
562 TpHandleRepoIface *contact_repo = tp_base_connection_get_handles(base,
563 TP_HANDLE_TYPE_CONTACT);
564 GError *error = NULL;
565 GPtrArray *result;
566 gchar **strings;
567 guint i;
569 TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED(base, context);
570 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::request_aliases called");
572 if (!tp_handles_are_valid(contact_repo, contacts, FALSE, &error)) {
573 dbus_g_method_return_error(context, error);
574 g_error_free(error);
575 return;
578 result = g_ptr_array_sized_new(contacts->len + 1);
580 for (i = 0; i < contacts->len; i++) {
581 TpHandle contact = g_array_index(contacts, TpHandle, i);
582 const gchar *alias = sipe_telepathy_buddy_get_alias(self->contact_list,
583 contact);
584 g_ptr_array_add(result, (gchar *) alias);
587 g_ptr_array_add(result, NULL);
588 strings = (gchar **) g_ptr_array_free(result, FALSE);
590 tp_svc_connection_interface_aliasing_return_from_request_aliases(context,
591 (const gchar **) strings);
592 g_free(strings);
595 static void set_aliases(TpSvcConnectionInterfaceAliasing *aliasing,
596 GHashTable *aliases,
597 DBusGMethodInvocation *context)
599 SipeConnection *self = SIPE_CONNECTION(aliasing);
600 TpBaseConnection *base = TP_BASE_CONNECTION(aliasing);
601 TpHandleRepoIface *contact_repo = tp_base_connection_get_handles(base,
602 TP_HANDLE_TYPE_CONTACT);
603 GHashTableIter iter;
604 gpointer key, value;
606 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::set_aliases called");
608 g_hash_table_iter_init(&iter, aliases);
610 while (g_hash_table_iter_next(&iter, &key, NULL)) {
611 GError *error = NULL;
613 if (!tp_handle_is_valid(contact_repo,
614 GPOINTER_TO_UINT(key),
615 &error)) {
616 dbus_g_method_return_error(context, error);
617 g_error_free(error);
618 return;
622 g_hash_table_iter_init(&iter, aliases);
624 while (g_hash_table_iter_next(&iter, &key, &value)) {
625 sipe_telepathy_buddy_set_alias(self->contact_list,
626 GPOINTER_TO_UINT(key),
627 value);
630 tp_svc_connection_interface_aliasing_return_from_set_aliases(context);
633 static void init_aliasing(gpointer iface,
634 SIPE_UNUSED_PARAMETER gpointer iface_data)
636 TpSvcConnectionInterfaceAliasingClass *klass = iface;
638 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::init_aliasing called");
640 tp_svc_connection_interface_aliasing_implement_get_alias_flags(klass, get_alias_flags);
641 tp_svc_connection_interface_aliasing_implement_request_aliases(klass, request_aliases);
642 tp_svc_connection_interface_aliasing_implement_get_aliases(klass, get_aliases);
643 tp_svc_connection_interface_aliasing_implement_set_aliases(klass, set_aliases);
646 /* create new connection object */
647 TpBaseConnection *sipe_telepathy_connection_new(TpBaseProtocol *protocol,
648 GHashTable *params,
649 SIPE_UNUSED_PARAMETER GError **error)
651 SipeConnection *conn = g_object_new(SIPE_TYPE_CONNECTION,
652 "protocol", tp_base_protocol_get_name(protocol),
653 NULL);
654 const gchar *value;
655 guint port;
656 gboolean valid;
658 SIPE_DEBUG_INFO_NOFORMAT("sipe_telepathy_connection_new");
660 /* initialize private fields */
661 conn->is_disconnecting = FALSE;
663 /* account & login are required fields */
664 conn->account = g_strdup(tp_asv_get_string(params, "account"));
665 conn->login = g_strdup(tp_asv_get_string(params, "login"));
667 /* password */
668 value = tp_asv_get_string(params, "password");
669 if (value && strlen(value))
670 conn->password = g_strdup(value);
671 else
672 conn->password = NULL;
674 /* server name */
675 value = tp_asv_get_string(params, "server");
676 if (value && strlen(value))
677 conn->server = g_strdup(value);
678 else
679 conn->server = NULL;
681 /* server port: core expects a string */
682 port = tp_asv_get_uint32(params, "port", &valid);
683 if (valid)
684 conn->port = g_strdup_printf("%d", port);
685 else
686 conn->port = NULL;
688 /* transport type */
689 value = tp_asv_get_string(params, "transport");
690 if (sipe_strequal(value, "auto")) {
691 conn->transport = conn->server ?
692 SIPE_TRANSPORT_TLS : SIPE_TRANSPORT_AUTO;
693 } else if (sipe_strequal(value, "tls")) {
694 conn->transport = SIPE_TRANSPORT_TLS;
695 } else {
696 conn->transport = SIPE_TRANSPORT_TCP;
699 /* User-Agent: override */
700 value = tp_asv_get_string(params, "useragent");
701 if (value && strlen(value))
702 conn->user_agent = g_strdup(value);
703 else
704 conn->user_agent = NULL;
706 /* authentication type */
707 value = tp_asv_get_string(params, "authentication");
708 if (value && strlen(value) && strcmp(value, "ntlm"))
709 conn->authentication = g_strdup(value);
710 else
711 conn->authentication = NULL; /* NTLM is default */
713 return(TP_BASE_CONNECTION(conn));
716 void sipe_telepathy_connection_alias_updated(TpBaseConnection *connection,
717 guint contact,
718 const gchar *alias)
720 GPtrArray *aliases = g_ptr_array_sized_new(1);
721 GValueArray *pair = g_value_array_new(2);
723 g_value_array_append(pair, NULL);
724 g_value_array_append(pair, NULL);
725 g_value_init(pair->values + 0, G_TYPE_UINT);
726 g_value_init(pair->values + 1, G_TYPE_STRING);
727 g_value_set_uint(pair->values + 0, contact);
728 g_value_set_string(pair->values + 1, alias);
729 g_ptr_array_add(aliases, pair);
731 tp_svc_connection_interface_aliasing_emit_aliases_changed(SIPE_CONNECTION(connection),
732 aliases);
734 g_ptr_array_unref(aliases);
735 g_value_array_free(pair);
738 struct sipe_backend_private *sipe_telepathy_connection_private(GObject *object)
740 SipeConnection *self = SIPE_CONNECTION(object);
741 /* connected to core already? */
742 if (self->private.public)
743 return(&self->private);
744 else
745 return(NULL);
749 * Backend adaptor functions
751 void sipe_backend_connection_completed(struct sipe_core_public *sipe_public)
753 SipeConnection *self = SIPE_PUBLIC_TO_CONNECTION;
754 TpBaseConnection *base = TP_BASE_CONNECTION(self);
756 /* we are only allowed to do this once */
757 if (base->status != TP_CONNECTION_STATUS_CONNECTED)
758 tp_base_connection_change_status(base,
759 TP_CONNECTION_STATUS_CONNECTED,
760 TP_CONNECTION_STATUS_REASON_REQUESTED);
763 void sipe_backend_connection_error(struct sipe_core_public *sipe_public,
764 sipe_connection_error error,
765 const gchar *msg)
767 SipeConnection *self = SIPE_PUBLIC_TO_CONNECTION;
768 TpBaseConnection *base = TP_BASE_CONNECTION(self);
769 GHashTable *details = tp_asv_new("server-message", G_TYPE_STRING, msg,
770 NULL);
771 TpConnectionStatusReason reason;
772 const gchar *name;
774 self->is_disconnecting = TRUE;
776 switch (error) {
777 case SIPE_CONNECTION_ERROR_NETWORK:
778 reason = TP_CONNECTION_STATUS_REASON_NETWORK_ERROR;
779 if (base->status == TP_CONNECTION_STATUS_CONNECTING)
780 name = TP_ERROR_STR_CONNECTION_FAILED;
781 else
782 name = TP_ERROR_STR_CONNECTION_LOST;
783 break;
785 case SIPE_CONNECTION_ERROR_INVALID_USERNAME:
786 case SIPE_CONNECTION_ERROR_INVALID_SETTINGS:
787 case SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED:
788 case SIPE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE:
789 /* copied from haze code. I agree there should be better ones */
790 reason = TP_CONNECTION_STATUS_REASON_AUTHENTICATION_FAILED;
791 name = TP_ERROR_STR_AUTHENTICATION_FAILED;
792 break;
794 default:
795 reason = TP_CONNECTION_STATUS_REASON_NONE_SPECIFIED;
796 name = TP_ERROR_STR_DISCONNECTED;
797 break;
800 SIPE_DEBUG_ERROR("sipe_backend_connection_error: %s (%s)", name, msg);
801 tp_base_connection_disconnect_with_dbus_error(base,
802 name,
803 details,
804 reason);
805 g_hash_table_unref(details);
808 gboolean sipe_backend_connection_is_disconnecting(struct sipe_core_public *sipe_public)
810 SipeConnection *self = SIPE_PUBLIC_TO_CONNECTION;
812 /* disconnect was requested or transport was already disconnected */
813 return(self->is_disconnecting ||
814 self->private.transport == NULL);
817 gboolean sipe_backend_connection_is_valid(struct sipe_core_public *sipe_public)
819 return(!sipe_backend_connection_is_disconnecting(sipe_public));
822 const gchar *sipe_backend_setting(struct sipe_core_public *sipe_public,
823 sipe_setting type)
825 SipeConnection *self = SIPE_PUBLIC_TO_CONNECTION;
826 const gchar *value;
828 switch (type) {
829 case SIPE_SETTING_USER_AGENT:
830 value = self->user_agent;
831 break;
832 default:
833 /* @TODO: update when settings are implemented */
834 value = NULL;
835 break;
838 return(value);
843 Local Variables:
844 mode: c
845 c-file-style: "bsd"
846 indent-tabs-mode: t
847 tab-width: 8
848 End: