telepathy: add automatic authentication scheme option
[siplcs.git] / src / telepathy / telepathy-connection.c
blob5315129ad8ecf01f5e6df62c85415c2cf66bcc37
1 /**
2 * @file telepathy-connection.c
4 * pidgin-sipe
6 * Copyright (C) 2012-2014 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 gchar *login_domain = NULL;
148 gchar *login_account = NULL;
149 struct sipe_core_public *sipe_public;
150 const gchar *errmsg;
152 /* login name specified? */
153 if (self->login && strlen(self->login)) {
154 /* Allowed domain-account separators are / or \ */
155 gchar **domain_user = g_strsplit_set(self->login, "/\\", 2);
156 gboolean has_domain = domain_user[1] != NULL;
157 SIPE_DEBUG_INFO("connect_to_core: login '%s'", self->login);
158 login_domain = has_domain ? g_strdup(domain_user[0]) : NULL;
159 login_account = g_strdup(domain_user[has_domain ? 1 : 0]);
160 SIPE_DEBUG_INFO("connect_to_core: auth domain '%s' user '%s'",
161 login_domain ? login_domain : "",
162 login_account);
163 g_strfreev(domain_user);
164 } else {
165 /* No -> duplicate username */
166 login_account = g_strdup(self->account);
169 sipe_public = sipe_core_allocate(self->account,
170 self->sso,
171 login_domain, login_account,
172 self->password,
173 NULL, /* @TODO: email */
174 NULL, /* @TODO: email_url */
175 &errmsg);
176 g_free(login_domain);
177 g_free(login_account);
179 SIPE_DEBUG_INFO("connect_to_core: created %p", sipe_public);
181 if (sipe_public) {
182 struct sipe_backend_private *telepathy_private = &self->private;
184 /* initialize backend private data */
185 sipe_public->backend_private = telepathy_private;
186 telepathy_private->public = sipe_public;
187 telepathy_private->contact_list = self->contact_list;
188 telepathy_private->connection = self;
189 telepathy_private->activity = SIPE_ACTIVITY_UNSET;
190 telepathy_private->cache_dir = g_build_path(G_DIR_SEPARATOR_S,
191 g_get_user_cache_dir(),
192 "telepathy",
193 "sipe",
194 self->account,
195 NULL);
196 telepathy_private->message = NULL;
197 telepathy_private->tls_manager = self->tls_manager;
198 telepathy_private->transport = NULL;
199 telepathy_private->ipaddress = NULL;
201 /* make sure cache directory exists */
202 if (!g_file_test(telepathy_private->cache_dir,
203 G_FILE_TEST_IS_DIR) &&
204 (g_mkdir_with_parents(telepathy_private->cache_dir,
205 S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
206 == 0))
207 SIPE_DEBUG_INFO("connect_to_core: created cache directory %s",
208 telepathy_private->cache_dir);
210 SIPE_CORE_FLAG_UNSET(DONT_PUBLISH);
211 if (self->dont_publish)
212 SIPE_CORE_FLAG_SET(DONT_PUBLISH);
214 sipe_core_transport_sip_connect(sipe_public,
215 self->transport,
216 self->authentication_type,
217 self->server,
218 self->port);
220 return(TRUE);
221 } else {
222 g_set_error_literal(error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
223 errmsg);
224 return(FALSE);
228 static void password_manager_cb(GObject *source,
229 GAsyncResult *result,
230 gpointer data)
232 SipeConnection *self = data;
233 TpBaseConnection *base = TP_BASE_CONNECTION(self);
234 GError *error = NULL;
235 const GString *password = tp_simple_password_manager_prompt_finish(
236 TP_SIMPLE_PASSWORD_MANAGER(source),
237 result,
238 &error);
240 if (password == NULL) {
241 SIPE_DEBUG_ERROR("password_manager_cb: failed: %s",
242 error ? error->message : "UNKNOWN");
244 if (base->status != TP_CONNECTION_STATUS_DISCONNECTED) {
245 tp_base_connection_disconnect_with_dbus_error(base,
246 error ? tp_error_get_dbus_name(error->code) : "",
247 NULL,
248 TP_CONNECTION_STATUS_REASON_AUTHENTICATION_FAILED);
250 g_error_free(error);
251 } else {
253 g_free(self->password);
254 self->password = g_strdup(password->str);
256 if (!connect_to_core(self, &error)) {
257 if (base->status != TP_CONNECTION_STATUS_DISCONNECTED) {
258 tp_base_connection_disconnect_with_dbus_error(base,
259 tp_error_get_dbus_name(error->code),
260 NULL,
261 TP_CONNECTION_STATUS_REASON_AUTHENTICATION_FAILED);
263 g_error_free(error);
268 static gboolean start_connecting(TpBaseConnection *base,
269 GError **error)
271 SipeConnection *self = SIPE_CONNECTION(base);
272 gboolean rc = TRUE;
273 gchar *uri = sipe_telepathy_protocol_normalize_contact(NULL,
274 self->account,
275 error);
277 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::start_connecting");
279 /* set up mandatory self-handle */
280 if (uri) {
281 base->self_handle = tp_handle_ensure(tp_base_connection_get_handles(base,
282 TP_HANDLE_TYPE_CONTACT),
283 uri,
284 NULL,
285 error);
286 g_free(uri);
287 if (!base->self_handle) {
288 SIPE_DEBUG_ERROR("SipeConnection::start_connecting: self handle creation failed: %s",
289 (*error)->message);
290 return(FALSE);
292 } else {
293 SIPE_DEBUG_ERROR("SipeConnection::start_connecting: %s",
294 (*error)->message);
295 return(FALSE);
298 tp_base_connection_change_status(base, TP_CONNECTION_STATUS_CONNECTING,
299 TP_CONNECTION_STATUS_REASON_REQUESTED);
301 /* map option list to flags - default is automatic */
302 self->authentication_type = SIPE_AUTHENTICATION_TYPE_AUTOMATIC;
303 if (sipe_strequal(self->authentication, "ntlm")) {
304 SIPE_DEBUG_INFO_NOFORMAT("start_connecting: NTLM selected");
305 self->authentication_type = SIPE_AUTHENTICATION_TYPE_NTLM;
306 } else
307 #ifdef HAVE_GSSAPI_GSSAPI_H
308 if (sipe_strequal(self->authentication, "krb5")) {
309 SIPE_DEBUG_INFO_NOFORMAT("start_connecting: KRB5 selected");
310 self->authentication_type = SIPE_AUTHENTICATION_TYPE_KERBEROS;
311 } else
312 #endif
313 if (sipe_strequal(self->authentication, "tls-dsk")) {
314 SIPE_DEBUG_INFO_NOFORMAT("start_connecting: TLS-DSK selected");
315 self->authentication_type = SIPE_AUTHENTICATION_TYPE_TLS_DSK;
318 /* Only ask for a password when required */
319 if (!sipe_core_transport_sip_requires_password(self->authentication_type,
320 self->sso) ||
321 (self->password && strlen(self->password)))
322 rc = connect_to_core(self, error);
323 else {
324 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::start_connecting: requesting password from user");
325 tp_simple_password_manager_prompt_async(self->password_manager,
326 password_manager_cb,
327 self);
330 return(rc);
333 static gboolean disconnect_from_core(gpointer data)
335 TpBaseConnection *base = data;
336 SipeConnection *self = SIPE_CONNECTION(base);
337 struct sipe_backend_private *telepathy_private = &self->private;
338 struct sipe_core_public *sipe_public = telepathy_private->public;
340 SIPE_DEBUG_INFO("disconnect_from_core: %p", sipe_public);
342 if (sipe_public)
343 sipe_core_deallocate(sipe_public);
344 telepathy_private->public = NULL;
345 telepathy_private->transport = NULL;
347 g_free(telepathy_private->ipaddress);
348 telepathy_private->ipaddress = NULL;
350 g_free(telepathy_private->message);
351 telepathy_private->message = NULL;
353 g_free(telepathy_private->cache_dir);
354 telepathy_private->cache_dir = NULL;
356 SIPE_DEBUG_INFO_NOFORMAT("disconnect_from_core: core deallocated");
358 /* now it is OK to destroy the connection object */
359 tp_base_connection_finish_shutdown(base);
361 return(FALSE);
364 static void shut_down(TpBaseConnection *base)
366 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::shut_down");
368 /* this can be called synchronously, defer destruction */
369 g_idle_add(disconnect_from_core, base);
372 static GPtrArray *create_channel_managers(TpBaseConnection *base)
374 SipeConnection *self = SIPE_CONNECTION(base);
375 GPtrArray *channel_managers = g_ptr_array_new();
377 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::create_channel_managers");
379 self->contact_list = sipe_telepathy_contact_list_new(base);
380 g_ptr_array_add(channel_managers, self->contact_list);
382 self->password_manager = tp_simple_password_manager_new(base);
383 g_ptr_array_add(channel_managers, self->password_manager);
385 g_ptr_array_add(channel_managers, sipe_telepathy_search_new(base));
387 self->tls_manager = sipe_telepathy_tls_new(base);
388 g_ptr_array_add(channel_managers, self->tls_manager);
390 return(channel_managers);
393 static void aliasing_fill_contact_attributes(GObject *object,
394 const GArray *contacts,
395 GHashTable *attributes)
397 SipeConnection *self = SIPE_CONNECTION(object);
398 guint i;
400 for (i = 0; i < contacts->len; i++) {
401 TpHandle contact = g_array_index(contacts, guint, i);
403 tp_contacts_mixin_set_contact_attribute(attributes,
404 contact,
405 TP_TOKEN_CONNECTION_INTERFACE_ALIASING_ALIAS,
406 tp_g_value_slice_new_string(
407 sipe_telepathy_buddy_get_alias(self->contact_list,
408 contact)));
412 static void avatars_fill_contact_attributes(GObject *object,
413 const GArray *contacts,
414 GHashTable *attributes)
416 SipeConnection *self = SIPE_CONNECTION(object);
417 guint i;
419 for (i = 0; i < contacts->len; i++) {
420 TpHandle contact = g_array_index(contacts, guint, i);
421 const gchar *hash = sipe_telepathy_buddy_get_hash(self->contact_list,
422 contact);
424 if (!hash) hash = "";
425 tp_contacts_mixin_set_contact_attribute(attributes,
426 contact,
427 TP_IFACE_CONNECTION_INTERFACE_AVATARS"/token",
428 tp_g_value_slice_new_string(hash));
432 static void contact_info_properties_getter(GObject *object,
433 SIPE_UNUSED_PARAMETER GQuark interface,
434 GQuark name,
435 GValue *value,
436 gpointer getter_data)
438 GQuark fields = g_quark_from_static_string("SupportedFields");
440 if (name == fields)
441 g_value_set_boxed(value,
442 SIPE_CONNECTION(object)->contact_info_fields);
443 else
444 g_value_set_uint(value,
445 GPOINTER_TO_UINT(getter_data));
448 static void sipe_connection_constructed(GObject *object)
450 SipeConnection *self = SIPE_CONNECTION(object);
451 TpBaseConnection *base = TP_BASE_CONNECTION(object);
452 void (*chain_up)(GObject *) = G_OBJECT_CLASS(sipe_connection_parent_class)->constructed;
454 if (chain_up)
455 chain_up(object);
457 tp_contacts_mixin_init(object,
458 G_STRUCT_OFFSET(SipeConnection, contacts_mixin));
459 tp_base_connection_register_with_contacts_mixin(base);
461 tp_base_contact_list_mixin_register_with_contacts_mixin(base);
463 tp_contacts_mixin_add_contact_attributes_iface(object,
464 TP_IFACE_CONNECTION_INTERFACE_ALIASING,
465 aliasing_fill_contact_attributes);
466 tp_contacts_mixin_add_contact_attributes_iface(object,
467 TP_IFACE_CONNECTION_INTERFACE_AVATARS,
468 avatars_fill_contact_attributes);
470 tp_presence_mixin_init(object,
471 G_STRUCT_OFFSET(SipeConnection,
472 presence_mixin));
473 tp_presence_mixin_simple_presence_register_with_contacts_mixin(object);
475 self->contact_info_fields = sipe_telepathy_contact_info_fields();
478 static void sipe_connection_finalize(GObject *object)
480 SipeConnection *self = SIPE_CONNECTION(object);
482 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::finalize");
484 tp_contacts_mixin_finalize(object);
485 tp_presence_mixin_finalize(object);
486 g_boxed_free(TP_ARRAY_TYPE_FIELD_SPECS, self->contact_info_fields);
488 g_free(self->authentication);
489 g_free(self->user_agent);
490 g_free(self->port);
491 g_free(self->server);
492 g_free(self->password);
493 g_free(self->login);
494 g_free(self->account);
496 G_OBJECT_CLASS(sipe_connection_parent_class)->finalize(object);
500 * Connection class - type implementation
502 static const gchar *interfaces_always_present[] = {
503 /* @TODO */
504 TP_IFACE_CONNECTION_INTERFACE_ALIASING,
505 TP_IFACE_CONNECTION_INTERFACE_AVATARS,
506 TP_IFACE_CONNECTION_INTERFACE_CONTACT_GROUPS,
507 TP_IFACE_CONNECTION_INTERFACE_CONTACT_INFO,
508 TP_IFACE_CONNECTION_INTERFACE_CONTACT_LIST,
509 TP_IFACE_CONNECTION_INTERFACE_CONTACTS,
510 TP_IFACE_CONNECTION_INTERFACE_PRESENCE,
511 TP_IFACE_CONNECTION_INTERFACE_REQUESTS,
512 TP_IFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE,
513 NULL
516 static void sipe_connection_class_init(SipeConnectionClass *klass)
518 GObjectClass *object_class = G_OBJECT_CLASS(klass);
519 TpBaseConnectionClass *base_class = TP_BASE_CONNECTION_CLASS(klass);
520 static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = {
522 /* 0 */
523 .name = TP_IFACE_CONNECTION_INTERFACE_CONTACT_INFO,
524 .getter = contact_info_properties_getter,
525 .setter = NULL,
528 /* LAST! */
529 .name = NULL,
533 /* initalize non-constant fields */
534 prop_interfaces[0].props = sipe_telepathy_contact_info_props();
536 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::class_init");
538 object_class->constructed = sipe_connection_constructed;
539 object_class->finalize = sipe_connection_finalize;
541 base_class->create_handle_repos = create_handle_repos;
542 base_class->start_connecting = start_connecting;
543 base_class->shut_down = shut_down;
544 base_class->create_channel_managers = create_channel_managers;
546 base_class->interfaces_always_present = interfaces_always_present;
548 klass->properties_mixin.interfaces = prop_interfaces;
549 tp_dbus_properties_mixin_class_init(object_class,
550 G_STRUCT_OFFSET(SipeConnectionClass,
551 properties_mixin));
552 tp_contacts_mixin_class_init(object_class,
553 G_STRUCT_OFFSET(SipeConnectionClass,
554 contacts_mixin));
555 sipe_telepathy_status_init(object_class,
556 G_STRUCT_OFFSET(SipeConnectionClass,
557 presence_mixin));
558 tp_presence_mixin_simple_presence_init_dbus_properties(object_class);
559 tp_base_contact_list_mixin_class_init(base_class);
562 static void sipe_connection_init(SIPE_UNUSED_PARAMETER SipeConnection *self)
564 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::init");
568 * Connection class - interface implementation
570 * Contact aliases
572 static void get_alias_flags(TpSvcConnectionInterfaceAliasing *aliasing,
573 DBusGMethodInvocation *context)
575 TpBaseConnection *base = TP_BASE_CONNECTION(aliasing);
577 TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED(base, context);
578 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::get_alias_flags called");
580 tp_svc_connection_interface_aliasing_return_from_get_alias_flags(context,
581 TP_CONNECTION_ALIAS_FLAG_USER_SET);
584 static void get_aliases(TpSvcConnectionInterfaceAliasing *aliasing,
585 const GArray *contacts,
586 DBusGMethodInvocation *context)
588 SipeConnection *self = SIPE_CONNECTION(aliasing);
589 TpBaseConnection *base = TP_BASE_CONNECTION(aliasing);
590 TpHandleRepoIface *contact_repo = tp_base_connection_get_handles(base,
591 TP_HANDLE_TYPE_CONTACT);
592 GError *error = NULL;
593 GHashTable *result;
594 guint i;
596 TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED(base, context);
597 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::get_aliases called");
599 if (!tp_handles_are_valid(contact_repo, contacts, FALSE, &error)) {
600 dbus_g_method_return_error(context, error);
601 g_error_free(error);
602 return;
605 result = g_hash_table_new(g_direct_hash, g_direct_equal);
607 for (i = 0; i < contacts->len; i++) {
608 TpHandle contact = g_array_index(contacts, TpHandle, i);
609 const gchar *alias = sipe_telepathy_buddy_get_alias(self->contact_list,
610 contact);
611 g_hash_table_insert(result,
612 GUINT_TO_POINTER(contact),
613 (gchar *) alias);
616 tp_svc_connection_interface_aliasing_return_from_get_aliases(context,
617 result);
618 g_hash_table_unref(result);
621 static void request_aliases(TpSvcConnectionInterfaceAliasing *aliasing,
622 const GArray *contacts,
623 DBusGMethodInvocation *context)
625 SipeConnection *self = SIPE_CONNECTION(aliasing);
626 TpBaseConnection *base = TP_BASE_CONNECTION(aliasing);
627 TpHandleRepoIface *contact_repo = tp_base_connection_get_handles(base,
628 TP_HANDLE_TYPE_CONTACT);
629 GError *error = NULL;
630 GPtrArray *result;
631 gchar **strings;
632 guint i;
634 TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED(base, context);
635 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::request_aliases called");
637 if (!tp_handles_are_valid(contact_repo, contacts, FALSE, &error)) {
638 dbus_g_method_return_error(context, error);
639 g_error_free(error);
640 return;
643 result = g_ptr_array_sized_new(contacts->len + 1);
645 for (i = 0; i < contacts->len; i++) {
646 TpHandle contact = g_array_index(contacts, TpHandle, i);
647 const gchar *alias = sipe_telepathy_buddy_get_alias(self->contact_list,
648 contact);
649 g_ptr_array_add(result, (gchar *) alias);
652 g_ptr_array_add(result, NULL);
653 strings = (gchar **) g_ptr_array_free(result, FALSE);
655 tp_svc_connection_interface_aliasing_return_from_request_aliases(context,
656 (const gchar **) strings);
657 g_free(strings);
660 static void set_aliases(TpSvcConnectionInterfaceAliasing *aliasing,
661 GHashTable *aliases,
662 DBusGMethodInvocation *context)
664 SipeConnection *self = SIPE_CONNECTION(aliasing);
665 TpBaseConnection *base = TP_BASE_CONNECTION(aliasing);
666 TpHandleRepoIface *contact_repo = tp_base_connection_get_handles(base,
667 TP_HANDLE_TYPE_CONTACT);
668 GHashTableIter iter;
669 gpointer key, value;
671 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::set_aliases called");
673 g_hash_table_iter_init(&iter, aliases);
675 while (g_hash_table_iter_next(&iter, &key, NULL)) {
676 GError *error = NULL;
678 if (!tp_handle_is_valid(contact_repo,
679 GPOINTER_TO_UINT(key),
680 &error)) {
681 dbus_g_method_return_error(context, error);
682 g_error_free(error);
683 return;
687 g_hash_table_iter_init(&iter, aliases);
689 while (g_hash_table_iter_next(&iter, &key, &value)) {
690 sipe_telepathy_buddy_set_alias(self->contact_list,
691 GPOINTER_TO_UINT(key),
692 value);
695 tp_svc_connection_interface_aliasing_return_from_set_aliases(context);
698 static void init_aliasing(gpointer iface,
699 SIPE_UNUSED_PARAMETER gpointer iface_data)
701 TpSvcConnectionInterfaceAliasingClass *klass = iface;
703 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::init_aliasing called");
705 tp_svc_connection_interface_aliasing_implement_get_alias_flags(klass, get_alias_flags);
706 tp_svc_connection_interface_aliasing_implement_request_aliases(klass, request_aliases);
707 tp_svc_connection_interface_aliasing_implement_get_aliases(klass, get_aliases);
708 tp_svc_connection_interface_aliasing_implement_set_aliases(klass, set_aliases);
711 /* create new connection object */
712 TpBaseConnection *sipe_telepathy_connection_new(TpBaseProtocol *protocol,
713 GHashTable *params,
714 SIPE_UNUSED_PARAMETER GError **error)
716 SipeConnection *conn = g_object_new(SIPE_TYPE_CONNECTION,
717 "protocol", tp_base_protocol_get_name(protocol),
718 NULL);
719 const gchar *value;
720 guint port;
721 gboolean boolean_value;
722 gboolean valid;
724 SIPE_DEBUG_INFO_NOFORMAT("sipe_telepathy_connection_new");
726 /* initialize private fields */
727 conn->is_disconnecting = FALSE;
729 /* account is required field */
730 conn->account = g_strdup(tp_asv_get_string(params, "account"));
732 /* if login is not specified, account value will be used in connect_to_core */
733 value = tp_asv_get_string(params, "login");
734 if (value && strlen(value))
735 conn->login = g_strdup(value);
736 else
737 conn->login = NULL;
739 /* password */
740 value = tp_asv_get_string(params, "password");
741 if (value && strlen(value))
742 conn->password = g_strdup(value);
743 else
744 conn->password = NULL;
746 /* server name */
747 value = tp_asv_get_string(params, "server");
748 if (value && strlen(value))
749 conn->server = g_strdup(value);
750 else
751 conn->server = NULL;
753 /* server port: core expects a string */
754 port = tp_asv_get_uint32(params, "port", &valid);
755 if (valid)
756 conn->port = g_strdup_printf("%d", port);
757 else
758 conn->port = NULL;
760 /* transport type */
761 value = tp_asv_get_string(params, "transport");
762 if (sipe_strequal(value, "auto")) {
763 conn->transport = conn->server ?
764 SIPE_TRANSPORT_TLS : SIPE_TRANSPORT_AUTO;
765 } else if (sipe_strequal(value, "tls")) {
766 conn->transport = SIPE_TRANSPORT_TLS;
767 } else {
768 conn->transport = SIPE_TRANSPORT_TCP;
771 /* User-Agent: override */
772 value = tp_asv_get_string(params, "useragent");
773 if (value && strlen(value))
774 conn->user_agent = g_strdup(value);
775 else
776 conn->user_agent = NULL;
778 /* authentication type */
779 value = tp_asv_get_string(params, "authentication");
780 if (value && strlen(value) && strcmp(value, "ntlm"))
781 conn->authentication = g_strdup(value);
782 else
783 conn->authentication = NULL; /* NTLM is default */
785 /* Single Sign-On */
786 boolean_value = tp_asv_get_boolean(params, "single-sign-on", &valid);
787 if (valid)
788 conn->sso = boolean_value;
789 else
790 conn->sso = FALSE;
792 /* Don't publish my calendar information */
793 boolean_value = tp_asv_get_boolean(params, "don't-publish-calendar", &valid);
794 if (valid)
795 conn->dont_publish = boolean_value;
796 else
797 conn->dont_publish = FALSE;
799 return(TP_BASE_CONNECTION(conn));
802 void sipe_telepathy_connection_alias_updated(TpBaseConnection *connection,
803 guint contact,
804 const gchar *alias)
806 GPtrArray *aliases = g_ptr_array_sized_new(1);
807 GValueArray *pair = g_value_array_new(2);
809 g_value_array_append(pair, NULL);
810 g_value_array_append(pair, NULL);
811 g_value_init(pair->values + 0, G_TYPE_UINT);
812 g_value_init(pair->values + 1, G_TYPE_STRING);
813 g_value_set_uint(pair->values + 0, contact);
814 g_value_set_string(pair->values + 1, alias);
815 g_ptr_array_add(aliases, pair);
817 tp_svc_connection_interface_aliasing_emit_aliases_changed(SIPE_CONNECTION(connection),
818 aliases);
820 g_ptr_array_unref(aliases);
821 g_value_array_free(pair);
824 struct sipe_backend_private *sipe_telepathy_connection_private(GObject *object)
826 SipeConnection *self = SIPE_CONNECTION(object);
827 /* connected to core already? */
828 if (self->private.public)
829 return(&self->private);
830 else
831 return(NULL);
835 * Backend adaptor functions
837 void sipe_backend_connection_completed(struct sipe_core_public *sipe_public)
839 SipeConnection *self = SIPE_PUBLIC_TO_CONNECTION;
840 TpBaseConnection *base = TP_BASE_CONNECTION(self);
842 /* we are only allowed to do this once */
843 if (base->status != TP_CONNECTION_STATUS_CONNECTED)
844 tp_base_connection_change_status(base,
845 TP_CONNECTION_STATUS_CONNECTED,
846 TP_CONNECTION_STATUS_REASON_REQUESTED);
849 void sipe_backend_connection_error(struct sipe_core_public *sipe_public,
850 sipe_connection_error error,
851 const gchar *msg)
853 SipeConnection *self = SIPE_PUBLIC_TO_CONNECTION;
854 TpBaseConnection *base = TP_BASE_CONNECTION(self);
855 GHashTable *details = tp_asv_new("server-message", G_TYPE_STRING, msg,
856 NULL);
857 TpConnectionStatusReason reason;
858 const gchar *name;
860 self->is_disconnecting = TRUE;
862 switch (error) {
863 case SIPE_CONNECTION_ERROR_NETWORK:
864 reason = TP_CONNECTION_STATUS_REASON_NETWORK_ERROR;
865 if (base->status == TP_CONNECTION_STATUS_CONNECTING)
866 name = TP_ERROR_STR_CONNECTION_FAILED;
867 else
868 name = TP_ERROR_STR_CONNECTION_LOST;
869 break;
871 case SIPE_CONNECTION_ERROR_INVALID_USERNAME:
872 case SIPE_CONNECTION_ERROR_INVALID_SETTINGS:
873 case SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED:
874 case SIPE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE:
875 /* copied from haze code. I agree there should be better ones */
876 reason = TP_CONNECTION_STATUS_REASON_AUTHENTICATION_FAILED;
877 name = TP_ERROR_STR_AUTHENTICATION_FAILED;
878 break;
880 default:
881 reason = TP_CONNECTION_STATUS_REASON_NONE_SPECIFIED;
882 name = TP_ERROR_STR_DISCONNECTED;
883 break;
886 SIPE_DEBUG_ERROR("sipe_backend_connection_error: %s (%s)", name, msg);
887 tp_base_connection_disconnect_with_dbus_error(base,
888 name,
889 details,
890 reason);
891 g_hash_table_unref(details);
894 gboolean sipe_backend_connection_is_disconnecting(struct sipe_core_public *sipe_public)
896 SipeConnection *self = SIPE_PUBLIC_TO_CONNECTION;
898 /* disconnect was requested or transport was already disconnected */
899 return(self->is_disconnecting ||
900 self->private.transport == NULL);
903 gboolean sipe_backend_connection_is_valid(struct sipe_core_public *sipe_public)
905 return(!sipe_backend_connection_is_disconnecting(sipe_public));
908 const gchar *sipe_backend_setting(struct sipe_core_public *sipe_public,
909 sipe_setting type)
911 SipeConnection *self = SIPE_PUBLIC_TO_CONNECTION;
912 const gchar *value;
914 switch (type) {
915 case SIPE_SETTING_USER_AGENT:
916 value = self->user_agent;
917 break;
918 default:
919 /* @TODO: update when settings are implemented */
920 value = NULL;
921 break;
924 return(value);
929 Local Variables:
930 mode: c
931 c-file-style: "bsd"
932 indent-tabs-mode: t
933 tab-width: 8
934 End: