telepathy: implement persistent photo cache
[siplcs.git] / src / telepathy / telepathy-connection.c
blob30f386d5e8b47ca95b44c0f4efae8f5ab7f64041
1 /**
2 * @file telepathy-connection.c
4 * pidgin-sipe
6 * Copyright (C) 2012 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 gchar *user_agent;
74 gchar *authentication;
75 gboolean is_disconnecting;
77 GPtrArray *contact_info_fields;
78 } SipeConnection;
80 #define SIPE_PUBLIC_TO_CONNECTION sipe_public->backend_private->connection
83 * Connection class - type macros
85 static GType sipe_connection_get_type(void) G_GNUC_CONST;
86 #define SIPE_TYPE_CONNECTION \
87 (sipe_connection_get_type())
88 #define SIPE_CONNECTION(obj) \
89 (G_TYPE_CHECK_INSTANCE_CAST((obj), SIPE_TYPE_CONNECTION, \
90 SipeConnection))
91 G_END_DECLS
94 * Connection class - type definition
96 static void init_aliasing (gpointer, gpointer);
97 G_DEFINE_TYPE_WITH_CODE(SipeConnection,
98 sipe_connection,
99 TP_TYPE_BASE_CONNECTION,
100 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_ALIASING,
101 init_aliasing);
102 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACTS,
103 tp_contacts_mixin_iface_init);
104 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACT_GROUPS,
105 tp_base_contact_list_mixin_groups_iface_init);
106 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACT_INFO,
107 sipe_telepathy_contact_info_iface_init);
108 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_CONTACT_LIST,
109 tp_base_contact_list_mixin_list_iface_init);
110 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_PRESENCE,
111 tp_presence_mixin_iface_init);
112 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CONNECTION_INTERFACE_SIMPLE_PRESENCE,
113 tp_presence_mixin_simple_presence_iface_init);
114 G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_DBUS_PROPERTIES,
115 tp_dbus_properties_mixin_iface_init);
120 * Connection class - instance methods
122 static gchar *normalize_contact(SIPE_UNUSED_PARAMETER TpHandleRepoIface *repo,
123 const gchar *id,
124 SIPE_UNUSED_PARAMETER gpointer context,
125 GError **error)
127 return(sipe_telepathy_protocol_normalize_contact(NULL, id, error));
130 static void create_handle_repos(SIPE_UNUSED_PARAMETER TpBaseConnection *conn,
131 TpHandleRepoIface *repos[NUM_TP_HANDLE_TYPES])
133 repos[TP_HANDLE_TYPE_CONTACT] = tp_dynamic_handle_repo_new(TP_HANDLE_TYPE_CONTACT,
134 normalize_contact,
135 NULL);
138 static gboolean connect_to_core(SipeConnection *self,
139 GError **error)
141 gchar *login_domain = NULL;
142 gchar *login_account = NULL;
143 struct sipe_core_public *sipe_public;
144 const gchar *errmsg;
146 /* login name specified? */
147 if (self->login && strlen(self->login)) {
148 /* Allowed domain-account separators are / or \ */
149 gchar **domain_user = g_strsplit_set(self->login, "/\\", 2);
150 gboolean has_domain = domain_user[1] != NULL;
151 SIPE_DEBUG_INFO("connect_to_core: login '%s'", self->login);
152 login_domain = has_domain ? g_strdup(domain_user[0]) : NULL;
153 login_account = g_strdup(domain_user[has_domain ? 1 : 0]);
154 SIPE_DEBUG_INFO("connect_to_core: auth domain '%s' user '%s'",
155 login_domain ? login_domain : "",
156 login_account);
157 g_strfreev(domain_user);
160 sipe_public = sipe_core_allocate(self->account,
161 login_domain, login_account,
162 self->password,
163 NULL, /* @TODO: email */
164 NULL, /* @TODO: email_url */
165 &errmsg);
166 g_free(login_domain);
167 g_free(login_account);
169 SIPE_DEBUG_INFO("connect_to_core: created %p", sipe_public);
171 if (sipe_public) {
172 struct sipe_backend_private *telepathy_private = &self->private;
174 /* initialize backend private data */
175 sipe_public->backend_private = telepathy_private;
176 telepathy_private->public = sipe_public;
177 telepathy_private->contact_list = self->contact_list;
178 telepathy_private->connection = self;
179 telepathy_private->activity = SIPE_ACTIVITY_UNSET;
180 telepathy_private->cache_dir = g_build_path(G_DIR_SEPARATOR_S,
181 g_get_user_cache_dir(),
182 "telepathy",
183 "sipe",
184 self->account,
185 NULL);
186 telepathy_private->message = NULL;
187 telepathy_private->transport = NULL;
188 telepathy_private->ipaddress = NULL;
190 /* make sure cache directory exists */
191 if (!g_file_test(telepathy_private->cache_dir,
192 G_FILE_TEST_IS_DIR) &&
193 (g_mkdir_with_parents(telepathy_private->cache_dir,
194 S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
195 == 0))
196 SIPE_DEBUG_INFO("connect_to_core: created cache directory %s",
197 telepathy_private->cache_dir);
199 /* map option list to flags - default is NTLM */
200 SIPE_CORE_FLAG_UNSET(KRB5);
201 SIPE_CORE_FLAG_UNSET(TLS_DSK);
202 #ifdef HAVE_LIBKRB5
203 if (sipe_strequal(self->authentication, "krb5")) {
204 SIPE_DEBUG_INFO_NOFORMAT("connect_to_core: KRB5 selected");
205 SIPE_CORE_FLAG_SET(KRB5);
206 } else
207 #endif
208 if (sipe_strequal(self->authentication, "tls-dsk")) {
209 SIPE_DEBUG_INFO_NOFORMAT("connect_to_core: TLS-DSK selected");
210 SIPE_CORE_FLAG_SET(TLS_DSK);
213 /* @TODO: add parameter for SSO */
214 SIPE_CORE_FLAG_UNSET(SSO);
216 sipe_core_transport_sip_connect(sipe_public,
217 self->transport,
218 self->server,
219 self->port);
221 return(TRUE);
222 } else {
223 g_set_error_literal(error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
224 errmsg);
225 return(FALSE);
229 static void password_manager_cb(GObject *source,
230 GAsyncResult *result,
231 gpointer data)
233 SipeConnection *self = data;
234 TpBaseConnection *base = TP_BASE_CONNECTION(self);
235 GError *error = NULL;
236 const GString *password = tp_simple_password_manager_prompt_finish(
237 TP_SIMPLE_PASSWORD_MANAGER(source),
238 result,
239 &error);
241 if (password == NULL) {
242 SIPE_DEBUG_ERROR("password_manager_cb: failed: %s",
243 error ? error->message : "UNKNOWN");
245 if (base->status != TP_CONNECTION_STATUS_DISCONNECTED) {
246 tp_base_connection_disconnect_with_dbus_error(base,
247 error ? tp_error_get_dbus_name(error->code) : "",
248 NULL,
249 TP_CONNECTION_STATUS_REASON_AUTHENTICATION_FAILED);
251 g_error_free(error);
252 } else {
254 g_free(self->password);
255 self->password = g_strdup(password->str);
257 if (!connect_to_core(self, &error)) {
258 if (base->status != TP_CONNECTION_STATUS_DISCONNECTED) {
259 tp_base_connection_disconnect_with_dbus_error(base,
260 tp_error_get_dbus_name(error->code),
261 NULL,
262 TP_CONNECTION_STATUS_REASON_AUTHENTICATION_FAILED);
264 g_error_free(error);
269 static gboolean start_connecting(TpBaseConnection *base,
270 GError **error)
272 SipeConnection *self = SIPE_CONNECTION(base);
273 gboolean rc = TRUE;
274 gchar *uri = sipe_telepathy_protocol_normalize_contact(NULL,
275 self->account,
276 error);
278 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::start_connecting");
280 /* set up mandatory self-handle */
281 if (uri) {
282 base->self_handle = tp_handle_ensure(tp_base_connection_get_handles(base,
283 TP_HANDLE_TYPE_CONTACT),
284 uri,
285 NULL,
286 error);
287 g_free(uri);
288 if (!base->self_handle) {
289 SIPE_DEBUG_ERROR("SipeConnection::start_connecting: self handle creation failed: %s",
290 (*error)->message);
291 return(FALSE);
293 } else {
294 SIPE_DEBUG_ERROR("SipeConnection::start_connecting: %s",
295 (*error)->message);
296 return(FALSE);
299 tp_base_connection_change_status(base, TP_CONNECTION_STATUS_CONNECTING,
300 TP_CONNECTION_STATUS_REASON_REQUESTED);
302 /* we need a password */
303 if (self->password)
304 rc = connect_to_core(self, error);
305 else {
306 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::start_connecting: requesting password from user");
307 tp_simple_password_manager_prompt_async(self->password_manager,
308 password_manager_cb,
309 self);
312 return(rc);
315 static gboolean disconnect_from_core(gpointer data)
317 TpBaseConnection *base = data;
318 SipeConnection *self = SIPE_CONNECTION(base);
319 struct sipe_backend_private *telepathy_private = &self->private;
320 struct sipe_core_public *sipe_public = telepathy_private->public;
322 SIPE_DEBUG_INFO("disconnect_from_core: %p", sipe_public);
324 if (sipe_public)
325 sipe_core_deallocate(sipe_public);
326 telepathy_private->public = NULL;
327 telepathy_private->transport = NULL;
329 g_free(telepathy_private->ipaddress);
330 telepathy_private->ipaddress = NULL;
332 g_free(telepathy_private->message);
333 telepathy_private->message = NULL;
335 g_free(telepathy_private->cache_dir);
336 telepathy_private->cache_dir = NULL;
338 SIPE_DEBUG_INFO_NOFORMAT("disconnect_from_core: core deallocated");
340 /* now it is OK to destroy the connection object */
341 tp_base_connection_finish_shutdown(base);
343 return(FALSE);
346 static void shut_down(TpBaseConnection *base)
348 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::shut_down");
350 /* this can be called synchronously, defer destruction */
351 g_idle_add(disconnect_from_core, base);
354 static GPtrArray *create_channel_managers(TpBaseConnection *base)
356 SipeConnection *self = SIPE_CONNECTION(base);
357 GPtrArray *channel_managers = g_ptr_array_new();
359 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::create_channel_managers");
361 self->contact_list = sipe_telepathy_contact_list_new(base);
362 g_ptr_array_add(channel_managers, self->contact_list);
364 self->password_manager = tp_simple_password_manager_new(base);
365 g_ptr_array_add(channel_managers, self->password_manager);
367 g_ptr_array_add(channel_managers, sipe_telepathy_search_new(base));
369 return(channel_managers);
372 static void aliasing_fill_contact_attributes(GObject *object,
373 const GArray *contacts,
374 GHashTable *attributes)
376 SipeConnection *self = SIPE_CONNECTION(object);
377 guint i;
379 for (i = 0; i < contacts->len; i++) {
380 TpHandle contact = g_array_index(contacts, guint, i);
382 tp_contacts_mixin_set_contact_attribute(attributes,
383 contact,
384 TP_TOKEN_CONNECTION_INTERFACE_ALIASING_ALIAS,
385 tp_g_value_slice_new_string(
386 sipe_telepathy_buddy_get_alias(self->contact_list,
387 contact)));
391 static void contact_info_properties_getter(GObject *object,
392 SIPE_UNUSED_PARAMETER GQuark interface,
393 GQuark name,
394 GValue *value,
395 gpointer getter_data)
397 GQuark fields = g_quark_from_static_string("SupportedFields");
399 if (name == fields)
400 g_value_set_boxed(value,
401 SIPE_CONNECTION(object)->contact_info_fields);
402 else
403 g_value_set_uint(value,
404 GPOINTER_TO_UINT(getter_data));
407 static void sipe_connection_constructed(GObject *object)
409 SipeConnection *self = SIPE_CONNECTION(object);
410 TpBaseConnection *base = TP_BASE_CONNECTION(object);
411 void (*chain_up)(GObject *) = G_OBJECT_CLASS(sipe_connection_parent_class)->constructed;
413 if (chain_up)
414 chain_up(object);
416 tp_contacts_mixin_init(object,
417 G_STRUCT_OFFSET(SipeConnection, contacts_mixin));
418 tp_base_connection_register_with_contacts_mixin(base);
420 tp_base_contact_list_mixin_register_with_contacts_mixin(base);
422 tp_contacts_mixin_add_contact_attributes_iface(object,
423 TP_IFACE_CONNECTION_INTERFACE_ALIASING,
424 aliasing_fill_contact_attributes);
426 tp_presence_mixin_init(object,
427 G_STRUCT_OFFSET(SipeConnection,
428 presence_mixin));
429 tp_presence_mixin_simple_presence_register_with_contacts_mixin(object);
431 self->contact_info_fields = sipe_telepathy_contact_info_fields();
434 static void sipe_connection_finalize(GObject *object)
436 SipeConnection *self = SIPE_CONNECTION(object);
438 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::finalize");
440 tp_contacts_mixin_finalize(object);
441 tp_presence_mixin_finalize(object);
442 g_boxed_free(TP_ARRAY_TYPE_FIELD_SPECS, self->contact_info_fields);
444 g_free(self->authentication);
445 g_free(self->user_agent);
446 g_free(self->port);
447 g_free(self->server);
448 g_free(self->password);
449 g_free(self->login);
450 g_free(self->account);
452 G_OBJECT_CLASS(sipe_connection_parent_class)->finalize(object);
456 * Connection class - type implementation
458 static const gchar *interfaces_always_present[] = {
459 /* @TODO */
460 TP_IFACE_CONNECTION_INTERFACE_ALIASING,
461 TP_IFACE_CONNECTION_INTERFACE_CONTACT_GROUPS,
462 TP_IFACE_CONNECTION_INTERFACE_CONTACT_INFO,
463 TP_IFACE_CONNECTION_INTERFACE_CONTACT_LIST,
464 TP_IFACE_CONNECTION_INTERFACE_CONTACTS,
465 TP_IFACE_CONNECTION_INTERFACE_PRESENCE,
466 TP_IFACE_CONNECTION_INTERFACE_REQUESTS,
467 TP_IFACE_CONNECTION_INTERFACE_SIMPLE_PRESENCE,
468 NULL
471 static void sipe_connection_class_init(SipeConnectionClass *klass)
473 GObjectClass *object_class = G_OBJECT_CLASS(klass);
474 TpBaseConnectionClass *base_class = TP_BASE_CONNECTION_CLASS(klass);
475 static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = {
477 /* 0 */
478 .name = TP_IFACE_CONNECTION_INTERFACE_CONTACT_INFO,
479 .getter = contact_info_properties_getter,
480 .setter = NULL,
483 /* LAST! */
484 .name = NULL,
488 /* initalize non-constant fields */
489 prop_interfaces[0].props = sipe_telepathy_contact_info_props();
491 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::class_init");
493 object_class->constructed = sipe_connection_constructed;
494 object_class->finalize = sipe_connection_finalize;
496 base_class->create_handle_repos = create_handle_repos;
497 base_class->start_connecting = start_connecting;
498 base_class->shut_down = shut_down;
499 base_class->create_channel_managers = create_channel_managers;
501 base_class->interfaces_always_present = interfaces_always_present;
503 klass->properties_mixin.interfaces = prop_interfaces;
504 tp_dbus_properties_mixin_class_init(object_class,
505 G_STRUCT_OFFSET(SipeConnectionClass,
506 properties_mixin));
507 tp_contacts_mixin_class_init(object_class,
508 G_STRUCT_OFFSET(SipeConnectionClass,
509 contacts_mixin));
510 sipe_telepathy_status_init(object_class,
511 G_STRUCT_OFFSET(SipeConnectionClass,
512 presence_mixin));
513 tp_presence_mixin_simple_presence_init_dbus_properties(object_class);
514 tp_base_contact_list_mixin_class_init(base_class);
517 static void sipe_connection_init(SIPE_UNUSED_PARAMETER SipeConnection *self)
519 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::init");
523 * Connection class - interface implementation
525 * Contact aliases
527 static void get_alias_flags(TpSvcConnectionInterfaceAliasing *aliasing,
528 DBusGMethodInvocation *context)
530 TpBaseConnection *base = TP_BASE_CONNECTION(aliasing);
532 TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED(base, context);
533 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::get_alias_flags called");
535 tp_svc_connection_interface_aliasing_return_from_get_alias_flags(context,
536 TP_CONNECTION_ALIAS_FLAG_USER_SET);
539 static void get_aliases(TpSvcConnectionInterfaceAliasing *aliasing,
540 const GArray *contacts,
541 DBusGMethodInvocation *context)
543 SipeConnection *self = SIPE_CONNECTION(aliasing);
544 TpBaseConnection *base = TP_BASE_CONNECTION(aliasing);
545 TpHandleRepoIface *contact_repo = tp_base_connection_get_handles(base,
546 TP_HANDLE_TYPE_CONTACT);
547 GError *error = NULL;
548 GHashTable *result;
549 guint i;
551 TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED(base, context);
552 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::get_aliases called");
554 if (!tp_handles_are_valid(contact_repo, contacts, FALSE, &error)) {
555 dbus_g_method_return_error(context, error);
556 g_error_free(error);
557 return;
560 result = g_hash_table_new(g_direct_hash, g_direct_equal);
562 for (i = 0; i < contacts->len; i++) {
563 TpHandle contact = g_array_index(contacts, TpHandle, i);
564 const gchar *alias = sipe_telepathy_buddy_get_alias(self->contact_list,
565 contact);
566 g_hash_table_insert(result,
567 GUINT_TO_POINTER(contact),
568 (gchar *) alias);
571 tp_svc_connection_interface_aliasing_return_from_get_aliases(context,
572 result);
573 g_hash_table_unref(result);
576 static void request_aliases(TpSvcConnectionInterfaceAliasing *aliasing,
577 const GArray *contacts,
578 DBusGMethodInvocation *context)
580 SipeConnection *self = SIPE_CONNECTION(aliasing);
581 TpBaseConnection *base = TP_BASE_CONNECTION(aliasing);
582 TpHandleRepoIface *contact_repo = tp_base_connection_get_handles(base,
583 TP_HANDLE_TYPE_CONTACT);
584 GError *error = NULL;
585 GPtrArray *result;
586 gchar **strings;
587 guint i;
589 TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED(base, context);
590 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::request_aliases called");
592 if (!tp_handles_are_valid(contact_repo, contacts, FALSE, &error)) {
593 dbus_g_method_return_error(context, error);
594 g_error_free(error);
595 return;
598 result = g_ptr_array_sized_new(contacts->len + 1);
600 for (i = 0; i < contacts->len; i++) {
601 TpHandle contact = g_array_index(contacts, TpHandle, i);
602 const gchar *alias = sipe_telepathy_buddy_get_alias(self->contact_list,
603 contact);
604 g_ptr_array_add(result, (gchar *) alias);
607 g_ptr_array_add(result, NULL);
608 strings = (gchar **) g_ptr_array_free(result, FALSE);
610 tp_svc_connection_interface_aliasing_return_from_request_aliases(context,
611 (const gchar **) strings);
612 g_free(strings);
615 static void set_aliases(TpSvcConnectionInterfaceAliasing *aliasing,
616 GHashTable *aliases,
617 DBusGMethodInvocation *context)
619 SipeConnection *self = SIPE_CONNECTION(aliasing);
620 TpBaseConnection *base = TP_BASE_CONNECTION(aliasing);
621 TpHandleRepoIface *contact_repo = tp_base_connection_get_handles(base,
622 TP_HANDLE_TYPE_CONTACT);
623 GHashTableIter iter;
624 gpointer key, value;
626 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::set_aliases called");
628 g_hash_table_iter_init(&iter, aliases);
630 while (g_hash_table_iter_next(&iter, &key, NULL)) {
631 GError *error = NULL;
633 if (!tp_handle_is_valid(contact_repo,
634 GPOINTER_TO_UINT(key),
635 &error)) {
636 dbus_g_method_return_error(context, error);
637 g_error_free(error);
638 return;
642 g_hash_table_iter_init(&iter, aliases);
644 while (g_hash_table_iter_next(&iter, &key, &value)) {
645 sipe_telepathy_buddy_set_alias(self->contact_list,
646 GPOINTER_TO_UINT(key),
647 value);
650 tp_svc_connection_interface_aliasing_return_from_set_aliases(context);
653 static void init_aliasing(gpointer iface,
654 SIPE_UNUSED_PARAMETER gpointer iface_data)
656 TpSvcConnectionInterfaceAliasingClass *klass = iface;
658 SIPE_DEBUG_INFO_NOFORMAT("SipeConnection::init_aliasing called");
660 tp_svc_connection_interface_aliasing_implement_get_alias_flags(klass, get_alias_flags);
661 tp_svc_connection_interface_aliasing_implement_request_aliases(klass, request_aliases);
662 tp_svc_connection_interface_aliasing_implement_get_aliases(klass, get_aliases);
663 tp_svc_connection_interface_aliasing_implement_set_aliases(klass, set_aliases);
666 /* create new connection object */
667 TpBaseConnection *sipe_telepathy_connection_new(TpBaseProtocol *protocol,
668 GHashTable *params,
669 SIPE_UNUSED_PARAMETER GError **error)
671 SipeConnection *conn = g_object_new(SIPE_TYPE_CONNECTION,
672 "protocol", tp_base_protocol_get_name(protocol),
673 NULL);
674 const gchar *value;
675 guint port;
676 gboolean valid;
678 SIPE_DEBUG_INFO_NOFORMAT("sipe_telepathy_connection_new");
680 /* initialize private fields */
681 conn->is_disconnecting = FALSE;
683 /* account & login are required fields */
684 conn->account = g_strdup(tp_asv_get_string(params, "account"));
685 conn->login = g_strdup(tp_asv_get_string(params, "login"));
687 /* password */
688 value = tp_asv_get_string(params, "password");
689 if (value && strlen(value))
690 conn->password = g_strdup(value);
691 else
692 conn->password = NULL;
694 /* server name */
695 value = tp_asv_get_string(params, "server");
696 if (value && strlen(value))
697 conn->server = g_strdup(value);
698 else
699 conn->server = NULL;
701 /* server port: core expects a string */
702 port = tp_asv_get_uint32(params, "port", &valid);
703 if (valid)
704 conn->port = g_strdup_printf("%d", port);
705 else
706 conn->port = NULL;
708 /* transport type */
709 value = tp_asv_get_string(params, "transport");
710 if (sipe_strequal(value, "auto")) {
711 conn->transport = conn->server ?
712 SIPE_TRANSPORT_TLS : SIPE_TRANSPORT_AUTO;
713 } else if (sipe_strequal(value, "tls")) {
714 conn->transport = SIPE_TRANSPORT_TLS;
715 } else {
716 conn->transport = SIPE_TRANSPORT_TCP;
719 /* User-Agent: override */
720 value = tp_asv_get_string(params, "useragent");
721 if (value && strlen(value))
722 conn->user_agent = g_strdup(value);
723 else
724 conn->user_agent = NULL;
726 /* authentication type */
727 value = tp_asv_get_string(params, "authentication");
728 if (value && strlen(value) && strcmp(value, "ntlm"))
729 conn->authentication = g_strdup(value);
730 else
731 conn->authentication = NULL; /* NTLM is default */
733 return(TP_BASE_CONNECTION(conn));
736 void sipe_telepathy_connection_alias_updated(TpBaseConnection *connection,
737 guint contact,
738 const gchar *alias)
740 GPtrArray *aliases = g_ptr_array_sized_new(1);
741 GValueArray *pair = g_value_array_new(2);
743 g_value_array_append(pair, NULL);
744 g_value_array_append(pair, NULL);
745 g_value_init(pair->values + 0, G_TYPE_UINT);
746 g_value_init(pair->values + 1, G_TYPE_STRING);
747 g_value_set_uint(pair->values + 0, contact);
748 g_value_set_string(pair->values + 1, alias);
749 g_ptr_array_add(aliases, pair);
751 tp_svc_connection_interface_aliasing_emit_aliases_changed(SIPE_CONNECTION(connection),
752 aliases);
754 g_ptr_array_unref(aliases);
755 g_value_array_free(pair);
758 struct sipe_backend_private *sipe_telepathy_connection_private(GObject *object)
760 SipeConnection *self = SIPE_CONNECTION(object);
761 /* connected to core already? */
762 if (self->private.public)
763 return(&self->private);
764 else
765 return(NULL);
769 * Backend adaptor functions
771 void sipe_backend_connection_completed(struct sipe_core_public *sipe_public)
773 SipeConnection *self = SIPE_PUBLIC_TO_CONNECTION;
774 TpBaseConnection *base = TP_BASE_CONNECTION(self);
776 /* we are only allowed to do this once */
777 if (base->status != TP_CONNECTION_STATUS_CONNECTED)
778 tp_base_connection_change_status(base,
779 TP_CONNECTION_STATUS_CONNECTED,
780 TP_CONNECTION_STATUS_REASON_REQUESTED);
783 void sipe_backend_connection_error(struct sipe_core_public *sipe_public,
784 sipe_connection_error error,
785 const gchar *msg)
787 SipeConnection *self = SIPE_PUBLIC_TO_CONNECTION;
788 TpBaseConnection *base = TP_BASE_CONNECTION(self);
789 GHashTable *details = tp_asv_new("server-message", G_TYPE_STRING, msg,
790 NULL);
791 TpConnectionStatusReason reason;
792 const gchar *name;
794 self->is_disconnecting = TRUE;
796 switch (error) {
797 case SIPE_CONNECTION_ERROR_NETWORK:
798 reason = TP_CONNECTION_STATUS_REASON_NETWORK_ERROR;
799 if (base->status == TP_CONNECTION_STATUS_CONNECTING)
800 name = TP_ERROR_STR_CONNECTION_FAILED;
801 else
802 name = TP_ERROR_STR_CONNECTION_LOST;
803 break;
805 case SIPE_CONNECTION_ERROR_INVALID_USERNAME:
806 case SIPE_CONNECTION_ERROR_INVALID_SETTINGS:
807 case SIPE_CONNECTION_ERROR_AUTHENTICATION_FAILED:
808 case SIPE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE:
809 /* copied from haze code. I agree there should be better ones */
810 reason = TP_CONNECTION_STATUS_REASON_AUTHENTICATION_FAILED;
811 name = TP_ERROR_STR_AUTHENTICATION_FAILED;
812 break;
814 default:
815 reason = TP_CONNECTION_STATUS_REASON_NONE_SPECIFIED;
816 name = TP_ERROR_STR_DISCONNECTED;
817 break;
820 SIPE_DEBUG_ERROR("sipe_backend_connection_error: %s (%s)", name, msg);
821 tp_base_connection_disconnect_with_dbus_error(base,
822 name,
823 details,
824 reason);
825 g_hash_table_unref(details);
828 gboolean sipe_backend_connection_is_disconnecting(struct sipe_core_public *sipe_public)
830 SipeConnection *self = SIPE_PUBLIC_TO_CONNECTION;
832 /* disconnect was requested or transport was already disconnected */
833 return(self->is_disconnecting ||
834 self->private.transport == NULL);
837 gboolean sipe_backend_connection_is_valid(struct sipe_core_public *sipe_public)
839 return(!sipe_backend_connection_is_disconnecting(sipe_public));
842 const gchar *sipe_backend_setting(struct sipe_core_public *sipe_public,
843 sipe_setting type)
845 SipeConnection *self = SIPE_PUBLIC_TO_CONNECTION;
846 const gchar *value;
848 switch (type) {
849 case SIPE_SETTING_USER_AGENT:
850 value = self->user_agent;
851 break;
852 default:
853 /* @TODO: update when settings are implemented */
854 value = NULL;
855 break;
858 return(value);
863 Local Variables:
864 mode: c
865 c-file-style: "bsd"
866 indent-tabs-mode: t
867 tab-width: 8
868 End: