pidgin/pidgin
Clone
Summary
Browse
Changes
Graph
Add some new methods to purple tags
default
tip
19 hours ago, Gary Kramlich
b45add2a840c
Add some new methods to purple tags
* purple_tags_exists is a simplier version of purple_tags_lookup.
* purple_tags_contains makes it easier to find multiple matching tags.
Testing Done:
Ran the unit tests under valgrind and had the turtles check in on things too.
Reviewed at https://reviews.imfreedom.org/r/3143/
/*
* Purple - Internet Messaging Library
* Copyright (C) Pidgin Developers <devel@pidgin.im>
*
* 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 library 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 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 General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this library; if not, see <https://www.gnu.org/licenses/>.
*/
#include
<glib/gi18n-lib.h>
#include
"purpleconversation.h"
#include
"debug.h"
#include
"notify.h"
#include
"purpleconversationmanager.h"
#include
"purpleconversationmember.h"
#include
"purpleenums.h"
#include
"purplehistorymanager.h"
#include
"purplemarkup.h"
#include
"purpleprivate.h"
#include
"purpleprotocolconversation.h"
#include
"purpletags.h"
#include
"signals.h"
#include
"util.h"
struct
_PurpleConversation
{
GObject
parent
;
char
*
id
;
PurpleConversationType
type
;
PurpleAccount
*
account
;
PurpleAvatar
*
avatar
;
char
*
name
;
char
*
title
;
PurpleConnectionFlags
features
;
gboolean
age_restricted
;
char
*
description
;
char
*
topic
;
PurpleContactInfo
*
topic_author
;
GDateTime
*
topic_updated
;
char
*
user_nickname
;
gboolean
favorite
;
GDateTime
*
created_on
;
PurpleContactInfo
*
creator
;
gboolean
online
;
gboolean
federated
;
PurpleTags
*
tags
;
GListStore
*
members
;
GListStore
*
messages
;
};
enum
{
PROP_0
,
PROP_ID
,
PROP_TYPE
,
PROP_ACCOUNT
,
PROP_AVATAR
,
PROP_NAME
,
PROP_TITLE
,
PROP_FEATURES
,
PROP_AGE_RESTRICTED
,
PROP_DESCRIPTION
,
PROP_TOPIC
,
PROP_TOPIC_AUTHOR
,
PROP_TOPIC_UPDATED
,
PROP_USER_NICKNAME
,
PROP_FAVORITE
,
PROP_CREATED_ON
,
PROP_CREATOR
,
PROP_ONLINE
,
PROP_FEDERATED
,
PROP_TAGS
,
PROP_MEMBERS
,
PROP_MESSAGES
,
N_PROPERTIES
,
};
static
GParamSpec
*
properties
[
N_PROPERTIES
]
=
{
NULL
,
};
enum
{
SIG_PRESENT
,
SIG_MEMBER_ADDED
,
SIG_MEMBER_REMOVED
,
N_SIGNALS
,
};
static
guint
signals
[
N_SIGNALS
]
=
{
0
,
};
G_DEFINE_FINAL_TYPE
(
PurpleConversation
,
purple_conversation
,
G_TYPE_OBJECT
)
static
void
purple_conversation_account_connected_cb
(
GObject
*
obj
,
GParamSpec
*
pspec
,
gpointer
data
);
/**************************************************************************
* Helpers
**************************************************************************/
static
void
purple_conversation_set_id
(
PurpleConversation
*
conversation
,
const
char
*
id
)
{
g_return_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
));
if
(
!
purple_strequal
(
id
,
conversation
->
id
))
{
g_free
(
conversation
->
id
);
conversation
->
id
=
g_strdup
(
id
);
g_object_notify_by_pspec
(
G_OBJECT
(
conversation
),
properties
[
PROP_ID
]);
}
}
static
void
purple_conversation_set_account
(
PurpleConversation
*
conversation
,
PurpleAccount
*
account
)
{
PurpleConversationMember
*
member
=
NULL
;
g_return_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
));
/* Remove the account from the conversation if it's a member. */
if
(
PURPLE_IS_ACCOUNT
(
conversation
->
account
))
{
if
(
PURPLE_IS_CONVERSATION_MEMBER
(
member
))
{
purple_conversation_remove_member
(
conversation
,
PURPLE_CONTACT_INFO
(
conversation
->
account
),
FALSE
,
NULL
);
}
}
if
(
g_set_object
(
&
conversation
->
account
,
account
))
{
if
(
PURPLE_IS_ACCOUNT
(
conversation
->
account
))
{
purple_conversation_add_member
(
conversation
,
PURPLE_CONTACT_INFO
(
account
),
FALSE
,
NULL
);
g_signal_connect_object
(
account
,
"notify::connected"
,
G_CALLBACK
(
purple_conversation_account_connected_cb
),
conversation
,
0
);
}
g_object_notify_by_pspec
(
G_OBJECT
(
conversation
),
properties
[
PROP_ACCOUNT
]);
}
}
static
void
purple_conversation_set_federated
(
PurpleConversation
*
conversation
,
gboolean
federated
)
{
g_return_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
));
if
(
conversation
->
federated
!=
federated
)
{
conversation
->
federated
=
federated
;
g_object_notify_by_pspec
(
G_OBJECT
(
conversation
),
properties
[
PROP_FEDERATED
]);
}
}
static
gboolean
purple_conversation_check_member_equal
(
gconstpointer
a
,
gconstpointer
b
)
{
PurpleConversationMember
*
member_a
=
(
PurpleConversationMember
*
)
a
;
PurpleConversationMember
*
member_b
=
(
PurpleConversationMember
*
)
b
;
PurpleContactInfo
*
info_a
=
NULL
;
PurpleContactInfo
*
info_b
=
NULL
;
info_a
=
purple_conversation_member_get_contact_info
(
member_a
);
info_b
=
purple_conversation_member_get_contact_info
(
member_b
);
return
(
purple_contact_info_compare
(
info_a
,
info_b
)
==
0
);
}
static
void
purple_conversation_send_message_async_old_cb
(
GObject
*
protocol
,
GAsyncResult
*
result
,
gpointer
data
)
{
PurpleProtocolConversation
*
protocol_conversation
=
NULL
;
PurpleMessage
*
message
=
data
;
GError
*
error
=
NULL
;
protocol_conversation
=
PURPLE_PROTOCOL_CONVERSATION
(
protocol
);
purple_protocol_conversation_send_message_finish
(
protocol_conversation
,
result
,
&
error
);
if
(
error
!=
NULL
)
{
g_warning
(
"failed to send message: %s"
,
error
->
message
);
g_clear_error
(
&
error
);
}
g_clear_object
(
&
message
);
}
static
void
purple_conversation_send_message_async_cb
(
GObject
*
source
,
GAsyncResult
*
result
,
gpointer
data
)
{
PurpleMessage
*
message
=
NULL
;
PurpleProtocolConversation
*
protocol
=
NULL
;
GError
*
error
=
NULL
;
GTask
*
task
=
data
;
gboolean
success
=
FALSE
;
/* task and result share a cancellable, so we just need to clear task to
* make sure its callback gets called.
*/
if
(
g_task_return_error_if_cancelled
(
G_TASK
(
task
)))
{
g_clear_object
(
&
task
);
return
;
}
protocol
=
PURPLE_PROTOCOL_CONVERSATION
(
source
);
message
=
g_task_get_task_data
(
G_TASK
(
task
));
success
=
purple_protocol_conversation_send_message_finish
(
protocol
,
result
,
&
error
);
if
(
!
success
)
{
if
(
error
==
NULL
)
{
error
=
g_error_new
(
PURPLE_CONVERSATION_DOMAIN
,
0
,
"unknown error"
);
}
purple_message_set_error
(
message
,
error
);
g_task_return_error
(
task
,
error
);
g_clear_error
(
&
error
);
}
else
{
/* If the protocol didn't set delivered, set it now. */
if
(
!
purple_message_get_delivered
(
message
))
{
purple_message_set_delivered
(
message
,
TRUE
);
}
g_task_return_boolean
(
task
,
TRUE
);
}
g_clear_object
(
&
task
);
}
static
void
common_send
(
PurpleConversation
*
conversation
,
const
char
*
message
,
PurpleMessageFlags
msgflags
)
{
PurpleAccount
*
account
;
PurpleConnection
*
gc
;
PurpleProtocol
*
protocol
=
NULL
;
char
*
displayed
=
NULL
;
const
char
*
sent
,
*
me
;
gint
err
=
0
;
if
(
*
message
==
'\0'
)
{
return
;
}
account
=
purple_conversation_get_account
(
conversation
);
g_return_if_fail
(
PURPLE_IS_ACCOUNT
(
account
));
gc
=
purple_account_get_connection
(
account
);
g_return_if_fail
(
PURPLE_IS_CONNECTION
(
gc
));
protocol
=
purple_account_get_protocol
(
account
);
me
=
purple_contact_info_get_name_for_display
(
PURPLE_CONTACT_INFO
(
account
));
/* Always linkify the text for display, unless we're explicitly asked to do
* otherwise. */
if
(
!
(
msgflags
&
PURPLE_MESSAGE_INVISIBLE
))
{
if
(
msgflags
&
PURPLE_MESSAGE_NO_LINKIFY
)
{
displayed
=
g_strdup
(
message
);
}
else
{
displayed
=
purple_markup_linkify
(
message
);
}
}
if
(
displayed
&&
(
conversation
->
features
&
PURPLE_CONNECTION_FLAG_HTML
)
&&
!
(
msgflags
&
PURPLE_MESSAGE_RAW
))
{
sent
=
displayed
;
}
else
{
sent
=
message
;
}
msgflags
|=
PURPLE_MESSAGE_SEND
;
if
(
PURPLE_IS_PROTOCOL_CONVERSATION
(
protocol
))
{
PurpleMessage
*
msg
=
NULL
;
PurpleProtocolConversation
*
protocol_conversation
=
NULL
;
msg
=
purple_message_new_outgoing
(
me
,
NULL
,
sent
,
msgflags
);
protocol_conversation
=
PURPLE_PROTOCOL_CONVERSATION
(
protocol
);
purple_protocol_conversation_send_message_async
(
protocol_conversation
,
conversation
,
msg
,
NULL
,
purple_conversation_send_message_async_old_cb
,
msg
);
g_clear_pointer
(
&
displayed
,
g_free
);
}
if
(
err
<
0
)
{
const
char
*
who
;
const
char
*
msg
;
who
=
purple_conversation_get_name
(
conversation
);
if
(
err
==
-
E2BIG
)
{
msg
=
_
(
"Unable to send message: The message is too large."
);
if
(
!
purple_conversation_present_error
(
who
,
account
,
msg
))
{
char
*
msg2
=
g_strdup_printf
(
_
(
"Unable to send message to %s."
),
who
);
purple_notify_error
(
gc
,
NULL
,
msg2
,
_
(
"The message is too large."
),
purple_request_cpar_from_connection
(
gc
));
g_free
(
msg2
);
}
}
else
if
(
err
==
-
ENOTCONN
)
{
purple_debug_error
(
"conversation"
,
"Not yet connected."
);
}
else
{
msg
=
_
(
"Unable to send message."
);
if
(
!
purple_conversation_present_error
(
who
,
account
,
msg
))
{
char
*
msg2
=
g_strdup_printf
(
_
(
"Unable to send message to %s."
),
who
);
purple_notify_error
(
gc
,
NULL
,
msg2
,
NULL
,
purple_request_cpar_from_connection
(
gc
));
g_free
(
msg2
);
}
}
}
g_free
(
displayed
);
}
/**************************************************************************
* Callbacks
**************************************************************************/
static
void
purple_conversation_account_connected_cb
(
GObject
*
obj
,
G_GNUC_UNUSED
GParamSpec
*
pspec
,
gpointer
data
)
{
PurpleConversation
*
conversation
=
data
;
gboolean
connected
=
purple_account_is_connected
(
PURPLE_ACCOUNT
(
obj
));
if
(
conversation
->
federated
)
{
/* If the account changed to connected and the conversation is
* federated we do nothing. But if the account went offline, we can
* safely set the conversation to offline.
*/
if
(
!
connected
)
{
purple_conversation_set_online
(
conversation
,
FALSE
);
}
}
else
{
purple_conversation_set_online
(
conversation
,
connected
);
}
}
/**************************************************************************
* GObject Implementation
**************************************************************************/
static
void
purple_conversation_set_property
(
GObject
*
obj
,
guint
param_id
,
const
GValue
*
value
,
GParamSpec
*
pspec
)
{
PurpleConversation
*
conversation
=
PURPLE_CONVERSATION
(
obj
);
switch
(
param_id
)
{
case
PROP_ID
:
purple_conversation_set_id
(
conversation
,
g_value_get_string
(
value
));
break
;
case
PROP_TYPE
:
purple_conversation_set_conversation_type
(
conversation
,
g_value_get_enum
(
value
));
break
;
case
PROP_ACCOUNT
:
purple_conversation_set_account
(
conversation
,
g_value_get_object
(
value
));
break
;
case
PROP_AVATAR
:
purple_conversation_set_avatar
(
conversation
,
g_value_get_object
(
value
));
break
;
case
PROP_NAME
:
purple_conversation_set_name
(
conversation
,
g_value_get_string
(
value
));
break
;
case
PROP_TITLE
:
purple_conversation_set_title
(
conversation
,
g_value_get_string
(
value
));
break
;
case
PROP_FEATURES
:
purple_conversation_set_features
(
conversation
,
g_value_get_flags
(
value
));
break
;
case
PROP_AGE_RESTRICTED
:
purple_conversation_set_age_restricted
(
conversation
,
g_value_get_boolean
(
value
));
break
;
case
PROP_DESCRIPTION
:
purple_conversation_set_description
(
conversation
,
g_value_get_string
(
value
));
break
;
case
PROP_TOPIC
:
purple_conversation_set_topic
(
conversation
,
g_value_get_string
(
value
));
break
;
case
PROP_TOPIC_AUTHOR
:
purple_conversation_set_topic_author
(
conversation
,
g_value_get_object
(
value
));
break
;
case
PROP_TOPIC_UPDATED
:
purple_conversation_set_topic_updated
(
conversation
,
g_value_get_boxed
(
value
));
break
;
case
PROP_USER_NICKNAME
:
purple_conversation_set_user_nickname
(
conversation
,
g_value_get_string
(
value
));
break
;
case
PROP_FAVORITE
:
purple_conversation_set_favorite
(
conversation
,
g_value_get_boolean
(
value
));
break
;
case
PROP_CREATED_ON
:
purple_conversation_set_created_on
(
conversation
,
g_value_get_boxed
(
value
));
break
;
case
PROP_CREATOR
:
purple_conversation_set_creator
(
conversation
,
g_value_get_object
(
value
));
break
;
case
PROP_ONLINE
:
purple_conversation_set_online
(
conversation
,
g_value_get_boolean
(
value
));
break
;
case
PROP_FEDERATED
:
purple_conversation_set_federated
(
conversation
,
g_value_get_boolean
(
value
));
break
;
default
:
G_OBJECT_WARN_INVALID_PROPERTY_ID
(
obj
,
param_id
,
pspec
);
break
;
}
}
static
void
purple_conversation_get_property
(
GObject
*
obj
,
guint
param_id
,
GValue
*
value
,
GParamSpec
*
pspec
)
{
PurpleConversation
*
conversation
=
PURPLE_CONVERSATION
(
obj
);
switch
(
param_id
)
{
case
PROP_ID
:
g_value_set_string
(
value
,
purple_conversation_get_id
(
conversation
));
break
;
case
PROP_TYPE
:
g_value_set_enum
(
value
,
purple_conversation_get_conversation_type
(
conversation
));
break
;
case
PROP_ACCOUNT
:
g_value_set_object
(
value
,
purple_conversation_get_account
(
conversation
));
break
;
case
PROP_AVATAR
:
g_value_set_object
(
value
,
purple_conversation_get_avatar
(
conversation
));
break
;
case
PROP_NAME
:
g_value_set_string
(
value
,
purple_conversation_get_name
(
conversation
));
break
;
case
PROP_TITLE
:
g_value_set_string
(
value
,
purple_conversation_get_title
(
conversation
));
break
;
case
PROP_FEATURES
:
g_value_set_flags
(
value
,
purple_conversation_get_features
(
conversation
));
break
;
case
PROP_AGE_RESTRICTED
:
g_value_set_boolean
(
value
,
purple_conversation_get_age_restricted
(
conversation
));
break
;
case
PROP_DESCRIPTION
:
g_value_set_string
(
value
,
purple_conversation_get_description
(
conversation
));
break
;
case
PROP_TOPIC
:
g_value_set_string
(
value
,
purple_conversation_get_topic
(
conversation
));
break
;
case
PROP_TOPIC_AUTHOR
:
g_value_set_object
(
value
,
purple_conversation_get_topic_author
(
conversation
));
break
;
case
PROP_TOPIC_UPDATED
:
g_value_set_boxed
(
value
,
purple_conversation_get_topic_updated
(
conversation
));
break
;
case
PROP_USER_NICKNAME
:
g_value_set_string
(
value
,
purple_conversation_get_user_nickname
(
conversation
));
break
;
case
PROP_FAVORITE
:
g_value_set_boolean
(
value
,
purple_conversation_get_favorite
(
conversation
));
break
;
case
PROP_CREATED_ON
:
g_value_set_boxed
(
value
,
purple_conversation_get_created_on
(
conversation
));
break
;
case
PROP_CREATOR
:
g_value_set_object
(
value
,
purple_conversation_get_creator
(
conversation
));
break
;
case
PROP_ONLINE
:
g_value_set_boolean
(
value
,
purple_conversation_get_online
(
conversation
));
break
;
case
PROP_FEDERATED
:
g_value_set_boolean
(
value
,
purple_conversation_get_federated
(
conversation
));
break
;
case
PROP_TAGS
:
g_value_set_object
(
value
,
purple_conversation_get_tags
(
conversation
));
break
;
case
PROP_MEMBERS
:
g_value_set_object
(
value
,
purple_conversation_get_members
(
conversation
));
break
;
case
PROP_MESSAGES
:
g_value_set_object
(
value
,
purple_conversation_get_messages
(
conversation
));
break
;
default
:
G_OBJECT_WARN_INVALID_PROPERTY_ID
(
obj
,
param_id
,
pspec
);
break
;
}
}
static
void
purple_conversation_init
(
PurpleConversation
*
conversation
)
{
conversation
->
tags
=
purple_tags_new
();
conversation
->
members
=
g_list_store_new
(
PURPLE_TYPE_CONVERSATION_MEMBER
);
conversation
->
messages
=
g_list_store_new
(
PURPLE_TYPE_MESSAGE
);
}
static
void
purple_conversation_constructed
(
GObject
*
object
)
{
PurpleConversation
*
conversation
=
PURPLE_CONVERSATION
(
object
);
PurpleAccount
*
account
;
PurpleConnection
*
gc
;
G_OBJECT_CLASS
(
purple_conversation_parent_class
)
->
constructed
(
object
);
g_object_get
(
object
,
"account"
,
&
account
,
NULL
);
gc
=
purple_account_get_connection
(
account
);
/* Check if we have a connection before we use it. The unit tests are one
* case where we will not have a connection.
*/
if
(
PURPLE_IS_CONNECTION
(
gc
))
{
purple_conversation_set_features
(
conversation
,
purple_connection_get_flags
(
gc
));
}
/* Auto-set the title. */
purple_conversation_autoset_title
(
conversation
);
g_object_unref
(
account
);
}
static
void
purple_conversation_dispose
(
GObject
*
obj
)
{
g_object_set_data
(
obj
,
"is-finalizing"
,
GINT_TO_POINTER
(
TRUE
));
}
static
void
purple_conversation_finalize
(
GObject
*
object
)
{
PurpleConversation
*
conversation
=
PURPLE_CONVERSATION
(
object
);
purple_request_close_with_handle
(
conversation
);
g_clear_pointer
(
&
conversation
->
id
,
g_free
);
g_clear_object
(
&
conversation
->
avatar
);
g_clear_pointer
(
&
conversation
->
name
,
g_free
);
g_clear_pointer
(
&
conversation
->
title
,
g_free
);
g_clear_pointer
(
&
conversation
->
description
,
g_free
);
g_clear_pointer
(
&
conversation
->
topic
,
g_free
);
g_clear_object
(
&
conversation
->
topic_author
);
g_clear_pointer
(
&
conversation
->
topic_updated
,
g_date_time_unref
);
g_clear_pointer
(
&
conversation
->
user_nickname
,
g_free
);
g_clear_pointer
(
&
conversation
->
created_on
,
g_date_time_unref
);
g_clear_object
(
&
conversation
->
creator
);
g_clear_object
(
&
conversation
->
tags
);
g_clear_object
(
&
conversation
->
members
);
g_clear_object
(
&
conversation
->
messages
);
G_OBJECT_CLASS
(
purple_conversation_parent_class
)
->
finalize
(
object
);
}
static
void
purple_conversation_class_init
(
PurpleConversationClass
*
klass
)
{
GObjectClass
*
obj_class
=
G_OBJECT_CLASS
(
klass
);
obj_class
->
constructed
=
purple_conversation_constructed
;
obj_class
->
dispose
=
purple_conversation_dispose
;
obj_class
->
finalize
=
purple_conversation_finalize
;
obj_class
->
get_property
=
purple_conversation_get_property
;
obj_class
->
set_property
=
purple_conversation_set_property
;
/**
* PurpleConversation:id:
*
* An opaque identifier for this conversation. Generally speaking this is
* protocol dependent and should only be used as a unique identifier.
*
* Since: 3.0
*/
properties
[
PROP_ID
]
=
g_param_spec_string
(
"id"
,
"id"
,
"The identifier for the conversation."
,
NULL
,
G_PARAM_READWRITE
|
G_PARAM_CONSTRUCT_ONLY
|
G_PARAM_STATIC_STRINGS
);
/**
* PurpleConversation:type:
*
* A type hint for the conversation. This may be useful for protocols, but
* libpurple treats all conversations the same.
*
* Since: 3.0
*/
properties
[
PROP_TYPE
]
=
g_param_spec_enum
(
"type"
,
"type"
,
"The type of the conversation."
,
PURPLE_TYPE_CONVERSATION_TYPE
,
PURPLE_CONVERSATION_TYPE_UNSET
,
G_PARAM_READWRITE
|
G_PARAM_STATIC_STRINGS
);
/**
* PurpleConversation:account:
*
* The account this conversation belongs to.
*
* Since: 3.0
*/
properties
[
PROP_ACCOUNT
]
=
g_param_spec_object
(
"account"
,
"Account"
,
"The account for the conversation."
,
PURPLE_TYPE_ACCOUNT
,
G_PARAM_READWRITE
|
G_PARAM_CONSTRUCT_ONLY
|
G_PARAM_STATIC_STRINGS
);
/**
* PurpleConversation:avatar:
*
* The [class@Avatar] for the conversation.
*
* Not all protocols support this and most user interfaces will use the
* avatar of the remote contact for direct messages.
*
* Since: 3.0
*/
properties
[
PROP_AVATAR
]
=
g_param_spec_object
(
"avatar"
,
"avatar"
,
"The avatar for this conversation."
,
PURPLE_TYPE_AVATAR
,
G_PARAM_READWRITE
|
G_PARAM_STATIC_STRINGS
);
/**
* PurpleConversation:name:
*
* The name of the conversation.
*
* Since: 3.0
*/
properties
[
PROP_NAME
]
=
g_param_spec_string
(
"name"
,
"Name"
,
"The name of the conversation."
,
NULL
,
G_PARAM_READWRITE
|
G_PARAM_CONSTRUCT
|
G_PARAM_STATIC_STRINGS
);
/**
* PurpleConversation:title:
*
* The title of the conversation.
*
* Since: 3.0
*/
properties
[
PROP_TITLE
]
=
g_param_spec_string
(
"title"
,
"Title"
,
"The title of the conversation."
,
NULL
,
G_PARAM_READWRITE
|
G_PARAM_STATIC_STRINGS
);
/**
* PurpleConversation:features:
*
* The features that this conversation supports.
*
* Since: 3.0
*/
properties
[
PROP_FEATURES
]
=
g_param_spec_flags
(
"features"
,
"Connection features"
,
"The connection features of the conversation."
,
PURPLE_TYPE_CONNECTION_FLAGS
,
0
,
G_PARAM_READWRITE
|
G_PARAM_STATIC_STRINGS
);
/**
* PurpleConversation:age-restricted:
*
* Whether or not the conversation is age restricted.
*
* This is typically set only by a protocol plugin.
*
* Since: 3.0
*/
properties
[
PROP_AGE_RESTRICTED
]
=
g_param_spec_boolean
(
"age-restricted"
,
"age-restricted"
,
"Whether or not the conversation is age restricted."
,
FALSE
,
G_PARAM_READWRITE
|
G_PARAM_STATIC_STRINGS
);
/**
* PurpleConversation:description:
*
* Sets the description of the conversation. This field is typically used
* to give more information about a conversation than that which would fit
* in [property@Conversation:topic].
*
* This is typically set only by a protocol plugin.
*
* Since: 3.0
*/
properties
[
PROP_DESCRIPTION
]
=
g_param_spec_string
(
"description"
,
"description"
,
"The description for the conversation."
,
NULL
,
G_PARAM_READWRITE
|
G_PARAM_STATIC_STRINGS
);
/**
* PurpleConversation:topic:
*
* The topic of the conversation.
*
* This is normally controlled by the protocol plugin and often times
* requires permission for the user to set.
*
* Since: 3.0
*/
properties
[
PROP_TOPIC
]
=
g_param_spec_string
(
"topic"
,
"topic"
,
"The topic for the conversation."
,
NULL
,
G_PARAM_READWRITE
|
G_PARAM_STATIC_STRINGS
);
/**
* PurpleConversation:topic-author:
*
* Sets the author of the topic for the conversation.
*
* This should typically only be set by a protocol plugin.
*
* Since: 3.0
*/
properties
[
PROP_TOPIC_AUTHOR
]
=
g_param_spec_object
(
"topic-author"
,
"topic-author"
,
"The author of the topic for the conversation."
,
PURPLE_TYPE_CONTACT_INFO
,
G_PARAM_READWRITE
|
G_PARAM_STATIC_STRINGS
);
/**
* PurpleConversation:topic-updated:
*
* Set to the time that the topic was last updated.
*
* This should typically only be set by a protocol plugin.
*
* Since: 3.0
*/
properties
[
PROP_TOPIC_UPDATED
]
=
g_param_spec_boxed
(
"topic-updated"
,
"topic-updated"
,
"The time when the topic was last updated for the conversation."
,
G_TYPE_DATE_TIME
,
G_PARAM_READWRITE
|
G_PARAM_STATIC_STRINGS
);
/**
* PurpleConversation:user-nickname:
*
* The user's nickname in this conversation.
*
* Some protocols allow the user to use a nickname rather than their normal
* contact information when joining a conversation. This field holds that
* value.
*
* Since: 3.0
*/
properties
[
PROP_USER_NICKNAME
]
=
g_param_spec_string
(
"user-nickname"
,
"user-nickname"
,
"The nickname for the user in the conversation."
,
NULL
,
G_PARAM_READWRITE
|
G_PARAM_STATIC_STRINGS
);
/**
* PurpleConversation:favorite:
*
* Whether or not the conversation has been marked as favorite by the user.
*
* Since: 3.0
*/
properties
[
PROP_FAVORITE
]
=
g_param_spec_boolean
(
"favorite"
,
"favorite"
,
"Whether or not the conversation is a favorite."
,
FALSE
,
G_PARAM_READWRITE
|
G_PARAM_STATIC_STRINGS
);
/**
* PurpleConversation:created-on:
*
* The [struct@GLib.DateTime] when this conversation was created. This can
* be %NULL if the value is not known or supported.
*
* This should typically only be set by a protocol plugin.
*
* Since: 3.0
*/
properties
[
PROP_CREATED_ON
]
=
g_param_spec_boxed
(
"created-on"
,
"created-on"
,
"When the conversation was created."
,
G_TYPE_DATE_TIME
,
G_PARAM_READWRITE
|
G_PARAM_STATIC_STRINGS
);
/**
* PurpleConversation:creator:
*
* The [class@ContactInfo] that created the conversation.
*
* This should typically only be set by a protocol plugin.
*
* Since: 3.0
*/
properties
[
PROP_CREATOR
]
=
g_param_spec_object
(
"creator"
,
"creator"
,
"The contact info of who created the conversation."
,
PURPLE_TYPE_CONTACT_INFO
,
G_PARAM_READWRITE
|
G_PARAM_STATIC_STRINGS
);
/**
* PurpleConversation:online:
*
* Whether or not the conversation is able to send and receive messages.
*
* This is typically tied to whether or not the account that this
* conversation belongs is online or not.
*
* However, if a protocol supports federated conversation, it is possible
* for a conversation to be offline if the server it is on is currently
* unreachable.
*
* See also [property@Conversation:federated].
*
* Since: 3.0
*/
properties
[
PROP_ONLINE
]
=
g_param_spec_boolean
(
"online"
,
"online"
,
"Whether or not the conversation can send and receive messages."
,
TRUE
,
G_PARAM_READWRITE
|
G_PARAM_STATIC_STRINGS
);
/**
* PurpleConversation:federated:
*
* Whether or this conversation is federated.
*
* This should only be set by protocols that support federated
* conversations.
*
* When this is %TRUE the [property@Conversation:online] property will not
* be automatically set to match the [property@Account:connected] property
* of the account that this conversation belongs to. It is the
* responsibility of the protocol to manage the online property in this
* case.
*
* Since: 3.0
*/
properties
[
PROP_FEDERATED
]
=
g_param_spec_boolean
(
"federated"
,
"federated"
,
"Whether or not this conversation is federated."
,
FALSE
,
G_PARAM_READWRITE
|
G_PARAM_CONSTRUCT_ONLY
|
G_PARAM_STATIC_STRINGS
);
/**
* PurpleConversation:tags:
*
* [class@Tags] for the conversation.
*
* Since: 3.0
*/
properties
[
PROP_TAGS
]
=
g_param_spec_object
(
"tags"
,
"tags"
,
"The tags for the conversation."
,
PURPLE_TYPE_TAGS
,
G_PARAM_READABLE
|
G_PARAM_STATIC_STRINGS
);
/**
* PurpleConversation:members:
*
* The members that are currently in this conversation.
*
* Since: 3.0
*/
properties
[
PROP_MEMBERS
]
=
g_param_spec_object
(
"members"
,
"members"
,
"The members that are currently in this conversation"
,
G_TYPE_LIST_MODEL
,
G_PARAM_READABLE
|
G_PARAM_STATIC_STRINGS
);
/**
* PurpleConversation:messages:
*
* A [iface.Gio.ListModel] of all the messages in this conversation.
*
* Since: 3.0
*/
properties
[
PROP_MESSAGES
]
=
g_param_spec_object
(
"messages"
,
"messages"
,
"All of the messages in this conversation's history."
,
G_TYPE_LIST_MODEL
,
G_PARAM_READABLE
|
G_PARAM_STATIC_STRINGS
);
g_object_class_install_properties
(
obj_class
,
N_PROPERTIES
,
properties
);
/**
* PurpleConversation::present:
* @conversation: The instance.
*
* Emitted by [method@Conversation.present] when something wants the
* conversation presented to the user.
*
* Since: 3.0
*/
signals
[
SIG_PRESENT
]
=
g_signal_new_class_handler
(
"present"
,
G_OBJECT_CLASS_TYPE
(
klass
),
G_SIGNAL_RUN_LAST
,
NULL
,
NULL
,
NULL
,
NULL
,
G_TYPE_NONE
,
0
);
/**
* PurpleConversation::member-added:
* @conversation: The instance.
* @member: The [class@Purple.ConversationMember] instance.
* @announce: Whether or not this addition should be announced.
* @message: (nullable): An optional message to use in the announcement.
*
* Emitted when a new member is added to this conversation.
*
* Since: 3.0
*/
signals
[
SIG_MEMBER_ADDED
]
=
g_signal_new_class_handler
(
"member-added"
,
G_OBJECT_CLASS_TYPE
(
klass
),
G_SIGNAL_RUN_LAST
,
NULL
,
NULL
,
NULL
,
NULL
,
G_TYPE_NONE
,
3
,
PURPLE_TYPE_CONVERSATION_MEMBER
,
G_TYPE_BOOLEAN
,
G_TYPE_STRING
);
/**
* PurpleConversation::member-removed:
* @conversation: The instance.
* @member: The [class@Purple.ConversationMember] instance.
* @announce: Whether or not this removal should be announced.
* @message: (nullable): An optional message to use in the announcement.
*
* Emitted when member is removed from this conversation.
*
* Since: 3.0
*/
signals
[
SIG_MEMBER_REMOVED
]
=
g_signal_new_class_handler
(
"member-removed"
,
G_OBJECT_CLASS_TYPE
(
klass
),
G_SIGNAL_RUN_LAST
,
NULL
,
NULL
,
NULL
,
NULL
,
G_TYPE_NONE
,
3
,
PURPLE_TYPE_CONVERSATION_MEMBER
,
G_TYPE_BOOLEAN
,
G_TYPE_STRING
);
}
/******************************************************************************
* Public API
*****************************************************************************/
gboolean
purple_conversation_is_dm
(
PurpleConversation
*
conversation
)
{
g_return_val_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
),
FALSE
);
return
conversation
->
type
==
PURPLE_CONVERSATION_TYPE_DM
;
}
gboolean
purple_conversation_is_group_dm
(
PurpleConversation
*
conversation
)
{
g_return_val_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
),
FALSE
);
return
conversation
->
type
==
PURPLE_CONVERSATION_TYPE_GROUP_DM
;
}
gboolean
purple_conversation_is_channel
(
PurpleConversation
*
conversation
)
{
g_return_val_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
),
FALSE
);
return
conversation
->
type
==
PURPLE_CONVERSATION_TYPE_CHANNEL
;
}
gboolean
purple_conversation_is_thread
(
PurpleConversation
*
conversation
)
{
g_return_val_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
),
FALSE
);
return
conversation
->
type
==
PURPLE_CONVERSATION_TYPE_THREAD
;
}
void
purple_conversation_present
(
PurpleConversation
*
conversation
)
{
g_return_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
));
g_signal_emit
(
conversation
,
signals
[
SIG_PRESENT
],
0
);
}
void
purple_conversation_set_features
(
PurpleConversation
*
conversation
,
PurpleConnectionFlags
features
)
{
g_return_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
));
if
(
conversation
->
features
!=
features
)
{
conversation
->
features
=
features
;
g_object_notify_by_pspec
(
G_OBJECT
(
conversation
),
properties
[
PROP_FEATURES
]);
}
}
PurpleConnectionFlags
purple_conversation_get_features
(
PurpleConversation
*
conversation
)
{
g_return_val_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
),
0
);
return
conversation
->
features
;
}
const
char
*
purple_conversation_get_id
(
PurpleConversation
*
conversation
)
{
g_return_val_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
),
NULL
);
return
conversation
->
id
;
}
PurpleConversationType
purple_conversation_get_conversation_type
(
PurpleConversation
*
conversation
)
{
g_return_val_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
),
PURPLE_CONVERSATION_TYPE_UNSET
);
return
conversation
->
type
;
}
void
purple_conversation_set_conversation_type
(
PurpleConversation
*
conversation
,
PurpleConversationType
type
)
{
g_return_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
));
if
(
type
!=
conversation
->
type
)
{
conversation
->
type
=
type
;
g_object_notify_by_pspec
(
G_OBJECT
(
conversation
),
properties
[
PROP_TYPE
]);
}
}
PurpleAccount
*
purple_conversation_get_account
(
PurpleConversation
*
conversation
)
{
g_return_val_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
),
NULL
);
return
conversation
->
account
;
}
PurpleConnection
*
purple_conversation_get_connection
(
PurpleConversation
*
conversation
)
{
PurpleAccount
*
account
;
g_return_val_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
),
NULL
);
account
=
purple_conversation_get_account
(
conversation
);
if
(
account
==
NULL
)
{
return
NULL
;
}
return
purple_account_get_connection
(
account
);
}
void
purple_conversation_set_title
(
PurpleConversation
*
conversation
,
const
char
*
title
)
{
g_return_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
));
g_return_if_fail
(
title
!=
NULL
);
if
(
!
purple_strequal
(
conversation
->
title
,
title
))
{
g_free
(
conversation
->
title
);
conversation
->
title
=
g_strdup
(
title
);
g_object_notify_by_pspec
(
G_OBJECT
(
conversation
),
properties
[
PROP_TITLE
]);
}
}
const
char
*
purple_conversation_get_title
(
PurpleConversation
*
conversation
)
{
g_return_val_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
),
NULL
);
return
conversation
->
title
;
}
void
purple_conversation_autoset_title
(
PurpleConversation
*
conversation
)
{
const
char
*
name
=
NULL
;
g_return_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
));
name
=
purple_conversation_get_name
(
conversation
);
purple_conversation_set_title
(
conversation
,
name
);
}
void
purple_conversation_set_name
(
PurpleConversation
*
conversation
,
const
char
*
name
)
{
g_return_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
));
if
(
!
purple_strequal
(
conversation
->
name
,
name
))
{
g_free
(
conversation
->
name
);
conversation
->
name
=
g_strdup
(
name
);
g_object_notify_by_pspec
(
G_OBJECT
(
conversation
),
properties
[
PROP_NAME
]);
}
}
const
char
*
purple_conversation_get_name
(
PurpleConversation
*
conversation
)
{
g_return_val_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
),
NULL
);
return
conversation
->
name
;
}
void
purple_conversation_write_message
(
PurpleConversation
*
conversation
,
PurpleMessage
*
message
)
{
g_return_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
));
g_return_if_fail
(
message
!=
NULL
);
if
(
purple_message_is_empty
(
message
))
{
return
;
}
if
(
!
(
purple_message_get_flags
(
message
)
&
PURPLE_MESSAGE_NO_LOG
))
{
GError
*
error
=
NULL
;
PurpleHistoryManager
*
manager
=
NULL
;
gboolean
success
=
FALSE
;
manager
=
purple_history_manager_get_default
();
/* We should probably handle this error somehow, but I don't think that
* spamming purple_debug_warning is necessarily the right call.
*/
success
=
purple_history_manager_write
(
manager
,
conversation
,
message
,
&
error
);
if
(
!
success
){
purple_debug_info
(
"conversation"
,
"history manager write returned error: %s"
,
error
->
message
);
g_clear_error
(
&
error
);
}
}
g_list_store_append
(
conversation
->
messages
,
message
);
}
void
purple_conversation_write_system_message
(
PurpleConversation
*
conversation
,
const
char
*
message
,
PurpleMessageFlags
flags
)
{
PurpleMessage
*
pmsg
=
NULL
;
g_return_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
));
pmsg
=
purple_message_new_system
(
message
,
flags
);
purple_conversation_write_message
(
conversation
,
pmsg
);
g_clear_object
(
&
pmsg
);
}
void
purple_conversation_send_message_async
(
PurpleConversation
*
conversation
,
PurpleMessage
*
message
,
GCancellable
*
cancellable
,
GAsyncReadyCallback
callback
,
gpointer
data
)
{
PurpleAccount
*
account
=
NULL
;
PurpleProtocol
*
protocol
=
NULL
;
GTask
*
task
=
NULL
;
g_return_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
));
g_return_if_fail
(
PURPLE_IS_MESSAGE
(
message
));
task
=
g_task_new
(
conversation
,
cancellable
,
callback
,
data
);
g_task_set_source_tag
(
task
,
purple_conversation_send_message_async
);
g_task_set_task_data
(
task
,
g_object_ref
(
message
),
g_object_unref
);
account
=
purple_conversation_get_account
(
conversation
);
protocol
=
purple_account_get_protocol
(
account
);
if
(
!
PURPLE_IS_PROTOCOL_CONVERSATION
(
protocol
))
{
g_task_return_new_error
(
task
,
PURPLE_CONVERSATION_DOMAIN
,
0
,
"protocol does not implement "
"PurpleProtocolConversation"
);
g_clear_object
(
&
task
);
return
;
}
purple_protocol_conversation_send_message_async
(
PURPLE_PROTOCOL_CONVERSATION
(
protocol
),
conversation
,
message
,
cancellable
,
purple_conversation_send_message_async_cb
,
task
);
}
gboolean
purple_conversation_send_message_finish
(
PurpleConversation
*
conversation
,
GAsyncResult
*
result
,
GError
**
error
)
{
g_return_val_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
),
FALSE
);
g_return_val_if_fail
(
G_IS_ASYNC_RESULT
(
result
),
FALSE
);
g_return_val_if_fail
(
g_task_get_source_tag
(
G_TASK
(
result
))
!=
purple_conversation_send_message_async
,
FALSE
);
return
g_task_propagate_boolean
(
G_TASK
(
result
),
error
);
}
void
purple_conversation_send
(
PurpleConversation
*
conversation
,
const
char
*
message
)
{
purple_conversation_send_with_flags
(
conversation
,
message
,
0
);
}
void
purple_conversation_send_with_flags
(
PurpleConversation
*
conversation
,
const
char
*
message
,
PurpleMessageFlags
flags
)
{
g_return_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
));
g_return_if_fail
(
message
!=
NULL
);
common_send
(
conversation
,
message
,
flags
);
}
gboolean
purple_conversation_has_focus
(
PurpleConversation
*
conversation
)
{
gboolean
ret
=
FALSE
;
g_return_val_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
),
FALSE
);
return
ret
;
}
gboolean
purple_conversation_present_error
(
const
char
*
who
,
PurpleAccount
*
account
,
const
char
*
what
)
{
PurpleConversation
*
conversation
=
NULL
;
PurpleConversationManager
*
manager
=
NULL
;
g_return_val_if_fail
(
who
!=
NULL
,
FALSE
);
g_return_val_if_fail
(
PURPLE_IS_ACCOUNT
(
account
),
FALSE
);
g_return_val_if_fail
(
what
!=
NULL
,
FALSE
);
manager
=
purple_conversation_manager_get_default
();
conversation
=
purple_conversation_manager_find
(
manager
,
account
,
who
);
if
(
PURPLE_IS_CONVERSATION
(
conversation
))
{
purple_conversation_write_system_message
(
conversation
,
what
,
PURPLE_MESSAGE_ERROR
);
return
TRUE
;
}
return
FALSE
;
}
gboolean
purple_conversation_get_age_restricted
(
PurpleConversation
*
conversation
)
{
g_return_val_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
),
FALSE
);
return
conversation
->
age_restricted
;
}
void
purple_conversation_set_age_restricted
(
PurpleConversation
*
conversation
,
gboolean
age_restricted
)
{
g_return_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
));
if
(
conversation
->
age_restricted
!=
age_restricted
)
{
conversation
->
age_restricted
=
age_restricted
;
g_object_notify_by_pspec
(
G_OBJECT
(
conversation
),
properties
[
PROP_AGE_RESTRICTED
]);
}
}
const
char
*
purple_conversation_get_description
(
PurpleConversation
*
conversation
)
{
g_return_val_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
),
NULL
);
return
conversation
->
description
;
}
void
purple_conversation_set_description
(
PurpleConversation
*
conversation
,
const
char
*
description
)
{
g_return_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
));
if
(
!
purple_strequal
(
conversation
->
description
,
description
))
{
g_free
(
conversation
->
description
);
conversation
->
description
=
g_strdup
(
description
);
g_object_notify_by_pspec
(
G_OBJECT
(
conversation
),
properties
[
PROP_DESCRIPTION
]);
}
}
const
char
*
purple_conversation_get_topic
(
PurpleConversation
*
conversation
)
{
g_return_val_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
),
NULL
);
return
conversation
->
topic
;
}
void
purple_conversation_set_topic
(
PurpleConversation
*
conversation
,
const
char
*
topic
)
{
g_return_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
));
if
(
!
purple_strequal
(
conversation
->
topic
,
topic
))
{
g_free
(
conversation
->
topic
);
conversation
->
topic
=
g_strdup
(
topic
);
g_object_notify_by_pspec
(
G_OBJECT
(
conversation
),
properties
[
PROP_TOPIC
]);
}
}
void
purple_conversation_set_topic_full
(
PurpleConversation
*
conversation
,
const
char
*
topic
,
PurpleContactInfo
*
author
,
GDateTime
*
updated
)
{
GObject
*
obj
=
NULL
;
g_return_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
));
obj
=
G_OBJECT
(
conversation
);
g_object_freeze_notify
(
obj
);
purple_conversation_set_topic
(
conversation
,
topic
);
purple_conversation_set_topic_author
(
conversation
,
author
);
purple_conversation_set_topic_updated
(
conversation
,
updated
);
g_object_thaw_notify
(
obj
);
}
PurpleContactInfo
*
purple_conversation_get_topic_author
(
PurpleConversation
*
conversation
)
{
g_return_val_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
),
NULL
);
return
conversation
->
topic_author
;
}
void
purple_conversation_set_topic_author
(
PurpleConversation
*
conversation
,
PurpleContactInfo
*
author
)
{
g_return_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
));
if
(
g_set_object
(
&
conversation
->
topic_author
,
author
))
{
g_object_notify_by_pspec
(
G_OBJECT
(
conversation
),
properties
[
PROP_TOPIC_AUTHOR
]);
}
}
GDateTime
*
purple_conversation_get_topic_updated
(
PurpleConversation
*
conversation
)
{
g_return_val_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
),
NULL
);
return
conversation
->
topic_updated
;
}
void
purple_conversation_set_topic_updated
(
PurpleConversation
*
conversation
,
GDateTime
*
updated
)
{
g_return_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
));
if
(
birb_date_time_set
(
&
conversation
->
topic_updated
,
updated
))
{
g_object_notify_by_pspec
(
G_OBJECT
(
conversation
),
properties
[
PROP_TOPIC_UPDATED
]);
}
}
const
char
*
purple_conversation_get_user_nickname
(
PurpleConversation
*
conversation
)
{
g_return_val_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
),
NULL
);
return
conversation
->
user_nickname
;
}
void
purple_conversation_set_user_nickname
(
PurpleConversation
*
conversation
,
const
char
*
nickname
)
{
g_return_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
));
if
(
!
purple_strequal
(
conversation
->
user_nickname
,
nickname
))
{
g_free
(
conversation
->
user_nickname
);
conversation
->
user_nickname
=
g_strdup
(
nickname
);
g_object_notify_by_pspec
(
G_OBJECT
(
conversation
),
properties
[
PROP_USER_NICKNAME
]);
}
}
gboolean
purple_conversation_get_favorite
(
PurpleConversation
*
conversation
)
{
g_return_val_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
),
FALSE
);
return
conversation
->
favorite
;
}
void
purple_conversation_set_favorite
(
PurpleConversation
*
conversation
,
gboolean
favorite
)
{
g_return_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
));
if
(
conversation
->
favorite
!=
favorite
)
{
conversation
->
favorite
=
favorite
;
g_object_notify_by_pspec
(
G_OBJECT
(
conversation
),
properties
[
PROP_FAVORITE
]);
}
}
GDateTime
*
purple_conversation_get_created_on
(
PurpleConversation
*
conversation
)
{
g_return_val_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
),
NULL
);
return
conversation
->
created_on
;
}
void
purple_conversation_set_created_on
(
PurpleConversation
*
conversation
,
GDateTime
*
created_on
)
{
g_return_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
));
if
(
birb_date_time_set
(
&
conversation
->
created_on
,
created_on
))
{
g_object_notify_by_pspec
(
G_OBJECT
(
conversation
),
properties
[
PROP_CREATED_ON
]);
}
}
PurpleContactInfo
*
purple_conversation_get_creator
(
PurpleConversation
*
conversation
)
{
g_return_val_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
),
NULL
);
return
conversation
->
creator
;
}
void
purple_conversation_set_creator
(
PurpleConversation
*
conversation
,
PurpleContactInfo
*
creator
)
{
g_return_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
));
if
(
g_set_object
(
&
conversation
->
creator
,
creator
))
{
g_object_notify_by_pspec
(
G_OBJECT
(
conversation
),
properties
[
PROP_CREATOR
]);
}
}
gboolean
purple_conversation_get_online
(
PurpleConversation
*
conversation
)
{
g_return_val_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
),
FALSE
);
return
conversation
->
online
;
}
void
purple_conversation_set_online
(
PurpleConversation
*
conversation
,
gboolean
online
)
{
g_return_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
));
if
(
conversation
->
online
!=
online
)
{
conversation
->
online
=
online
;
g_object_notify_by_pspec
(
G_OBJECT
(
conversation
),
properties
[
PROP_ONLINE
]);
}
}
gboolean
purple_conversation_get_federated
(
PurpleConversation
*
conversation
)
{
g_return_val_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
),
FALSE
);
return
conversation
->
federated
;
}
PurpleTags
*
purple_conversation_get_tags
(
PurpleConversation
*
conversation
)
{
g_return_val_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
),
NULL
);
return
conversation
->
tags
;
}
GListModel
*
purple_conversation_get_members
(
PurpleConversation
*
conversation
)
{
g_return_val_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
),
NULL
);
return
G_LIST_MODEL
(
conversation
->
members
);
}
gboolean
purple_conversation_has_member
(
PurpleConversation
*
conversation
,
PurpleContactInfo
*
info
,
guint
*
position
)
{
PurpleConversationMember
*
needle
=
NULL
;
gboolean
found
=
FALSE
;
g_return_val_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
),
FALSE
);
g_return_val_if_fail
(
PURPLE_IS_CONTACT_INFO
(
info
),
FALSE
);
needle
=
purple_conversation_member_new
(
info
);
found
=
g_list_store_find_with_equal_func
(
conversation
->
members
,
needle
,
purple_conversation_check_member_equal
,
position
);
g_clear_object
(
&
needle
);
return
found
;
}
PurpleConversationMember
*
purple_conversation_find_member
(
PurpleConversation
*
conversation
,
PurpleContactInfo
*
info
)
{
PurpleConversationMember
*
member
=
NULL
;
guint
position
=
0
;
g_return_val_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
),
NULL
);
g_return_val_if_fail
(
PURPLE_IS_CONTACT_INFO
(
info
),
NULL
);
if
(
purple_conversation_has_member
(
conversation
,
info
,
&
position
))
{
member
=
g_list_model_get_item
(
G_LIST_MODEL
(
conversation
->
members
),
position
);
/* We don't return a reference, but get_item does, so we need to get
* rid of that.
*/
g_object_unref
(
member
);
}
return
member
;
}
PurpleConversationMember
*
purple_conversation_add_member
(
PurpleConversation
*
conversation
,
PurpleContactInfo
*
info
,
gboolean
announce
,
const
char
*
message
)
{
PurpleConversationMember
*
member
=
NULL
;
g_return_val_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
),
NULL
);
g_return_val_if_fail
(
PURPLE_IS_CONTACT_INFO
(
info
),
NULL
);
member
=
purple_conversation_find_member
(
conversation
,
info
);
if
(
PURPLE_IS_CONVERSATION_MEMBER
(
member
))
{
return
member
;
}
member
=
purple_conversation_member_new
(
info
);
g_list_store_append
(
conversation
->
members
,
member
);
g_signal_emit
(
conversation
,
signals
[
SIG_MEMBER_ADDED
],
0
,
member
,
announce
,
message
);
g_object_unref
(
member
);
return
member
;
}
gboolean
purple_conversation_remove_member
(
PurpleConversation
*
conversation
,
PurpleContactInfo
*
info
,
gboolean
announce
,
const
char
*
message
)
{
PurpleConversationMember
*
member
=
NULL
;
guint
position
=
0
;
g_return_val_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
),
FALSE
);
g_return_val_if_fail
(
PURPLE_IS_CONTACT_INFO
(
info
),
FALSE
);
if
(
!
purple_conversation_has_member
(
conversation
,
info
,
&
position
))
{
return
FALSE
;
}
member
=
g_list_model_get_item
(
G_LIST_MODEL
(
conversation
->
members
),
position
);
g_list_store_remove
(
conversation
->
members
,
position
);
g_signal_emit
(
conversation
,
signals
[
SIG_MEMBER_REMOVED
],
0
,
member
,
announce
,
message
);
g_clear_object
(
&
member
);
return
TRUE
;
}
GListModel
*
purple_conversation_get_messages
(
PurpleConversation
*
conversation
)
{
g_return_val_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
),
NULL
);
if
(
G_IS_LIST_MODEL
(
conversation
->
messages
))
{
return
G_LIST_MODEL
(
conversation
->
messages
);
}
return
NULL
;
}
PurpleAvatar
*
purple_conversation_get_avatar
(
PurpleConversation
*
conversation
)
{
g_return_val_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
),
NULL
);
return
conversation
->
avatar
;
}
void
purple_conversation_set_avatar
(
PurpleConversation
*
conversation
,
PurpleAvatar
*
avatar
)
{
g_return_if_fail
(
PURPLE_IS_CONVERSATION
(
conversation
));
if
(
g_set_object
(
&
conversation
->
avatar
,
avatar
))
{
g_object_notify_by_pspec
(
G_OBJECT
(
conversation
),
properties
[
PROP_AVATAR
]);
}
}