/* * chan.c - an example text channel talking to a particular * contact. Similar code is used for 1-1 IM channels in many protocols * (IRC private messages ("/query"), XMPP IM etc.) * * Copyright (C) 2007 Collabora Ltd. * Copyright (C) 2007 Nokia Corporation * * Copying and distribution of this file, with or without modification, * are permitted in any medium without royalty provided the copyright * notice and this notice are preserved. */ #include "config.h" #include "echo-chan.h" #include #include static void destroyable_iface_init (gpointer iface, gpointer data); G_DEFINE_TYPE_WITH_CODE (TpTestsEchoChannel, tp_tests_echo_channel, TP_TYPE_BASE_CHANNEL, G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_TYPE_TEXT, tp_message_mixin_iface_init); G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_DESTROYABLE1, destroyable_iface_init); ) /* type definition stuff */ static GPtrArray * tp_tests_echo_channel_get_interfaces (TpBaseChannel *self) { GPtrArray *interfaces; interfaces = TP_BASE_CHANNEL_CLASS (tp_tests_echo_channel_parent_class)-> get_interfaces (self); g_ptr_array_add (interfaces, TP_IFACE_CHANNEL_INTERFACE_DESTROYABLE1); return interfaces; }; static void tp_tests_echo_channel_init (TpTestsEchoChannel *self) { } static void text_send (GObject *object, TpMessage *message, TpMessageSendingFlags flags); static void constructed (GObject *object) { TpTestsEchoChannel *self = TP_TESTS_ECHO_CHANNEL (object); TpBaseConnection *conn = tp_base_channel_get_connection (TP_BASE_CHANNEL (self)); const 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_assert (conn != NULL); G_OBJECT_CLASS (tp_tests_echo_channel_parent_class)->constructed (object); tp_base_channel_register (TP_BASE_CHANNEL (self)); tp_message_mixin_init (object, G_STRUCT_OFFSET (TpTestsEchoChannel, message), conn); tp_message_mixin_implement_sending (object, text_send, G_N_ELEMENTS (types), types, 0, 0, supported_content_types); } static void finalize (GObject *object) { tp_message_mixin_finalize (object); ((GObjectClass *) tp_tests_echo_channel_parent_class)->finalize (object); } static void tp_tests_echo_channel_close (TpTestsEchoChannel *self) { GObject *object = (GObject *) self; gboolean closed = tp_base_channel_is_destroyed (TP_BASE_CHANNEL (self)); if (!closed) { TpHandle first_sender; /* The manager wants to be able to respawn the channel if it has pending * messages. When respawned, the channel must have the initiator set * to the contact who sent us those messages (if it isn't already), * and the messages must be marked as having been rescued so they * don't get logged twice. */ if (tp_message_mixin_has_pending_messages (object, &first_sender)) { tp_base_channel_reopened (TP_BASE_CHANNEL (self), first_sender); tp_message_mixin_set_rescued (object); } else { tp_base_channel_destroyed (TP_BASE_CHANNEL (self)); } } } static void channel_close (TpBaseChannel *channel) { TpTestsEchoChannel *self = TP_TESTS_ECHO_CHANNEL (channel); tp_tests_echo_channel_close (self); } static void tp_tests_echo_channel_class_init (TpTestsEchoChannelClass *klass) { GObjectClass *object_class = (GObjectClass *) klass; TpBaseChannelClass *base_class = TP_BASE_CHANNEL_CLASS (klass); object_class->constructed = constructed; object_class->finalize = finalize; base_class->channel_type = TP_IFACE_CHANNEL_TYPE_TEXT; base_class->target_handle_type = TP_HANDLE_TYPE_CONTACT; base_class->get_interfaces = tp_tests_echo_channel_get_interfaces; base_class->close = channel_close; tp_message_mixin_init_dbus_properties (object_class); } static void text_send (GObject *object, TpMessage *message, TpMessageSendingFlags flags) { TpTestsEchoChannel *self = TP_TESTS_ECHO_CHANNEL (object); TpChannelTextMessageType type = tp_message_get_message_type (message); TpChannelTextMessageType echo_type = type; TpHandle target = tp_base_channel_get_target_handle (TP_BASE_CHANNEL (self)); gchar *echo; gint64 now = time (NULL); const GHashTable *part; const gchar *text; TpMessage *msg; /* Pretend that the remote contact has replied. Normally, you'd * call tp_text_mixin_receive or tp_text_mixin_receive_with_flags * in response to network events */ part = tp_message_peek (message, 1); text = tp_asv_get_string (part, "content"); switch (type) { case TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL: echo = g_strdup_printf ("You said: %s", text); break; case TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION: echo = g_strdup_printf ("notices that the user %s", text); break; case TP_CHANNEL_TEXT_MESSAGE_TYPE_NOTICE: echo = g_strdup_printf ("You sent a notice: %s", text); break; default: echo = g_strdup_printf ("You sent some weird message type, %u: \"%s\"", type, text); echo_type = TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL; } tp_message_mixin_sent (object, message, 0, "", NULL); msg = tp_cm_message_new ( tp_base_channel_get_connection (TP_BASE_CHANNEL (self)), 2); tp_cm_message_set_sender (msg, target); tp_message_set_uint32 (msg, 0, "message-type", echo_type); tp_message_set_int64 (msg, 0, "message-sent", now); tp_message_set_int64 (msg, 0, "message-received", now); tp_message_set_string (msg, 1, "content-type", "text/plain"); tp_message_set_string (msg, 1, "content", echo); tp_message_mixin_take_received (object, msg); g_free (echo); } static void destroyable_destroy (TpSvcChannelInterfaceDestroyable1 *iface, DBusGMethodInvocation *context) { TpTestsEchoChannel *self = TP_TESTS_ECHO_CHANNEL (iface); tp_message_mixin_clear ((GObject *) self); tp_base_channel_destroyed (TP_BASE_CHANNEL (self)); tp_svc_channel_interface_destroyable1_return_from_destroy (context); } static void destroyable_iface_init (gpointer iface, gpointer data) { TpSvcChannelInterfaceDestroyable1Class *klass = iface; #define IMPLEMENT(x) \ tp_svc_channel_interface_destroyable1_implement_##x (klass, destroyable_##x) IMPLEMENT (destroy); #undef IMPLEMENT }