/*
* This file is part of telepathy-idle
*
* Copyright (C) 2006-2007, 2012 Collabora Limited
* Copyright (C) 2006-2007 Nokia Corporation
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* version 2.1 as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "config.h"
#include "idle-im-channel.h"
#include <dbus/dbus-glib.h>
#define IDLE_DEBUG_FLAG IDLE_DEBUG_IM
#include "idle-connection.h"
#include "idle-debug.h"
#include "idle-text.h"
static void _destroyable_iface_init(gpointer, gpointer);
static GPtrArray *idle_im_channel_get_interfaces (TpBaseChannel *channel);
static void idle_im_channel_close (TpBaseChannel *base);
static void idle_im_channel_send (GObject *obj, TpMessage *message, TpMessageSendingFlags flags);
static void idle_im_channel_finalize (GObject *object);
G_DEFINE_TYPE_WITH_CODE(IdleIMChannel, idle_im_channel, TP_TYPE_BASE_CHANNEL,
G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CHANNEL_TYPE_TEXT, tp_message_mixin_text_iface_init);
G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_MESSAGES, tp_message_mixin_messages_iface_init);
G_IMPLEMENT_INTERFACE(TP_TYPE_SVC_CHANNEL_INTERFACE_DESTROYABLE, _destroyable_iface_init);
)
/* private structure */
typedef struct _IdleIMChannelPrivate IdleIMChannelPrivate;
struct _IdleIMChannelPrivate {
gpointer unused;
};
static void
idle_im_channel_init (IdleIMChannel *obj)
{
}
static void
idle_im_channel_constructed (GObject *obj)
{
TpChannelTextMessageType types[] = {
TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL,
TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION,
TP_CHANNEL_TEXT_MESSAGE_TYPE_NOTICE,
};
const gchar * supported_content_types[] = {
"text/plain",
NULL
};
G_OBJECT_CLASS (idle_im_channel_parent_class)->constructed (obj);
/* initialize message mixin */
tp_message_mixin_init (obj, G_STRUCT_OFFSET (IdleIMChannel, message_mixin),
tp_base_channel_get_connection (TP_BASE_CHANNEL (obj)));
tp_message_mixin_implement_sending (obj, idle_im_channel_send,
G_N_ELEMENTS (types), types, 0,
TP_DELIVERY_REPORTING_SUPPORT_FLAG_RECEIVE_FAILURES,
supported_content_types);
}
static void
idle_im_channel_fill_properties (
TpBaseChannel *chan,
GHashTable *properties)
{
TpBaseChannelClass *klass = TP_BASE_CHANNEL_CLASS (idle_im_channel_parent_class);
klass->fill_immutable_properties (chan, properties);
tp_dbus_properties_mixin_fill_properties_hash (
G_OBJECT (chan), properties,
TP_IFACE_CHANNEL_INTERFACE_MESSAGES, "MessagePartSupportFlags",
TP_IFACE_CHANNEL_INTERFACE_MESSAGES, "DeliveryReportingSupport",
TP_IFACE_CHANNEL_INTERFACE_MESSAGES, "SupportedContentTypes",
TP_IFACE_CHANNEL_INTERFACE_MESSAGES, "MessageTypes",
NULL);
}
static gchar *
idle_im_channel_get_path_suffix (TpBaseChannel *base)
{
return g_strdup_printf("ImChannel%u",
tp_base_channel_get_target_handle (base));
}
static void
idle_im_channel_class_init (IdleIMChannelClass *idle_im_channel_class)
{
TpBaseChannelClass *base_class = TP_BASE_CHANNEL_CLASS (idle_im_channel_class);
GObjectClass *object_class = G_OBJECT_CLASS (idle_im_channel_class);
g_type_class_add_private (idle_im_channel_class, sizeof (IdleIMChannelPrivate));
object_class->constructed = idle_im_channel_constructed;
object_class->finalize = idle_im_channel_finalize;
base_class->channel_type = TP_IFACE_CHANNEL_TYPE_TEXT;
base_class->target_handle_type = TP_HANDLE_TYPE_CONTACT;
base_class->close = idle_im_channel_close;
base_class->fill_immutable_properties = idle_im_channel_fill_properties;
base_class->get_object_path_suffix = idle_im_channel_get_path_suffix;
base_class->get_interfaces = idle_im_channel_get_interfaces;
tp_message_mixin_init_dbus_properties (object_class);
}
static void
idle_im_channel_finalize (GObject *object)
{
tp_message_mixin_finalize (object);
G_OBJECT_CLASS(idle_im_channel_parent_class)->finalize (object);
}
gboolean
idle_im_channel_receive (
IdleIMChannel *chan,
TpChannelTextMessageType type,
TpHandle sender,
const gchar *text)
{
TpBaseConnection *base_conn = tp_base_channel_get_connection (TP_BASE_CHANNEL (chan));
return idle_text_received (G_OBJECT (chan), base_conn, type, text, sender);
}
static void
idle_im_channel_close (TpBaseChannel *base)
{
IdleIMChannel *obj = IDLE_IM_CHANNEL (base);
/* The IM manager will resurrect the channel if we have pending
* messages. When we're resurrected, we want the initiator
* to be the contact who sent us those messages, if it isn't already */
if (tp_message_mixin_has_pending_messages ((GObject *)obj, NULL))
{
IDLE_DEBUG("%p not really closing, I still have pending messages", obj);
tp_message_mixin_set_rescued ((GObject *) obj);
tp_base_channel_reopened (base, tp_base_channel_get_target_handle (base));
}
else
{
IDLE_DEBUG ("%p actually closing, I have no pending messages", obj);
tp_base_channel_destroyed (base);
}
}
static GPtrArray *
idle_im_channel_get_interfaces (TpBaseChannel *channel)
{
GPtrArray *interfaces =
TP_BASE_CHANNEL_CLASS (idle_im_channel_parent_class)->get_interfaces (
channel);
g_ptr_array_add (interfaces, TP_IFACE_CHANNEL_INTERFACE_MESSAGES);
g_ptr_array_add (interfaces, TP_IFACE_CHANNEL_INTERFACE_DESTROYABLE);
return interfaces;
}
/**
* idle_im_channel_send
*
* Indirectly implements (via TpMessageMixin) D-Bus method Send on interface
* org.freedesktop.Telepathy.Channel.Type.Text and D-Bus method SendMessage on
* Channel.Interface.Messages
*/
static void
idle_im_channel_send (
GObject *obj,
TpMessage *message,
TpMessageSendingFlags flags)
{
TpBaseChannel *base = TP_BASE_CHANNEL (obj);
TpBaseConnection *conn = tp_base_channel_get_connection (base);
const gchar *recipient = tp_handle_inspect (
tp_base_connection_get_handles (conn, TP_HANDLE_TYPE_CONTACT),
tp_base_channel_get_target_handle (base));
idle_text_send (obj, message, flags, recipient, IDLE_CONNECTION (conn));
}
static void
idle_im_channel_destroy (
TpSvcChannelInterfaceDestroyable *iface,
DBusGMethodInvocation *context)
{
TpBaseChannel *chan = TP_BASE_CHANNEL (iface);
GObject *obj = (GObject *) chan;
IDLE_DEBUG ("called on %p with %spending messages", obj,
tp_message_mixin_has_pending_messages (obj, NULL) ? "" : "no ");
tp_message_mixin_clear (obj);
tp_base_channel_destroyed (chan);
tp_svc_channel_interface_destroyable_return_from_destroy(context);
}
static void
_destroyable_iface_init (
gpointer klass,
gpointer iface_data)
{
#define IMPLEMENT(x) tp_svc_channel_interface_destroyable_implement_##x (\
klass, idle_im_channel_##x)
IMPLEMENT (destroy);
#undef IMPLEMENT
}