telepathy: add TLS manager class
[siplcs.git] / src / telepathy / telepathy-connection.c
blob09e9fbf20afefc386e946bddfe0493ec5de41bcc
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;
66 struct sipe_backend_private private;
67 gchar *account;
68 gchar *login;
69 gchar *password;
70 gchar *server;
71 gchar *port;
72 guint transport;
73 guint authentication_type;
74 gchar *user_agent;
75 gchar *authentication;
76 gboolean is_disconnecting;
78 GPtrArray *contact_info_fields;
79 } SipeConnection;
81 #define SIPE_PUBLIC_TO_CONNECTION sipe_public->backend_private->connection
84 * Connection class - type macros
86 static GType sipe_connection_get_type(void) G_GNUC_CONST;
87 #define SIPE_TYPE_CONNECTION \
88 (sipe_connection_get_type())
89 #define SIPE_CONNECTION(obj) \
90 (G_TYPE_CHECK_INSTANCE_CAST((obj), SIPE_TYPE_CONNECTION, \
91 SipeConnection))
92 G_END_DECLS
95 * Connection class - type definition
97 static void init_aliasing (gpointer, gpointer);
98 G_DEFINE_TYPE_WITH_CODE(SipeConnection,
99 sipe_connection,
100 TP_TYPE_BASE_CONNECTION,
101 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_ALIASING,
102 init_aliasing);
103 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_AVATARS,
104 sipe_telepathy_avatars_iface_init);
105 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACTS,
106 tp_contacts_mixin_iface_init);
107 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACT_GROUPS,
108 tp_base_contact_list_mixin_groups_iface_init);
109 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACT_INFO,
110 sipe_telepathy_contact_info_iface_init);
111 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACT_LIST,
112 tp_base_contact_list_mixin_list_iface_init);
113 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_PRESENCE,
114 tp_presence_mixin_iface_init);
115 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_SIMPLE_PRESENCE,
116 tp_presence_mixin_simple_presence_iface_init);
117 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_DBUS_PROPERTIES,
118 tp_dbus_properties_mixin_iface_init);
123 * Connection class - instance methods
125 static gchar *normalize_contact(SIPE_UNUSED_PARAMETER TpHandleRepoIface *repo,
126 const gchar *id,
127 SIPE_UNUSED_PARAMETER gpointer context,
128 GError **error)
130 return(sipe_telepathy_protocol_normalize_contact(NULL, id, error));
133 static void create_handle_repos(SIPE_UNUSED_PARAMETER TpBaseConnection *conn,
134 TpHandleRepoIface *repos[NUM_TP_HANDLE_TYPES])
136 repos[TP_HANDLE_TYPE_CONTACT] = tp_dynamic_handle_repo_new(TP_HANDLE_TYPE_CONTACT,
137 normalize_contact,
138 NULL);
141 static gboolean connect_to_core(SipeConnection *self,
142 GError **error)
144 gchar *login_domain = NULL;
145 gchar *login_account = NULL;
146 struct sipe_core_public *sipe_public;
147 const gchar *errmsg;
149 /* login name specified? */
150 if (self->login && strlen(self->login)) {
151 /* Allowed domain-account separators are / or \ */
152 gchar **domain_user = g_strsplit_set(self->login, "/\\", 2);
153 gboolean has_domain = domain_user[1] != NULL;
154 SIPE_DEBUG_INFO("connect_to_core: login '%s'", self->login);
155 login_domain = has_domain ? g_strdup(domain_user[0]) : NULL;
156 login_account = g_strdup(domain_user[has_domain ? 1 : 0]);
157 SIPE_DEBUG_INFO("connect_to_core: auth domain '%s' user '%s'",
158 login_domain ? login_domain : "",
159 login_account);
160 g_strfreev(domain_user);
161 } else {
162 /* No -> duplicate username */
163 login_account = g_strdup(self->account);
166 sipe_public = sipe_core_allocate(self->account,
167 /* @TODO: add parameter for SSO */
168 FALSE,
169 login_domain, login_account,
170 self->password,
171 NULL, /* @TODO: email */
172 NULL, /* @TODO: email_url */
173 &errmsg);
174 g_free(login_domain);
175 g_free(login_account);
177 SIPE_DEBUG_INFO("connect_to_core: created %p", sipe_public);
179 if (sipe_public) {
180 struct sipe_backend_private *telepathy_private = &self->private;
182 /* initialize backend private data */
183 sipe_public->backend_private = telepathy_private;
184 telepathy_private->public = sipe_public;
185 telepathy_private->contact_list = self->contact_list;
186 telepathy_private->connection = self;
187 telepathy_private->activity = SIPE_ACTIVITY_UNSET;
188 telepathy_private->cache_dir = g_build_path(G_DIR_SEPARATOR_S,
189 g_get_user_cache_dir(),
190 "telepathy",
191 "sipe",
192 self->account,
193 NULL);
194 telepathy_private->message = NULL;
195 telepathy_private->transport = NULL;
196 telepathy_private->ipaddress = NULL;
198 /* make sure cache directory exists */
199 if (!g_file_test(telepathy_private->cache_dir,
200 G_FILE_TEST_IS_DIR) &&
201 (g_mkdir_with_parents(telepathy_private->cache_dir,
202 S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
203 == 0))
204 SIPE_DEBUG_INFO("connect_to_core: created cache directory %s",
205 telepathy_private->cache_dir);
207 sipe_core_transport_sip_connect(sipe_public,
208 self->transport,
209 self->authentication_type,
210 self->server,
211 self->port);
213 return(TRUE);
214 } else {
215 g_set_error_literal(error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
216 errmsg);
217 return(FALSE);
221 static void password_manager_cb(GObject *source,
222 GAsyncResult *result,
223 gpointer data)
225 SipeConnection *self = data;
226 TpBaseConnection *base = TP_BASE_CONNECTION(self);
227 GError *error = NULL;
228 const GString *password = tp_simple_password_manager_prompt_finish(
229 TP_SIMPLE_PASSWORD_MANAGER(source),
230 result,
231 &error);
233 if (password == NULL) {
234 SIPE_DEBUG_ERROR("password_manager_cb: failed: %s",
235 error ? error->message : "UNKNOWN");
237 if (base->status != TP_CONNECTION_STATUS_DISCONNECTED) {
238 tp_base_connection_disconnect_with_dbus_error(base,
239 error ? tp_error_get_dbus_name(error->code) : "",
240 NULL,
241 TP_CONNECTION_STATUS_REASON_AUTHENTICATION_FAILED);
243 g_error_free(error);
244 } else {
246 g_free(self->password);
247 self->password = g_strdup(password->str);
249 if (!connect_to_core(self, &error)) {
250 if (base->status != TP_CONNECTION_STATUS_DISCONNECTED) {
251 tp_base_connection_disconnect_with_dbus_error(base,
252 tp_error_get_dbus_name(error->code),
253 NULL,
254 TP_CONNECTION_STATUS_REASON_AUTHENTICATION_FAILED);
256 g_error_free(error);
261 static gboolean start_connecting(TpBaseConnection *base,
262 GError **error)
264 SipeConnection *self = SIPE_CONNECTION(base);
265 gboolean rc = TRUE;
266 gchar *uri = sipe_telepathy_protocol_normalize_contact(NULL,
267 self->account,
268 error);
270 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::start_connecting");
272 /* set up mandatory self-handle */
273 if (uri) {
274 base->self_handle = tp_handle_ensure(tp_base_connection_get_handles(base,
275 TP_HANDLE_TYPE_CONTACT),
276 uri,
277 NULL,
278 error);
279 g_free(uri);
280 if (!base->self_handle) {
281 SIPE_DEBUG_ERROR("SipeConnection::start_connecting: self handle creation failed: %s",
282 (*error)->message);
283 return(FALSE);
285 } else {
286 SIPE_DEBUG_ERROR("SipeConnection::start_connecting: %s",
287 (*error)->message);
288 return(FALSE);
291 tp_base_connection_change_status(base, TP_CONNECTION_STATUS_CONNECTING,
292 TP_CONNECTION_STATUS_REASON_REQUESTED);
294 /* map option list to flags - default is NTLM */
295 self->authentication_type = SIPE_AUTHENTICATION_TYPE_NTLM;
296 #ifdef HAVE_LIBKRB5
297 if (sipe_strequal(self->authentication, "krb5")) {
298 SIPE_DEBUG_INFO_NOFORMAT("start_connecting: KRB5 selected");
299 self->authentication_type = SIPE_AUTHENTICATION_TYPE_KERBEROS;
300 } else
301 #endif
302 if (sipe_strequal(self->authentication, "tls-dsk")) {
303 SIPE_DEBUG_INFO_NOFORMAT("start_connecting: TLS-DSK selected");
304 self->authentication_type = SIPE_AUTHENTICATION_TYPE_TLS_DSK;
307 /* Only ask for a password when required */
308 /* @TODO: add parameter for SSO */
309 if (!sipe_core_transport_sip_requires_password(self->authentication_type,
310 FALSE) ||
311 (self->password && strlen(self->password)))
312 rc = connect_to_core(self, error);
313 else {
314 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::start_connecting: requesting password from user");
315 tp_simple_password_manager_prompt_async(self->password_manager,
316 password_manager_cb,
317 self);
320 return(rc);
323 static gboolean disconnect_from_core(gpointer data)
325 TpBaseConnection *base = data;
326 SipeConnection *self = SIPE_CONNECTION(base);
327 struct sipe_backend_private *telepathy_private = &self->private;
328 struct sipe_core_public *sipe_public = telepathy_private->public;
330 SIPE_DEBUG_INFO("disconnect_from_core: %p", sipe_public);
332 if (sipe_public)
333 sipe_core_deallocate(sipe_public);
334 telepathy_private->public = NULL;
335 telepathy_private->transport = NULL;
337 g_free(telepathy_private->ipaddress);
338 telepathy_private->ipaddress = NULL;
340 g_free(telepathy_private->message);
341 telepathy_private->message = NULL;
343 g_free(telepathy_private->cache_dir);
344 telepathy_private->cache_dir = NULL;
346 SIPE_DEBUG_INFO_NOFORMAT("disconnect_from_core: core deallocated");
348 /* now it is OK to destroy the connection object */
349 tp_base_connection_finish_shutdown(base);
351 return(FALSE);
354 static void shut_down(TpBaseConnection *base)
356 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::shut_down");
358 /* this can be called synchronously, defer destruction */
359 g_idle_add(disconnect_from_core, base);
362 static GPtrArray *create_channel_managers(TpBaseConnection *base)
364 SipeConnection *self = SIPE_CONNECTION(base);
365 GPtrArray *channel_managers = g_ptr_array_new();
367 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::create_channel_managers");
369 self->contact_list = sipe_telepathy_contact_list_new(base);
370 g_ptr_array_add(channel_managers, self->contact_list);
372 self->password_manager = tp_simple_password_manager_new(base);
373 g_ptr_array_add(channel_managers, self->password_manager);
375 g_ptr_array_add(channel_managers, sipe_telepathy_search_new(base));
376 g_ptr_array_add(channel_managers, sipe_telepathy_tls_new(base));
378 return(channel_managers);
381 static void aliasing_fill_contact_attributes(GObject *object,
382 const GArray *contacts,
383 GHashTable *attributes)
385 SipeConnection *self = SIPE_CONNECTION(object);
386 guint i;
388 for (i = 0; i < contacts->len; i++) {
389 TpHandle contact = g_array_index(contacts, guint, i);
391 tp_contacts_mixin_set_contact_attribute(attributes,
392 contact,
393 TP_TOKEN_CONNECTION_INTERFACE_ALIASING_ALIAS,
394 tp_g_value_slice_new_string(
395 sipe_telepathy_buddy_get_alias(self->contact_list,
396 contact)));
400 static void avatars_fill_contact_attributes(GObject *object,
401 const GArray *contacts,
402 GHashTable *attributes)
404 SipeConnection *self = SIPE_CONNECTION(object);
405 guint i;
407 for (i = 0; i < contacts->len; i++) {
408 TpHandle contact = g_array_index(contacts, guint, i);
409 const gchar *hash = sipe_telepathy_buddy_get_hash(self->contact_list,
410 contact);
412 if (!hash) hash = "";
413 tp_contacts_mixin_set_contact_attribute(attributes,
414 contact,
415 TP_IFACE_CONNECTION_INTERFACE_AVATARS"/token",
416 tp_g_value_slice_new_string(hash));
420 static void contact_info_properties_getter(GObject *object,
421 SIPE_UNUSED_PARAMETER GQuark interface,
422 GQuark name,
423 GValue *value,
424 gpointer getter_data)
426 GQuark fields = g_quark_from_static_string("SupportedFields");
428 if (name == fields)
429 g_value_set_boxed(value,
430 SIPE_CONNECTION(object)->contact_info_fields);
431 else
432 g_value_set_uint(value,
433 GPOINTER_TO_UINT(getter_data));
436 static void sipe_connection_constructed(GObject *object)
438 SipeConnection *self = SIPE_CONNECTION(object);
439 TpBaseConnection *base = TP_BASE_CONNECTION(object);
440 void (*chain_up)(GObject *) = G_OBJECT_CLASS(sipe_connection_parent_class)->constructed;
442 if (chain_up)
443 chain_up(object);
445 tp_contacts_mixin_init(object,
446 G_STRUCT_OFFSET(SipeConnection, contacts_mixin));
447 tp_base_connection_register_with_contacts_mixin(base);
449 tp_base_contact_list_mixin_register_with_contacts_mixin(base);
451 tp_contacts_mixin_add_contact_attributes_iface(object,
452 TP_IFACE_CONNECTION_INTERFACE_ALIASING,
453 aliasing_fill_contact_attributes);
454 tp_contacts_mixin_add_contact_attributes_iface(object,
455 TP_IFACE_CONNECTION_INTERFACE_AVATARS,
456 avatars_fill_contact_attributes);
458 tp_presence_mixin_init(object,
459 G_STRUCT_OFFSET(SipeConnection,
460 presence_mixin));
461 tp_presence_mixin_simple_presence_register_with_contacts_mixin(object);
463 self->contact_info_fields = sipe_telepathy_contact_info_fields();
466 static void sipe_connection_finalize(GObject *object)
468 SipeConnection *self = SIPE_CONNECTION(object);
470 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::finalize");
472 tp_contacts_mixin_finalize(object);
473 tp_presence_mixin_finalize(object);
474 g_boxed_free(TP_ARRAY_TYPE_FIELD_SPECS, self->contact_info_fields);
476 g_free(self->authentication);
477 g_free(self->user_agent);
478 g_free(self->port);
479 g_free(self->server);
480 g_free(self->password);
481 g_free(self->login);
482 g_free(self->account);
484 G_OBJECT_CLASS(sipe_connection_parent_class)->finalize(object);
488 * Connection class - type implementation
490 static const gchar *interfaces_always_present[] = {
491 /* @TODO */
492 TP_IFACE_CONNECTION_INTERFACE_ALIASING,
493 TP_IFACE_CONNECTION_INTERFACE_AVATARS,
494 TP_IFACE_CONNECTION_INTERFACE_CONTACT_GROUPS,
495 TP_IFACE_CONNECTION_INTERFACE_CONTACT_INFO,
496 TP_IFACE_CONNECTION_INTERFACE_CONTACT_LIST,
497 TP_IFACE_CONNECTION_INTERFACE_CONTACTS,
498 TP_IFACE_CONNECTION_INTERFACE_PRESENCE,
499 TP_IFACE_CONNECTION_INTERFACE_REQUESTS,
500 TP_IFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE,
501 NULL
504 static void sipe_connection_class_init(SipeConnectionClass *klass)
506 GObjectClass *object_class = G_OBJECT_CLASS(klass);
507 TpBaseConnectionClass *base_class = TP_BASE_CONNECTION_CLASS(klass);
508 static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = {
510 /* 0 */
511 .name = TP_IFACE_CONNECTION_INTERFACE_CONTACT_INFO,
512 .getter = contact_info_properties_getter,
513 .setter = NULL,
516 /* LAST! */
517 .name = NULL,
521 /* initalize non-constant fields */
522 prop_interfaces[0].props = sipe_telepathy_contact_info_props();
524 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::class_init");
526 object_class->constructed = sipe_connection_constructed;
527 object_class->finalize = sipe_connection_finalize;
529 base_class->create_handle_repos = create_handle_repos;
530 base_class->start_connecting = start_connecting;
531 base_class->shut_down = shut_down;
532 base_class->create_channel_managers = create_channel_managers;
534 base_class->interfaces_always_present = interfaces_always_present;
536 klass->properties_mixin.interfaces = prop_interfaces;
537 tp_dbus_properties_mixin_class_init(object_class,
538 G_STRUCT_OFFSET(SipeConnectionClass,
539 properties_mixin));
540 tp_contacts_mixin_class_init(object_class,
541 G_STRUCT_OFFSET(SipeConnectionClass,
542 contacts_mixin));
543 sipe_telepathy_status_init(object_class,
544 G_STRUCT_OFFSET(SipeConnectionClass,
545 presence_mixin));
546 tp_presence_mixin_simple_presence_init_dbus_properties(object_class);
547 tp_base_contact_list_mixin_class_init(base_class);
550 static void sipe_connection_init(SIPE_UNUSED_PARAMETER SipeConnection *self)
552 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::init");
556 * Connection class - interface implementation
558 * Contact aliases
560 static void get_alias_flags(TpSvcConnectionInterfaceAliasing *aliasing,
561 DBusGMethodInvocation *context)
563 TpBaseConnection *base = TP_BASE_CONNECTION(aliasing);
565 TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED(base, context);
566 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::get_alias_flags called");
568 tp_svc_connection_interface_aliasing_return_from_get_alias_flags(context,
569 TP_CONNECTION_ALIAS_FLAG_USER_SET);
572 static void get_aliases(TpSvcConnectionInterfaceAliasing *aliasing,
573 const GArray *contacts,
574 DBusGMethodInvocation *context)
576 SipeConnection *self = SIPE_CONNECTION(aliasing);
577 TpBaseConnection *base = TP_BASE_CONNECTION(aliasing);
578 TpHandleRepoIface *contact_repo = tp_base_connection_get_handles(base,
579 TP_HANDLE_TYPE_CONTACT);
580 GError *error = NULL;
581 GHashTable *result;
582 guint i;
584 TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED(base, context);
585 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::get_aliases called");
587 if (!tp_handles_are_valid(contact_repo, contacts, FALSE, &error)) {
588 dbus_g_method_return_error(context, error);
589 g_error_free(error);
590 return;
593 result = g_hash_table_new(g_direct_hash, g_direct_equal);
595 for (i = 0; i < contacts->len; i++) {
596 TpHandle contact = g_array_index(contacts, TpHandle, i);
597 const gchar *alias = sipe_telepathy_buddy_get_alias(self->contact_list,
598 contact);
599 g_hash_table_insert(result,
600 GUINT_TO_POINTER(contact),
601 (gchar *) alias);
604 tp_svc_connection_interface_aliasing_return_from_get_aliases(context,
605 result);
606 g_hash_table_unref(result);
609 static void request_aliases(TpSvcConnectionInterfaceAliasing *aliasing,
610 const GArray *contacts,
611 DBusGMethodInvocation *context)
613 SipeConnection *self = SIPE_CONNECTION(aliasing);
614 TpBaseConnection *base = TP_BASE_CONNECTION(aliasing);
615 TpHandleRepoIface *contact_repo = tp_base_connection_get_handles(base,
616 TP_HANDLE_TYPE_CONTACT);
617 GError *error = NULL;
618 GPtrArray *result;
619 gchar **strings;
620 guint i;
622 TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED(base, context);
623 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::request_aliases called");
625 if (!tp_handles_are_valid(contact_repo, contacts, FALSE, &error)) {
626 dbus_g_method_return_error(context, error);
627 g_error_free(error);
628 return;
631 result = g_ptr_array_sized_new(contacts->len + 1);
633 for (i = 0; i < contacts->len; i++) {
634 TpHandle contact = g_array_index(contacts, TpHandle, i);
635 const gchar *alias = sipe_telepathy_buddy_get_alias(self->contact_list,
636 contact);
637 g_ptr_array_add(result, (gchar *) alias);
640 g_ptr_array_add(result, NULL);
641 strings = (gchar **) g_ptr_array_free(result, FALSE);
643 tp_svc_connection_interface_aliasing_return_from_request_aliases(context,
644 (const gchar **) strings);
645 g_free(strings);
648 static void set_aliases(TpSvcConnectionInterfaceAliasing *aliasing,
649 GHashTable *aliases,
650 DBusGMethodInvocation *context)
652 SipeConnection *self = SIPE_CONNECTION(aliasing);
653 TpBaseConnection *base = TP_BASE_CONNECTION(aliasing);
654 TpHandleRepoIface *contact_repo = tp_base_connection_get_handles(base,
655 TP_HANDLE_TYPE_CONTACT);
656 GHashTableIter iter;
657 gpointer key, value;
659 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::set_aliases called");
661 g_hash_table_iter_init(&iter, aliases);
663 while (g_hash_table_iter_next(&iter, &key, NULL)) {
664 GError *error = NULL;
666 if (!tp_handle_is_valid(contact_repo,
667 GPOINTER_TO_UINT(key),
668 &error)) {
669 dbus_g_method_return_error(context, error);
670 g_error_free(error);
671 return;
675 g_hash_table_iter_init(&iter, aliases);
677 while (g_hash_table_iter_next(&iter, &key, &value)) {
678 sipe_telepathy_buddy_set_alias(self->contact_list,
679 GPOINTER_TO_UINT(key),
680 value);
683 tp_svc_connection_interface_aliasing_return_from_set_aliases(context);
686 static void init_aliasing(gpointer iface,
687 SIPE_UNUSED_PARAMETER gpointer iface_data)
689 TpSvcConnectionInterfaceAliasingClass *klass = iface;
691 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::init_aliasing called");
693 tp_svc_connection_interface_aliasing_implement_get_alias_flags(klass, get_alias_flags);
694 tp_svc_connection_interface_aliasing_implement_request_aliases(klass, request_aliases);
695 tp_svc_connection_interface_aliasing_implement_get_aliases(klass, get_aliases);
696 tp_svc_connection_interface_aliasing_implement_set_aliases(klass, set_aliases);
699 /* create new connection object */
700 TpBaseConnection *sipe_telepathy_connection_new(TpBaseProtocol *protocol,
701 GHashTable *params,
702 SIPE_UNUSED_PARAMETER GError **error)
704 SipeConnection *conn = g_object_new(SIPE_TYPE_CONNECTION,
705 "protocol", tp_base_protocol_get_name(protocol),
706 NULL);
707 const gchar *value;
708 guint port;
709 gboolean valid;
711 SIPE_DEBUG_INFO_NOFORMAT("sipe_telepathy_connection_new");
713 /* initialize private fields */
714 conn->is_disconnecting = FALSE;
716 /* account & login are required fields */
717 conn->account = g_strdup(tp_asv_get_string(params, "account"));
718 conn->login = g_strdup(tp_asv_get_string(params, "login"));
720 /* password */
721 value = tp_asv_get_string(params, "password");
722 if (value && strlen(value))
723 conn->password = g_strdup(value);
724 else
725 conn->password = NULL;
727 /* server name */
728 value = tp_asv_get_string(params, "server");
729 if (value && strlen(value))
730 conn->server = g_strdup(value);
731 else
732 conn->server = NULL;
734 /* server port: core expects a string */
735 port = tp_asv_get_uint32(params, "port", &valid);
736 if (valid)
737 conn->port = g_strdup_printf("%d", port);
738 else
739 conn->port = NULL;
741 /* transport type */
742 value = tp_asv_get_string(params, "transport");
743 if (sipe_strequal(value, "auto")) {
744 conn->transport = conn->server ?
745 SIPE_TRANSPORT_TLS : SIPE_TRANSPORT_AUTO;
746 } else if (sipe_strequal(value, "tls")) {
747 conn->transport = SIPE_TRANSPORT_TLS;
748 } else {
749 conn->transport = SIPE_TRANSPORT_TCP;
752 /* User-Agent: override */
753 value = tp_asv_get_string(params, "useragent");
754 if (value && strlen(value))
755 conn->user_agent = g_strdup(value);
756 else
757 conn->user_agent = NULL;
759 /* authentication type */
760 value = tp_asv_get_string(params, "authentication");
761 if (value && strlen(value) && strcmp(value, "ntlm"))
762 conn->authentication = g_strdup(value);
763 else
764 conn->authentication = NULL; /* NTLM is default */
766 return(TP_BASE_CONNECTION(conn));
769 void sipe_telepathy_connection_alias_updated(TpBaseConnection *connection,
770 guint contact,
771 const gchar *alias)
773 GPtrArray *aliases = g_ptr_array_sized_new(1);
774 GValueArray *pair = g_value_array_new(2);
776 g_value_array_append(pair, NULL);
777 g_value_array_append(pair, NULL);
778 g_value_init(pair->values + 0, G_TYPE_UINT);
779 g_value_init(pair->values + 1, G_TYPE_STRING);
780 g_value_set_uint(pair->values + 0, contact);
781 g_value_set_string(pair->values + 1, alias);
782 g_ptr_array_add(aliases, pair);
784 tp_svc_connection_interface_aliasing_emit_aliases_changed(SIPE_CONNECTION(connection),
785 aliases);
787 g_ptr_array_unref(aliases);
788 g_value_array_free(pair);
791 struct sipe_backend_private *sipe_telepathy_connection_private(GObject *object)
793 SipeConnection *self = SIPE_CONNECTION(object);
794 /* connected to core already? */
795 if (self->private.public)
796 return(&self->private);
797 else
798 return(NULL);
802 * Backend adaptor functions
804 void sipe_backend_connection_completed(struct sipe_core_public *sipe_public)
806 SipeConnection *self = SIPE_PUBLIC_TO_CONNECTION;
807 TpBaseConnection *base = TP_BASE_CONNECTION(self);
809 /* we are only allowed to do this once */
810 if (base->status != TP_CONNECTION_STATUS_CONNECTED)
811 tp_base_connection_change_status(base,
812 TP_CONNECTION_STATUS_CONNECTED,
813 TP_CONNECTION_STATUS_REASON_REQUESTED);
816 void sipe_backend_connection_error(struct sipe_core_public *sipe_public,
817 sipe_connection_error error,
818 const gchar *msg)
820 SipeConnection *self = SIPE_PUBLIC_TO_CONNECTION;
821 TpBaseConnection *base = TP_BASE_CONNECTION(self);
822 GHashTable *details = tp_asv_new("server-message", G_TYPE_STRING, msg,
823 NULL);
824 TpConnectionStatusReason reason;
825 const gchar *name;
827 self->is_disconnecting = TRUE;
829 switch (error) {
830 case SIPE_CONNECTION_ERROR_NETWORK:
831 reason = TP_CONNECTION_STATUS_REASON_NETWORK_ERROR;
832 if (base->status == TP_CONNECTION_STATUS_CONNECTING)
833 name = TP_ERROR_STR_CONNECTION_FAILED;
834 else
835 name = TP_ERROR_STR_CONNECTION_LOST;
836 break;
838 case SIPE_CONNECTION_ERROR_INVALID_USERNAME:
839 case SIPE_CONNECTION_ERROR_INVALID_SETTINGS:
840 case SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED:
841 case SIPE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE:
842 /* copied from haze code. I agree there should be better ones */
843 reason = TP_CONNECTION_STATUS_REASON_AUTHENTICATION_FAILED;
844 name = TP_ERROR_STR_AUTHENTICATION_FAILED;
845 break;
847 default:
848 reason = TP_CONNECTION_STATUS_REASON_NONE_SPECIFIED;
849 name = TP_ERROR_STR_DISCONNECTED;
850 break;
853 SIPE_DEBUG_ERROR("sipe_backend_connection_error: %s (%s)", name, msg);
854 tp_base_connection_disconnect_with_dbus_error(base,
855 name,
856 details,
857 reason);
858 g_hash_table_unref(details);
861 gboolean sipe_backend_connection_is_disconnecting(struct sipe_core_public *sipe_public)
863 SipeConnection *self = SIPE_PUBLIC_TO_CONNECTION;
865 /* disconnect was requested or transport was already disconnected */
866 return(self->is_disconnecting ||
867 self->private.transport == NULL);
870 gboolean sipe_backend_connection_is_valid(struct sipe_core_public *sipe_public)
872 return(!sipe_backend_connection_is_disconnecting(sipe_public));
875 const gchar *sipe_backend_setting(struct sipe_core_public *sipe_public,
876 sipe_setting type)
878 SipeConnection *self = SIPE_PUBLIC_TO_CONNECTION;
879 const gchar *value;
881 switch (type) {
882 case SIPE_SETTING_USER_AGENT:
883 value = self->user_agent;
884 break;
885 default:
886 /* @TODO: update when settings are implemented */
887 value = NULL;
888 break;
891 return(value);
896 Local Variables:
897 mode: c
898 c-file-style: "bsd"
899 indent-tabs-mode: t
900 tab-width: 8
901 End: