#include <folks/folks.h>
#include <folks/folks-telepathy.h>
+#include <dbus/dbus-protocol.h>
+
#include <telepathy-glib/account-manager.h>
#include <telepathy-glib/connection.h>
#include <telepathy-glib/channel.h>
#include "empathy-client-factory.h"
#include "empathy-utils.h"
-#include "empathy-contact-manager.h"
#include "empathy-individual-manager.h"
#include "empathy-presence-manager.h"
#include "empathy-request-util.h"
{ NULL, },
};
+static gboolean
+properties_contains (gchar **list,
+ gint length,
+ const gchar *property);
+
+static gboolean
+check_writeable_property (TpConnection *connection,
+ FolksIndividual *individual,
+ gchar *property);
+
void
empathy_init (void)
{
g_hash_table_insert (errors, TP_ERROR_STR_CONNECTION_LOST,
_("Connection has been lost"));
g_hash_table_insert (errors, TP_ERROR_STR_ALREADY_CONNECTED,
- _("This resource is already connected to the server"));
+ _("This account is already connected to the server"));
g_hash_table_insert (errors, TP_ERROR_STR_CONNECTION_REPLACED,
_("Connection has been replaced by a new connection using the "
"same resource"));
_("The length of the server certificate, or the depth of the "
"server certificate chain, exceed the limits imposed by the "
"cryptography library"));
+ g_hash_table_insert (errors, TP_ERROR_STR_SOFTWARE_UPGRADE_REQUIRED,
+ _("Your software is too old"));
+ g_hash_table_insert (errors, DBUS_ERROR_NO_REPLY,
+ _("Internal error"));
return errors;
}
{
const gchar *dbus_error;
const gchar *message;
- const GHashTable *details = NULL;
+ const GHashTable *details = NULL;
TpConnectionStatusReason reason;
dbus_error = tp_account_get_detailed_error (account, &details);
if (message != NULL)
return message;
+ tp_account_get_connection_status (account, &reason);
+
DEBUG ("Don't understand error '%s'; fallback to the status reason (%u)",
dbus_error, reason);
- tp_account_get_connection_status (account, &reason);
-
return empathy_status_reason_get_default_message (reason);
}
}
gboolean
-empathy_connection_can_alias_personas (TpConnection *connection)
+empathy_connection_can_alias_personas (TpConnection *connection,
+ FolksIndividual *individual)
{
gboolean retval;
- FolksPersonaStore *persona_store;
g_return_val_if_fail (TP_IS_CONNECTION (connection), FALSE);
TP_CONNECTION_STATUS_CONNECTED)
return FALSE;
- persona_store = FOLKS_PERSONA_STORE (
- empathy_dup_persona_store_for_connection (connection));
-
- retval = (folks_persona_store_get_can_alias_personas (persona_store) ==
- FOLKS_MAYBE_BOOL_TRUE);
-
- g_clear_object (&persona_store);
+ retval = check_writeable_property (connection, individual, "alias");
return retval;
}
gboolean
-empathy_connection_can_group_personas (TpConnection *connection)
+empathy_connection_can_group_personas (TpConnection *connection,
+ FolksIndividual *individual)
{
gboolean retval;
- FolksPersonaStore *persona_store;
g_return_val_if_fail (TP_IS_CONNECTION (connection), FALSE);
TP_CONNECTION_STATUS_CONNECTED)
return FALSE;
- persona_store = FOLKS_PERSONA_STORE (
- empathy_dup_persona_store_for_connection (connection));
-
- retval = (folks_persona_store_get_can_group_personas (persona_store) ==
- FOLKS_MAYBE_BOOL_TRUE);
-
- g_clear_object (&persona_store);
+ retval = check_writeable_property (connection, individual, "groups");
return retval;
}
return FALSE;
}
+
+/* Return the TpContact on @conn associated with @individual, if any */
+TpContact *
+empathy_get_tp_contact_for_individual (FolksIndividual *individual,
+ TpConnection *conn)
+{
+ TpContact *contact = NULL;
+ GeeSet *personas;
+ GeeIterator *iter;
+
+ personas = folks_individual_get_personas (individual);
+ iter = gee_iterable_iterator (GEE_ITERABLE (personas));
+ while (contact == NULL && gee_iterator_next (iter))
+ {
+ TpfPersona *persona = gee_iterator_get (iter);
+ TpConnection *contact_conn;
+ TpContact *contact_cur = NULL;
+
+ if (TPF_IS_PERSONA (persona))
+ {
+ contact_cur = tpf_persona_get_contact (persona);
+ if (contact_cur != NULL)
+ {
+ contact_conn = tp_contact_get_connection (contact_cur);
+
+ if (!tp_strdiff (tp_proxy_get_object_path (contact_conn),
+ tp_proxy_get_object_path (conn)))
+ contact = contact_cur;
+ }
+ }
+
+ g_clear_object (&persona);
+ }
+ g_clear_object (&iter);
+
+ return contact;
+}
+
+static gboolean
+properties_contains (gchar **list,
+ gint length,
+ const gchar *property)
+{
+ gint i;
+
+ for (i = 0; i < length; i++)
+ {
+ if (!tp_strdiff (list[i], property))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+check_writeable_property (TpConnection *connection,
+ FolksIndividual *individual,
+ gchar *property)
+{
+ gchar **properties;
+ gint prop_len;
+ gboolean retval = FALSE;
+ GeeSet *personas;
+ GeeIterator *iter;
+ FolksPersonaStore *persona_store;
+
+ persona_store = FOLKS_PERSONA_STORE (
+ empathy_dup_persona_store_for_connection (connection));
+
+ properties =
+ folks_persona_store_get_always_writeable_properties (persona_store,
+ &prop_len);
+ retval = properties_contains (properties, prop_len, property);
+ if (retval == TRUE)
+ goto out;
+
+ /* Lets see if the Individual contains a Persona with the given property */
+ personas = folks_individual_get_personas (individual);
+ iter = gee_iterable_iterator (GEE_ITERABLE (personas));
+ while (!retval && gee_iterator_next (iter))
+ {
+ FolksPersona *persona = gee_iterator_get (iter);
+
+ properties =
+ folks_persona_get_writeable_properties (persona, &prop_len);
+ retval = properties_contains (properties, prop_len, property);
+
+ g_clear_object (&persona);
+
+ if (retval == TRUE)
+ break;
+ }
+ g_clear_object (&iter);
+
+out:
+ g_clear_object (&persona_store);
+ return retval;
+}
+
+/* Calculate whether the Individual can do audio or video calls.
+ * FIXME: We can remove this once libfolks has grown capabilities support
+ * again: bgo#626179. */
+void
+empathy_individual_can_audio_video_call (FolksIndividual *individual,
+ gboolean *can_audio_call,
+ gboolean *can_video_call,
+ EmpathyContact **out_contact)
+{
+ GeeSet *personas;
+ GeeIterator *iter;
+ gboolean can_audio = FALSE, can_video = FALSE;
+
+ personas = folks_individual_get_personas (individual);
+ iter = gee_iterable_iterator (GEE_ITERABLE (personas));
+ while (gee_iterator_next (iter))
+ {
+ FolksPersona *persona = gee_iterator_get (iter);
+ TpContact *tp_contact;
+
+ if (!empathy_folks_persona_is_interesting (persona))
+ goto while_finish;
+
+ tp_contact = tpf_persona_get_contact (TPF_PERSONA (persona));
+ if (tp_contact != NULL)
+ {
+ EmpathyContact *contact;
+
+ contact = empathy_contact_dup_from_tp_contact (tp_contact);
+ empathy_contact_set_persona (contact, persona);
+
+ can_audio = can_audio || empathy_contact_get_capabilities (contact) &
+ EMPATHY_CAPABILITIES_AUDIO;
+ can_video = can_video || empathy_contact_get_capabilities (contact) &
+ EMPATHY_CAPABILITIES_VIDEO;
+
+ if (out_contact != NULL)
+ *out_contact = g_object_ref (contact);
+
+ g_object_unref (contact);
+ }
+
+while_finish:
+ g_clear_object (&persona);
+
+ if (can_audio && can_video)
+ break;
+ }
+
+ g_clear_object (&iter);
+
+ if (can_audio_call != NULL)
+ *can_audio_call = can_audio;
+
+ if (can_video_call != NULL)
+ *can_video_call = can_video;
+}
+
+gboolean
+empathy_sasl_channel_supports_mechanism (TpChannel *channel,
+ const gchar *mechanism)
+{
+ GHashTable *props;
+ const gchar * const *available_mechanisms;
+
+ props = tp_channel_borrow_immutable_properties (channel);
+ available_mechanisms = tp_asv_get_boxed (props,
+ TP_PROP_CHANNEL_INTERFACE_SASL_AUTHENTICATION_AVAILABLE_MECHANISMS,
+ G_TYPE_STRV);
+
+ return tp_strv_contains (available_mechanisms, mechanism);
+}
+
+FolksIndividual *
+empathy_create_individual_from_tp_contact (TpContact *contact)
+{
+ GeeSet *personas;
+ TpfPersona *persona;
+ FolksIndividual *individual;
+
+ persona = tpf_persona_dup_for_contact (contact);
+ if (persona == NULL)
+ {
+ DEBUG ("Failed to get a persona for %s",
+ tp_contact_get_identifier (contact));
+ return NULL;
+ }
+
+ personas = GEE_SET (
+ gee_hash_set_new (FOLKS_TYPE_PERSONA, g_object_ref, g_object_unref,
+ g_direct_hash, g_direct_equal));
+
+ gee_collection_add (GEE_COLLECTION (personas), persona);
+
+ individual = folks_individual_new (personas);
+
+ g_clear_object (&persona);
+ g_clear_object (&personas);
+
+ return individual;
+}
+
+/* Look for a FolksIndividual containing @contact as one of his persona
+ * and create one if needed */
+FolksIndividual *
+empathy_ensure_individual_from_tp_contact (TpContact *contact)
+{
+ EmpathyIndividualManager *mgr;
+ FolksIndividual *individual;
+
+ mgr = empathy_individual_manager_dup_singleton ();
+ individual = empathy_individual_manager_lookup_by_contact (mgr, contact);
+
+ if (individual != NULL)
+ g_object_ref (individual);
+ else
+ individual = empathy_create_individual_from_tp_contact (contact);
+
+ g_object_unref (mgr);
+ return individual;
+}