utils: add IPv6 private addresses
[siplcs.git] / src / telepathy / telepathy-connection.c
blobd8f8999e5a6765a8ef2b3a8e1c736c544b9b19d8
1 /**
2 * @file telepathy-connection.c
4 * pidgin-sipe
6 * Copyright (C) 2012-2017 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 dont_publish;
79 gboolean is_disconnecting;
81 GPtrArray *contact_info_fields;
82 } SipeConnection;
84 #define SIPE_PUBLIC_TO_CONNECTION sipe_public->backend_private->connection
87 * Connection class - type macros
89 static GType sipe_connection_get_type(void) G_GNUC_CONST;
90 #define SIPE_TYPE_CONNECTION \
91 (sipe_connection_get_type())
92 #define SIPE_CONNECTION(obj) \
93 (G_TYPE_CHECK_INSTANCE_CAST((obj), SIPE_TYPE_CONNECTION, \
94 SipeConnection))
95 G_END_DECLS
98 * Connection class - type definition
100 static void init_aliasing (gpointer, gpointer);
101 G_DEFINE_TYPE_WITH_CODE(SipeConnection,
102 sipe_connection,
103 TP_TYPE_BASE_CONNECTION,
104 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_ALIASING,
105 init_aliasing);
106 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_AVATARS,
107 sipe_telepathy_avatars_iface_init);
108 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACTS,
109 tp_contacts_mixin_iface_init);
110 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACT_GROUPS,
111 tp_base_contact_list_mixin_groups_iface_init);
112 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACT_INFO,
113 sipe_telepathy_contact_info_iface_init);
114 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACT_LIST,
115 tp_base_contact_list_mixin_list_iface_init);
116 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_PRESENCE,
117 tp_presence_mixin_iface_init);
118 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_SIMPLE_PRESENCE,
119 tp_presence_mixin_simple_presence_iface_init);
120 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_DBUS_PROPERTIES,
121 tp_dbus_properties_mixin_iface_init);
126 * Connection class - instance methods
128 static gchar *normalize_contact(SIPE_UNUSED_PARAMETER TpHandleRepoIface *repo,
129 const gchar *id,
130 SIPE_UNUSED_PARAMETER gpointer context,
131 GError **error)
133 return(sipe_telepathy_protocol_normalize_contact(NULL, id, error));
136 static void create_handle_repos(SIPE_UNUSED_PARAMETER TpBaseConnection *conn,
137 TpHandleRepoIface *repos[NUM_TP_HANDLE_TYPES])
139 repos[TP_HANDLE_TYPE_CONTACT] = tp_dynamic_handle_repo_new(TP_HANDLE_TYPE_CONTACT,
140 normalize_contact,
141 NULL);
144 static gboolean connect_to_core(SipeConnection *self,
145 GError **error)
147 struct sipe_core_public *sipe_public;
148 const gchar *errmsg;
150 sipe_public = sipe_core_allocate(self->account,
151 self->sso,
152 self->login,
153 self->password,
154 NULL, /* @TODO: email */
155 NULL, /* @TODO: email_url */
156 &errmsg);
158 SIPE_DEBUG_INFO("connect_to_core: created %p", sipe_public);
160 if (sipe_public) {
161 struct sipe_backend_private *telepathy_private = &self->private;
163 /* initialize backend private data */
164 sipe_public->backend_private = telepathy_private;
165 telepathy_private->public = sipe_public;
166 telepathy_private->contact_list = self->contact_list;
167 telepathy_private->connection = self;
168 telepathy_private->activity = SIPE_ACTIVITY_UNSET;
169 telepathy_private->cache_dir = g_build_path(G_DIR_SEPARATOR_S,
170 g_get_user_cache_dir(),
171 "telepathy",
172 "sipe",
173 self->account,
174 NULL);
175 telepathy_private->message = NULL;
176 telepathy_private->tls_manager = self->tls_manager;
177 telepathy_private->transport = NULL;
179 /* make sure cache directory exists */
180 if (!g_file_test(telepathy_private->cache_dir,
181 G_FILE_TEST_IS_DIR) &&
182 (g_mkdir_with_parents(telepathy_private->cache_dir,
183 S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
184 == 0))
185 SIPE_DEBUG_INFO("connect_to_core: created cache directory %s",
186 telepathy_private->cache_dir);
188 SIPE_CORE_FLAG_UNSET(DONT_PUBLISH);
189 if (self->dont_publish)
190 SIPE_CORE_FLAG_SET(DONT_PUBLISH);
192 sipe_core_transport_sip_connect(sipe_public,
193 self->transport,
194 self->authentication_type,
195 self->server,
196 self->port);
198 return(TRUE);
199 } else {
200 g_set_error_literal(error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
201 errmsg);
202 return(FALSE);
206 static void password_manager_cb(GObject *source,
207 GAsyncResult *result,
208 gpointer data)
210 SipeConnection *self = data;
211 TpBaseConnection *base = TP_BASE_CONNECTION(self);
212 GError *error = NULL;
213 const GString *password = tp_simple_password_manager_prompt_finish(
214 TP_SIMPLE_PASSWORD_MANAGER(source),
215 result,
216 &error);
218 if (password == NULL) {
219 SIPE_DEBUG_ERROR("password_manager_cb: failed: %s",
220 error ? error->message : "UNKNOWN");
222 if (base->status != TP_CONNECTION_STATUS_DISCONNECTED) {
223 tp_base_connection_disconnect_with_dbus_error(base,
224 error ? tp_error_get_dbus_name(error->code) : "",
225 NULL,
226 TP_CONNECTION_STATUS_REASON_AUTHENTICATION_FAILED);
228 if (error)
229 g_error_free(error);
230 } else {
232 g_free(self->password);
233 self->password = g_strdup(password->str);
235 if (!connect_to_core(self, &error)) {
236 if (base->status != TP_CONNECTION_STATUS_DISCONNECTED) {
237 tp_base_connection_disconnect_with_dbus_error(base,
238 tp_error_get_dbus_name(error->code),
239 NULL,
240 TP_CONNECTION_STATUS_REASON_AUTHENTICATION_FAILED);
242 g_error_free(error);
247 static gboolean start_connecting(TpBaseConnection *base,
248 GError **error)
250 SipeConnection *self = SIPE_CONNECTION(base);
251 gboolean rc = TRUE;
252 gchar *uri = sipe_telepathy_protocol_normalize_contact(NULL,
253 self->account,
254 error);
256 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::start_connecting");
258 /* set up mandatory self-handle */
259 if (uri) {
260 base->self_handle = tp_handle_ensure(tp_base_connection_get_handles(base,
261 TP_HANDLE_TYPE_CONTACT),
262 uri,
263 NULL,
264 error);
265 g_free(uri);
266 if (!base->self_handle) {
267 SIPE_DEBUG_ERROR("SipeConnection::start_connecting: self handle creation failed: %s",
268 (*error)->message);
269 return(FALSE);
271 } else {
272 SIPE_DEBUG_ERROR("SipeConnection::start_connecting: %s",
273 (*error)->message);
274 return(FALSE);
277 tp_base_connection_change_status(base, TP_CONNECTION_STATUS_CONNECTING,
278 TP_CONNECTION_STATUS_REASON_REQUESTED);
280 /* map option list to flags - default is automatic */
281 self->authentication_type = SIPE_AUTHENTICATION_TYPE_AUTOMATIC;
282 if (sipe_strequal(self->authentication, "ntlm")) {
283 SIPE_DEBUG_INFO_NOFORMAT("start_connecting: NTLM selected");
284 self->authentication_type = SIPE_AUTHENTICATION_TYPE_NTLM;
285 } else
286 #ifdef HAVE_GSSAPI_GSSAPI_H
287 if (sipe_strequal(self->authentication, "krb5")) {
288 SIPE_DEBUG_INFO_NOFORMAT("start_connecting: KRB5 selected");
289 self->authentication_type = SIPE_AUTHENTICATION_TYPE_KERBEROS;
290 } else
291 #endif
292 if (sipe_strequal(self->authentication, "tls-dsk")) {
293 SIPE_DEBUG_INFO_NOFORMAT("start_connecting: TLS-DSK selected");
294 self->authentication_type = SIPE_AUTHENTICATION_TYPE_TLS_DSK;
297 /* Only ask for a password when required */
298 if (!sipe_core_transport_sip_requires_password(self->authentication_type,
299 self->sso) ||
300 (self->password && strlen(self->password)))
301 rc = connect_to_core(self, error);
302 else {
303 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::start_connecting: requesting password from user");
304 tp_simple_password_manager_prompt_async(self->password_manager,
305 password_manager_cb,
306 self);
309 return(rc);
312 static gboolean disconnect_from_core(gpointer data)
314 TpBaseConnection *base = data;
315 SipeConnection *self = SIPE_CONNECTION(base);
316 struct sipe_backend_private *telepathy_private = &self->private;
317 struct sipe_core_public *sipe_public = telepathy_private->public;
319 SIPE_DEBUG_INFO("disconnect_from_core: %p", sipe_public);
321 if (sipe_public)
322 sipe_core_deallocate(sipe_public);
323 telepathy_private->public = NULL;
324 telepathy_private->transport = NULL;
326 g_free(telepathy_private->message);
327 telepathy_private->message = NULL;
329 g_free(telepathy_private->cache_dir);
330 telepathy_private->cache_dir = NULL;
332 SIPE_DEBUG_INFO_NOFORMAT("disconnect_from_core: core deallocated");
334 /* now it is OK to destroy the connection object */
335 tp_base_connection_finish_shutdown(base);
337 return(FALSE);
340 static void shut_down(TpBaseConnection *base)
342 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::shut_down");
344 /* this can be called synchronously, defer destruction */
345 g_idle_add(disconnect_from_core, base);
348 static GPtrArray *create_channel_managers(TpBaseConnection *base)
350 SipeConnection *self = SIPE_CONNECTION(base);
351 GPtrArray *channel_managers = g_ptr_array_new();
353 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::create_channel_managers");
355 self->contact_list = sipe_telepathy_contact_list_new(base);
356 g_ptr_array_add(channel_managers, self->contact_list);
358 self->password_manager = tp_simple_password_manager_new(base);
359 g_ptr_array_add(channel_managers, self->password_manager);
361 g_ptr_array_add(channel_managers, sipe_telepathy_search_new(base));
363 self->tls_manager = sipe_telepathy_tls_new(base);
364 g_ptr_array_add(channel_managers, self->tls_manager);
366 return(channel_managers);
369 static void aliasing_fill_contact_attributes(GObject *object,
370 const GArray *contacts,
371 GHashTable *attributes)
373 SipeConnection *self = SIPE_CONNECTION(object);
374 guint i;
376 for (i = 0; i < contacts->len; i++) {
377 TpHandle contact = g_array_index(contacts, guint, i);
379 tp_contacts_mixin_set_contact_attribute(attributes,
380 contact,
381 TP_TOKEN_CONNECTION_INTERFACE_ALIASING_ALIAS,
382 tp_g_value_slice_new_string(
383 sipe_telepathy_buddy_get_alias(self->contact_list,
384 contact)));
388 static void avatars_fill_contact_attributes(GObject *object,
389 const GArray *contacts,
390 GHashTable *attributes)
392 SipeConnection *self = SIPE_CONNECTION(object);
393 guint i;
395 for (i = 0; i < contacts->len; i++) {
396 TpHandle contact = g_array_index(contacts, guint, i);
397 const gchar *hash = sipe_telepathy_buddy_get_hash(self->contact_list,
398 contact);
400 if (!hash) hash = "";
401 tp_contacts_mixin_set_contact_attribute(attributes,
402 contact,
403 TP_IFACE_CONNECTION_INTERFACE_AVATARS"/token",
404 tp_g_value_slice_new_string(hash));
408 static void contact_info_properties_getter(GObject *object,
409 SIPE_UNUSED_PARAMETER GQuark interface,
410 GQuark name,
411 GValue *value,
412 gpointer getter_data)
414 GQuark fields = g_quark_from_static_string("SupportedFields");
416 if (name == fields)
417 g_value_set_boxed(value,
418 SIPE_CONNECTION(object)->contact_info_fields);
419 else
420 g_value_set_uint(value,
421 GPOINTER_TO_UINT(getter_data));
424 static void sipe_connection_constructed(GObject *object)
426 SipeConnection *self = SIPE_CONNECTION(object);
427 TpBaseConnection *base = TP_BASE_CONNECTION(object);
428 void (*chain_up)(GObject *) = G_OBJECT_CLASS(sipe_connection_parent_class)->constructed;
430 if (chain_up)
431 chain_up(object);
433 tp_contacts_mixin_init(object,
434 G_STRUCT_OFFSET(SipeConnection, contacts_mixin));
435 tp_base_connection_register_with_contacts_mixin(base);
437 tp_base_contact_list_mixin_register_with_contacts_mixin(base);
439 tp_contacts_mixin_add_contact_attributes_iface(object,
440 TP_IFACE_CONNECTION_INTERFACE_ALIASING,
441 aliasing_fill_contact_attributes);
442 tp_contacts_mixin_add_contact_attributes_iface(object,
443 TP_IFACE_CONNECTION_INTERFACE_AVATARS,
444 avatars_fill_contact_attributes);
446 tp_presence_mixin_init(object,
447 G_STRUCT_OFFSET(SipeConnection,
448 presence_mixin));
449 tp_presence_mixin_simple_presence_register_with_contacts_mixin(object);
451 self->contact_info_fields = sipe_telepathy_contact_info_fields();
454 static void sipe_connection_finalize(GObject *object)
456 SipeConnection *self = SIPE_CONNECTION(object);
458 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::finalize");
460 tp_contacts_mixin_finalize(object);
461 tp_presence_mixin_finalize(object);
462 g_boxed_free(TP_ARRAY_TYPE_FIELD_SPECS, self->contact_info_fields);
464 g_free(self->authentication);
465 g_free(self->user_agent);
466 g_free(self->port);
467 g_free(self->server);
468 g_free(self->password);
469 g_free(self->login);
470 g_free(self->account);
472 G_OBJECT_CLASS(sipe_connection_parent_class)->finalize(object);
476 * Connection class - type implementation
478 static const gchar *interfaces_always_present[] = {
479 /* @TODO */
480 TP_IFACE_CONNECTION_INTERFACE_ALIASING,
481 TP_IFACE_CONNECTION_INTERFACE_AVATARS,
482 TP_IFACE_CONNECTION_INTERFACE_CONTACT_GROUPS,
483 TP_IFACE_CONNECTION_INTERFACE_CONTACT_INFO,
484 TP_IFACE_CONNECTION_INTERFACE_CONTACT_LIST,
485 TP_IFACE_CONNECTION_INTERFACE_CONTACTS,
486 TP_IFACE_CONNECTION_INTERFACE_PRESENCE,
487 TP_IFACE_CONNECTION_INTERFACE_REQUESTS,
488 TP_IFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE,
489 NULL
492 static void sipe_connection_class_init(SipeConnectionClass *klass)
494 GObjectClass *object_class = G_OBJECT_CLASS(klass);
495 TpBaseConnectionClass *base_class = TP_BASE_CONNECTION_CLASS(klass);
496 static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = {
498 /* 0 */
499 .name = TP_IFACE_CONNECTION_INTERFACE_CONTACT_INFO,
500 .getter = contact_info_properties_getter,
501 .setter = NULL,
504 /* LAST! */
505 .name = NULL,
509 /* initalize non-constant fields */
510 prop_interfaces[0].props = sipe_telepathy_contact_info_props();
512 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::class_init");
514 object_class->constructed = sipe_connection_constructed;
515 object_class->finalize = sipe_connection_finalize;
517 base_class->create_handle_repos = create_handle_repos;
518 base_class->start_connecting = start_connecting;
519 base_class->shut_down = shut_down;
520 base_class->create_channel_managers = create_channel_managers;
522 base_class->interfaces_always_present = interfaces_always_present;
524 klass->properties_mixin.interfaces = prop_interfaces;
525 tp_dbus_properties_mixin_class_init(object_class,
526 G_STRUCT_OFFSET(SipeConnectionClass,
527 properties_mixin));
528 tp_contacts_mixin_class_init(object_class,
529 G_STRUCT_OFFSET(SipeConnectionClass,
530 contacts_mixin));
531 sipe_telepathy_status_init(object_class,
532 G_STRUCT_OFFSET(SipeConnectionClass,
533 presence_mixin));
534 tp_presence_mixin_simple_presence_init_dbus_properties(object_class);
535 tp_base_contact_list_mixin_class_init(base_class);
538 static void sipe_connection_init(SIPE_UNUSED_PARAMETER SipeConnection *self)
540 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::init");
544 * Connection class - interface implementation
546 * Contact aliases
548 static void get_alias_flags(TpSvcConnectionInterfaceAliasing *aliasing,
549 DBusGMethodInvocation *context)
551 TpBaseConnection *base = TP_BASE_CONNECTION(aliasing);
553 TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED(base, context);
554 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::get_alias_flags called");
556 tp_svc_connection_interface_aliasing_return_from_get_alias_flags(context,
557 TP_CONNECTION_ALIAS_FLAG_USER_SET);
560 static void get_aliases(TpSvcConnectionInterfaceAliasing *aliasing,
561 const GArray *contacts,
562 DBusGMethodInvocation *context)
564 SipeConnection *self = SIPE_CONNECTION(aliasing);
565 TpBaseConnection *base = TP_BASE_CONNECTION(aliasing);
566 TpHandleRepoIface *contact_repo = tp_base_connection_get_handles(base,
567 TP_HANDLE_TYPE_CONTACT);
568 GError *error = NULL;
569 GHashTable *result;
570 guint i;
572 TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED(base, context);
573 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::get_aliases called");
575 if (!tp_handles_are_valid(contact_repo, contacts, FALSE, &error)) {
576 dbus_g_method_return_error(context, error);
577 g_error_free(error);
578 return;
581 result = g_hash_table_new(g_direct_hash, g_direct_equal);
583 for (i = 0; i < contacts->len; i++) {
584 TpHandle contact = g_array_index(contacts, TpHandle, i);
585 const gchar *alias = sipe_telepathy_buddy_get_alias(self->contact_list,
586 contact);
587 g_hash_table_insert(result,
588 GUINT_TO_POINTER(contact),
589 (gchar *) alias);
592 tp_svc_connection_interface_aliasing_return_from_get_aliases(context,
593 result);
594 g_hash_table_unref(result);
597 static void request_aliases(TpSvcConnectionInterfaceAliasing *aliasing,
598 const GArray *contacts,
599 DBusGMethodInvocation *context)
601 SipeConnection *self = SIPE_CONNECTION(aliasing);
602 TpBaseConnection *base = TP_BASE_CONNECTION(aliasing);
603 TpHandleRepoIface *contact_repo = tp_base_connection_get_handles(base,
604 TP_HANDLE_TYPE_CONTACT);
605 GError *error = NULL;
606 GPtrArray *result;
607 gchar **strings;
608 guint i;
610 TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED(base, context);
611 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::request_aliases called");
613 if (!tp_handles_are_valid(contact_repo, contacts, FALSE, &error)) {
614 dbus_g_method_return_error(context, error);
615 g_error_free(error);
616 return;
619 result = g_ptr_array_sized_new(contacts->len + 1);
621 for (i = 0; i < contacts->len; i++) {
622 TpHandle contact = g_array_index(contacts, TpHandle, i);
623 const gchar *alias = sipe_telepathy_buddy_get_alias(self->contact_list,
624 contact);
625 g_ptr_array_add(result, (gchar *) alias);
628 g_ptr_array_add(result, NULL);
629 strings = (gchar **) g_ptr_array_free(result, FALSE);
631 tp_svc_connection_interface_aliasing_return_from_request_aliases(context,
632 (const gchar **) strings);
633 g_free(strings);
636 static void set_aliases(TpSvcConnectionInterfaceAliasing *aliasing,
637 GHashTable *aliases,
638 DBusGMethodInvocation *context)
640 SipeConnection *self = SIPE_CONNECTION(aliasing);
641 TpBaseConnection *base = TP_BASE_CONNECTION(aliasing);
642 TpHandleRepoIface *contact_repo = tp_base_connection_get_handles(base,
643 TP_HANDLE_TYPE_CONTACT);
644 GHashTableIter iter;
645 gpointer key, value;
647 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::set_aliases called");
649 g_hash_table_iter_init(&iter, aliases);
651 while (g_hash_table_iter_next(&iter, &key, NULL)) {
652 GError *error = NULL;
654 if (!tp_handle_is_valid(contact_repo,
655 GPOINTER_TO_UINT(key),
656 &error)) {
657 dbus_g_method_return_error(context, error);
658 g_error_free(error);
659 return;
663 g_hash_table_iter_init(&iter, aliases);
665 while (g_hash_table_iter_next(&iter, &key, &value)) {
666 sipe_telepathy_buddy_set_alias(self->contact_list,
667 GPOINTER_TO_UINT(key),
668 value);
671 tp_svc_connection_interface_aliasing_return_from_set_aliases(context);
674 static void init_aliasing(gpointer iface,
675 SIPE_UNUSED_PARAMETER gpointer iface_data)
677 TpSvcConnectionInterfaceAliasingClass *klass = iface;
679 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::init_aliasing called");
681 tp_svc_connection_interface_aliasing_implement_get_alias_flags(klass, get_alias_flags);
682 tp_svc_connection_interface_aliasing_implement_request_aliases(klass, request_aliases);
683 tp_svc_connection_interface_aliasing_implement_get_aliases(klass, get_aliases);
684 tp_svc_connection_interface_aliasing_implement_set_aliases(klass, set_aliases);
687 /* create new connection object */
688 TpBaseConnection *sipe_telepathy_connection_new(TpBaseProtocol *protocol,
689 GHashTable *params,
690 SIPE_UNUSED_PARAMETER GError **error)
692 SipeConnection *conn = g_object_new(SIPE_TYPE_CONNECTION,
693 "protocol", tp_base_protocol_get_name(protocol),
694 NULL);
695 const gchar *value;
696 guint port;
697 gboolean boolean_value;
698 gboolean valid;
700 SIPE_DEBUG_INFO_NOFORMAT("sipe_telepathy_connection_new");
702 /* initialize private fields */
703 conn->is_disconnecting = FALSE;
705 /* account is required field */
706 conn->account = g_strdup(tp_asv_get_string(params, "account"));
708 /* if login is not specified, account value will be used in connect_to_core */
709 value = tp_asv_get_string(params, "login");
710 if (value && strlen(value))
711 conn->login = g_strdup(value);
712 else
713 conn->login = NULL;
715 /* password */
716 value = tp_asv_get_string(params, "password");
717 if (value && strlen(value))
718 conn->password = g_strdup(value);
719 else
720 conn->password = NULL;
722 /* server name */
723 value = tp_asv_get_string(params, "server");
724 if (value && strlen(value))
725 conn->server = g_strdup(value);
726 else
727 conn->server = NULL;
729 /* server port: core expects a string */
730 port = tp_asv_get_uint32(params, "port", &valid);
731 if (valid)
732 conn->port = g_strdup_printf("%d", port);
733 else
734 conn->port = NULL;
736 /* transport type */
737 value = tp_asv_get_string(params, "transport");
738 if (sipe_strequal(value, "auto")) {
739 conn->transport = conn->server ?
740 SIPE_TRANSPORT_TLS : SIPE_TRANSPORT_AUTO;
741 } else if (sipe_strequal(value, "tls")) {
742 conn->transport = SIPE_TRANSPORT_TLS;
743 } else {
744 conn->transport = SIPE_TRANSPORT_TCP;
747 /* User-Agent: override */
748 value = tp_asv_get_string(params, "useragent");
749 if (value && strlen(value))
750 conn->user_agent = g_strdup(value);
751 else
752 conn->user_agent = NULL;
754 /* authentication type */
755 value = tp_asv_get_string(params, "authentication");
756 if (value && strlen(value) && strcmp(value, "ntlm"))
757 conn->authentication = g_strdup(value);
758 else
759 conn->authentication = NULL; /* NTLM is default */
761 /* Single Sign-On */
762 boolean_value = tp_asv_get_boolean(params, "single-sign-on", &valid);
763 if (valid)
764 conn->sso = boolean_value;
765 else
766 conn->sso = FALSE;
768 /* Don't publish my calendar information */
769 boolean_value = tp_asv_get_boolean(params, "don't-publish-calendar", &valid);
770 if (valid)
771 conn->dont_publish = boolean_value;
772 else
773 conn->dont_publish = FALSE;
775 return(TP_BASE_CONNECTION(conn));
778 void sipe_telepathy_connection_alias_updated(TpBaseConnection *connection,
779 guint contact,
780 const gchar *alias)
782 GPtrArray *aliases = g_ptr_array_sized_new(1);
783 GValueArray *pair = g_value_array_new(2);
785 g_value_array_append(pair, NULL);
786 g_value_array_append(pair, NULL);
787 g_value_init(pair->values + 0, G_TYPE_UINT);
788 g_value_init(pair->values + 1, G_TYPE_STRING);
789 g_value_set_uint(pair->values + 0, contact);
790 g_value_set_string(pair->values + 1, alias);
791 g_ptr_array_add(aliases, pair);
793 tp_svc_connection_interface_aliasing_emit_aliases_changed(SIPE_CONNECTION(connection),
794 aliases);
796 g_ptr_array_unref(aliases);
797 g_value_array_free(pair);
800 struct sipe_backend_private *sipe_telepathy_connection_private(GObject *object)
802 SipeConnection *self = SIPE_CONNECTION(object);
803 /* connected to core already? */
804 if (self->private.public)
805 return(&self->private);
806 else
807 return(NULL);
811 * Backend adaptor functions
813 void sipe_backend_connection_completed(struct sipe_core_public *sipe_public)
815 SipeConnection *self = SIPE_PUBLIC_TO_CONNECTION;
816 TpBaseConnection *base = TP_BASE_CONNECTION(self);
818 /* we are only allowed to do this once */
819 if (base->status != TP_CONNECTION_STATUS_CONNECTED)
820 tp_base_connection_change_status(base,
821 TP_CONNECTION_STATUS_CONNECTED,
822 TP_CONNECTION_STATUS_REASON_REQUESTED);
825 void sipe_backend_connection_error(struct sipe_core_public *sipe_public,
826 sipe_connection_error error,
827 const gchar *msg)
829 SipeConnection *self = SIPE_PUBLIC_TO_CONNECTION;
830 TpBaseConnection *base = TP_BASE_CONNECTION(self);
831 GHashTable *details = tp_asv_new("server-message", G_TYPE_STRING, msg,
832 NULL);
833 TpConnectionStatusReason reason;
834 const gchar *name;
836 self->is_disconnecting = TRUE;
838 switch (error) {
839 case SIPE_CONNECTION_ERROR_NETWORK:
840 reason = TP_CONNECTION_STATUS_REASON_NETWORK_ERROR;
841 if (base->status == TP_CONNECTION_STATUS_CONNECTING)
842 name = TP_ERROR_STR_CONNECTION_FAILED;
843 else
844 name = TP_ERROR_STR_CONNECTION_LOST;
845 break;
847 case SIPE_CONNECTION_ERROR_INVALID_USERNAME:
848 case SIPE_CONNECTION_ERROR_INVALID_SETTINGS:
849 case SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED:
850 case SIPE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE:
851 /* copied from haze code. I agree there should be better ones */
852 reason = TP_CONNECTION_STATUS_REASON_AUTHENTICATION_FAILED;
853 name = TP_ERROR_STR_AUTHENTICATION_FAILED;
854 break;
856 default:
857 reason = TP_CONNECTION_STATUS_REASON_NONE_SPECIFIED;
858 name = TP_ERROR_STR_DISCONNECTED;
859 break;
862 SIPE_DEBUG_ERROR("sipe_backend_connection_error: %s (%s)", name, msg);
863 tp_base_connection_disconnect_with_dbus_error(base,
864 name,
865 details,
866 reason);
867 g_hash_table_unref(details);
870 gboolean sipe_backend_connection_is_disconnecting(struct sipe_core_public *sipe_public)
872 SipeConnection *self = SIPE_PUBLIC_TO_CONNECTION;
874 /* disconnect was requested or transport was already disconnected */
875 return(self->is_disconnecting ||
876 self->private.transport == NULL);
879 gboolean sipe_backend_connection_is_valid(struct sipe_core_public *sipe_public)
881 return(!sipe_backend_connection_is_disconnecting(sipe_public));
884 const gchar *sipe_backend_setting(struct sipe_core_public *sipe_public,
885 sipe_setting type)
887 SipeConnection *self = SIPE_PUBLIC_TO_CONNECTION;
888 const gchar *value;
890 switch (type) {
891 case SIPE_SETTING_USER_AGENT:
892 value = self->user_agent;
893 break;
894 default:
895 /* @TODO: update when settings are implemented */
896 value = NULL;
897 break;
900 return(value);
905 Local Variables:
906 mode: c
907 c-file-style: "bsd"
908 indent-tabs-mode: t
909 tab-width: 8
910 End: