diff options
author | Olli Salli <olli.salli@collabora.co.uk> | 2007-01-29 15:47:36 +0000 |
---|---|---|
committer | Olli Salli <olli.salli@collabora.co.uk> | 2007-01-29 15:47:36 +0000 |
commit | 7a897b917168505139de0c726e96663e2c7ed977 (patch) | |
tree | ae8ec0815c2f66152812bdc85439c44bc708cd67 /src/idle-im-channel.c | |
parent | 36e7ba52d4397763aca609c368bc6f2472b644a1 (diff) |
Initial import (migration from SF.net SVN)
Diffstat (limited to 'src/idle-im-channel.c')
-rw-r--r-- | src/idle-im-channel.c | 814 |
1 files changed, 814 insertions, 0 deletions
diff --git a/src/idle-im-channel.c b/src/idle-im-channel.c new file mode 100644 index 0000000..8982c79 --- /dev/null +++ b/src/idle-im-channel.c @@ -0,0 +1,814 @@ +/* + * This file is part of telepathy-idle + * + * Copyright (C) 2006 Nokia Corporation. All rights reserved. + * + * + * 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 <glib.h> +#include <dbus/dbus-glib.h> + +#define _GNU_SOURCE +#include <string.h> +#include <time.h> + +#include "idle-connection.h" +#include "idle-handles.h" +#include "telepathy-constants.h" +#include "telepathy-errors.h" +#include "telepathy-helpers.h" +#include "telepathy-interfaces.h" + +#include "idle-im-channel.h" +#include "idle-im-channel-glue.h" +#include "idle-im-channel-signals-marshal.h" + +#define IRC_MSG_MAXLEN 510 + +G_DEFINE_TYPE(IdleIMChannel, idle_im_channel, G_TYPE_OBJECT) + +/* signal enum */ +enum +{ + CLOSED, + RECEIVED, + SENT, + SEND_ERROR, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = {0}; + +/* property enum */ +enum +{ + PROP_CONNECTION = 1, + PROP_OBJECT_PATH, + PROP_CHANNEL_TYPE, + PROP_HANDLE_TYPE, + PROP_HANDLE, + LAST_PROPERTY_ENUM +}; + +typedef struct _IdleIMPendingMessage IdleIMPendingMessage; + +struct _IdleIMPendingMessage +{ + guint id; + + time_t timestamp; + IdleHandle sender; + + TpChannelTextMessageType type; + + gchar *text; +}; + +/* private structure */ +typedef struct _IdleIMChannelPrivate IdleIMChannelPrivate; + +struct _IdleIMChannelPrivate +{ + IdleConnection *connection; + gchar *object_path; + IdleHandle handle; + + guint recv_id; + GQueue *pending_messages; + + IdleIMPendingMessage *last_msg; + + gboolean closed; + + gboolean dispose_has_run; +}; + +#define _idle_im_pending_new() \ + (g_slice_new(IdleIMPendingMessage)) +#define _idle_im_pending_new0() \ + (g_slice_new0(IdleIMPendingMessage)) + +static void _idle_im_pending_free(IdleIMPendingMessage *msg) +{ + if (msg->text) + { + g_free(msg->text); + } + + g_slice_free(IdleIMPendingMessage, msg); +} + +#define IDLE_IM_CHANNEL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), IDLE_TYPE_IM_CHANNEL, IdleIMChannelPrivate)) + +static void +idle_im_channel_init (IdleIMChannel *obj) +{ + IdleIMChannelPrivate *priv = IDLE_IM_CHANNEL_GET_PRIVATE (obj); + + priv->pending_messages = g_queue_new(); + + priv->last_msg = _idle_im_pending_new0(); +} + +static void idle_im_channel_dispose (GObject *object); +static void idle_im_channel_finalize (GObject *object); + +static GObject *idle_im_channel_constructor(GType type, guint n_props, GObjectConstructParam *props) +{ + GObject *obj; + IdleIMChannelPrivate *priv; + DBusGConnection *bus; + IdleHandleStorage *handles; + gboolean valid; + + obj = G_OBJECT_CLASS(idle_im_channel_parent_class)->constructor(type, n_props, props); + priv = IDLE_IM_CHANNEL_GET_PRIVATE(IDLE_IM_CHANNEL(obj)); + + handles = _idle_connection_get_handles(priv->connection); + valid = idle_handle_ref(handles, TP_HANDLE_TYPE_CONTACT, priv->handle); + g_assert(valid); + + bus = tp_get_bus(); + dbus_g_connection_register_g_object(bus, priv->object_path, obj); + + return obj; +} + +static void idle_im_channel_get_property(GObject *object, guint property_id, + GValue *value, GParamSpec *pspec) +{ + IdleIMChannel *chan; + IdleIMChannelPrivate *priv; + + g_assert(object != NULL); + g_assert(IDLE_IS_IM_CHANNEL(object)); + + chan = IDLE_IM_CHANNEL(object); + priv = IDLE_IM_CHANNEL_GET_PRIVATE(chan); + + switch (property_id) + { + case PROP_CONNECTION: + { + g_value_set_object(value, priv->connection); + } + break; + case PROP_OBJECT_PATH: + { + g_value_set_string(value, priv->object_path); + } + break; + case PROP_CHANNEL_TYPE: + { + g_value_set_string(value, TP_IFACE_CHANNEL_TYPE_TEXT); + } + break; + case PROP_HANDLE_TYPE: + { + g_value_set_uint(value, TP_HANDLE_TYPE_CONTACT); + } + break; + case PROP_HANDLE: + { + g_value_set_uint(value, priv->handle); + } + break; + default: + { + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + } + break; + } +} + +static void idle_im_channel_set_property(GObject *object, guint property_id, const GValue *value, + GParamSpec *pspec) +{ + IdleIMChannel *chan = IDLE_IM_CHANNEL(object); + IdleIMChannelPrivate *priv; + + g_assert(chan != NULL); + g_assert(IDLE_IS_IM_CHANNEL(chan)); + + priv = IDLE_IM_CHANNEL_GET_PRIVATE(chan); + + switch (property_id) + { + case PROP_CONNECTION: + { + priv->connection = g_value_get_object(value); + } + break; + case PROP_OBJECT_PATH: + { + if (priv->object_path) + { + g_free(priv->object_path); + } + + priv->object_path = g_value_dup_string(value); + } + break; + case PROP_HANDLE: + { + priv->handle = g_value_get_uint(value); + } + break; + default: + { + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + } + break; + } +} + +static void +idle_im_channel_class_init (IdleIMChannelClass *idle_im_channel_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (idle_im_channel_class); + GParamSpec *param_spec; + + g_type_class_add_private (idle_im_channel_class, sizeof (IdleIMChannelPrivate)); + + object_class->constructor = idle_im_channel_constructor; + + object_class->get_property = idle_im_channel_get_property; + object_class->set_property = idle_im_channel_set_property; + + object_class->dispose = idle_im_channel_dispose; + object_class->finalize = idle_im_channel_finalize; + + param_spec = g_param_spec_object ("connection", "IdleConnection object", + "The IdleConnection object that owns this " + "IMChannel object.", + IDLE_TYPE_CONNECTION, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE | + G_PARAM_STATIC_NICK | + G_PARAM_STATIC_BLURB); + g_object_class_install_property (object_class, PROP_CONNECTION, param_spec); + + param_spec = g_param_spec_string ("object-path", "D-Bus object path", + "The D-Bus object path used for this " + "object on the bus.", + NULL, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE | + G_PARAM_STATIC_NAME | + G_PARAM_STATIC_BLURB); + g_object_class_install_property (object_class, PROP_OBJECT_PATH, param_spec); + + param_spec = g_param_spec_string ("channel-type", "Telepathy channel type", + "The D-Bus interface representing the " + "type of this channel.", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_NAME | + G_PARAM_STATIC_BLURB); + g_object_class_install_property (object_class, PROP_CHANNEL_TYPE, param_spec); + + param_spec = g_param_spec_uint ("handle-type", "Contact handle type", + "The TpHandleType representing a " + "contact handle.", + 0, G_MAXUINT32, 0, + G_PARAM_READABLE | + G_PARAM_STATIC_NAME | + G_PARAM_STATIC_BLURB); + g_object_class_install_property (object_class, PROP_HANDLE_TYPE, param_spec); + + param_spec = g_param_spec_uint ("handle", "Contact handle", + "The IdleHandle representing the contact " + "with whom this channel communicates.", + 0, G_MAXUINT32, 0, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE | + G_PARAM_STATIC_NAME | + G_PARAM_STATIC_BLURB); + g_object_class_install_property (object_class, PROP_HANDLE, param_spec); + + signals[CLOSED] = + g_signal_new ("closed", + G_OBJECT_CLASS_TYPE (idle_im_channel_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + 0, + NULL, NULL, + idle_im_channel_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[RECEIVED] = + g_signal_new ("received", + G_OBJECT_CLASS_TYPE (idle_im_channel_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + 0, + NULL, NULL, + idle_im_channel_marshal_VOID__INT_INT_INT_INT_INT_STRING, + G_TYPE_NONE, 6, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING); + + signals[SENT] = + g_signal_new ("sent", + G_OBJECT_CLASS_TYPE (idle_im_channel_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + 0, + NULL, NULL, + idle_im_channel_marshal_VOID__INT_INT_STRING, + G_TYPE_NONE, 3, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING); + + signals[SEND_ERROR] = + g_signal_new("send-error", + G_OBJECT_CLASS_TYPE(idle_im_channel_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + 0, + NULL, NULL, + idle_im_channel_marshal_VOID__INT_INT_INT_STRING, + G_TYPE_NONE, 4, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING); + + dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (idle_im_channel_class), &dbus_glib_idle_im_channel_object_info); +} + +void +idle_im_channel_dispose (GObject *object) +{ + IdleIMChannel *self = IDLE_IM_CHANNEL (object); + IdleIMChannelPrivate *priv = IDLE_IM_CHANNEL_GET_PRIVATE (self); + + g_assert(object != NULL); + + if (priv->dispose_has_run) + return; + + priv->dispose_has_run = TRUE; + + if (!priv->closed) + { + g_signal_emit(self, signals[CLOSED], 0); + priv->closed = TRUE; + } + + if (G_OBJECT_CLASS (idle_im_channel_parent_class)->dispose) + G_OBJECT_CLASS (idle_im_channel_parent_class)->dispose (object); +} + +void +idle_im_channel_finalize (GObject *object) +{ + IdleIMChannel *self = IDLE_IM_CHANNEL (object); + IdleIMChannelPrivate *priv = IDLE_IM_CHANNEL_GET_PRIVATE (self); + IdleHandleStorage *handles; + IdleIMPendingMessage *msg; + + handles = _idle_connection_get_handles(priv->connection); + idle_handle_unref(handles, TP_HANDLE_TYPE_CONTACT, priv->handle); + + if (priv->object_path) + { + g_free(priv->object_path); + } + + while ((msg = g_queue_pop_head(priv->pending_messages)) != NULL) + { + _idle_im_pending_free(msg); + } + + g_queue_free(priv->pending_messages); + + _idle_im_pending_free(priv->last_msg); + + G_OBJECT_CLASS (idle_im_channel_parent_class)->finalize (object); +} + +gboolean _idle_im_channel_receive(IdleIMChannel *chan, TpChannelTextMessageType type, IdleHandle sender, const gchar *text) +{ + IdleIMChannelPrivate *priv; + IdleIMPendingMessage *msg; + + g_assert(chan != NULL); + g_assert(IDLE_IS_IM_CHANNEL(chan)); + + priv = IDLE_IM_CHANNEL_GET_PRIVATE(chan); + + msg = _idle_im_pending_new(); + + msg->id = priv->recv_id++; + msg->timestamp = time(NULL); + msg->sender = sender; + msg->type = type; + msg->text = g_strdup(text); + + g_queue_push_tail(priv->pending_messages, msg); + + g_signal_emit(chan, signals[RECEIVED], 0, + msg->id, + msg->timestamp, + msg->sender, + msg->type, + 0, + msg->text); + + g_debug("%s: queued message %u", G_STRFUNC, msg->id); + + return FALSE; +} + +void _idle_im_channel_rename(IdleIMChannel *chan, IdleHandle new) +{ + IdleIMChannelPrivate *priv; + IdleHandleStorage *handles; + gboolean valid; + + g_assert(chan != NULL); + g_assert(IDLE_IS_IM_CHANNEL(chan)); + + g_assert(new != 0); + + priv = IDLE_IM_CHANNEL_GET_PRIVATE(chan); + handles = _idle_connection_get_handles(priv->connection); + + idle_handle_unref(handles, TP_HANDLE_TYPE_CONTACT, priv->handle); + priv->handle = new; + valid = idle_handle_ref(handles, TP_HANDLE_TYPE_CONTACT, priv->handle); + g_assert(valid); + + g_debug("%s: changed to handle %u", G_STRFUNC, new); +} + +void _idle_im_channel_nosuchnick(IdleIMChannel *chan) +{ + IdleIMChannelPrivate *priv; + IdleIMPendingMessage *last_msg; + + g_assert(chan != NULL); + g_assert(IDLE_IS_IM_CHANNEL(chan)); + + priv = IDLE_IM_CHANNEL_GET_PRIVATE(chan); + + g_assert(priv->last_msg != NULL); + last_msg = priv->last_msg; + + /* TODO this is so incorrect, we are assuming it was always the most recent message etc... */ + + g_signal_emit(chan, signals[SEND_ERROR], 0, TP_CHANNEL_TEXT_SEND_ERROR_OFFLINE, last_msg->timestamp, last_msg->type, last_msg->text); +} + +static gint idle_pending_message_compare(gconstpointer msg, gconstpointer id) +{ + IdleIMPendingMessage *message = (IdleIMPendingMessage *)(msg); + + return (message->id != GPOINTER_TO_INT(id)); +} + +/** + * idle_im_channel_acknowledge_pending_messages + * + * Implements DBus method AcknowledgePendingMessages + * on interface org.freedesktop.Telepathy.Channel.Type.Text + * + * @error: Used to return a pointer to a GError detailing any error + * that occured, DBus will throw the error only if this + * function returns false. + * + * Returns: TRUE if successful, FALSE if an error was thrown. + */ +gboolean idle_im_channel_acknowledge_pending_messages (IdleIMChannel *obj, const GArray *ids, GError **error) +{ + IdleIMChannelPrivate *priv; + int i; + + g_assert(obj != NULL); + g_assert(IDLE_IS_IM_CHANNEL(obj)); + + priv = IDLE_IM_CHANNEL_GET_PRIVATE(obj); + + for (i=0; i < ids->len; i++) + { + GList *node; + IdleIMPendingMessage *msg; + guint id = g_array_index(ids, guint, i); + + node = g_queue_find_custom(priv->pending_messages, + GINT_TO_POINTER(id), + idle_pending_message_compare); + + if (!node) + { + g_debug("%s: message id %u not found", G_STRFUNC, id); + + *error = g_error_new(TELEPATHY_ERRORS, InvalidArgument, "message id %u not found", id); + + return FALSE; + } + + msg = (IdleIMPendingMessage *)(node->data); + + g_debug("%s: acknowledging message id %u", G_STRFUNC, id); + + g_queue_delete_link(priv->pending_messages, node); + + _idle_im_pending_free(msg); + } + + return TRUE; +} + + +/** + * idle_im_channel_close + * + * Implements DBus method Close + * on interface org.freedesktop.Telepathy.Channel + * + * @error: Used to return a pointer to a GError detailing any error + * that occured, DBus will throw the error only if this + * function returns false. + * + * Returns: TRUE if successful, FALSE if an error was thrown. + */ +gboolean idle_im_channel_close (IdleIMChannel *obj, GError **error) +{ + IdleIMChannelPrivate *priv; + + g_assert(obj != NULL); + g_assert(IDLE_IS_IM_CHANNEL(obj)); + + priv = IDLE_IM_CHANNEL_GET_PRIVATE(obj); + priv->closed = TRUE; + + g_debug("%s called on %p", G_STRFUNC, obj); + g_signal_emit(obj, signals[CLOSED], 0); + + return TRUE; +} + + +/** + * idle_im_channel_get_channel_type + * + * Implements DBus method GetChannelType + * on interface org.freedesktop.Telepathy.Channel + * + * @error: Used to return a pointer to a GError detailing any error + * that occured, DBus will throw the error only if this + * function returns false. + * + * Returns: TRUE if successful, FALSE if an error was thrown. + */ +gboolean idle_im_channel_get_channel_type (IdleIMChannel *obj, gchar ** ret, GError **error) +{ + *ret = g_strdup(TP_IFACE_CHANNEL_TYPE_TEXT); + + return TRUE; +} + + +/** + * idle_im_channel_get_handle + * + * Implements DBus method GetHandle + * on interface org.freedesktop.Telepathy.Channel + * + * @error: Used to return a pointer to a GError detailing any error + * that occured, DBus will throw the error only if this + * function returns false. + * + * Returns: TRUE if successful, FALSE if an error was thrown. + */ +gboolean idle_im_channel_get_handle (IdleIMChannel *obj, guint* ret, guint* ret1, GError **error) +{ + IdleIMChannelPrivate *priv; + + g_assert(obj != NULL); + g_assert(IDLE_IS_IM_CHANNEL(obj)); + + priv = IDLE_IM_CHANNEL_GET_PRIVATE(obj); + + *ret = TP_HANDLE_TYPE_CONTACT; + *ret1 = priv->handle; + + return TRUE; +} + + +/** + * idle_im_channel_get_interfaces + * + * Implements DBus method GetInterfaces + * on interface org.freedesktop.Telepathy.Channel + * + * @error: Used to return a pointer to a GError detailing any error + * that occured, DBus will throw the error only if this + * function returns false. + * + * Returns: TRUE if successful, FALSE if an error was thrown. + */ +gboolean idle_im_channel_get_interfaces (IdleIMChannel *obj, gchar *** ret, GError **error) +{ + const gchar *interfaces[] = {NULL}; + + *ret = g_strdupv((gchar **)(interfaces)); + + return TRUE; +} + + +/** + * idle_im_channel_list_pending_messages + * + * Implements DBus method ListPendingMessages + * on interface org.freedesktop.Telepathy.Channel.Type.Text + * + * @error: Used to return a pointer to a GError detailing any error + * that occured, DBus will throw the error only if this + * function returns false. + * + * Returns: TRUE if successful, FALSE if an error was thrown. + */ +gboolean idle_im_channel_list_pending_messages (IdleIMChannel *obj, + gboolean clear, + GPtrArray ** ret, + GError **error) +{ + IdleIMChannelPrivate *priv; + guint count; + GPtrArray *messages; + GList *cur; + + g_assert (IDLE_IS_IM_CHANNEL (obj)); + + priv = IDLE_IM_CHANNEL_GET_PRIVATE (obj); + + count = g_queue_get_length (priv->pending_messages); + messages = g_ptr_array_sized_new (count); + + for (cur = g_queue_peek_head_link(priv->pending_messages); + cur != NULL; + cur = cur->next) + { + IdleIMPendingMessage *msg = (IdleIMPendingMessage *)(cur->data); + GValueArray *vals; + + vals = g_value_array_new (6); + + g_value_array_append (vals, NULL); + g_value_init (g_value_array_get_nth (vals, 0), G_TYPE_UINT); + g_value_set_uint (g_value_array_get_nth (vals, 0), msg->id); + + g_value_array_append (vals, NULL); + g_value_init (g_value_array_get_nth (vals, 1), G_TYPE_UINT); + g_value_set_uint (g_value_array_get_nth (vals, 1), msg->timestamp); + + g_value_array_append (vals, NULL); + g_value_init (g_value_array_get_nth (vals, 2), G_TYPE_UINT); + g_value_set_uint (g_value_array_get_nth (vals, 2), msg->sender); + + g_value_array_append (vals, NULL); + g_value_init (g_value_array_get_nth (vals, 3), G_TYPE_UINT); + g_value_set_uint (g_value_array_get_nth (vals, 3), msg->type); + + g_value_array_append (vals, NULL); + g_value_init (g_value_array_get_nth (vals, 4), G_TYPE_UINT); + g_value_set_uint (g_value_array_get_nth (vals, 4), 0); + + g_value_array_append (vals, NULL); + g_value_init (g_value_array_get_nth (vals, 5), G_TYPE_STRING); + g_value_set_string (g_value_array_get_nth (vals, 5), msg->text); + + g_ptr_array_add (messages, vals); + } + + if (clear) + { + IdleIMPendingMessage *msg; + + while ((msg = g_queue_pop_head(priv->pending_messages)) != NULL) + { + _idle_im_pending_free(msg); + } + } + + *ret = messages; + + return TRUE; +} + + +/** + * idle_im_channel_send + * + * Implements DBus method Send + * on interface org.freedesktop.Telepathy.Channel.Type.Text + * + * @error: Used to return a pointer to a GError detailing any error + * that occured, DBus will throw the error only if this + * function returns false. + * + * Returns: TRUE if successful, FALSE if an error was thrown. + */ +gboolean idle_im_channel_send (IdleIMChannel *obj, guint type, const gchar * text, GError **error) +{ + IdleIMChannelPrivate *priv; + gchar msg[IRC_MSG_MAXLEN+1]; + const char *recipient; + time_t timestamp; + const gchar *final_text = text; + gsize len; + gchar *part; + gsize headerlen; + + g_assert(obj != NULL); + g_assert(IDLE_IS_IM_CHANNEL(obj)); + + priv = IDLE_IM_CHANNEL_GET_PRIVATE(obj); + + recipient = idle_handle_inspect(_idle_connection_get_handles(priv->connection), TP_HANDLE_TYPE_CONTACT, + priv->handle); + + if ((recipient == NULL) || (strlen(recipient) == 0)) + { + g_debug("%s: invalid recipient", G_STRFUNC); + + *error = g_error_new(TELEPATHY_ERRORS, NotAvailable, "invalid recipient"); + + return FALSE; + } + + len = strlen(final_text); + part = (gchar*)final_text; + + if (type == TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL) + { + g_snprintf(msg, IRC_MSG_MAXLEN+1, "PRIVMSG %s :", recipient); + } + else if (type == TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION) + { + g_snprintf(msg, IRC_MSG_MAXLEN+1, "PRIVMSG %s :\001ACTION ", recipient); + } + else if (type == TP_CHANNEL_TEXT_MESSAGE_TYPE_NOTICE) + { + g_snprintf(msg, IRC_MSG_MAXLEN+1, "NOTICE %s :", recipient); + } + else + { + g_debug("%s: invalid message type %u", G_STRFUNC, type); + + *error = g_error_new(TELEPATHY_ERRORS, InvalidArgument, "invalid message type %u", type); + + return FALSE; + } + + headerlen = strlen(msg); + + while (part < final_text+len) + { + char *br = strchr (part, '\n'); + size_t len = IRC_MSG_MAXLEN-headerlen; + if (br) + { + len = (len < br - part) ? len : br - part; + } + + if (type == TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION) + { + g_snprintf(msg+headerlen, len + 1, "%s\001", part); + len -= 1; + } + else + { + g_strlcpy(msg+headerlen, part, len + 1); + } + part += len; + if (br) + { + part++; + } + + _idle_connection_send(priv->connection, msg); + } + + timestamp = time(NULL); + + g_signal_emit(obj, signals[SENT], 0, timestamp, type, text); + + if (priv->last_msg->text) + { + g_free(priv->last_msg->text); + } + + priv->last_msg->timestamp = timestamp; + priv->last_msg->type = type; + priv->last_msg->text = g_strdup(text); + + return TRUE; +} + |