Release 1.25.0 -- Buddy Idle Time, RTF
[siplcs.git] / src / telepathy / telepathy-connection.c
blobc4ff4e1830429f03dedea8558c4156700642b5cc
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 allow_web_photo;
80 gboolean is_disconnecting;
82 GPtrArray *contact_info_fields;
83 } SipeConnection;
85 #define SIPE_PUBLIC_TO_CONNECTION sipe_public->backend_private->connection
88 * Connection class - type macros
90 static GType sipe_connection_get_type(void) G_GNUC_CONST;
91 #define SIPE_TYPE_CONNECTION \
92 (sipe_connection_get_type())
93 #define SIPE_CONNECTION(obj) \
94 (G_TYPE_CHECK_INSTANCE_CAST((obj), SIPE_TYPE_CONNECTION, \
95 SipeConnection))
96 G_END_DECLS
99 * Connection class - type definition
101 static void init_aliasing (gpointer, gpointer);
102 G_DEFINE_TYPE_WITH_CODE(SipeConnection,
103 sipe_connection,
104 TP_TYPE_BASE_CONNECTION,
105 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_ALIASING,
106 init_aliasing);
107 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_AVATARS,
108 sipe_telepathy_avatars_iface_init);
109 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACTS,
110 tp_contacts_mixin_iface_init);
111 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACT_GROUPS,
112 tp_base_contact_list_mixin_groups_iface_init);
113 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACT_INFO,
114 sipe_telepathy_contact_info_iface_init);
115 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACT_LIST,
116 tp_base_contact_list_mixin_list_iface_init);
117 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_PRESENCE,
118 tp_presence_mixin_iface_init);
119 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_SIMPLE_PRESENCE,
120 tp_presence_mixin_simple_presence_iface_init);
121 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_DBUS_PROPERTIES,
122 tp_dbus_properties_mixin_iface_init);
127 * Connection class - instance methods
129 static gchar *normalize_contact(SIPE_UNUSED_PARAMETER TpHandleRepoIface *repo,
130 const gchar *id,
131 SIPE_UNUSED_PARAMETER gpointer context,
132 GError **error)
134 return(sipe_telepathy_protocol_normalize_contact(NULL, id, error));
137 static void create_handle_repos(SIPE_UNUSED_PARAMETER TpBaseConnection *conn,
138 TpHandleRepoIface *repos[NUM_TP_HANDLE_TYPES])
140 repos[TP_HANDLE_TYPE_CONTACT] = tp_dynamic_handle_repo_new(TP_HANDLE_TYPE_CONTACT,
141 normalize_contact,
142 NULL);
145 static gboolean connect_to_core(SipeConnection *self,
146 GError **error)
148 struct sipe_core_public *sipe_public;
149 const gchar *errmsg;
151 sipe_public = sipe_core_allocate(self->account,
152 self->sso,
153 self->login,
154 self->password,
155 NULL, /* @TODO: email */
156 NULL, /* @TODO: email_url */
157 &errmsg);
159 SIPE_DEBUG_INFO("connect_to_core: created %p", sipe_public);
161 if (sipe_public) {
162 struct sipe_backend_private *telepathy_private = &self->private;
164 /* initialize backend private data */
165 sipe_public->backend_private = telepathy_private;
166 telepathy_private->public = sipe_public;
167 telepathy_private->contact_list = self->contact_list;
168 telepathy_private->connection = self;
169 telepathy_private->activity = SIPE_ACTIVITY_UNSET;
170 telepathy_private->cache_dir = g_build_path(G_DIR_SEPARATOR_S,
171 g_get_user_cache_dir(),
172 "telepathy",
173 "sipe",
174 self->account,
175 NULL);
176 telepathy_private->message = NULL;
177 telepathy_private->tls_manager = self->tls_manager;
178 telepathy_private->transport = NULL;
180 /* make sure cache directory exists */
181 if (!g_file_test(telepathy_private->cache_dir,
182 G_FILE_TEST_IS_DIR) &&
183 (g_mkdir_with_parents(telepathy_private->cache_dir,
184 S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
185 == 0))
186 SIPE_DEBUG_INFO("connect_to_core: created cache directory %s",
187 telepathy_private->cache_dir);
189 SIPE_CORE_FLAG_UNSET(DONT_PUBLISH);
190 if (self->dont_publish)
191 SIPE_CORE_FLAG_SET(DONT_PUBLISH);
192 SIPE_CORE_FLAG_UNSET(ALLOW_WEB_PHOTO);
193 if (self->allow_web_photo)
194 SIPE_CORE_FLAG_SET(ALLOW_WEB_PHOTO);
196 sipe_core_transport_sip_connect(sipe_public,
197 self->transport,
198 self->authentication_type,
199 self->server,
200 self->port);
202 return(TRUE);
203 } else {
204 g_set_error_literal(error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
205 errmsg);
206 return(FALSE);
210 static void password_manager_cb(GObject *source,
211 GAsyncResult *result,
212 gpointer data)
214 SipeConnection *self = data;
215 TpBaseConnection *base = TP_BASE_CONNECTION(self);
216 GError *error = NULL;
217 const GString *password = tp_simple_password_manager_prompt_finish(
218 TP_SIMPLE_PASSWORD_MANAGER(source),
219 result,
220 &error);
222 if (password == NULL) {
223 SIPE_DEBUG_ERROR("password_manager_cb: failed: %s",
224 error ? error->message : "UNKNOWN");
226 if (base->status != TP_CONNECTION_STATUS_DISCONNECTED) {
227 tp_base_connection_disconnect_with_dbus_error(base,
228 error ? tp_error_get_dbus_name(error->code) : "",
229 NULL,
230 TP_CONNECTION_STATUS_REASON_AUTHENTICATION_FAILED);
232 if (error)
233 g_error_free(error);
234 } else {
236 g_free(self->password);
237 self->password = g_strdup(password->str);
239 if (!connect_to_core(self, &error)) {
240 if (base->status != TP_CONNECTION_STATUS_DISCONNECTED) {
241 tp_base_connection_disconnect_with_dbus_error(base,
242 tp_error_get_dbus_name(error->code),
243 NULL,
244 TP_CONNECTION_STATUS_REASON_AUTHENTICATION_FAILED);
246 g_error_free(error);
251 static gboolean start_connecting(TpBaseConnection *base,
252 GError **error)
254 SipeConnection *self = SIPE_CONNECTION(base);
255 gboolean rc = TRUE;
256 gchar *uri = sipe_telepathy_protocol_normalize_contact(NULL,
257 self->account,
258 error);
260 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::start_connecting");
262 /* set up mandatory self-handle */
263 if (uri) {
264 base->self_handle = tp_handle_ensure(tp_base_connection_get_handles(base,
265 TP_HANDLE_TYPE_CONTACT),
266 uri,
267 NULL,
268 error);
269 g_free(uri);
270 if (!base->self_handle) {
271 SIPE_DEBUG_ERROR("SipeConnection::start_connecting: self handle creation failed: %s",
272 (*error)->message);
273 return(FALSE);
275 } else {
276 SIPE_DEBUG_ERROR("SipeConnection::start_connecting: %s",
277 (*error)->message);
278 return(FALSE);
281 tp_base_connection_change_status(base, TP_CONNECTION_STATUS_CONNECTING,
282 TP_CONNECTION_STATUS_REASON_REQUESTED);
284 /* map option list to flags - default is automatic */
285 self->authentication_type = SIPE_AUTHENTICATION_TYPE_AUTOMATIC;
286 if (sipe_strequal(self->authentication, "ntlm")) {
287 SIPE_DEBUG_INFO_NOFORMAT("start_connecting: NTLM selected");
288 self->authentication_type = SIPE_AUTHENTICATION_TYPE_NTLM;
289 } else
290 #ifdef HAVE_GSSAPI_GSSAPI_H
291 if (sipe_strequal(self->authentication, "krb5")) {
292 SIPE_DEBUG_INFO_NOFORMAT("start_connecting: KRB5 selected");
293 self->authentication_type = SIPE_AUTHENTICATION_TYPE_KERBEROS;
294 } else
295 #endif
296 if (sipe_strequal(self->authentication, "tls-dsk")) {
297 SIPE_DEBUG_INFO_NOFORMAT("start_connecting: TLS-DSK selected");
298 self->authentication_type = SIPE_AUTHENTICATION_TYPE_TLS_DSK;
301 /* Only ask for a password when required */
302 if (!sipe_core_transport_sip_requires_password(self->authentication_type,
303 self->sso) ||
304 (self->password && strlen(self->password)))
305 rc = connect_to_core(self, error);
306 else {
307 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::start_connecting: requesting password from user");
308 tp_simple_password_manager_prompt_async(self->password_manager,
309 password_manager_cb,
310 self);
313 return(rc);
316 static gboolean disconnect_from_core(gpointer data)
318 TpBaseConnection *base = data;
319 SipeConnection *self = SIPE_CONNECTION(base);
320 struct sipe_backend_private *telepathy_private = &self->private;
321 struct sipe_core_public *sipe_public = telepathy_private->public;
323 SIPE_DEBUG_INFO("disconnect_from_core: %p", sipe_public);
325 if (sipe_public)
326 sipe_core_deallocate(sipe_public);
327 telepathy_private->public = NULL;
328 telepathy_private->transport = NULL;
330 g_free(telepathy_private->message);
331 telepathy_private->message = NULL;
333 g_free(telepathy_private->cache_dir);
334 telepathy_private->cache_dir = NULL;
336 SIPE_DEBUG_INFO_NOFORMAT("disconnect_from_core: core deallocated");
338 /* now it is OK to destroy the connection object */
339 tp_base_connection_finish_shutdown(base);
341 return(FALSE);
344 static void shut_down(TpBaseConnection *base)
346 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::shut_down");
348 /* this can be called synchronously, defer destruction */
349 g_idle_add(disconnect_from_core, base);
352 static GPtrArray *create_channel_managers(TpBaseConnection *base)
354 SipeConnection *self = SIPE_CONNECTION(base);
355 GPtrArray *channel_managers = g_ptr_array_new();
357 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::create_channel_managers");
359 self->contact_list = sipe_telepathy_contact_list_new(base);
360 g_ptr_array_add(channel_managers, self->contact_list);
362 self->password_manager = tp_simple_password_manager_new(base);
363 g_ptr_array_add(channel_managers, self->password_manager);
365 g_ptr_array_add(channel_managers, sipe_telepathy_search_new(base));
367 self->tls_manager = sipe_telepathy_tls_new(base);
368 g_ptr_array_add(channel_managers, self->tls_manager);
370 return(channel_managers);
373 static void aliasing_fill_contact_attributes(GObject *object,
374 const GArray *contacts,
375 GHashTable *attributes)
377 SipeConnection *self = SIPE_CONNECTION(object);
378 guint i;
380 for (i = 0; i < contacts->len; i++) {
381 TpHandle contact = g_array_index(contacts, guint, i);
383 tp_contacts_mixin_set_contact_attribute(attributes,
384 contact,
385 TP_TOKEN_CONNECTION_INTERFACE_ALIASING_ALIAS,
386 tp_g_value_slice_new_string(
387 sipe_telepathy_buddy_get_alias(self->contact_list,
388 contact)));
392 static void avatars_fill_contact_attributes(GObject *object,
393 const GArray *contacts,
394 GHashTable *attributes)
396 SipeConnection *self = SIPE_CONNECTION(object);
397 guint i;
399 for (i = 0; i < contacts->len; i++) {
400 TpHandle contact = g_array_index(contacts, guint, i);
401 const gchar *hash = sipe_telepathy_buddy_get_hash(self->contact_list,
402 contact);
404 if (!hash) hash = "";
405 tp_contacts_mixin_set_contact_attribute(attributes,
406 contact,
407 TP_IFACE_CONNECTION_INTERFACE_AVATARS"/token",
408 tp_g_value_slice_new_string(hash));
412 static void contact_info_properties_getter(GObject *object,
413 SIPE_UNUSED_PARAMETER GQuark interface,
414 GQuark name,
415 GValue *value,
416 gpointer getter_data)
418 GQuark fields = g_quark_from_static_string("SupportedFields");
420 if (name == fields)
421 g_value_set_boxed(value,
422 SIPE_CONNECTION(object)->contact_info_fields);
423 else
424 g_value_set_uint(value,
425 GPOINTER_TO_UINT(getter_data));
428 static void sipe_connection_constructed(GObject *object)
430 SipeConnection *self = SIPE_CONNECTION(object);
431 TpBaseConnection *base = TP_BASE_CONNECTION(object);
432 void (*chain_up)(GObject *) = G_OBJECT_CLASS(sipe_connection_parent_class)->constructed;
434 if (chain_up)
435 chain_up(object);
437 tp_contacts_mixin_init(object,
438 G_STRUCT_OFFSET(SipeConnection, contacts_mixin));
439 tp_base_connection_register_with_contacts_mixin(base);
441 tp_base_contact_list_mixin_register_with_contacts_mixin(base);
443 tp_contacts_mixin_add_contact_attributes_iface(object,
444 TP_IFACE_CONNECTION_INTERFACE_ALIASING,
445 aliasing_fill_contact_attributes);
446 tp_contacts_mixin_add_contact_attributes_iface(object,
447 TP_IFACE_CONNECTION_INTERFACE_AVATARS,
448 avatars_fill_contact_attributes);
450 tp_presence_mixin_init(object,
451 G_STRUCT_OFFSET(SipeConnection,
452 presence_mixin));
453 tp_presence_mixin_simple_presence_register_with_contacts_mixin(object);
455 self->contact_info_fields = sipe_telepathy_contact_info_fields();
458 static void sipe_connection_finalize(GObject *object)
460 SipeConnection *self = SIPE_CONNECTION(object);
462 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::finalize");
464 tp_contacts_mixin_finalize(object);
465 tp_presence_mixin_finalize(object);
466 g_boxed_free(TP_ARRAY_TYPE_FIELD_SPECS, self->contact_info_fields);
468 g_free(self->authentication);
469 g_free(self->user_agent);
470 g_free(self->port);
471 g_free(self->server);
472 g_free(self->password);
473 g_free(self->login);
474 g_free(self->account);
476 G_OBJECT_CLASS(sipe_connection_parent_class)->finalize(object);
480 * Connection class - type implementation
482 static const gchar *interfaces_always_present[] = {
483 /* @TODO */
484 TP_IFACE_CONNECTION_INTERFACE_ALIASING,
485 TP_IFACE_CONNECTION_INTERFACE_AVATARS,
486 TP_IFACE_CONNECTION_INTERFACE_CONTACT_GROUPS,
487 TP_IFACE_CONNECTION_INTERFACE_CONTACT_INFO,
488 TP_IFACE_CONNECTION_INTERFACE_CONTACT_LIST,
489 TP_IFACE_CONNECTION_INTERFACE_CONTACTS,
490 TP_IFACE_CONNECTION_INTERFACE_PRESENCE,
491 TP_IFACE_CONNECTION_INTERFACE_REQUESTS,
492 TP_IFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE,
493 NULL
496 static void sipe_connection_class_init(SipeConnectionClass *klass)
498 GObjectClass *object_class = G_OBJECT_CLASS(klass);
499 TpBaseConnectionClass *base_class = TP_BASE_CONNECTION_CLASS(klass);
500 static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = {
502 /* 0 */
503 .name = TP_IFACE_CONNECTION_INTERFACE_CONTACT_INFO,
504 .getter = contact_info_properties_getter,
505 .setter = NULL,
508 /* LAST! */
509 .name = NULL,
513 /* initalize non-constant fields */
514 prop_interfaces[0].props = sipe_telepathy_contact_info_props();
516 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::class_init");
518 object_class->constructed = sipe_connection_constructed;
519 object_class->finalize = sipe_connection_finalize;
521 base_class->create_handle_repos = create_handle_repos;
522 base_class->start_connecting = start_connecting;
523 base_class->shut_down = shut_down;
524 base_class->create_channel_managers = create_channel_managers;
526 base_class->interfaces_always_present = interfaces_always_present;
528 klass->properties_mixin.interfaces = prop_interfaces;
529 tp_dbus_properties_mixin_class_init(object_class,
530 G_STRUCT_OFFSET(SipeConnectionClass,
531 properties_mixin));
532 tp_contacts_mixin_class_init(object_class,
533 G_STRUCT_OFFSET(SipeConnectionClass,
534 contacts_mixin));
535 sipe_telepathy_status_init(object_class,
536 G_STRUCT_OFFSET(SipeConnectionClass,
537 presence_mixin));
538 tp_presence_mixin_simple_presence_init_dbus_properties(object_class);
539 tp_base_contact_list_mixin_class_init(base_class);
542 static void sipe_connection_init(SIPE_UNUSED_PARAMETER SipeConnection *self)
544 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::init");
548 * Connection class - interface implementation
550 * Contact aliases
552 static void get_alias_flags(TpSvcConnectionInterfaceAliasing *aliasing,
553 DBusGMethodInvocation *context)
555 TpBaseConnection *base = TP_BASE_CONNECTION(aliasing);
557 TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED(base, context);
558 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::get_alias_flags called");
560 tp_svc_connection_interface_aliasing_return_from_get_alias_flags(context,
561 TP_CONNECTION_ALIAS_FLAG_USER_SET);
564 static void get_aliases(TpSvcConnectionInterfaceAliasing *aliasing,
565 const GArray *contacts,
566 DBusGMethodInvocation *context)
568 SipeConnection *self = SIPE_CONNECTION(aliasing);
569 TpBaseConnection *base = TP_BASE_CONNECTION(aliasing);
570 TpHandleRepoIface *contact_repo = tp_base_connection_get_handles(base,
571 TP_HANDLE_TYPE_CONTACT);
572 GError *error = NULL;
573 GHashTable *result;
574 guint i;
576 TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED(base, context);
577 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::get_aliases called");
579 if (!tp_handles_are_valid(contact_repo, contacts, FALSE, &error)) {
580 dbus_g_method_return_error(context, error);
581 g_error_free(error);
582 return;
585 result = g_hash_table_new(g_direct_hash, g_direct_equal);
587 for (i = 0; i < contacts->len; i++) {
588 TpHandle contact = g_array_index(contacts, TpHandle, i);
589 const gchar *alias = sipe_telepathy_buddy_get_alias(self->contact_list,
590 contact);
591 g_hash_table_insert(result,
592 GUINT_TO_POINTER(contact),
593 (gchar *) alias);
596 tp_svc_connection_interface_aliasing_return_from_get_aliases(context,
597 result);
598 g_hash_table_unref(result);
601 static void request_aliases(TpSvcConnectionInterfaceAliasing *aliasing,
602 const GArray *contacts,
603 DBusGMethodInvocation *context)
605 SipeConnection *self = SIPE_CONNECTION(aliasing);
606 TpBaseConnection *base = TP_BASE_CONNECTION(aliasing);
607 TpHandleRepoIface *contact_repo = tp_base_connection_get_handles(base,
608 TP_HANDLE_TYPE_CONTACT);
609 GError *error = NULL;
610 GPtrArray *result;
611 gchar **strings;
612 guint i;
614 TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED(base, context);
615 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::request_aliases called");
617 if (!tp_handles_are_valid(contact_repo, contacts, FALSE, &error)) {
618 dbus_g_method_return_error(context, error);
619 g_error_free(error);
620 return;
623 result = g_ptr_array_sized_new(contacts->len + 1);
625 for (i = 0; i < contacts->len; i++) {
626 TpHandle contact = g_array_index(contacts, TpHandle, i);
627 const gchar *alias = sipe_telepathy_buddy_get_alias(self->contact_list,
628 contact);
629 g_ptr_array_add(result, (gchar *) alias);
632 g_ptr_array_add(result, NULL);
633 strings = (gchar **) g_ptr_array_free(result, FALSE);
635 tp_svc_connection_interface_aliasing_return_from_request_aliases(context,
636 (const gchar **) strings);
637 g_free(strings);
640 static void set_aliases(TpSvcConnectionInterfaceAliasing *aliasing,
641 GHashTable *aliases,
642 DBusGMethodInvocation *context)
644 SipeConnection *self = SIPE_CONNECTION(aliasing);
645 TpBaseConnection *base = TP_BASE_CONNECTION(aliasing);
646 TpHandleRepoIface *contact_repo = tp_base_connection_get_handles(base,
647 TP_HANDLE_TYPE_CONTACT);
648 GHashTableIter iter;
649 gpointer key, value;
651 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::set_aliases called");
653 g_hash_table_iter_init(&iter, aliases);
655 while (g_hash_table_iter_next(&iter, &key, NULL)) {
656 GError *error = NULL;
658 if (!tp_handle_is_valid(contact_repo,
659 GPOINTER_TO_UINT(key),
660 &error)) {
661 dbus_g_method_return_error(context, error);
662 g_error_free(error);
663 return;
667 g_hash_table_iter_init(&iter, aliases);
669 while (g_hash_table_iter_next(&iter, &key, &value)) {
670 sipe_telepathy_buddy_set_alias(self->contact_list,
671 GPOINTER_TO_UINT(key),
672 value);
675 tp_svc_connection_interface_aliasing_return_from_set_aliases(context);
678 static void init_aliasing(gpointer iface,
679 SIPE_UNUSED_PARAMETER gpointer iface_data)
681 TpSvcConnectionInterfaceAliasingClass *klass = iface;
683 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::init_aliasing called");
685 tp_svc_connection_interface_aliasing_implement_get_alias_flags(klass, get_alias_flags);
686 tp_svc_connection_interface_aliasing_implement_request_aliases(klass, request_aliases);
687 tp_svc_connection_interface_aliasing_implement_get_aliases(klass, get_aliases);
688 tp_svc_connection_interface_aliasing_implement_set_aliases(klass, set_aliases);
691 /* create new connection object */
692 TpBaseConnection *sipe_telepathy_connection_new(TpBaseProtocol *protocol,
693 GHashTable *params,
694 SIPE_UNUSED_PARAMETER GError **error)
696 SipeConnection *conn = g_object_new(SIPE_TYPE_CONNECTION,
697 "protocol", tp_base_protocol_get_name(protocol),
698 NULL);
699 const gchar *value;
700 guint port;
701 gboolean boolean_value;
702 gboolean valid;
704 SIPE_DEBUG_INFO_NOFORMAT("sipe_telepathy_connection_new");
706 /* initialize private fields */
707 conn->is_disconnecting = FALSE;
709 /* account is required field */
710 conn->account = g_strdup(tp_asv_get_string(params, "account"));
712 /* if login is not specified, account value will be used in connect_to_core */
713 value = tp_asv_get_string(params, "login");
714 if (value && strlen(value))
715 conn->login = g_strdup(value);
716 else
717 conn->login = NULL;
719 /* password */
720 value = tp_asv_get_string(params, "password");
721 if (value && strlen(value))
722 conn->password = g_strdup(value);
723 else
724 conn->password = NULL;
726 /* server name */
727 value = tp_asv_get_string(params, "server");
728 if (value && strlen(value))
729 conn->server = g_strdup(value);
730 else
731 conn->server = NULL;
733 /* server port: core expects a string */
734 port = tp_asv_get_uint32(params, "port", &valid);
735 if (valid)
736 conn->port = g_strdup_printf("%d", port);
737 else
738 conn->port = NULL;
740 /* transport type */
741 value = tp_asv_get_string(params, "transport");
742 if (sipe_strequal(value, "auto")) {
743 conn->transport = conn->server ?
744 SIPE_TRANSPORT_TLS : SIPE_TRANSPORT_AUTO;
745 } else if (sipe_strequal(value, "tls")) {
746 conn->transport = SIPE_TRANSPORT_TLS;
747 } else {
748 conn->transport = SIPE_TRANSPORT_TCP;
751 /* User-Agent: override */
752 value = tp_asv_get_string(params, "useragent");
753 if (value && strlen(value))
754 conn->user_agent = g_strdup(value);
755 else
756 conn->user_agent = NULL;
758 /* authentication type */
759 value = tp_asv_get_string(params, "authentication");
760 if (value && strlen(value) && strcmp(value, "ntlm"))
761 conn->authentication = g_strdup(value);
762 else
763 conn->authentication = NULL; /* NTLM is default */
765 /* Single Sign-On */
766 boolean_value = tp_asv_get_boolean(params, "single-sign-on", &valid);
767 if (valid)
768 conn->sso = boolean_value;
769 else
770 conn->sso = FALSE;
772 /* Don't publish my calendar information */
773 boolean_value = tp_asv_get_boolean(params, "don't-publish-calendar", &valid);
774 if (valid)
775 conn->dont_publish = boolean_value;
776 else
777 conn->dont_publish = FALSE;
779 /* Allow insecure download of buddy icons from web */
780 boolean_value = tp_asv_get_boolean(params, "allow-web-photo", &valid);
781 if (valid)
782 conn->allow_web_photo = boolean_value;
783 else
784 conn->allow_web_photo = FALSE;
786 return(TP_BASE_CONNECTION(conn));
789 void sipe_telepathy_connection_alias_updated(TpBaseConnection *connection,
790 guint contact,
791 const gchar *alias)
793 GPtrArray *aliases = g_ptr_array_sized_new(1);
794 GValueArray *pair = g_value_array_new(2);
796 g_value_array_append(pair, NULL);
797 g_value_array_append(pair, NULL);
798 g_value_init(pair->values + 0, G_TYPE_UINT);
799 g_value_init(pair->values + 1, G_TYPE_STRING);
800 g_value_set_uint(pair->values + 0, contact);
801 g_value_set_string(pair->values + 1, alias);
802 g_ptr_array_add(aliases, pair);
804 tp_svc_connection_interface_aliasing_emit_aliases_changed(SIPE_CONNECTION(connection),
805 aliases);
807 g_ptr_array_unref(aliases);
808 g_value_array_free(pair);
811 struct sipe_backend_private *sipe_telepathy_connection_private(GObject *object)
813 SipeConnection *self = SIPE_CONNECTION(object);
814 /* connected to core already? */
815 if (self->private.public)
816 return(&self->private);
817 else
818 return(NULL);
822 * Backend adaptor functions
824 void sipe_backend_connection_completed(struct sipe_core_public *sipe_public)
826 SipeConnection *self = SIPE_PUBLIC_TO_CONNECTION;
827 TpBaseConnection *base = TP_BASE_CONNECTION(self);
829 /* we are only allowed to do this once */
830 if (base->status != TP_CONNECTION_STATUS_CONNECTED)
831 tp_base_connection_change_status(base,
832 TP_CONNECTION_STATUS_CONNECTED,
833 TP_CONNECTION_STATUS_REASON_REQUESTED);
836 void sipe_backend_connection_error(struct sipe_core_public *sipe_public,
837 sipe_connection_error error,
838 const gchar *msg)
840 SipeConnection *self = SIPE_PUBLIC_TO_CONNECTION;
841 TpBaseConnection *base = TP_BASE_CONNECTION(self);
842 GHashTable *details = tp_asv_new("server-message", G_TYPE_STRING, msg,
843 NULL);
844 TpConnectionStatusReason reason;
845 const gchar *name;
847 self->is_disconnecting = TRUE;
849 switch (error) {
850 case SIPE_CONNECTION_ERROR_NETWORK:
851 reason = TP_CONNECTION_STATUS_REASON_NETWORK_ERROR;
852 if (base->status == TP_CONNECTION_STATUS_CONNECTING)
853 name = TP_ERROR_STR_CONNECTION_FAILED;
854 else
855 name = TP_ERROR_STR_CONNECTION_LOST;
856 break;
858 case SIPE_CONNECTION_ERROR_INVALID_USERNAME:
859 case SIPE_CONNECTION_ERROR_INVALID_SETTINGS:
860 case SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED:
861 case SIPE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE:
862 /* copied from haze code. I agree there should be better ones */
863 reason = TP_CONNECTION_STATUS_REASON_AUTHENTICATION_FAILED;
864 name = TP_ERROR_STR_AUTHENTICATION_FAILED;
865 break;
867 default:
868 reason = TP_CONNECTION_STATUS_REASON_NONE_SPECIFIED;
869 name = TP_ERROR_STR_DISCONNECTED;
870 break;
873 SIPE_DEBUG_ERROR("sipe_backend_connection_error: %s (%s)", name, msg);
874 tp_base_connection_disconnect_with_dbus_error(base,
875 name,
876 details,
877 reason);
878 g_hash_table_unref(details);
881 gboolean sipe_backend_connection_is_disconnecting(struct sipe_core_public *sipe_public)
883 SipeConnection *self = SIPE_PUBLIC_TO_CONNECTION;
885 /* disconnect was requested or transport was already disconnected */
886 return(self->is_disconnecting ||
887 self->private.transport == NULL);
890 gboolean sipe_backend_connection_is_valid(struct sipe_core_public *sipe_public)
892 return(!sipe_backend_connection_is_disconnecting(sipe_public));
895 const gchar *sipe_backend_setting(struct sipe_core_public *sipe_public,
896 sipe_setting type)
898 SipeConnection *self = SIPE_PUBLIC_TO_CONNECTION;
899 const gchar *value;
901 switch (type) {
902 case SIPE_SETTING_USER_AGENT:
903 value = self->user_agent;
904 break;
905 default:
906 /* @TODO: update when settings are implemented */
907 value = NULL;
908 break;
911 return(value);
916 Local Variables:
917 mode: c
918 c-file-style: "bsd"
919 indent-tabs-mode: t
920 tab-width: 8
921 End: