* Authors: Xavier Claessens <xclaesse@gmail.com>
*/
-#include <config.h>
-
-#include <string.h>
-
-#include <telepathy-glib/telepathy-glib.h>
+#include "config.h"
+#include "empathy-tp-chat.h"
-#include <extensions/extensions.h>
+#include <tp-account-widgets/tpaw-utils.h>
+#include <telepathy-glib/telepathy-glib-dbus.h>
-#include "empathy-tp-chat.h"
#include "empathy-request-util.h"
-#include "empathy-time.h"
#include "empathy-utils.h"
#define DEBUG_FLAG EMPATHY_DEBUG_TP | EMPATHY_DEBUG_CHAT
/* GSimpleAsyncResult used when preparing EMPATHY_TP_CHAT_FEATURE_CORE */
GSimpleAsyncResult *ready_result;
+ gboolean preparing_password;
};
enum
DEBUG ("Error %s: %s", (gchar *) user_data, error->message);
}
+static void
+update_config_cb (TpChannel *proxy,
+ const GError *error,
+ gpointer user_data,
+ GObject *weak_object)
+{
+ if (error != NULL)
+ DEBUG ("Failed to change config of the room: %s", error->message);
+}
+
static void
create_conference_cb (GObject *source,
GAsyncResult *result,
gpointer user_data)
{
+ TpChannel *channel;
GError *error = NULL;
+ GHashTable *props;
- if (!tp_account_channel_request_create_channel_finish (
- TP_ACCOUNT_CHANNEL_REQUEST (source), result, &error))
+ channel = tp_account_channel_request_create_and_observe_channel_finish (
+ TP_ACCOUNT_CHANNEL_REQUEST (source), result, &error);
+ if (channel == NULL)
{
DEBUG ("Failed to create conference channel: %s", error->message);
g_error_free (error);
+ return;
}
+
+ /* Make the channel more confidential as only people invited are supposed to
+ * join it. */
+ props = tp_asv_new (
+ "Private", G_TYPE_BOOLEAN, TRUE,
+ "InviteOnly", G_TYPE_BOOLEAN, TRUE,
+ NULL);
+
+ tp_cli_channel_interface_room_config_call_update_configuration (channel, -1,
+ props, update_config_cb, NULL, NULL, NULL);
+
+ g_object_unref (channel);
+ g_hash_table_unref (props);
}
void
else if (self->priv->can_upgrade_to_muc)
{
TpAccountChannelRequest *req;
- GHashTable *props;
- const char *object_path;
- GPtrArray channels = { (gpointer *) &object_path, 1 };
+ const gchar *channels[2] = { NULL, };
const char *invitees[2] = { NULL, };
+ TpAccount *account;
invitees[0] = empathy_contact_get_id (contact);
- object_path = tp_proxy_get_object_path (self);
-
- props = tp_asv_new (
- TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
- TP_IFACE_CHANNEL_TYPE_TEXT,
- TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT,
- TP_HANDLE_TYPE_NONE,
- TP_PROP_CHANNEL_INTERFACE_CONFERENCE_INITIAL_CHANNELS,
- TP_ARRAY_TYPE_OBJECT_PATH_LIST, &channels,
- TP_PROP_CHANNEL_INTERFACE_CONFERENCE_INITIAL_INVITEE_IDS,
- G_TYPE_STRV, invitees,
- /* FIXME: InvitationMessage ? */
- NULL);
-
- req = tp_account_channel_request_new (self->priv->account, props,
+ channels[0] = tp_proxy_get_object_path (self);
+
+ account = empathy_tp_chat_get_account (self);
+
+ req = tp_account_channel_request_new_text (account,
TP_USER_ACTION_TIME_NOT_USER_ACTION);
+ tp_account_channel_request_set_conference_initial_channels (req,
+ channels);
+
+ tp_account_channel_request_set_initial_invitee_ids (req, invitees);
+
+ /* FIXME: InvitationMessage ? */
+
/* Although this is a MUC, it's anonymous, so CreateChannel is
* valid. */
- tp_account_channel_request_create_channel_async (req,
- EMPATHY_CHAT_BUS_NAME, NULL, create_conference_cb, NULL);
+ tp_account_channel_request_create_and_observe_channel_async (req,
+ EMPATHY_CHAT_TP_BUS_NAME, NULL, create_conference_cb, NULL);
g_object_unref (req);
- g_hash_table_unref (props);
}
else
{
{
GList *messages, *l;
- messages = tp_text_channel_get_pending_messages (TP_TEXT_CHANNEL (self));
+ messages = tp_text_channel_dup_pending_messages (TP_TEXT_CHANNEL (self));
for (l = messages; l != NULL; l = g_list_next (l))
{
handle_incoming_message (self, message, FALSE);
}
- g_list_free (messages);
+ g_list_free_full (messages, g_object_unref);
}
static void
{
EmpathyTpChat *self = EMPATHY_TP_CHAT (object);
- tp_clear_object (&self->priv->account);
tp_clear_object (&self->priv->remote_contact);
tp_clear_object (&self->priv->user);
if (self->priv->user == NULL)
return;
+ if (self->priv->preparing_password)
+ return;
+
/* We need either the members (room) or the remote contact (private chat).
* If the chat is protected by a password we can't get these information so
* consider the chat as ready so it can be presented to the user. */
switch (param_id)
{
- case PROP_ACCOUNT:
- g_value_set_object (value, self->priv->account);
- break;
case PROP_SELF_CONTACT:
g_value_set_object (value, self->priv->user);
break;
};
}
-static void
-tp_chat_set_property (GObject *object,
- guint param_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- EmpathyTpChat *self = EMPATHY_TP_CHAT (object);
-
- switch (param_id)
- {
- case PROP_ACCOUNT:
- self->priv->account = g_value_dup_object (value);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
- break;
- };
-}
-
enum {
FEAT_READY,
N_FEAT
tp_chat_list_features (TpProxyClass *cls G_GNUC_UNUSED)
{
static TpProxyFeature features[N_FEAT + 1] = { { 0 } };
- static GQuark need[2] = {0, 0};
+ static GQuark need[3] = {0, 0, 0};
if (G_LIKELY (features[0].name != 0))
return features;
features[FEAT_READY].name = EMPATHY_TP_CHAT_FEATURE_READY;
need[0] = TP_TEXT_CHANNEL_FEATURE_INCOMING_MESSAGES;
+ need[1] = TP_CHANNEL_FEATURE_CONTACTS;
features[FEAT_READY].depends_on = need;
features[FEAT_READY].prepare_async =
tp_chat_prepare_ready_async;
object_class->dispose = tp_chat_dispose;
object_class->finalize = tp_chat_finalize;
object_class->get_property = tp_chat_get_property;
- object_class->set_property = tp_chat_set_property;
proxy_class->list_features = tp_chat_list_features;
- g_object_class_install_property (object_class, PROP_ACCOUNT,
- g_param_spec_object ("account", "TpAccount",
- "the account associated with the chat",
- TP_TYPE_ACCOUNT,
- G_PARAM_READWRITE |
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_STRINGS));
-
/**
* EmpathyTpChat:self-contact:
*
EmpathyTpChat *
empathy_tp_chat_new (TpSimpleClientFactory *factory,
- TpAccount *account,
TpConnection *conn,
const gchar *object_path,
const GHashTable *immutable_properties)
{
- g_return_val_if_fail (TP_IS_ACCOUNT (account), NULL);
g_return_val_if_fail (TP_IS_CONNECTION (conn), NULL);
g_return_val_if_fail (immutable_properties != NULL, NULL);
return g_object_new (EMPATHY_TYPE_TP_CHAT,
"factory", factory,
- "account", account,
"connection", conn,
"dbus-daemon", tp_proxy_get_dbus_daemon (conn),
"bus-name", tp_proxy_get_bus_name (conn),
g_return_val_if_fail (EMPATHY_IS_TP_CHAT (self), NULL);
id = tp_channel_get_identifier ((TpChannel *) self);
- if (!EMP_STR_EMPTY (id))
+ if (!TPAW_STR_EMPTY (id))
return id;
else if (self->priv->remote_contact)
return empathy_contact_get_id (self->priv->remote_contact);
TpAccount *
empathy_tp_chat_get_account (EmpathyTpChat *self)
{
+ TpConnection *connection;
+
g_return_val_if_fail (EMPATHY_IS_TP_CHAT (self), NULL);
- return self->priv->account;
+ connection = tp_channel_get_connection (TP_CHANNEL (self));
+
+ return tp_connection_get_account (connection);
}
void
}
static void
-tp_chat_prepare_ready_async (TpProxy *proxy,
- const TpProxyFeature *feature,
- GAsyncReadyCallback callback,
- gpointer user_data)
+password_feature_prepare_cb (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
{
- EmpathyTpChat *self = (EmpathyTpChat *) proxy;
- TpChannel *channel = (TpChannel *) proxy;
+ EmpathyTpChat *self = user_data;
+ GError *error = NULL;
+
+ if (!tp_proxy_prepare_finish (source, result, &error))
+ {
+ DEBUG ("Failed to prepare Password: %s", error->message);
+ g_error_free (error);
+ }
+
+ self->priv->preparing_password = FALSE;
+
+ check_almost_ready (self);
+}
+
+static void
+continue_preparing (EmpathyTpChat *self)
+{
+ TpChannel *channel = (TpChannel *) self;
TpConnection *connection;
gboolean listen_for_dbus_properties_changed = FALSE;
- g_assert (self->priv->ready_result == NULL);
- self->priv->ready_result = g_simple_async_result_new (G_OBJECT (self),
- callback, user_data, tp_chat_prepare_ready_async);
+ connection = tp_channel_get_connection (channel);
- connection = tp_channel_borrow_connection (channel);
+ if (tp_proxy_has_interface_by_id (self,
+ TP_IFACE_QUARK_CHANNEL_INTERFACE_PASSWORD))
+ {
+ /* The password feature can't be a hard dep on our own feature has we
+ * depend on it only if the channel implements the
+ * Password interface.
+ */
+ GQuark features[] = { TP_CHANNEL_FEATURE_PASSWORD , 0 };
+
+ self->priv->preparing_password = TRUE;
+
+ tp_proxy_prepare_async (self, features, password_feature_prepare_cb,
+ self);
+ }
if (tp_proxy_has_interface_by_id (self,
TP_IFACE_QUARK_CHANNEL_INTERFACE_GROUP))
G_OBJECT (self), NULL);
}
}
+
+static void
+conn_connected_cb (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ EmpathyTpChat *self = user_data;
+ GError *error = NULL;
+
+ if (!tp_proxy_prepare_finish (source, result, &error))
+ {
+ DEBUG ("Failed to prepare Connected: %s", error->message);
+ g_simple_async_result_take_error (self->priv->ready_result, error);
+ g_simple_async_result_complete (self->priv->ready_result);
+ tp_clear_object (&self->priv->ready_result);
+ return;
+ }
+
+ continue_preparing (self);
+}
+
+static void
+tp_chat_prepare_ready_async (TpProxy *proxy,
+ const TpProxyFeature *feature,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ EmpathyTpChat *self = (EmpathyTpChat *) proxy;
+ TpChannel *channel = (TpChannel *) proxy;
+ TpConnection *connection;
+ GQuark features[] = { TP_CONNECTION_FEATURE_CONNECTED, 0 };
+
+ g_assert (self->priv->ready_result == NULL);
+
+ self->priv->ready_result = g_simple_async_result_new (G_OBJECT (self),
+ callback, user_data, tp_chat_prepare_ready_async);
+
+ connection = tp_channel_get_connection (channel);
+
+ /* First we have to make sure that TP_CONNECTION_FEATURE_CONNECTED is
+ * prepared as we rely on TpConnection::self-contact
+ * in continue_preparing().
+ *
+ * It would be nice if tp-glib could do this for us: fdo#59126 */
+ tp_proxy_prepare_async (connection, features, conn_connected_cb, proxy);
+}