telepathy: add Single Sign-On account parameter
[siplcs.git] / src / telepathy / telepathy-connection.c
blob9c377a7a03ba347950a331001d2c7343ea46892f
1 /**
2 * @file telepathy-connection.c
4 * pidgin-sipe
6 * Copyright (C) 2012-2013 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>
28 #include <sys/stat.h>
30 #include <glib-object.h>
31 #include <glib/gstdio.h>
32 #include <telepathy-glib/base-connection.h>
33 #include <telepathy-glib/base-protocol.h>
34 #include <telepathy-glib/contacts-mixin.h>
35 #include <telepathy-glib/handle-repo-dynamic.h>
36 #include <telepathy-glib/presence-mixin.h>
37 #include <telepathy-glib/simple-password-manager.h>
38 #include <telepathy-glib/telepathy-glib.h>
40 #include "sipe-backend.h"
41 #include "sipe-common.h"
42 #include "sipe-core.h"
44 #include "telepathy-private.h"
46 G_BEGIN_DECLS
48 * Connection class - data structures
50 typedef struct _SipeConnectionClass {
51 TpBaseConnectionClass parent_class;
52 TpDBusPropertiesMixinClass properties_mixin;
53 TpContactsMixinClass contacts_mixin;
54 TpPresenceMixinClass presence_mixin;
55 } SipeConnectionClass;
57 typedef struct _SipeConnection {
58 TpBaseConnection parent;
59 TpContactsMixinClass contacts_mixin;
60 TpPresenceMixin presence_mixin;
62 /* channel managers */
63 TpSimplePasswordManager *password_manager;
64 struct _SipeContactList *contact_list;
65 struct _SipeTLSManager *tls_manager;
67 struct sipe_backend_private private;
68 gchar *account;
69 gchar *login;
70 gchar *password;
71 gchar *server;
72 gchar *port;
73 guint transport;
74 guint authentication_type;
75 gchar *user_agent;
76 gchar *authentication;
77 gboolean sso;
78 gboolean is_disconnecting;
80 GPtrArray *contact_info_fields;
81 } SipeConnection;
83 #define SIPE_PUBLIC_TO_CONNECTION sipe_public->backend_private->connection
86 * Connection class - type macros
88 static GType sipe_connection_get_type(void) G_GNUC_CONST;
89 #define SIPE_TYPE_CONNECTION \
90 (sipe_connection_get_type())
91 #define SIPE_CONNECTION(obj) \
92 (G_TYPE_CHECK_INSTANCE_CAST((obj), SIPE_TYPE_CONNECTION, \
93 SipeConnection))
94 G_END_DECLS
97 * Connection class - type definition
99 static void init_aliasing (gpointer, gpointer);
100 G_DEFINE_TYPE_WITH_CODE(SipeConnection,
101 sipe_connection,
102 TP_TYPE_BASE_CONNECTION,
103 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_ALIASING,
104 init_aliasing);
105 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_AVATARS,
106 sipe_telepathy_avatars_iface_init);
107 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACTS,
108 tp_contacts_mixin_iface_init);
109 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACT_GROUPS,
110 tp_base_contact_list_mixin_groups_iface_init);
111 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACT_INFO,
112 sipe_telepathy_contact_info_iface_init);
113 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACT_LIST,
114 tp_base_contact_list_mixin_list_iface_init);
115 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_PRESENCE,
116 tp_presence_mixin_iface_init);
117 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_SIMPLE_PRESENCE,
118 tp_presence_mixin_simple_presence_iface_init);
119 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_DBUS_PROPERTIES,
120 tp_dbus_properties_mixin_iface_init);
125 * Connection class - instance methods
127 static gchar *normalize_contact(SIPE_UNUSED_PARAMETER TpHandleRepoIface *repo,
128 const gchar *id,
129 SIPE_UNUSED_PARAMETER gpointer context,
130 GError **error)
132 return(sipe_telepathy_protocol_normalize_contact(NULL, id, error));
135 static void create_handle_repos(SIPE_UNUSED_PARAMETER TpBaseConnection *conn,
136 TpHandleRepoIface *repos[NUM_TP_HANDLE_TYPES])
138 repos[TP_HANDLE_TYPE_CONTACT] = tp_dynamic_handle_repo_new(TP_HANDLE_TYPE_CONTACT,
139 normalize_contact,
140 NULL);
143 static gboolean connect_to_core(SipeConnection *self,
144 GError **error)
146 gchar *login_domain = NULL;
147 gchar *login_account = NULL;
148 struct sipe_core_public *sipe_public;
149 const gchar *errmsg;
151 /* login name specified? */
152 if (self->login && strlen(self->login)) {
153 /* Allowed domain-account separators are / or \ */
154 gchar **domain_user = g_strsplit_set(self->login, "/\\", 2);
155 gboolean has_domain = domain_user[1] != NULL;
156 SIPE_DEBUG_INFO("connect_to_core: login '%s'", self->login);
157 login_domain = has_domain ? g_strdup(domain_user[0]) : NULL;
158 login_account = g_strdup(domain_user[has_domain ? 1 : 0]);
159 SIPE_DEBUG_INFO("connect_to_core: auth domain '%s' user '%s'",
160 login_domain ? login_domain : "",
161 login_account);
162 g_strfreev(domain_user);
163 } else {
164 /* No -> duplicate username */
165 login_account = g_strdup(self->account);
168 sipe_public = sipe_core_allocate(self->account,
169 self->sso,
170 login_domain, login_account,
171 self->password,
172 NULL, /* @TODO: email */
173 NULL, /* @TODO: email_url */
174 &errmsg);
175 g_free(login_domain);
176 g_free(login_account);
178 SIPE_DEBUG_INFO("connect_to_core: created %p", sipe_public);
180 if (sipe_public) {
181 struct sipe_backend_private *telepathy_private = &self->private;
183 /* initialize backend private data */
184 sipe_public->backend_private = telepathy_private;
185 telepathy_private->public = sipe_public;
186 telepathy_private->contact_list = self->contact_list;
187 telepathy_private->connection = self;
188 telepathy_private->activity = SIPE_ACTIVITY_UNSET;
189 telepathy_private->cache_dir = g_build_path(G_DIR_SEPARATOR_S,
190 g_get_user_cache_dir(),
191 "telepathy",
192 "sipe",
193 self->account,
194 NULL);
195 telepathy_private->message = NULL;
196 telepathy_private->tls_manager = self->tls_manager;
197 telepathy_private->transport = NULL;
198 telepathy_private->ipaddress = NULL;
200 /* make sure cache directory exists */
201 if (!g_file_test(telepathy_private->cache_dir,
202 G_FILE_TEST_IS_DIR) &&
203 (g_mkdir_with_parents(telepathy_private->cache_dir,
204 S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
205 == 0))
206 SIPE_DEBUG_INFO("connect_to_core: created cache directory %s",
207 telepathy_private->cache_dir);
209 sipe_core_transport_sip_connect(sipe_public,
210 self->transport,
211 self->authentication_type,
212 self->server,
213 self->port);
215 return(TRUE);
216 } else {
217 g_set_error_literal(error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
218 errmsg);
219 return(FALSE);
223 static void password_manager_cb(GObject *source,
224 GAsyncResult *result,
225 gpointer data)
227 SipeConnection *self = data;
228 TpBaseConnection *base = TP_BASE_CONNECTION(self);
229 GError *error = NULL;
230 const GString *password = tp_simple_password_manager_prompt_finish(
231 TP_SIMPLE_PASSWORD_MANAGER(source),
232 result,
233 &error);
235 if (password == NULL) {
236 SIPE_DEBUG_ERROR("password_manager_cb: failed: %s",
237 error ? error->message : "UNKNOWN");
239 if (base->status != TP_CONNECTION_STATUS_DISCONNECTED) {
240 tp_base_connection_disconnect_with_dbus_error(base,
241 error ? tp_error_get_dbus_name(error->code) : "",
242 NULL,
243 TP_CONNECTION_STATUS_REASON_AUTHENTICATION_FAILED);
245 g_error_free(error);
246 } else {
248 g_free(self->password);
249 self->password = g_strdup(password->str);
251 if (!connect_to_core(self, &error)) {
252 if (base->status != TP_CONNECTION_STATUS_DISCONNECTED) {
253 tp_base_connection_disconnect_with_dbus_error(base,
254 tp_error_get_dbus_name(error->code),
255 NULL,
256 TP_CONNECTION_STATUS_REASON_AUTHENTICATION_FAILED);
258 g_error_free(error);
263 static gboolean start_connecting(TpBaseConnection *base,
264 GError **error)
266 SipeConnection *self = SIPE_CONNECTION(base);
267 gboolean rc = TRUE;
268 gchar *uri = sipe_telepathy_protocol_normalize_contact(NULL,
269 self->account,
270 error);
272 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::start_connecting");
274 /* set up mandatory self-handle */
275 if (uri) {
276 base->self_handle = tp_handle_ensure(tp_base_connection_get_handles(base,
277 TP_HANDLE_TYPE_CONTACT),
278 uri,
279 NULL,
280 error);
281 g_free(uri);
282 if (!base->self_handle) {
283 SIPE_DEBUG_ERROR("SipeConnection::start_connecting: self handle creation failed: %s",
284 (*error)->message);
285 return(FALSE);
287 } else {
288 SIPE_DEBUG_ERROR("SipeConnection::start_connecting: %s",
289 (*error)->message);
290 return(FALSE);
293 tp_base_connection_change_status(base, TP_CONNECTION_STATUS_CONNECTING,
294 TP_CONNECTION_STATUS_REASON_REQUESTED);
296 /* map option list to flags - default is NTLM */
297 self->authentication_type = SIPE_AUTHENTICATION_TYPE_NTLM;
298 #ifdef HAVE_LIBKRB5
299 if (sipe_strequal(self->authentication, "krb5")) {
300 SIPE_DEBUG_INFO_NOFORMAT("start_connecting: KRB5 selected");
301 self->authentication_type = SIPE_AUTHENTICATION_TYPE_KERBEROS;
302 } else
303 #endif
304 if (sipe_strequal(self->authentication, "tls-dsk")) {
305 SIPE_DEBUG_INFO_NOFORMAT("start_connecting: TLS-DSK selected");
306 self->authentication_type = SIPE_AUTHENTICATION_TYPE_TLS_DSK;
309 /* Only ask for a password when required */
310 if (!sipe_core_transport_sip_requires_password(self->authentication_type,
311 self->sso) ||
312 (self->password && strlen(self->password)))
313 rc = connect_to_core(self, error);
314 else {
315 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::start_connecting: requesting password from user");
316 tp_simple_password_manager_prompt_async(self->password_manager,
317 password_manager_cb,
318 self);
321 return(rc);
324 static gboolean disconnect_from_core(gpointer data)
326 TpBaseConnection *base = data;
327 SipeConnection *self = SIPE_CONNECTION(base);
328 struct sipe_backend_private *telepathy_private = &self->private;
329 struct sipe_core_public *sipe_public = telepathy_private->public;
331 SIPE_DEBUG_INFO("disconnect_from_core: %p", sipe_public);
333 if (sipe_public)
334 sipe_core_deallocate(sipe_public);
335 telepathy_private->public = NULL;
336 telepathy_private->transport = NULL;
338 g_free(telepathy_private->ipaddress);
339 telepathy_private->ipaddress = NULL;
341 g_free(telepathy_private->message);
342 telepathy_private->message = NULL;
344 g_free(telepathy_private->cache_dir);
345 telepathy_private->cache_dir = NULL;
347 SIPE_DEBUG_INFO_NOFORMAT("disconnect_from_core: core deallocated");
349 /* now it is OK to destroy the connection object */
350 tp_base_connection_finish_shutdown(base);
352 return(FALSE);
355 static void shut_down(TpBaseConnection *base)
357 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::shut_down");
359 /* this can be called synchronously, defer destruction */
360 g_idle_add(disconnect_from_core, base);
363 static GPtrArray *create_channel_managers(TpBaseConnection *base)
365 SipeConnection *self = SIPE_CONNECTION(base);
366 GPtrArray *channel_managers = g_ptr_array_new();
368 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::create_channel_managers");
370 self->contact_list = sipe_telepathy_contact_list_new(base);
371 g_ptr_array_add(channel_managers, self->contact_list);
373 self->password_manager = tp_simple_password_manager_new(base);
374 g_ptr_array_add(channel_managers, self->password_manager);
376 g_ptr_array_add(channel_managers, sipe_telepathy_search_new(base));
378 self->tls_manager = sipe_telepathy_tls_new(base);
379 g_ptr_array_add(channel_managers, self->tls_manager);
381 return(channel_managers);
384 static void aliasing_fill_contact_attributes(GObject *object,
385 const GArray *contacts,
386 GHashTable *attributes)
388 SipeConnection *self = SIPE_CONNECTION(object);
389 guint i;
391 for (i = 0; i < contacts->len; i++) {
392 TpHandle contact = g_array_index(contacts, guint, i);
394 tp_contacts_mixin_set_contact_attribute(attributes,
395 contact,
396 TP_TOKEN_CONNECTION_INTERFACE_ALIASING_ALIAS,
397 tp_g_value_slice_new_string(
398 sipe_telepathy_buddy_get_alias(self->contact_list,
399 contact)));
403 static void avatars_fill_contact_attributes(GObject *object,
404 const GArray *contacts,
405 GHashTable *attributes)
407 SipeConnection *self = SIPE_CONNECTION(object);
408 guint i;
410 for (i = 0; i < contacts->len; i++) {
411 TpHandle contact = g_array_index(contacts, guint, i);
412 const gchar *hash = sipe_telepathy_buddy_get_hash(self->contact_list,
413 contact);
415 if (!hash) hash = "";
416 tp_contacts_mixin_set_contact_attribute(attributes,
417 contact,
418 TP_IFACE_CONNECTION_INTERFACE_AVATARS"/token",
419 tp_g_value_slice_new_string(hash));
423 static void contact_info_properties_getter(GObject *object,
424 SIPE_UNUSED_PARAMETER GQuark interface,
425 GQuark name,
426 GValue *value,
427 gpointer getter_data)
429 GQuark fields = g_quark_from_static_string("SupportedFields");
431 if (name == fields)
432 g_value_set_boxed(value,
433 SIPE_CONNECTION(object)->contact_info_fields);
434 else
435 g_value_set_uint(value,
436 GPOINTER_TO_UINT(getter_data));
439 static void sipe_connection_constructed(GObject *object)
441 SipeConnection *self = SIPE_CONNECTION(object);
442 TpBaseConnection *base = TP_BASE_CONNECTION(object);
443 void (*chain_up)(GObject *) = G_OBJECT_CLASS(sipe_connection_parent_class)->constructed;
445 if (chain_up)
446 chain_up(object);
448 tp_contacts_mixin_init(object,
449 G_STRUCT_OFFSET(SipeConnection, contacts_mixin));
450 tp_base_connection_register_with_contacts_mixin(base);
452 tp_base_contact_list_mixin_register_with_contacts_mixin(base);
454 tp_contacts_mixin_add_contact_attributes_iface(object,
455 TP_IFACE_CONNECTION_INTERFACE_ALIASING,
456 aliasing_fill_contact_attributes);
457 tp_contacts_mixin_add_contact_attributes_iface(object,
458 TP_IFACE_CONNECTION_INTERFACE_AVATARS,
459 avatars_fill_contact_attributes);
461 tp_presence_mixin_init(object,
462 G_STRUCT_OFFSET(SipeConnection,
463 presence_mixin));
464 tp_presence_mixin_simple_presence_register_with_contacts_mixin(object);
466 self->contact_info_fields = sipe_telepathy_contact_info_fields();
469 static void sipe_connection_finalize(GObject *object)
471 SipeConnection *self = SIPE_CONNECTION(object);
473 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::finalize");
475 tp_contacts_mixin_finalize(object);
476 tp_presence_mixin_finalize(object);
477 g_boxed_free(TP_ARRAY_TYPE_FIELD_SPECS, self->contact_info_fields);
479 g_free(self->authentication);
480 g_free(self->user_agent);
481 g_free(self->port);
482 g_free(self->server);
483 g_free(self->password);
484 g_free(self->login);
485 g_free(self->account);
487 G_OBJECT_CLASS(sipe_connection_parent_class)->finalize(object);
491 * Connection class - type implementation
493 static const gchar *interfaces_always_present[] = {
494 /* @TODO */
495 TP_IFACE_CONNECTION_INTERFACE_ALIASING,
496 TP_IFACE_CONNECTION_INTERFACE_AVATARS,
497 TP_IFACE_CONNECTION_INTERFACE_CONTACT_GROUPS,
498 TP_IFACE_CONNECTION_INTERFACE_CONTACT_INFO,
499 TP_IFACE_CONNECTION_INTERFACE_CONTACT_LIST,
500 TP_IFACE_CONNECTION_INTERFACE_CONTACTS,
501 TP_IFACE_CONNECTION_INTERFACE_PRESENCE,
502 TP_IFACE_CONNECTION_INTERFACE_REQUESTS,
503 TP_IFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE,
504 NULL
507 static void sipe_connection_class_init(SipeConnectionClass *klass)
509 GObjectClass *object_class = G_OBJECT_CLASS(klass);
510 TpBaseConnectionClass *base_class = TP_BASE_CONNECTION_CLASS(klass);
511 static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = {
513 /* 0 */
514 .name = TP_IFACE_CONNECTION_INTERFACE_CONTACT_INFO,
515 .getter = contact_info_properties_getter,
516 .setter = NULL,
519 /* LAST! */
520 .name = NULL,
524 /* initalize non-constant fields */
525 prop_interfaces[0].props = sipe_telepathy_contact_info_props();
527 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::class_init");
529 object_class->constructed = sipe_connection_constructed;
530 object_class->finalize = sipe_connection_finalize;
532 base_class->create_handle_repos = create_handle_repos;
533 base_class->start_connecting = start_connecting;
534 base_class->shut_down = shut_down;
535 base_class->create_channel_managers = create_channel_managers;
537 base_class->interfaces_always_present = interfaces_always_present;
539 klass->properties_mixin.interfaces = prop_interfaces;
540 tp_dbus_properties_mixin_class_init(object_class,
541 G_STRUCT_OFFSET(SipeConnectionClass,
542 properties_mixin));
543 tp_contacts_mixin_class_init(object_class,
544 G_STRUCT_OFFSET(SipeConnectionClass,
545 contacts_mixin));
546 sipe_telepathy_status_init(object_class,
547 G_STRUCT_OFFSET(SipeConnectionClass,
548 presence_mixin));
549 tp_presence_mixin_simple_presence_init_dbus_properties(object_class);
550 tp_base_contact_list_mixin_class_init(base_class);
553 static void sipe_connection_init(SIPE_UNUSED_PARAMETER SipeConnection *self)
555 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::init");
559 * Connection class - interface implementation
561 * Contact aliases
563 static void get_alias_flags(TpSvcConnectionInterfaceAliasing *aliasing,
564 DBusGMethodInvocation *context)
566 TpBaseConnection *base = TP_BASE_CONNECTION(aliasing);
568 TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED(base, context);
569 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::get_alias_flags called");
571 tp_svc_connection_interface_aliasing_return_from_get_alias_flags(context,
572 TP_CONNECTION_ALIAS_FLAG_USER_SET);
575 static void get_aliases(TpSvcConnectionInterfaceAliasing *aliasing,
576 const GArray *contacts,
577 DBusGMethodInvocation *context)
579 SipeConnection *self = SIPE_CONNECTION(aliasing);
580 TpBaseConnection *base = TP_BASE_CONNECTION(aliasing);
581 TpHandleRepoIface *contact_repo = tp_base_connection_get_handles(base,
582 TP_HANDLE_TYPE_CONTACT);
583 GError *error = NULL;
584 GHashTable *result;
585 guint i;
587 TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED(base, context);
588 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::get_aliases called");
590 if (!tp_handles_are_valid(contact_repo, contacts, FALSE, &error)) {
591 dbus_g_method_return_error(context, error);
592 g_error_free(error);
593 return;
596 result = g_hash_table_new(g_direct_hash, g_direct_equal);
598 for (i = 0; i < contacts->len; i++) {
599 TpHandle contact = g_array_index(contacts, TpHandle, i);
600 const gchar *alias = sipe_telepathy_buddy_get_alias(self->contact_list,
601 contact);
602 g_hash_table_insert(result,
603 GUINT_TO_POINTER(contact),
604 (gchar *) alias);
607 tp_svc_connection_interface_aliasing_return_from_get_aliases(context,
608 result);
609 g_hash_table_unref(result);
612 static void request_aliases(TpSvcConnectionInterfaceAliasing *aliasing,
613 const GArray *contacts,
614 DBusGMethodInvocation *context)
616 SipeConnection *self = SIPE_CONNECTION(aliasing);
617 TpBaseConnection *base = TP_BASE_CONNECTION(aliasing);
618 TpHandleRepoIface *contact_repo = tp_base_connection_get_handles(base,
619 TP_HANDLE_TYPE_CONTACT);
620 GError *error = NULL;
621 GPtrArray *result;
622 gchar **strings;
623 guint i;
625 TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED(base, context);
626 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::request_aliases called");
628 if (!tp_handles_are_valid(contact_repo, contacts, FALSE, &error)) {
629 dbus_g_method_return_error(context, error);
630 g_error_free(error);
631 return;
634 result = g_ptr_array_sized_new(contacts->len + 1);
636 for (i = 0; i < contacts->len; i++) {
637 TpHandle contact = g_array_index(contacts, TpHandle, i);
638 const gchar *alias = sipe_telepathy_buddy_get_alias(self->contact_list,
639 contact);
640 g_ptr_array_add(result, (gchar *) alias);
643 g_ptr_array_add(result, NULL);
644 strings = (gchar **) g_ptr_array_free(result, FALSE);
646 tp_svc_connection_interface_aliasing_return_from_request_aliases(context,
647 (const gchar **) strings);
648 g_free(strings);
651 static void set_aliases(TpSvcConnectionInterfaceAliasing *aliasing,
652 GHashTable *aliases,
653 DBusGMethodInvocation *context)
655 SipeConnection *self = SIPE_CONNECTION(aliasing);
656 TpBaseConnection *base = TP_BASE_CONNECTION(aliasing);
657 TpHandleRepoIface *contact_repo = tp_base_connection_get_handles(base,
658 TP_HANDLE_TYPE_CONTACT);
659 GHashTableIter iter;
660 gpointer key, value;
662 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::set_aliases called");
664 g_hash_table_iter_init(&iter, aliases);
666 while (g_hash_table_iter_next(&iter, &key, NULL)) {
667 GError *error = NULL;
669 if (!tp_handle_is_valid(contact_repo,
670 GPOINTER_TO_UINT(key),
671 &error)) {
672 dbus_g_method_return_error(context, error);
673 g_error_free(error);
674 return;
678 g_hash_table_iter_init(&iter, aliases);
680 while (g_hash_table_iter_next(&iter, &key, &value)) {
681 sipe_telepathy_buddy_set_alias(self->contact_list,
682 GPOINTER_TO_UINT(key),
683 value);
686 tp_svc_connection_interface_aliasing_return_from_set_aliases(context);
689 static void init_aliasing(gpointer iface,
690 SIPE_UNUSED_PARAMETER gpointer iface_data)
692 TpSvcConnectionInterfaceAliasingClass *klass = iface;
694 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::init_aliasing called");
696 tp_svc_connection_interface_aliasing_implement_get_alias_flags(klass, get_alias_flags);
697 tp_svc_connection_interface_aliasing_implement_request_aliases(klass, request_aliases);
698 tp_svc_connection_interface_aliasing_implement_get_aliases(klass, get_aliases);
699 tp_svc_connection_interface_aliasing_implement_set_aliases(klass, set_aliases);
702 /* create new connection object */
703 TpBaseConnection *sipe_telepathy_connection_new(TpBaseProtocol *protocol,
704 GHashTable *params,
705 SIPE_UNUSED_PARAMETER GError **error)
707 SipeConnection *conn = g_object_new(SIPE_TYPE_CONNECTION,
708 "protocol", tp_base_protocol_get_name(protocol),
709 NULL);
710 const gchar *value;
711 guint port;
712 gboolean boolean_value;
713 gboolean valid;
715 SIPE_DEBUG_INFO_NOFORMAT("sipe_telepathy_connection_new");
717 /* initialize private fields */
718 conn->is_disconnecting = FALSE;
720 /* account & login are required fields */
721 conn->account = g_strdup(tp_asv_get_string(params, "account"));
722 conn->login = g_strdup(tp_asv_get_string(params, "login"));
724 /* password */
725 value = tp_asv_get_string(params, "password");
726 if (value && strlen(value))
727 conn->password = g_strdup(value);
728 else
729 conn->password = NULL;
731 /* server name */
732 value = tp_asv_get_string(params, "server");
733 if (value && strlen(value))
734 conn->server = g_strdup(value);
735 else
736 conn->server = NULL;
738 /* server port: core expects a string */
739 port = tp_asv_get_uint32(params, "port", &valid);
740 if (valid)
741 conn->port = g_strdup_printf("%d", port);
742 else
743 conn->port = NULL;
745 /* transport type */
746 value = tp_asv_get_string(params, "transport");
747 if (sipe_strequal(value, "auto")) {
748 conn->transport = conn->server ?
749 SIPE_TRANSPORT_TLS : SIPE_TRANSPORT_AUTO;
750 } else if (sipe_strequal(value, "tls")) {
751 conn->transport = SIPE_TRANSPORT_TLS;
752 } else {
753 conn->transport = SIPE_TRANSPORT_TCP;
756 /* User-Agent: override */
757 value = tp_asv_get_string(params, "useragent");
758 if (value && strlen(value))
759 conn->user_agent = g_strdup(value);
760 else
761 conn->user_agent = NULL;
763 /* authentication type */
764 value = tp_asv_get_string(params, "authentication");
765 if (value && strlen(value) && strcmp(value, "ntlm"))
766 conn->authentication = g_strdup(value);
767 else
768 conn->authentication = NULL; /* NTLM is default */
770 /* Single Sign-On */
771 boolean_value = tp_asv_get_boolean(params, "single-sign-on", &valid);
772 if (valid)
773 conn->sso = boolean_value;
774 else
775 conn->sso = FALSE;
777 return(TP_BASE_CONNECTION(conn));
780 void sipe_telepathy_connection_alias_updated(TpBaseConnection *connection,
781 guint contact,
782 const gchar *alias)
784 GPtrArray *aliases = g_ptr_array_sized_new(1);
785 GValueArray *pair = g_value_array_new(2);
787 g_value_array_append(pair, NULL);
788 g_value_array_append(pair, NULL);
789 g_value_init(pair->values + 0, G_TYPE_UINT);
790 g_value_init(pair->values + 1, G_TYPE_STRING);
791 g_value_set_uint(pair->values + 0, contact);
792 g_value_set_string(pair->values + 1, alias);
793 g_ptr_array_add(aliases, pair);
795 tp_svc_connection_interface_aliasing_emit_aliases_changed(SIPE_CONNECTION(connection),
796 aliases);
798 g_ptr_array_unref(aliases);
799 g_value_array_free(pair);
802 struct sipe_backend_private *sipe_telepathy_connection_private(GObject *object)
804 SipeConnection *self = SIPE_CONNECTION(object);
805 /* connected to core already? */
806 if (self->private.public)
807 return(&self->private);
808 else
809 return(NULL);
813 * Backend adaptor functions
815 void sipe_backend_connection_completed(struct sipe_core_public *sipe_public)
817 SipeConnection *self = SIPE_PUBLIC_TO_CONNECTION;
818 TpBaseConnection *base = TP_BASE_CONNECTION(self);
820 /* we are only allowed to do this once */
821 if (base->status != TP_CONNECTION_STATUS_CONNECTED)
822 tp_base_connection_change_status(base,
823 TP_CONNECTION_STATUS_CONNECTED,
824 TP_CONNECTION_STATUS_REASON_REQUESTED);
827 void sipe_backend_connection_error(struct sipe_core_public *sipe_public,
828 sipe_connection_error error,
829 const gchar *msg)
831 SipeConnection *self = SIPE_PUBLIC_TO_CONNECTION;
832 TpBaseConnection *base = TP_BASE_CONNECTION(self);
833 GHashTable *details = tp_asv_new("server-message", G_TYPE_STRING, msg,
834 NULL);
835 TpConnectionStatusReason reason;
836 const gchar *name;
838 self->is_disconnecting = TRUE;
840 switch (error) {
841 case SIPE_CONNECTION_ERROR_NETWORK:
842 reason = TP_CONNECTION_STATUS_REASON_NETWORK_ERROR;
843 if (base->status == TP_CONNECTION_STATUS_CONNECTING)
844 name = TP_ERROR_STR_CONNECTION_FAILED;
845 else
846 name = TP_ERROR_STR_CONNECTION_LOST;
847 break;
849 case SIPE_CONNECTION_ERROR_INVALID_USERNAME:
850 case SIPE_CONNECTION_ERROR_INVALID_SETTINGS:
851 case SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED:
852 case SIPE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE:
853 /* copied from haze code. I agree there should be better ones */
854 reason = TP_CONNECTION_STATUS_REASON_AUTHENTICATION_FAILED;
855 name = TP_ERROR_STR_AUTHENTICATION_FAILED;
856 break;
858 default:
859 reason = TP_CONNECTION_STATUS_REASON_NONE_SPECIFIED;
860 name = TP_ERROR_STR_DISCONNECTED;
861 break;
864 SIPE_DEBUG_ERROR("sipe_backend_connection_error: %s (%s)", name, msg);
865 tp_base_connection_disconnect_with_dbus_error(base,
866 name,
867 details,
868 reason);
869 g_hash_table_unref(details);
872 gboolean sipe_backend_connection_is_disconnecting(struct sipe_core_public *sipe_public)
874 SipeConnection *self = SIPE_PUBLIC_TO_CONNECTION;
876 /* disconnect was requested or transport was already disconnected */
877 return(self->is_disconnecting ||
878 self->private.transport == NULL);
881 gboolean sipe_backend_connection_is_valid(struct sipe_core_public *sipe_public)
883 return(!sipe_backend_connection_is_disconnecting(sipe_public));
886 const gchar *sipe_backend_setting(struct sipe_core_public *sipe_public,
887 sipe_setting type)
889 SipeConnection *self = SIPE_PUBLIC_TO_CONNECTION;
890 const gchar *value;
892 switch (type) {
893 case SIPE_SETTING_USER_AGENT:
894 value = self->user_agent;
895 break;
896 default:
897 /* @TODO: update when settings are implemented */
898 value = NULL;
899 break;
902 return(value);
907 Local Variables:
908 mode: c
909 c-file-style: "bsd"
910 indent-tabs-mode: t
911 tab-width: 8
912 End: