pidgin/pidgin

cb26b9c6d4d0
Parents e2c4be9e3aa6
Children 77d7bc9e5151
Move PurpleIMConversation to its own file

Move PurpleIMConversation to it's own file.

Testing Done:
Compiled and was able to send an IM. It's not yet using `G_DECLARE_FINAL_TYPE` because `PurpleConversation` is not using `G_DECLARE_*` so it fails if I try to use it. I didn't clean up too much of the code yet, but I tried to get most of the formatting changes we have.

Reviewed at https://reviews.imfreedom.org/r/60/
--- a/libpurple/conversationtypes.c Mon Aug 10 19:59:56 2020 -0500
+++ b/libpurple/conversationtypes.c Thu Aug 13 18:29:17 2020 -0500
@@ -28,37 +28,6 @@
#include "enums.h"
#include "purpleprivate.h"
-#define SEND_TYPED_TIMEOUT_SECONDS 5
-
-/**************************************************************************/
-/* PurpleIMConversation */
-/**************************************************************************/
-
-/*
- * Data specific to Instant Messages.
- */
-typedef struct
-{
- PurpleIMTypingState typing_state; /* The current typing state. */
- guint typing_timeout; /* The typing timer handle. */
- time_t type_again; /* The type again time. */
- guint send_typed_timeout; /* The type again timer handle. */
- PurpleBuddyIcon *icon; /* The buddy icon. */
-} PurpleIMConversationPrivate;
-
-/* IM Property enums */
-enum {
- IM_PROP_0,
- IM_PROP_TYPING_STATE,
- IM_PROP_ICON,
- IM_PROP_LAST
-};
-
-static GParamSpec *im_properties[IM_PROP_LAST];
-
-G_DEFINE_TYPE_WITH_PRIVATE(PurpleIMConversation, purple_im_conversation,
- PURPLE_TYPE_CONVERSATION);
-
/**************************************************************************/
/* PurpleChatConversation */
/**************************************************************************/
@@ -149,434 +118,6 @@
PurpleChatUser *b);
/**************************************************************************
- * IM Conversation API
- **************************************************************************/
-static gboolean
-reset_typing_cb(gpointer data)
-{
- PurpleIMConversation *im = (PurpleIMConversation *)data;
-
- purple_im_conversation_set_typing_state(im, PURPLE_IM_NOT_TYPING);
- purple_im_conversation_stop_typing_timeout(im);
-
- return FALSE;
-}
-
-static gboolean
-send_typed_cb(gpointer data)
-{
- PurpleIMConversation *im = PURPLE_IM_CONVERSATION(data);
- PurpleConnection *gc;
- const char *name;
-
- g_return_val_if_fail(im != NULL, FALSE);
-
- gc = purple_conversation_get_connection(PURPLE_CONVERSATION(im));
- name = purple_conversation_get_name(PURPLE_CONVERSATION(im));
-
- if (gc != NULL && name != NULL) {
- /* We set this to 1 so that PURPLE_IM_TYPING will be sent
- * if the Purple user types anything else.
- */
- purple_im_conversation_set_type_again(im, 1);
-
- purple_serv_send_typing(gc, name, PURPLE_IM_TYPED);
-
- purple_debug(PURPLE_DEBUG_MISC, "conversationtypes", "typed...\n");
- }
-
- return FALSE;
-}
-
-void
-purple_im_conversation_set_icon(PurpleIMConversation *im, PurpleBuddyIcon *icon)
-{
- PurpleIMConversationPrivate *priv = NULL;
-
- g_return_if_fail(PURPLE_IS_IM_CONVERSATION(im));
-
- priv = purple_im_conversation_get_instance_private(im);
- if (priv->icon != icon)
- {
- purple_buddy_icon_unref(priv->icon);
-
- priv->icon = (icon == NULL ? NULL : purple_buddy_icon_ref(icon));
-
- g_object_notify_by_pspec(G_OBJECT(im), im_properties[IM_PROP_ICON]);
- }
-
- purple_conversation_update(PURPLE_CONVERSATION(im),
- PURPLE_CONVERSATION_UPDATE_ICON);
-}
-
-PurpleBuddyIcon *
-purple_im_conversation_get_icon(PurpleIMConversation *im)
-{
- PurpleIMConversationPrivate *priv = NULL;
-
- g_return_val_if_fail(PURPLE_IS_IM_CONVERSATION(im), NULL);
-
- priv = purple_im_conversation_get_instance_private(im);
- return priv->icon;
-}
-
-void
-purple_im_conversation_set_typing_state(PurpleIMConversation *im, PurpleIMTypingState state)
-{
- PurpleIMConversationPrivate *priv = NULL;
- PurpleAccount *account;
- const char *name;
-
- g_return_if_fail(PURPLE_IS_IM_CONVERSATION(im));
-
- priv = purple_im_conversation_get_instance_private(im);
- name = purple_conversation_get_name(PURPLE_CONVERSATION(im));
- account = purple_conversation_get_account(PURPLE_CONVERSATION(im));
-
- if (priv->typing_state != state)
- {
- priv->typing_state = state;
-
- g_object_notify_by_pspec(G_OBJECT(im),
- im_properties[IM_PROP_TYPING_STATE]);
-
- switch (state)
- {
- case PURPLE_IM_TYPING:
- purple_signal_emit(purple_conversations_get_handle(),
- "buddy-typing", account, name);
- break;
- case PURPLE_IM_TYPED:
- purple_signal_emit(purple_conversations_get_handle(),
- "buddy-typed", account, name);
- break;
- case PURPLE_IM_NOT_TYPING:
- purple_signal_emit(purple_conversations_get_handle(),
- "buddy-typing-stopped", account, name);
- break;
- }
-
- purple_im_conversation_update_typing(im);
- }
-}
-
-PurpleIMTypingState
-purple_im_conversation_get_typing_state(PurpleIMConversation *im)
-{
- PurpleIMConversationPrivate *priv = NULL;
-
- g_return_val_if_fail(PURPLE_IS_IM_CONVERSATION(im), 0);
-
- priv = purple_im_conversation_get_instance_private(im);
- return priv->typing_state;
-}
-
-void
-purple_im_conversation_start_typing_timeout(PurpleIMConversation *im, int timeout)
-{
- PurpleIMConversationPrivate *priv = NULL;
-
- g_return_if_fail(PURPLE_IS_IM_CONVERSATION(im));
-
- priv = purple_im_conversation_get_instance_private(im);
- if (priv->typing_timeout > 0)
- purple_im_conversation_stop_typing_timeout(im);
-
- priv->typing_timeout = g_timeout_add_seconds(timeout, reset_typing_cb, im);
-}
-
-void
-purple_im_conversation_stop_typing_timeout(PurpleIMConversation *im)
-{
- PurpleIMConversationPrivate *priv = NULL;
-
- g_return_if_fail(PURPLE_IS_IM_CONVERSATION(im));
-
- priv = purple_im_conversation_get_instance_private(im);
- if (priv->typing_timeout == 0)
- return;
-
- g_source_remove(priv->typing_timeout);
- priv->typing_timeout = 0;
-}
-
-guint
-purple_im_conversation_get_typing_timeout(PurpleIMConversation *im)
-{
- PurpleIMConversationPrivate *priv = NULL;
-
- g_return_val_if_fail(PURPLE_IS_IM_CONVERSATION(im), 0);
-
- priv = purple_im_conversation_get_instance_private(im);
- return priv->typing_timeout;
-}
-
-void
-purple_im_conversation_set_type_again(PurpleIMConversation *im, unsigned int val)
-{
- PurpleIMConversationPrivate *priv = NULL;
-
- g_return_if_fail(PURPLE_IS_IM_CONVERSATION(im));
-
- priv = purple_im_conversation_get_instance_private(im);
- if (val == 0)
- priv->type_again = 0;
- else
- priv->type_again = time(NULL) + val;
-}
-
-time_t
-purple_im_conversation_get_type_again(PurpleIMConversation *im)
-{
- PurpleIMConversationPrivate *priv = NULL;
-
- g_return_val_if_fail(PURPLE_IS_IM_CONVERSATION(im), 0);
-
- priv = purple_im_conversation_get_instance_private(im);
- return priv->type_again;
-}
-
-void
-purple_im_conversation_start_send_typed_timeout(PurpleIMConversation *im)
-{
- PurpleIMConversationPrivate *priv = NULL;
-
- g_return_if_fail(PURPLE_IS_IM_CONVERSATION(im));
-
- priv = purple_im_conversation_get_instance_private(im);
- priv->send_typed_timeout = g_timeout_add_seconds(SEND_TYPED_TIMEOUT_SECONDS,
- send_typed_cb, im);
-}
-
-void
-purple_im_conversation_stop_send_typed_timeout(PurpleIMConversation *im)
-{
- PurpleIMConversationPrivate *priv = NULL;
-
- g_return_if_fail(PURPLE_IS_IM_CONVERSATION(im));
-
- priv = purple_im_conversation_get_instance_private(im);
- if (priv->send_typed_timeout == 0)
- return;
-
- g_source_remove(priv->send_typed_timeout);
- priv->send_typed_timeout = 0;
-}
-
-guint
-purple_im_conversation_get_send_typed_timeout(PurpleIMConversation *im)
-{
- PurpleIMConversationPrivate *priv = NULL;
-
- g_return_val_if_fail(PURPLE_IS_IM_CONVERSATION(im), 0);
-
- priv = purple_im_conversation_get_instance_private(im);
- return priv->send_typed_timeout;
-}
-
-void
-purple_im_conversation_update_typing(PurpleIMConversation *im)
-{
- g_return_if_fail(PURPLE_IS_IM_CONVERSATION(im));
-
- purple_conversation_update(PURPLE_CONVERSATION(im),
- PURPLE_CONVERSATION_UPDATE_TYPING);
-}
-
-static void
-im_conversation_write_message(PurpleConversation *conv, PurpleMessage *msg)
-{
- PurpleIMConversation *im = PURPLE_IM_CONVERSATION(conv);
- gboolean is_recv;
-
- g_return_if_fail(im != NULL);
- g_return_if_fail(msg != NULL);
-
- is_recv = (purple_message_get_flags(msg) & PURPLE_MESSAGE_RECV);
-
- if (is_recv)
- purple_im_conversation_set_typing_state(im, PURPLE_IM_NOT_TYPING);
-
- _purple_conversation_write_common(conv, msg);
-}
-
-/**************************************************************************
- * GObject code for IMs
- **************************************************************************/
-
-/* Set method for GObject properties */
-static void
-purple_im_conversation_set_property(GObject *obj, guint param_id, const GValue *value,
- GParamSpec *pspec)
-{
- PurpleIMConversation *im = PURPLE_IM_CONVERSATION(obj);
-
- switch (param_id) {
- case IM_PROP_TYPING_STATE:
- purple_im_conversation_set_typing_state(im, g_value_get_enum(value));
- break;
- case IM_PROP_ICON:
- purple_im_conversation_set_icon(im, g_value_get_pointer(value));
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
- break;
- }
-}
-
-/* Get method for GObject properties */
-static void
-purple_im_conversation_get_property(GObject *obj, guint param_id, GValue *value,
- GParamSpec *pspec)
-{
- PurpleIMConversation *im = PURPLE_IM_CONVERSATION(obj);
-
- switch (param_id) {
- case IM_PROP_TYPING_STATE:
- g_value_set_enum(value, purple_im_conversation_get_typing_state(im));
- break;
- case IM_PROP_ICON:
- g_value_set_pointer(value, purple_im_conversation_get_icon(im));
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
- break;
- }
-}
-
-/* GObject initialization function */
-static void purple_im_conversation_init(PurpleIMConversation *im)
-{
-}
-
-/* Called when done constructing */
-static void
-purple_im_conversation_constructed(GObject *object)
-{
- PurpleIMConversation *im = PURPLE_IM_CONVERSATION(object);
- PurpleAccount *account;
- PurpleBuddyIcon *icon;
- gchar *name;
-
- G_OBJECT_CLASS(purple_im_conversation_parent_class)->
- constructed(object);
-
- g_object_get(object,
- "account", &account,
- "name", &name,
- NULL);
-
- if ((icon = purple_buddy_icons_find(account, name)))
- {
- purple_im_conversation_set_icon(im, icon);
- /* purple_im_conversation_set_icon refs the icon. */
- purple_buddy_icon_unref(icon);
- }
-
- if (purple_prefs_get_bool("/purple/logging/log_ims"))
- purple_conversation_set_logging(PURPLE_CONVERSATION(im), TRUE);
-
- g_object_unref(account);
- g_free(name);
-}
-
-/* GObject dispose function */
-static void
-purple_im_conversation_dispose(GObject *object)
-{
- PurpleIMConversationPrivate *priv =
- purple_im_conversation_get_instance_private(
- PURPLE_IM_CONVERSATION(object));
-
- if (priv->icon) {
- purple_buddy_icon_unref(priv->icon);
- priv->icon = NULL;
- }
-
- G_OBJECT_CLASS(purple_im_conversation_parent_class)->dispose(object);
-}
-
-/* GObject finalize function */
-static void
-purple_im_conversation_finalize(GObject *object)
-{
- PurpleIMConversation *im = PURPLE_IM_CONVERSATION(object);
- PurpleConnection *gc = purple_conversation_get_connection(PURPLE_CONVERSATION(im));
- PurpleProtocol *protocol = NULL;
- const char *name = purple_conversation_get_name(PURPLE_CONVERSATION(im));
-
- if (gc != NULL)
- {
- /* Still connected */
- protocol = purple_connection_get_protocol(gc);
-
- if (purple_prefs_get_bool("/purple/conversations/im/send_typing"))
- purple_serv_send_typing(gc, name, PURPLE_IM_NOT_TYPING);
-
- purple_protocol_client_iface_convo_closed(protocol, gc, name);
- }
-
- purple_im_conversation_stop_typing_timeout(im);
- purple_im_conversation_stop_send_typed_timeout(im);
-
- G_OBJECT_CLASS(purple_im_conversation_parent_class)->finalize(object);
-}
-
-/* Class initializer function */
-static void purple_im_conversation_class_init(PurpleIMConversationClass *klass)
-{
- GObjectClass *obj_class = G_OBJECT_CLASS(klass);
- PurpleConversationClass *conv_class = PURPLE_CONVERSATION_CLASS(klass);
-
- obj_class->dispose = purple_im_conversation_dispose;
- obj_class->finalize = purple_im_conversation_finalize;
- obj_class->constructed = purple_im_conversation_constructed;
-
- /* Setup properties */
- obj_class->get_property = purple_im_conversation_get_property;
- obj_class->set_property = purple_im_conversation_set_property;
-
- conv_class->write_message = im_conversation_write_message;
-
- im_properties[IM_PROP_TYPING_STATE] =
- g_param_spec_enum("typing-state", "Typing state",
- "Status of the user's typing of a message.",
- PURPLE_TYPE_IM_TYPING_STATE, PURPLE_IM_NOT_TYPING,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
- im_properties[IM_PROP_ICON] = g_param_spec_pointer(
- "icon", "Buddy icon", "The buddy icon for the IM.",
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
-
- g_object_class_install_properties(obj_class, IM_PROP_LAST, im_properties);
-}
-
-PurpleIMConversation *
-purple_im_conversation_new(PurpleAccount *account, const char *name)
-{
- PurpleIMConversation *im;
- PurpleConnection *gc;
-
- g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
- g_return_val_if_fail(name != NULL, NULL);
-
- /* Check if this conversation already exists. */
- if ((im = purple_conversations_find_im_with_account(name, account)) != NULL)
- return im;
-
- gc = purple_account_get_connection(account);
- g_return_val_if_fail(PURPLE_IS_CONNECTION(gc), NULL);
-
- im = g_object_new(PURPLE_TYPE_IM_CONVERSATION,
- "account", account,
- "name", name,
- "title", name,
- NULL);
-
- return im;
-}
-
-/**************************************************************************
* Chat Conversation API
**************************************************************************/
static guint
--- a/libpurple/conversationtypes.h Mon Aug 10 19:59:56 2020 -0500
+++ b/libpurple/conversationtypes.h Thu Aug 13 18:29:17 2020 -0500
@@ -25,27 +25,18 @@
#ifndef PURPLE_CONVERSATION_TYPES_H
#define PURPLE_CONVERSATION_TYPES_H
+
/**
* SECTION:conversationtypes
* @section_id: libpurple-conversationtypes
* @short_description: <filename>conversationtypes.h</filename>
- * @title: Chat and IM Conversation Objects
+ * @title: Chat Conversation Objects
*/
/**************************************************************************/
/* Data Structures */
/**************************************************************************/
-#define PURPLE_TYPE_IM_CONVERSATION (purple_im_conversation_get_type())
-#define PURPLE_IM_CONVERSATION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_IM_CONVERSATION, PurpleIMConversation))
-#define PURPLE_IM_CONVERSATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_IM_CONVERSATION, PurpleIMConversationClass))
-#define PURPLE_IS_IM_CONVERSATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_IM_CONVERSATION))
-#define PURPLE_IS_IM_CONVERSATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), PURPLE_TYPE_IM_CONVERSATION))
-#define PURPLE_IM_CONVERSATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_IM_CONVERSATION, PurpleIMConversationClass))
-
-typedef struct _PurpleIMConversation PurpleIMConversation;
-typedef struct _PurpleIMConversationClass PurpleIMConversationClass;
-
#define PURPLE_TYPE_CHAT_CONVERSATION (purple_chat_conversation_get_type())
#define PURPLE_CHAT_CONVERSATION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_CHAT_CONVERSATION, PurpleChatConversation))
#define PURPLE_CHAT_CONVERSATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_CHAT_CONVERSATION, PurpleChatConversationClass))
@@ -59,22 +50,6 @@
typedef struct _PurpleChatUser PurpleChatUser;
/**
- * PurpleIMTypingState:
- * @PURPLE_IM_NOT_TYPING: Not typing.
- * @PURPLE_IM_TYPING: Currently typing.
- * @PURPLE_IM_TYPED: Stopped typing momentarily.
- *
- * The typing state of a user.
- */
-typedef enum
-{
- PURPLE_IM_NOT_TYPING = 0,
- PURPLE_IM_TYPING,
- PURPLE_IM_TYPED
-
-} PurpleIMTypingState;
-
-/**
* PurpleChatUserFlags:
* @PURPLE_CHAT_USER_NONE: No flags
* @PURPLE_CHAT_USER_VOICE: Voiced user or "Participant"
@@ -98,37 +73,10 @@
} PurpleChatUserFlags;
+#include "purpleimconversation.h"
#include "conversation.h"
/**************************************************************************/
-/* PurpleIMConversation */
-/**************************************************************************/
-/**
- * PurpleIMConversation:
- *
- * Structure representing an IM conversation instance.
- */
-struct _PurpleIMConversation
-{
- PurpleConversation parent_object;
-};
-
-/**
- * PurpleIMConversationClass:
- *
- * Base class for all #PurpleIMConversation's
- */
-struct _PurpleIMConversationClass {
- PurpleConversationClass parent_class;
-
- /*< private >*/
- void (*_purple_reserved1)(void);
- void (*_purple_reserved2)(void);
- void (*_purple_reserved3)(void);
- void (*_purple_reserved4)(void);
-};
-
-/**************************************************************************/
/* PurpleChatConversation */
/**************************************************************************/
/**
@@ -159,160 +107,6 @@
G_BEGIN_DECLS
/**************************************************************************/
-/* IM Conversation API */
-/**************************************************************************/
-
-/**
- * purple_im_conversation_get_type:
- *
- * Returns: The #GType for the IMConversation object.
- */
-GType purple_im_conversation_get_type(void);
-
-/**
- * purple_im_conversation_new:
- * @account: The account opening the conversation window on the purple
- * user's end.
- * @name: Name of the buddy.
- *
- * Creates a new IM conversation.
- *
- * Returns: The new conversation.
- */
-PurpleIMConversation *purple_im_conversation_new(PurpleAccount *account,
- const char *name);
-
-/**
- * purple_im_conversation_set_icon:
- * @im: The IM.
- * @icon: The buddy icon.
- *
- * Sets the IM's buddy icon.
- *
- * This should only be called from within Purple. You probably want to
- * call purple_buddy_icon_set_data().
- *
- * See purple_buddy_icon_set_data().
- */
-void purple_im_conversation_set_icon(PurpleIMConversation *im, PurpleBuddyIcon *icon);
-
-/**
- * purple_im_conversation_get_icon:
- * @im: The IM.
- *
- * Returns the IM's buddy icon.
- *
- * Returns: The buddy icon.
- */
-PurpleBuddyIcon *purple_im_conversation_get_icon(PurpleIMConversation *im);
-
-/**
- * purple_im_conversation_set_typing_state:
- * @im: The IM.
- * @state: The typing state.
- *
- * Sets the IM's typing state.
- */
-void purple_im_conversation_set_typing_state(PurpleIMConversation *im, PurpleIMTypingState state);
-
-/**
- * purple_im_conversation_get_typing_state:
- * @im: The IM.
- *
- * Returns the IM's typing state.
- *
- * Returns: The IM's typing state.
- */
-PurpleIMTypingState purple_im_conversation_get_typing_state(PurpleIMConversation *im);
-
-/**
- * purple_im_conversation_start_typing_timeout:
- * @im: The IM.
- * @timeout: How long in seconds to wait before setting the typing state
- * to PURPLE_IM_NOT_TYPING.
- *
- * Starts the IM's typing timeout.
- */
-void purple_im_conversation_start_typing_timeout(PurpleIMConversation *im, int timeout);
-
-/**
- * purple_im_conversation_stop_typing_timeout:
- * @im: The IM.
- *
- * Stops the IM's typing timeout.
- */
-void purple_im_conversation_stop_typing_timeout(PurpleIMConversation *im);
-
-/**
- * purple_im_conversation_get_typing_timeout:
- * @im: The IM.
- *
- * Returns the IM's typing timeout.
- *
- * Returns: The timeout.
- */
-guint purple_im_conversation_get_typing_timeout(PurpleIMConversation *im);
-
-/**
- * purple_im_conversation_set_type_again:
- * @im: The IM.
- * @val: The number of seconds to wait before allowing another
- * PURPLE_IM_TYPING message to be sent to the user. Or 0 to
- * not send another PURPLE_IM_TYPING message.
- *
- * Sets the quiet-time when no PURPLE_IM_TYPING messages will be sent.
- * Few protocols need this (maybe only MSN). If the user is still
- * typing after this quiet-period, then another PURPLE_IM_TYPING message
- * will be sent.
- */
-void purple_im_conversation_set_type_again(PurpleIMConversation *im, unsigned int val);
-
-/**
- * purple_im_conversation_get_type_again:
- * @im: The IM.
- *
- * Returns the time after which another PURPLE_IM_TYPING message should be sent.
- *
- * Returns: The time in seconds since the epoch. Or 0 if no additional
- * PURPLE_IM_TYPING message should be sent.
- */
-time_t purple_im_conversation_get_type_again(PurpleIMConversation *im);
-
-/**
- * purple_im_conversation_start_send_typed_timeout:
- * @im: The IM.
- *
- * Starts the IM's type again timeout.
- */
-void purple_im_conversation_start_send_typed_timeout(PurpleIMConversation *im);
-
-/**
- * purple_im_conversation_stop_send_typed_timeout:
- * @im: The IM.
- *
- * Stops the IM's type again timeout.
- */
-void purple_im_conversation_stop_send_typed_timeout(PurpleIMConversation *im);
-
-/**
- * purple_im_conversation_get_send_typed_timeout:
- * @im: The IM.
- *
- * Returns the IM's type again timeout interval.
- *
- * Returns: The type again timeout interval.
- */
-guint purple_im_conversation_get_send_typed_timeout(PurpleIMConversation *im);
-
-/**
- * purple_im_conversation_update_typing:
- * @im: The IM.
- *
- * Updates the visual typing notification for an IM conversation.
- */
-void purple_im_conversation_update_typing(PurpleIMConversation *im);
-
-/**************************************************************************/
/* Chat Conversation API */
/**************************************************************************/
--- a/libpurple/meson.build Mon Aug 10 19:59:56 2020 -0500
+++ b/libpurple/meson.build Thu Aug 13 18:29:17 2020 -0500
@@ -49,6 +49,7 @@
'purple-gio.c',
'purpleaccountoption.c',
'purpleaccountusersplit.c',
+ 'purpleimconversation.c',
'purplekeyvaluepair.c',
'purpleprotocolfactory.c',
'purpleuiinfo.c',
@@ -128,6 +129,7 @@
'purple-gio.h',
'purpleaccountoption.h',
'purpleaccountusersplit.h',
+ 'purpleimconversation.h',
'purplekeyvaluepair.h',
'purpleprotocolfactory.h',
'purpleuiinfo.h',
@@ -209,6 +211,7 @@
'plugins.h',
'protocol.h',
'protocols.h',
+ 'purpleimconversation.h',
'roomlist.h',
'status.h',
'sound.h',
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/purpleimconversation.c Thu Aug 13 18:29:17 2020 -0500
@@ -0,0 +1,425 @@
+/*
+ * purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here. Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <libpurple/purpleimconversation.h>
+
+#include <libpurple/enums.h>
+#include <libpurple/purpleprivate.h>
+
+struct _PurpleIMConversation {
+ PurpleConversation parent;
+
+ PurpleIMTypingState typing_state;
+ guint typing_timeout;
+ time_t type_again;
+ guint send_typed_timeout;
+
+ PurpleBuddyIcon *icon;
+};
+
+enum {
+ PROP_0 = 0,
+ PROP_TYPING_STATE,
+ PROP_ICON,
+ N_PROPERTIES,
+};
+static GParamSpec *properties[N_PROPERTIES];
+
+#define SEND_TYPED_TIMEOUT_SECONDS 5
+
+/******************************************************************************
+ * Callbacks
+ *****************************************************************************/
+static gboolean
+purple_im_conversation_reset_typing_cb(gpointer data)
+{
+ PurpleIMConversation *im = PURPLE_IM_CONVERSATION(data);
+
+ purple_im_conversation_set_typing_state(im, PURPLE_IM_NOT_TYPING);
+ purple_im_conversation_stop_typing_timeout(im);
+
+ return FALSE;
+}
+
+static gboolean
+purple_im_conversation_send_typed_cb(gpointer data)
+{
+ PurpleIMConversation *im = PURPLE_IM_CONVERSATION(data);
+ PurpleConnection *pc = NULL;
+ const gchar *name;
+
+ g_return_val_if_fail(im != NULL, FALSE);
+
+ pc = purple_conversation_get_connection(PURPLE_CONVERSATION(im));
+ name = purple_conversation_get_name(PURPLE_CONVERSATION(im));
+
+ if(pc != NULL && name != NULL) {
+ /* We set this to 1 so that PURPLE_IM_TYPING will be sent if the Purple
+ * user types anything else.
+ */
+ purple_im_conversation_set_type_again(im, 1);
+
+ purple_serv_send_typing(pc, name, PURPLE_IM_TYPED);
+
+ purple_debug(PURPLE_DEBUG_MISC, "purple-im-conversation", "typed...\n");
+ }
+
+ return FALSE;
+}
+
+/******************************************************************************
+ * PurpleConversation Implementation
+ *****************************************************************************/
+static void
+im_conversation_write_message(PurpleConversation *conv, PurpleMessage *msg) {
+ PurpleIMConversation *im = PURPLE_IM_CONVERSATION(conv);
+ gboolean is_recv = FALSE;
+
+ g_return_if_fail(im != NULL);
+ g_return_if_fail(msg != NULL);
+
+ is_recv = (purple_message_get_flags(msg) & PURPLE_MESSAGE_RECV);
+
+ if(is_recv) {
+ purple_im_conversation_set_typing_state(im, PURPLE_IM_NOT_TYPING);
+ }
+
+ _purple_conversation_write_common(conv, msg);
+}
+
+/******************************************************************************
+ * GObject Implementation
+ *****************************************************************************/
+G_DEFINE_TYPE(PurpleIMConversation, purple_im_conversation,
+ PURPLE_TYPE_CONVERSATION);
+
+static void
+purple_im_conversation_get_property(GObject *obj, guint param_id, GValue *value,
+ GParamSpec *pspec)
+{
+ PurpleIMConversation *im = PURPLE_IM_CONVERSATION(obj);
+
+ switch (param_id) {
+ case PROP_TYPING_STATE:
+ g_value_set_enum(value,
+ purple_im_conversation_get_typing_state(im));
+ break;
+ case PROP_ICON:
+ g_value_set_pointer(value, purple_im_conversation_get_icon(im));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+ break;
+ }
+}
+
+static void
+purple_im_conversation_set_property(GObject *obj, guint param_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ PurpleIMConversation *im = PURPLE_IM_CONVERSATION(obj);
+
+ switch (param_id) {
+ case PROP_TYPING_STATE:
+ purple_im_conversation_set_typing_state(im,
+ g_value_get_enum(value));
+ break;
+ case PROP_ICON:
+ purple_im_conversation_set_icon(im, g_value_get_pointer(value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
+ break;
+ }
+}
+
+static void
+purple_im_conversation_init(PurpleIMConversation *im) {
+}
+
+static void
+purple_im_conversation_constructed(GObject *object) {
+ PurpleIMConversation *im = PURPLE_IM_CONVERSATION(object);
+ PurpleAccount *account = NULL;
+ PurpleBuddyIcon *icon = NULL;
+ gchar *name = NULL;
+
+ G_OBJECT_CLASS(purple_im_conversation_parent_class)->constructed(object);
+
+ g_object_get(object,
+ "account", &account,
+ "name", &name,
+ NULL);
+
+ if((icon = purple_buddy_icons_find(account, name))) {
+ purple_im_conversation_set_icon(im, icon);
+ /* purple_im_conversation_set_icon refs the icon. */
+ purple_buddy_icon_unref(icon);
+ }
+
+ if(purple_prefs_get_bool("/purple/logging/log_ims")) {
+ purple_conversation_set_logging(PURPLE_CONVERSATION(im), TRUE);
+ }
+
+ g_object_unref(account);
+ g_free(name);
+}
+
+static void
+purple_im_conversation_dispose(GObject *obj) {
+ PurpleIMConversation *im = PURPLE_IM_CONVERSATION(obj);
+
+ g_clear_pointer(&im->icon, purple_buddy_icon_unref);
+
+ G_OBJECT_CLASS(purple_im_conversation_parent_class)->dispose(obj);
+}
+
+static void
+purple_im_conversation_finalize(GObject *obj) {
+ PurpleIMConversation *im = PURPLE_IM_CONVERSATION(obj);
+ PurpleConnection *pc = purple_conversation_get_connection(PURPLE_CONVERSATION(im));
+ PurpleProtocol *protocol = NULL;
+ const gchar *name = purple_conversation_get_name(PURPLE_CONVERSATION(im));
+
+ if(pc != NULL) {
+ /* Still connected */
+ protocol = purple_connection_get_protocol(pc);
+
+ if(purple_prefs_get_bool("/purple/conversations/im/send_typing")) {
+ purple_serv_send_typing(pc, name, PURPLE_IM_NOT_TYPING);
+ }
+
+ purple_protocol_client_iface_convo_closed(protocol, pc, name);
+ }
+
+ purple_im_conversation_stop_typing_timeout(im);
+ purple_im_conversation_stop_send_typed_timeout(im);
+
+ G_OBJECT_CLASS(purple_im_conversation_parent_class)->finalize(obj);
+}
+
+static void
+purple_im_conversation_class_init(PurpleIMConversationClass *klass) {
+ GObjectClass *obj_class = G_OBJECT_CLASS(klass);
+ PurpleConversationClass *conv_class = PURPLE_CONVERSATION_CLASS(klass);
+
+ obj_class->get_property = purple_im_conversation_get_property;
+ obj_class->set_property = purple_im_conversation_set_property;
+ obj_class->dispose = purple_im_conversation_dispose;
+ obj_class->finalize = purple_im_conversation_finalize;
+ obj_class->constructed = purple_im_conversation_constructed;
+
+ conv_class->write_message = im_conversation_write_message;
+
+ properties[PROP_TYPING_STATE] = g_param_spec_enum(
+ "typing-state", "Typing state",
+ "Status of the user's typing of a message.",
+ PURPLE_TYPE_IM_TYPING_STATE, PURPLE_IM_NOT_TYPING,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_ICON] = g_param_spec_pointer(
+ "icon", "Buddy icon", "The buddy icon for the IM.",
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties(obj_class, N_PROPERTIES, properties);
+}
+
+/******************************************************************************
+ * Public API
+ *****************************************************************************/
+PurpleIMConversation *
+purple_im_conversation_new(PurpleAccount *account, const char *name)
+{
+ PurpleIMConversation *im = NULL;
+
+ g_return_val_if_fail(PURPLE_IS_ACCOUNT(account), NULL);
+ g_return_val_if_fail(name != NULL, NULL);
+
+ /* Check if this conversation already exists. */
+ if((im = purple_conversations_find_im_with_account(name, account)) != NULL) {
+ return g_object_ref(im);
+ }
+
+ im = g_object_new(PURPLE_TYPE_IM_CONVERSATION,
+ "account", account,
+ "name", name,
+ "title", name,
+ NULL);
+
+ return im;
+}
+
+void
+purple_im_conversation_set_icon(PurpleIMConversation *im,
+ PurpleBuddyIcon *icon)
+{
+ g_return_if_fail(PURPLE_IS_IM_CONVERSATION(im));
+
+ if(im->icon != icon) {
+ purple_buddy_icon_unref(im->icon);
+
+ im->icon = (icon == NULL) ? NULL : purple_buddy_icon_ref(icon);
+
+ g_object_notify_by_pspec(G_OBJECT(im), properties[PROP_ICON]);
+ }
+
+ purple_conversation_update(PURPLE_CONVERSATION(im),
+ PURPLE_CONVERSATION_UPDATE_ICON);
+}
+
+PurpleBuddyIcon *
+purple_im_conversation_get_icon(PurpleIMConversation *im) {
+ g_return_val_if_fail(PURPLE_IS_IM_CONVERSATION(im), NULL);
+
+ return im->icon;
+}
+
+void
+purple_im_conversation_set_typing_state(PurpleIMConversation *im,
+ PurpleIMTypingState state)
+{
+ PurpleAccount *account = NULL;
+ const gchar *name = NULL;
+
+ g_return_if_fail(PURPLE_IS_IM_CONVERSATION(im));
+
+ name = purple_conversation_get_name(PURPLE_CONVERSATION(im));
+ account = purple_conversation_get_account(PURPLE_CONVERSATION(im));
+
+ if(im->typing_state != state) {
+ im->typing_state = state;
+
+ g_object_notify_by_pspec(G_OBJECT(im), properties[PROP_TYPING_STATE]);
+
+ switch (state) {
+ case PURPLE_IM_TYPING:
+ purple_signal_emit(purple_conversations_get_handle(),
+ "buddy-typing", account, name);
+ break;
+ case PURPLE_IM_TYPED:
+ purple_signal_emit(purple_conversations_get_handle(),
+ "buddy-typed", account, name);
+ break;
+ case PURPLE_IM_NOT_TYPING:
+ purple_signal_emit(purple_conversations_get_handle(),
+ "buddy-typing-stopped", account, name);
+ break;
+ }
+
+ purple_im_conversation_update_typing(im);
+ }
+}
+
+PurpleIMTypingState
+purple_im_conversation_get_typing_state(PurpleIMConversation *im) {
+ g_return_val_if_fail(PURPLE_IS_IM_CONVERSATION(im), 0);
+
+ return im->typing_state;
+}
+
+void
+purple_im_conversation_start_typing_timeout(PurpleIMConversation *im,
+ gint timeout)
+{
+ g_return_if_fail(PURPLE_IS_IM_CONVERSATION(im));
+
+ if(im->typing_timeout > 0) {
+ purple_im_conversation_stop_typing_timeout(im);
+ }
+
+ im->typing_timeout =
+ g_timeout_add_seconds(timeout, purple_im_conversation_reset_typing_cb,
+ im);
+}
+
+void
+purple_im_conversation_stop_typing_timeout(PurpleIMConversation *im) {
+ g_return_if_fail(PURPLE_IS_IM_CONVERSATION(im));
+
+ if(im->typing_timeout == 0) {
+ return;
+ }
+
+ g_source_remove(im->typing_timeout);
+ im->typing_timeout = 0;
+}
+
+guint
+purple_im_conversation_get_typing_timeout(PurpleIMConversation *im) {
+ g_return_val_if_fail(PURPLE_IS_IM_CONVERSATION(im), 0);
+
+ return im->typing_timeout;
+}
+
+void
+purple_im_conversation_set_type_again(PurpleIMConversation *im, guint val) {
+ g_return_if_fail(PURPLE_IS_IM_CONVERSATION(im));
+
+ if(val == 0) {
+ im->type_again = 0;
+ } else {
+ im->type_again = time(NULL) + val;
+ }
+}
+
+time_t
+purple_im_conversation_get_type_again(PurpleIMConversation *im) {
+ g_return_val_if_fail(PURPLE_IS_IM_CONVERSATION(im), 0);
+
+ return im->type_again;
+}
+
+void
+purple_im_conversation_start_send_typed_timeout(PurpleIMConversation *im) {
+ g_return_if_fail(PURPLE_IS_IM_CONVERSATION(im));
+
+ purple_im_conversation_stop_send_typed_timeout(im);
+ im->send_typed_timeout =
+ g_timeout_add_seconds(SEND_TYPED_TIMEOUT_SECONDS,
+ purple_im_conversation_send_typed_cb, im);
+}
+
+void
+purple_im_conversation_stop_send_typed_timeout(PurpleIMConversation *im) {
+ g_return_if_fail(PURPLE_IS_IM_CONVERSATION(im));
+
+ if(im->send_typed_timeout == 0) {
+ return;
+ }
+
+ g_source_remove(im->send_typed_timeout);
+ im->send_typed_timeout = 0;
+}
+
+guint
+purple_im_conversation_get_send_typed_timeout(PurpleIMConversation *im) {
+ g_return_val_if_fail(PURPLE_IS_IM_CONVERSATION(im), 0);
+
+ return im->send_typed_timeout;
+}
+
+void
+purple_im_conversation_update_typing(PurpleIMConversation *im) {
+ g_return_if_fail(PURPLE_IS_IM_CONVERSATION(im));
+
+ purple_conversation_update(PURPLE_CONVERSATION(im),
+ PURPLE_CONVERSATION_UPDATE_TYPING);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/purpleimconversation.h Thu Aug 13 18:29:17 2020 -0500
@@ -0,0 +1,237 @@
+/*
+ * purple
+ *
+ * Purple is the legal property of its developers, whose names are too numerous
+ * to list here. Please refer to the COPYRIGHT file distributed with this
+ * source distribution.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#if !defined(PURPLE_GLOBAL_HEADER_INSIDE) && !defined(PURPLE_COMPILATION)
+# error "only <purple.h> may be included directly"
+#endif
+
+#ifndef PURPLE_IM_CONVERSATION_H
+#define PURPLE_IM_CONVERSATION_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+/**
+ * SECTION:imconversation
+ * @section_id: libpurple-imconversation
+ * @title: IM Conversation Objects
+ */
+
+/**
+ * PurpleIMTypingState:
+ * @PURPLE_IM_NOT_TYPING: Not typing.
+ * @PURPLE_IM_TYPING: Currently typing.
+ * @PURPLE_IM_TYPED: Stopped typing momentarily.
+ *
+ * The typing state of a user.
+ */
+typedef enum
+{
+ PURPLE_IM_NOT_TYPING = 0,
+ PURPLE_IM_TYPING,
+ PURPLE_IM_TYPED
+
+} PurpleIMTypingState;
+
+#define PURPLE_TYPE_IM_CONVERSATION (purple_im_conversation_get_type())
+#define PURPLE_IM_CONVERSATION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), PURPLE_TYPE_IM_CONVERSATION, PurpleIMConversation))
+#define PURPLE_IM_CONVERSATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), PURPLE_TYPE_IM_CONVERSATION, PurpleIMConversationClass))
+#define PURPLE_IS_IM_CONVERSATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), PURPLE_TYPE_IM_CONVERSATION))
+#define PURPLE_IS_IM_CONVERSATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), PURPLE_TYPE_IM_CONVERSATION))
+#define PURPLE_IM_CONVERSATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), PURPLE_TYPE_IM_CONVERSATION, PurpleIMConversationClass))
+
+typedef struct _PurpleIMConversation PurpleIMConversation;
+typedef struct _PurpleIMConversationClass PurpleIMConversationClass;
+
+#include <conversation.h>
+
+/**
+ * PurpleIMConversation:
+ *
+ * Structure representing an IM conversation instance.
+ */
+
+/**
+ * PurpleIMConversationClass:
+ *
+ * Base class for all #PurpleIMConversation's
+ */
+struct _PurpleIMConversationClass {
+ PurpleConversationClass parent_class;
+
+ /*< private >*/
+ gpointer _purple_reserved[4];
+};
+
+G_BEGIN_DECLS
+
+/**
+ * purple_im_conversation_get_type:
+ *
+ * Returns: The #GType for the IMConversation object.
+ */
+GType purple_im_conversation_get_type(void);
+
+/**
+ * purple_im_conversation_new:
+ * @account: The account opening the conversation window on the purple user's
+ * end.
+ * @name: Name of the buddy.
+ *
+ * Creates a new IM conversation.
+ *
+ * Returns: The new conversation.
+ */
+PurpleIMConversation *purple_im_conversation_new(PurpleAccount *account, const gchar *name);
+
+/**
+ * purple_im_conversation_set_icon:
+ * @im: The IM.
+ * @icon: The buddy icon.
+ *
+ * Sets the IM's buddy icon.
+ *
+ * This should only be called from within Purple. You probably want to
+ * call purple_buddy_icon_set_data().
+ *
+ * See purple_buddy_icon_set_data().
+ */
+void purple_im_conversation_set_icon(PurpleIMConversation *im, PurpleBuddyIcon *icon);
+
+/**
+ * purple_im_conversation_get_icon:
+ * @im: The IM.
+ *
+ * Returns the IM's buddy icon.
+ *
+ * Returns: (transfer none): The buddy icon.
+ */
+PurpleBuddyIcon *purple_im_conversation_get_icon(PurpleIMConversation *im);
+
+/**
+ * purple_im_conversation_set_typing_state:
+ * @im: The IM.
+ * @state: The typing state.
+ *
+ * Sets the IM's typing state.
+ */
+void purple_im_conversation_set_typing_state(PurpleIMConversation *im, PurpleIMTypingState state);
+
+/**
+ * purple_im_conversation_get_typing_state:
+ * @im: The IM.
+ *
+ * Returns the IM's typing state.
+ *
+ * Returns: The IM's typing state.
+ */
+PurpleIMTypingState purple_im_conversation_get_typing_state(PurpleIMConversation *im);
+
+/**
+ * purple_im_conversation_start_typing_timeout:
+ * @im: The IM.
+ * @timeout: How long in seconds to wait before setting the typing state to
+ * PURPLE_IM_NOT_TYPING.
+ *
+ * Starts the IM's typing timeout.
+ */
+void purple_im_conversation_start_typing_timeout(PurpleIMConversation *im, int timeout);
+
+/**
+ * purple_im_conversation_stop_typing_timeout:
+ * @im: The IM.
+ *
+ * Stops the IM's typing timeout.
+ */
+void purple_im_conversation_stop_typing_timeout(PurpleIMConversation *im);
+
+/**
+ * purple_im_conversation_get_typing_timeout:
+ * @im: The IM.
+ *
+ * Returns the IM's typing timeout.
+ *
+ * Returns: The timeout.
+ */
+guint purple_im_conversation_get_typing_timeout(PurpleIMConversation *im);
+
+/**
+ * purple_im_conversation_set_type_again:
+ * @im: The IM.
+ * @val: The number of seconds to wait before allowing another #PURPLE_IM_TYPING
+ * message to be sent to the user. Or 0 to not send another
+ * #PURPLE_IM_TYPING message.
+ *
+ * Sets the quiet-time when no #PURPLE_IM_TYPING messages will be sent.
+ * Few protocols need this (maybe only MSN). If the user is still
+ * typing after this quiet-period, then another #PURPLE_IM_TYPING message
+ * will be sent.
+ */
+void purple_im_conversation_set_type_again(PurpleIMConversation *im, guint val);
+
+/**
+ * purple_im_conversation_get_type_again:
+ * @im: The IM.
+ *
+ * Returns the time after which another PURPLE_IM_TYPING message should be sent.
+ *
+ * Returns: The time in seconds since the epoch. Or 0 if no additional
+ * PURPLE_IM_TYPING message should be sent.
+ */
+time_t purple_im_conversation_get_type_again(PurpleIMConversation *im);
+
+/**
+ * purple_im_conversation_start_send_typed_timeout:
+ * @im: The IM.
+ *
+ * Starts the IM's type again timeout.
+ */
+void purple_im_conversation_start_send_typed_timeout(PurpleIMConversation *im);
+
+/**
+ * purple_im_conversation_stop_send_typed_timeout:
+ * @im: The IM.
+ *
+ * Stops the IM's type again timeout.
+ */
+void purple_im_conversation_stop_send_typed_timeout(PurpleIMConversation *im);
+
+/**
+ * purple_im_conversation_get_send_typed_timeout:
+ * @im: The IM.
+ *
+ * Returns the IM's type again timeout interval.
+ *
+ * Returns: The type again timeout interval.
+ */
+guint purple_im_conversation_get_send_typed_timeout(PurpleIMConversation *im);
+
+/**
+ * purple_im_conversation_update_typing:
+ * @im: The IM.
+ *
+ * Updates the visual typing notification for an IM conversation.
+ */
+void purple_im_conversation_update_typing(PurpleIMConversation *im);
+
+G_END_DECLS
+
+#endif /* PURPLE_IM_CONVERSATION_H */