summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXavier Claessens <xavier.claessens@collabora.co.uk>2012-05-09 20:45:36 +0200
committerXavier Claessens <xavier.claessens@collabora.co.uk>2012-05-09 22:06:44 +0200
commitebd725a6d90cfdca41d2433e671af79baf68f4f4 (patch)
tree929d3dba110cafc4315cf7c7489918b93fb15e9e
parentf4ad3d7c7bb697d0e4cd73fd88583c375dea643c (diff)
parent53cf9df185364f552d60415de885936ed6a51b81 (diff)
Merge branch 'master' into next
Conflicts: configure.ac docs/reference/telepathy-glib-sections.txt examples/client/extended-client.c examples/client/inspect-contact.c examples/cm/echo-message-parts/chan.c spec/Protocol_Interface_Presence1.xml spec/all.xml telepathy-glib/Makefile.am telepathy-glib/abi.am telepathy-glib/base-connection.c telepathy-glib/base-connection.h telepathy-glib/connection-contact-list.c telepathy-glib/contacts-mixin.c telepathy-glib/intset.c telepathy-glib/message-mixin.c telepathy-glib/message-mixin.h telepathy-glib/stream-tube-channel.c telepathy-glib/text-channel.c tests/lib/util.c
-rw-r--r--.gitignore1
-rw-r--r--NEWS38
-rw-r--r--docs/reference/telepathy-glib-docs.sgml2
-rw-r--r--docs/reference/telepathy-glib-sections.txt87
-rw-r--r--examples/client/extended-client.c48
-rw-r--r--examples/client/inspect-contact.c91
-rw-r--r--examples/cm/echo-message-parts/chan.c15
-rw-r--r--spec/Channel_Type_Call1.xml11
-rw-r--r--spec/Connection_Interface_Contacts.xml58
-rw-r--r--spec/Connection_Manager.xml3
-rw-r--r--spec/Protocol_Interface_Presence1.xml3
-rw-r--r--spec/all.xml33
-rw-r--r--telepathy-glib/Makefile.am5
-rw-r--r--telepathy-glib/account-channel-request.c22
-rw-r--r--telepathy-glib/account.c34
-rw-r--r--telepathy-glib/base-connection.c15
-rw-r--r--telepathy-glib/capabilities.c14
-rw-r--r--telepathy-glib/channel-contacts.c8
-rw-r--r--telepathy-glib/channel.c27
-rw-r--r--telepathy-glib/channel.h3
-rw-r--r--telepathy-glib/cli-misc.h2
-rw-r--r--telepathy-glib/codegen.am6
-rw-r--r--telepathy-glib/connection-contact-list.c43
-rw-r--r--telepathy-glib/connection-manager.c2
-rw-r--r--telepathy-glib/connection.c9
-rw-r--r--telepathy-glib/contact.c299
-rw-r--r--telepathy-glib/contact.h29
-rw-r--r--telepathy-glib/contacts-mixin.c54
-rw-r--r--telepathy-glib/dbus-internal.h2
-rw-r--r--telepathy-glib/dbus.c26
-rw-r--r--telepathy-glib/debug-client.c24
-rw-r--r--telepathy-glib/debug-internal.h3
-rw-r--r--telepathy-glib/debug-message.c24
-rw-r--r--telepathy-glib/debug.c4
-rw-r--r--telepathy-glib/defs.h10
-rw-r--r--telepathy-glib/extra-gtkdoc.h4
-rw-r--r--telepathy-glib/introspection.am2
-rw-r--r--telepathy-glib/message-mixin.c260
-rw-r--r--telepathy-glib/message-mixin.h19
-rw-r--r--telepathy-glib/proxy.c5
-rw-r--r--telepathy-glib/room-info.c26
-rw-r--r--telepathy-glib/room-list.c26
-rw-r--r--telepathy-glib/stream-tube-channel.c3
-rw-r--r--telepathy-glib/telepathy-glib.h1
-rw-r--r--telepathy-glib/text-channel.c120
-rw-r--r--telepathy-glib/text-channel.h9
-rw-r--r--telepathy-glib/tls-certificate-rejection-internal.h30
-rw-r--r--telepathy-glib/tls-certificate-rejection.c339
-rw-r--r--telepathy-glib/tls-certificate-rejection.h92
-rw-r--r--telepathy-glib/tls-certificate.c923
-rw-r--r--telepathy-glib/tls-certificate.h127
-rw-r--r--telepathy-glib/versions/0.19.0.abi97
-rw-r--r--tests/dbus/Makefile.am3
-rw-r--r--tests/dbus/text-channel.c77
-rw-r--r--tests/dbus/tls-certificate.c355
-rw-r--r--tests/lib/Makefile.am2
-rw-r--r--tests/lib/tls-certificate.c353
-rw-r--r--tests/lib/tls-certificate.h68
-rw-r--r--tests/lib/util.c27
-rw-r--r--tools/check-c-style.sh7
60 files changed, 3749 insertions, 281 deletions
diff --git a/.gitignore b/.gitignore
index 546bff798..c8c5ed200 100644
--- a/.gitignore
+++ b/.gitignore
@@ -79,6 +79,7 @@ stamp-h1
tags
/telepathy-glib-0.*
/telepathy-glib/tmp-introspect*/
+telepathy-glib/version.h
tests/dbus/dbus-installed/session.conf
tests/dbus/dbus-uninstalled/session.conf
tests/dbus/run-test.sh
diff --git a/NEWS b/NEWS
index ec8d98fee..7eecc1ac0 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,4 @@
-telepathy-glib 0.19.0 (UNRELEASED)
+telepathy-glib 0.19.0 (2012-05-09)
==================================
Dependencies:
@@ -9,23 +9,40 @@ Deprecations:
• Deprecations are now versioned. telepathy-glib users can define
TP_VERSION_MIN_REQUIRED and/or TP_VERSION_MAX_ALLOWED, which work like the
- corresponding macros in GLib 2.32.
+ corresponding macros in GLib 2.32. (Simon)
• All TpChannel APIs using contact TpHandle have been deprecated in favor of
their TpContact variants. Note that replacement APIs are only guaranteed to
work with Connection Managers implementing spec >= 0.23.4. Any CMs using
telepathy-glib's TpGroupMixin for implementing the channel's group iface
- are fine.
+ are fine. (Xavier)
-• TpTextMixin is (officially) deprecated, use TpMessageMixin.
+• TpTextMixin is (officially) deprecated, use TpMessageMixin. (Xavier)
• TpIntsetIter is deprecated, use TpIntsetFastIter. The typedefs
- TpIntSetIter and TpIntSetFastIter are also deprecated.
+ TpIntSetIter and TpIntSetFastIter are also deprecated. (Simon)
• TP_ERRORS has officially been deprecated since 0.11; it now produces
- deprecation warnings too.
+ deprecation warnings too. (Simon)
-• Reimplementation of the RequestHandles method is deprecated.
+• Reimplementation of the RequestHandles method is deprecated. (Simon)
+
+• tp_connection_get_contacts_by_id is deprecated and replaced by
+ tp_connection_dup_contact_by_id_async, for proper GAsyncResult API, and is
+ now for single identifier to simplify most common use case.
+ (fd.o #27687 and #30874, Xavier)
+
+• tp_connection_get_contacts_by_handle() is deprecated with no replacement. It
+ is deprecated to create a TpContact without knowing both its id and handle.
+ (fd.o #27687 and #30874, Xavier)
+
+• tp_connection_upgrade_contacts is deprecated and replaced by
+ tp_connection_upgrade_contacts_async, for proper GAsyncResult API. Note that
+ the connection must implement the Contacts interface to use this new API.
+ (fd.o #27687 and #30874, Xavier)
+
+• TP_CHANNEL_FEATURE_CHAT_STATES and its corresponding APIs are deprecated and
+ replaced by similar API on TpTextChannel.
Enhancements:
@@ -37,7 +54,7 @@ Enhancements:
• A new meta-header, <telepathy-glib/telepathy-glib-dbus.h>, now includes
all generated code. Please include it in any file that uses tp_svc_*,
tp_cli_*, TP_IFACE_*, TP_HASH_TYPE_*, TP_STRUCT_TYPE_* or TP_ARRAY_TYPE_*.
- In telepathy-glib 1.0, it will become a separate pkg-config module.
+ In telepathy-glib 1.0, it will become a separate pkg-config module. (Simon)
• Replace --disable-coding-style-checks and --disable-doc-checks with
--disable-fatal-warnings. In addition to what the removed options did,
@@ -73,6 +90,11 @@ Enhancements:
clean, but less thorough than distclean (in particular, it doesn't
forget your ./configure options) (Simon)
+• Add TpTLSCertificate, a TpProxy subclass representing a TLS
+ certificate (fdo #30460, Guillaume)
+
+• TpMessageMixin now has helpers to implement the ChatState interface.
+
Fixes:
• Make it safe to hold refs to a remaining GAsyncResult after returning
diff --git a/docs/reference/telepathy-glib-docs.sgml b/docs/reference/telepathy-glib-docs.sgml
index b5e33e0fc..0ee30c5f0 100644
--- a/docs/reference/telepathy-glib-docs.sgml
+++ b/docs/reference/telepathy-glib-docs.sgml
@@ -61,6 +61,8 @@
<xi:include href="xml/debug-message.xml"/>
<xi:include href="xml/room-list.xml"/>
<xi:include href="xml/room-info.xml"/>
+ <xi:include href="xml/tls-certificate.xml"/>
+ <xi:include href="xml/tls-certificate-rejection.xml"/>
</chapter>
<chapter id="ch-service-base">
diff --git a/docs/reference/telepathy-glib-sections.txt b/docs/reference/telepathy-glib-sections.txt
index 02a616751..9ab85be16 100644
--- a/docs/reference/telepathy-glib-sections.txt
+++ b/docs/reference/telepathy-glib-sections.txt
@@ -946,6 +946,9 @@ TpSvcConnectionInterfaceContactsClass
tp_svc_connection_interface_contacts_get_contact_attributes_impl
tp_svc_connection_interface_contacts_implement_get_contact_attributes
tp_svc_connection_interface_contacts_return_from_get_contact_attributes
+tp_svc_connection_interface_contacts_get_contact_by_id_impl
+tp_svc_connection_interface_contacts_implement_get_contact_by_id
+tp_svc_connection_interface_contacts_return_from_get_contact_by_id
<SUBSECTION Standard>
TP_IS_SVC_CONNECTION_INTERFACE_CONTACTS
TP_SVC_CONNECTION_INTERFACE_CONTACTS
@@ -2064,6 +2067,12 @@ tp_message_mixin_set_rescued
tp_message_mixin_take_received
tp_message_mixin_has_pending_messages
tp_message_mixin_clear
+<SUBSECTION>
+TpMessageMixinSendChatStateImpl
+tp_message_mixin_chat_state_iface_init
+tp_message_mixin_change_chat_state
+tp_message_mixin_implement_send_chat_state
+tp_message_mixin_maybe_send_gone
<SUBSECTION Private>
TpMessageMixinPrivate
</SECTION>
@@ -3528,6 +3537,8 @@ tp_cli_connection_interface_cellular_signal_callback_imsi_changed
<INCLUDE>telepathy-glib/telepathy-glib-dbus.h</INCLUDE>
tp_cli_connection_interface_contacts_call_get_contact_attributes
tp_cli_connection_interface_contacts_callback_for_get_contact_attributes
+tp_cli_connection_interface_contacts_call_get_contact_by_id
+tp_cli_connection_interface_contacts_callback_for_get_contact_by_id
</SECTION>
<SECTION>
@@ -3821,6 +3832,12 @@ TP_CONTACT_FEATURE_SUBSCRIPTION_STATES
tp_contact_get_subscribe_state
tp_contact_get_publish_state
tp_contact_get_publish_request
+<SUBSECTION>
+tp_connection_dup_contact_by_id_async
+tp_connection_dup_contact_by_id_finish
+tp_connection_upgrade_contacts_async
+tp_connection_upgrade_contacts_finish
+<SUBSECTION operations>
tp_contact_request_subscription_async
tp_contact_request_subscription_finish
tp_contact_authorize_publication_async
@@ -5343,11 +5360,15 @@ tp_text_channel_ack_all_pending_messages_finish
tp_text_channel_set_chat_state_async
tp_text_channel_set_chat_state_finish
tp_text_channel_supports_message_type
+<SUBSECTION>
TP_TEXT_CHANNEL_FEATURE_SMS
tp_text_channel_is_sms_channel
tp_text_channel_get_sms_flash
tp_text_channel_get_sms_length_async
tp_text_channel_get_sms_length_finish
+<SUBSECTION>
+TP_TEXT_CHANNEL_FEATURE_CHAT_STATES
+tp_text_channel_get_chat_state
<SUBSECTION Standard>
TP_IS_TEXT_CHANNEL
TP_IS_TEXT_CHANNEL_CLASS
@@ -5360,6 +5381,7 @@ TpTextChannelPrivate
<SUBSECTION Private>
tp_text_channel_get_feature_quark_incoming_messages
tp_text_channel_get_feature_quark_sms
+tp_text_channel_get_feature_quark_chat_states
</SECTION>
<SECTION>
@@ -6111,3 +6133,68 @@ tp_room_info_get_type
<SUBSECTION Private>
TpRoomInfoPriv
</SECTION>
+
+<SECTION>
+<FILE>tls-certificate</FILE>
+<INCLUDE>telepathy-glib/telepathy-glib.h</INCLUDE>
+<TITLE>TpTLSCertificate</TITLE>
+TpTLSCertificate
+tp_tls_certificate_init_known_interfaces
+tp_tls_certificate_new
+TP_TLS_CERTIFICATE_FEATURE_CORE
+tp_tls_certificate_get_rejection
+tp_tls_certificate_get_nth_rejection
+tp_tls_certificate_accept_async
+tp_tls_certificate_accept_finish
+tp_tls_certificate_add_rejection
+tp_tls_certificate_reject_async
+tp_tls_certificate_reject_finish
+tp_tls_certificate_get_cert_type
+tp_tls_certificate_get_cert_data
+tp_tls_certificate_get_state
+<SUBSECTION Private>
+tp_cli_authentication_tls_certificate_call_accept
+tp_cli_authentication_tls_certificate_call_reject
+tp_cli_authentication_tls_certificate_callback_for_accept
+tp_cli_authentication_tls_certificate_callback_for_reject
+tp_cli_authentication_tls_certificate_connect_to_accepted
+tp_cli_authentication_tls_certificate_connect_to_rejected
+tp_cli_authentication_tls_certificate_signal_callback_accepted
+tp_cli_authentication_tls_certificate_signal_callback_rejected
+tp_cli_tls_cert_add_signals
+<SUBSECTION Standard>
+tp_tls_certificate_get_feature_quark_core
+TP_IS_TLS_CERTIFICATE
+TP_IS_TLS_CERTIFICATE_CLASS
+TP_TLS_CERTIFICATE
+TP_TLS_CERTIFICATE_CLASS
+TP_TLS_CERTIFICATE_GET_CLASS
+TP_TYPE_TLS_CERTIFICATE
+TpTLSCertificateClass
+TpTLSCertificateClassPrivate
+TpTLSCertificatePrivate
+tp_tls_certificate_get_type
+</SECTION>
+
+<SECTION>
+<FILE>tls-certificate-rejection</FILE>
+<INCLUDE>telepathy-glib/telepathy-glib.h</INCLUDE>
+<TITLE>TpTLSCertificateRejection</TITLE>
+TpTLSCertificateRejection
+tp_tls_certificate_rejection_get_dbus_error
+tp_tls_certificate_rejection_get_details
+tp_tls_certificate_rejection_get_error
+tp_tls_certificate_rejection_get_reason
+tp_tls_certificate_rejection_raise_error
+<SUBSECTION Standard>
+TP_IS_TLS_CERTIFICATE_REJECTION
+TP_IS_TLS_CERTIFICATE_REJECTION_CLASS
+TP_TLS_CERTIFICATE_REJECTION
+TP_TLS_CERTIFICATE_REJECTION_CLASS
+TP_TLS_CERTIFICATE_REJECTION_GET_CLASS
+TP_TYPE_TLS_CERTIFICATE_REJECTION
+TpTLSCertificateRejectionClass
+tp_tls_certificate_rejection_get_type
+<SUBSECTION Private>
+TpTLSCertificateRejectionPriv
+</SECTION>
diff --git a/examples/client/extended-client.c b/examples/client/extended-client.c
index 4750986dc..9caa0d567 100644
--- a/examples/client/extended-client.c
+++ b/examples/client/extended-client.c
@@ -120,36 +120,25 @@ contact_pair_free (gpointer p)
}
static void
-contacts_ready_cb (TpConnection *conn,
- guint n_contacts,
- TpContact * const *contacts,
- const gchar * const *requested_ids,
- GHashTable *failed_id_errors,
- const GError *general_error,
- gpointer user_data,
- GObject *weak_object)
+contact_ready_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
{
- GHashTableIter iter;
- gpointer k, v;
+ TpConnection *conn = (TpConnection *) object;
GHashTable *asv;
ContactPair *pair;
+ GError *error = NULL;
- /* This runs if tp_connection_get_contacts_by_id failed completely (e.g.
- * the CM crashed) */
- if (die_if (general_error, "tp_connection_get_contacts_by_id()"))
- return;
-
- /* If any making a TpContact for one of the requested IDs fails, they'll
- * be present in this hash table with an error as value */
- g_hash_table_iter_init (&iter, failed_id_errors);
+ pair = g_slice_new0 (ContactPair);
+ pair->contacts[0] = tp_connection_dup_contact_by_id_finish (conn,
+ result, &error);
+ pair->contacts[1] = g_object_ref (tp_connection_get_self_contact (conn));
- while (g_hash_table_iter_next (&iter, &k, &v))
+ if (die_if (error, "tp_connection_dup_contact_by_id_async()"))
{
- const gchar *failed_id = k;
- const GError *contact_error = v;
-
- if (die_if (contact_error, failed_id))
- return;
+ g_clear_error (&error);
+ contact_pair_free (pair);
+ return;
}
asv = g_hash_table_new_full (g_str_hash, g_str_equal, NULL,
@@ -157,10 +146,6 @@ contacts_ready_cb (TpConnection *conn,
g_hash_table_insert (asv, "previous-owner",
tp_g_value_slice_new_static_string ("Shadowman"));
- pair = g_slice_new0 (ContactPair);
- pair->contacts[0] = g_object_ref (contacts[0]);
- pair->contacts[1] = g_object_ref (contacts[1]);
-
example_cli_connection_interface_hats_call_set_hat (conn, -1,
"red", EXAMPLE_HAT_STYLE_FEDORA, asv,
set_hat_cb, pair, contact_pair_free, NULL);
@@ -174,7 +159,6 @@ conn_ready (GObject *source,
gpointer user_data)
{
GError *error = NULL;
- static const gchar * const names[] = { "myself@server", "other@server" };
TpConnection *conn = TP_CONNECTION (source);
if (!tp_proxy_prepare_finish (conn, result, &error))
@@ -193,9 +177,9 @@ conn_ready (GObject *source,
return;
}
- /* Get contact objects for myself and someone else */
- tp_connection_get_contacts_by_id (conn, 2, names, NULL,
- contacts_ready_cb, NULL, NULL, NULL);
+ /* Get contact object for someone else */
+ tp_connection_dup_contact_by_id_async (conn, "other@server", NULL,
+ contact_ready_cb, NULL);
}
static void
diff --git a/examples/client/inspect-contact.c b/examples/client/inspect-contact.c
index 0d7464ba9..9fe9681ee 100644
--- a/examples/client/inspect-contact.c
+++ b/examples/client/inspect-contact.c
@@ -44,75 +44,62 @@ display_contact (TpContact *contact)
}
static void
-contacts_upgraded_cb (TpConnection *connection,
- guint n_contacts,
- TpContact * const *contacts,
- const GError *error,
- gpointer user_data,
- GObject *weak_object)
+contacts_upgraded_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
{
+ TpConnection *connection = (TpConnection *) object;
InspectContactData *data = user_data;
+ GPtrArray *contacts;
+ GError *error = NULL;
- if (error == NULL)
+ if (!tp_connection_upgrade_contacts_finish (connection, result,
+ &contacts, &error))
+ {
+ g_warning ("Error getting contacts: %s", error->message);
+ data->exit_status = 1;
+ g_clear_error (&error);
+ }
+ else
{
guint i;
data->exit_status = 0;
- for (i = 0; i < n_contacts; i++)
+ for (i = 0; i < contacts->len; i++)
{
- display_contact (contacts[i]);
+ display_contact (g_ptr_array_index (contacts, i));
}
- }
- else
- {
- g_warning ("Error getting contacts: %s", error->message);
- data->exit_status = 1;
+ g_ptr_array_unref (contacts);
}
g_main_loop_quit (data->main_loop);
}
static void
-got_contacts_by_id (TpConnection *connection,
- guint n_contacts,
- TpContact * const *contacts,
- const gchar * const *good_ids,
- GHashTable *bad_ids,
- const GError *error,
- gpointer user_data,
- GObject *weak_object)
+got_contacts_by_id (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
{
+ TpConnection *connection = (TpConnection *) object;
InspectContactData *data = user_data;
+ TpContact *contact;
+ GError *error = NULL;
- if (error == NULL)
- {
- guint i;
- GHashTableIter hash_iter;
- gpointer key, value;
-
- data->exit_status = 0;
-
- for (i = 0; i < n_contacts; i++)
- {
- display_contact (contacts[i]);
- }
-
- g_hash_table_iter_init (&hash_iter, bad_ids);
-
- while (g_hash_table_iter_next (&hash_iter, &key, &value))
- {
- gchar *id = key;
- GError *e = value;
+ contact = tp_connection_dup_contact_by_id_finish (connection, result, &error);
- g_warning ("Invalid ID \"%s\": %s", id, e->message);
- data->exit_status = 1;
- }
- }
- else
+ if (contact == NULL)
{
g_warning ("Error getting contacts: %s", error->message);
data->exit_status = 1;
+ g_clear_error (&error);
+ }
+ else
+ {
+ data->exit_status = 0;
+
+ display_contact (contact);
+ g_object_unref (contact);
}
g_main_loop_quit (data->main_loop);
@@ -146,21 +133,19 @@ connection_ready_cb (GObject *source,
{
TpContact *self_contact = tp_connection_get_self_contact (connection);
- tp_connection_upgrade_contacts (connection,
+ tp_connection_upgrade_contacts_async (connection,
1, &self_contact,
features,
contacts_upgraded_cb,
- data, NULL, NULL);
+ data);
}
else
{
- const gchar *contacts[] = { data->to_inspect, NULL };
-
- tp_connection_get_contacts_by_id (connection,
- 1, contacts,
+ tp_connection_dup_contact_by_id_async (connection,
+ data->to_inspect,
features,
got_contacts_by_id,
- data, NULL, NULL);
+ data);
}
}
diff --git a/examples/cm/echo-message-parts/chan.c b/examples/cm/echo-message-parts/chan.c
index 7c1d8d450..47325793b 100644
--- a/examples/cm/echo-message-parts/chan.c
+++ b/examples/cm/echo-message-parts/chan.c
@@ -29,6 +29,8 @@ G_DEFINE_TYPE_WITH_CODE (ExampleEcho2Channel,
TP_TYPE_BASE_CHANNEL,
G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_TYPE_TEXT,
tp_message_mixin_iface_init)
+ G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_CHAT_STATE,
+ tp_message_mixin_chat_state_iface_init)
G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_DESTROYABLE,
destroyable_iface_init)
G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_SMS, sms_iface_init)
@@ -46,6 +48,8 @@ example_echo_2_channel_get_interfaces (TpBaseChannel *self)
g_ptr_array_add (interfaces, TP_IFACE_CHANNEL_INTERFACE_DESTROYABLE);
g_ptr_array_add (interfaces, TP_IFACE_CHANNEL_INTERFACE_SMS);
+ g_ptr_array_add (interfaces, TP_IFACE_CHANNEL_INTERFACE_CHAT_STATE);
+
return interfaces;
};
@@ -173,6 +177,13 @@ finally:
}
}
+static gboolean
+send_chat_state (GObject *object,
+ TpChannelChatState state,
+ GError **error)
+{
+ return TRUE;
+}
static GObject *
constructor (GType type,
@@ -203,6 +214,8 @@ constructor (GType type,
TP_DELIVERY_REPORTING_SUPPORT_FLAG_RECEIVE_FAILURES,
content_types);
+ tp_message_mixin_implement_send_chat_state (object, send_chat_state);
+
return object;
}
@@ -219,6 +232,8 @@ example_echo_2_channel_close (TpBaseChannel *self)
{
GObject *object = (GObject *) self;
+ tp_message_mixin_maybe_send_gone (object);
+
if (!tp_base_channel_is_destroyed (self))
{
TpHandle first_sender;
diff --git a/spec/Channel_Type_Call1.xml b/spec/Channel_Type_Call1.xml
index 548b79ce4..6809ff269 100644
--- a/spec/Channel_Type_Call1.xml
+++ b/spec/Channel_Type_Call1.xml
@@ -917,13 +917,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
<p>The change was requested by the contact indicated by the Actor
member of a <tp:type>Call_State_Reason</tp:type> struct.</p>
- <p>If the Actor is the local user, the DBus_Reason SHOULD be the
- empty string.</p>
-
- <p>If the Actor is a remote user, the DBus_Reason SHOULD be the empty
- string if the call was terminated normally, but MAY be a non-empty
- error name to indicate error-like call termination reasons (call
- rejected as busy, kicked from a conference by a moderator, etc.).</p>
+ <p>The DBus_Reason SHOULD be the empty string if the call
+ was terminated normally, but MAY be a non-empty error name
+ to indicate error-like call termination reasons (kicked from
+ a conference by a moderator, etc.).</p>
</tp:docstring>
</tp:enumvalue>
diff --git a/spec/Connection_Interface_Contacts.xml b/spec/Connection_Interface_Contacts.xml
index 1a16d2468..c2be7ff9d 100644
--- a/spec/Connection_Interface_Contacts.xml
+++ b/spec/Connection_Interface_Contacts.xml
@@ -171,6 +171,64 @@
<tp:error name="im.telepathy1.Error.Disconnected"/>
</tp:possible-errors>
</method>
+
+ <method name="GetContactByID"
+ tp:name-for-bindings="Get_Contact_By_ID">
+ <tp:added version="0.27.0"/>
+ <tp:docstring>
+ Return any number of contact attributes for the given identifier.
+ <tp:rationale>
+ This is for a single identifier to make it simpler to use for the most
+ common use case. For multiple contacts case,
+ <tp:member-ref>GetContactAttributes</tp:member-ref> should be used.
+ </tp:rationale>
+ </tp:docstring>
+
+ <arg direction="in" name="Identifier" type="s">
+ <tp:docstring>
+ An identifier representing a contact.
+ </tp:docstring>
+ </arg>
+
+ <arg direction="in" name="Interfaces" type="as"
+ tp:type="DBus_Interface[]">
+ <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
+ <p>A list of strings indicating which D-Bus interfaces the calling
+ process is interested in. All supported attributes from these
+ interfaces, whose values can be obtained without additional network
+ activity, will be in the reply.</p>
+ <p>See <tp:member-ref>GetContactAttributes</tp:member-ref> for
+ details.</p>
+ </tp:docstring>
+ </arg>
+
+ <arg direction="out" name="Handle" type="u" tp:type="Contact_Handle">
+ <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
+ <p>The contact's handle, as returned by <tp:dbus-ref
+ namespace="ofdT.Connection">RequestHandles</tp:dbus-ref></p>
+ </tp:docstring>
+ </arg>
+
+ <arg direction="out" type="a{sv}" name="Attributes"
+ tp:type="Single_Contact_Attributes_Map">
+ <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
+ <p>All supported attributes of the contact on
+ the given interfaces that can be returned without network
+ round-trips. If contact attributes are not immediately known, the
+ behaviour is defined by the interface; the attribute should either
+ be omitted from the result or replaced with a default value.</p>
+
+ <p>The contact's attributes will always include at least the
+ identifier that would be obtained by inspecting the handle
+ (<code>org.freedesktop.Telepathy.Connection/contact-id</code>).</p>
+ </tp:docstring>
+ </arg>
+
+ <tp:possible-errors>
+ <tp:error name="org.freedesktop.Telepathy.Error.Disconnected"/>
+ <tp:error name="org.freedesktop.Telepathy.Error.InvalidHandle"/>
+ </tp:possible-errors>
+ </method>
</interface>
</node>
<!-- vim:set sw=2 sts=2 et ft=xml: -->
diff --git a/spec/Connection_Manager.xml b/spec/Connection_Manager.xml
index abcdae7db..090908a31 100644
--- a/spec/Connection_Manager.xml
+++ b/spec/Connection_Manager.xml
@@ -216,7 +216,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.</
</tp:mapping>
<property name="Protocols" tp:name-for-bindings="Protocols"
- access="read" type="a{sa{sv}}" tp:type="Protocol_Properties_Map">
+ access="read" type="a{sa{sv}}" tp:type="Protocol_Properties_Map"
+ tp:immutable="yes">
<tp:docstring xmlns="http://www.w3.org/1999/xhtml">
<p>A map from protocol identifiers supported by this connection
manager to the immutable properties of the corresponding
diff --git a/spec/Protocol_Interface_Presence1.xml b/spec/Protocol_Interface_Presence1.xml
index 9ae79e5ca..a0cc12588 100644
--- a/spec/Protocol_Interface_Presence1.xml
+++ b/spec/Protocol_Interface_Presence1.xml
@@ -96,7 +96,8 @@ status-chat=2 settable message
<property name="Statuses"
tp:name-for-bindings="Statuses"
- type="a{s(ubb)}" tp:type="Status_Spec_Map" access="read">
+ type="a{s(ubb)}" tp:type="Status_Spec_Map" access="read"
+ tp:immutable="yes">
<tp:docstring>
<p>The statuses that might appear in the <tp:dbus-ref
namespace="im.telepathy1"
diff --git a/spec/all.xml b/spec/all.xml
index a792a09fd..8e903f59e 100644
--- a/spec/all.xml
+++ b/spec/all.xml
@@ -3,7 +3,7 @@
xmlns:xi="http://www.w3.org/2001/XInclude">
<tp:title>Telepathy D-Bus Interface Specification</tp:title>
-<tp:version>0.25.2.1</tp:version>
+<tp:version>0.27.0</tp:version>
<tp:copyright>Copyright © 2005-2012 Collabora Limited</tp:copyright>
<tp:copyright>Copyright © 2005-2011 Nokia Corporation</tp:copyright>
@@ -141,7 +141,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.</
<xi:include href="Channel_Type_Text.xml"/>
</tp:section>
- <tp:section name="Channel Interfaces">
+ <tp:section name="Channel interfaces">
<tp:docstring xmlns="http://www.w3.org/1999/xhtml">
<p>
A Channel may also implement one or more of the following interfaces,
@@ -217,6 +217,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.</
</tp:section>
<tp:section name="Calls">
+<<<<<<< HEAD
<xi:include href="Call1_Content.xml"/>
<xi:include href="Call1_Content_Interface_Media.xml"/>
<xi:include href="Call1_Interface_Mute.xml"/>
@@ -231,6 +232,34 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.</
<xi:include href="Call1_Stream.xml"/>
<xi:include href="Call1_Stream_Interface_Media.xml"/>
<xi:include href="Call1_Stream_Endpoint.xml"/>
+=======
+ <xi:include href="Call_Content.xml"/>
+ <xi:include href="Call_Content_Interface_DTMF.xml"/>
+ <xi:include href="Call_Stream.xml"/>
+ <xi:include href="Call_Interface_Mute.xml"/>
+ </tp:section>
+
+ <tp:section name="Call media interfaces">
+ <tp:docstring xmlns="http://www.w3.org/1999/xhtml">
+ <p>
+ These interfaces are used when a <tp:dbus-ref
+ namespace='ofdT.Channel.Type'>Call1</tp:dbus-ref> channel
+ doesn't have <tp:dbus-ref
+ namespace="ofdT.Channel.Type.Call1">HardwareStreaming</tp:dbus-ref> to
+ implement the media streaming aspects of a call.
+ </p>
+ </tp:docstring>
+ <xi:include href="Call_Content_Interface_Media.xml"/>
+ <xi:include href="Call_Content_Interface_Video_Control.xml"/>
+ <xi:include href="Call_Content_Interface_Audio_Control.xml"/>
+ <xi:include href="Call_Content_Media_Description.xml"/>
+ <xi:include href="Call_Content_Media_Description_Interface_RTP_Header_Extensions.xml"/>
+ <xi:include href="Call_Content_Media_Description_Interface_RTCP_Feedback.xml"/>
+ <xi:include
+ href="Call_Content_Media_Description_Interface_RTCP_Extended_Reports.xml"/>
+ <xi:include href="Call_Stream_Interface_Media.xml"/>
+ <xi:include href="Call_Stream_Endpoint.xml"/>
+>>>>>>> master
</tp:section>
<tp:section name="Debugging">
diff --git a/telepathy-glib/Makefile.am b/telepathy-glib/Makefile.am
index bf0f9338f..aeba99057 100644
--- a/telepathy-glib/Makefile.am
+++ b/telepathy-glib/Makefile.am
@@ -126,6 +126,8 @@ tpginclude_HEADERS = \
stream-tube-connection.h \
telepathy-glib.h \
text-channel.h \
+ tls-certificate.h \
+ tls-certificate-rejection.h \
util.h \
$(NULL)
@@ -328,6 +330,9 @@ libtelepathy_glib_main_internal_la_SOURCES = \
stream-tube-connection-internal.h \
stream-tube-connection.c \
text-channel.c \
+ tls-certificate.c \
+ tls-certificate-rejection.c \
+ tls-certificate-rejection-internal.h \
util.c \
util-internal.h
diff --git a/telepathy-glib/account-channel-request.c b/telepathy-glib/account-channel-request.c
index a3128fa81..fbc4bd00f 100644
--- a/telepathy-glib/account-channel-request.c
+++ b/telepathy-glib/account-channel-request.c
@@ -1634,7 +1634,7 @@ _tp_account_channel_request_get_client (TpAccountChannelRequest *self)
* This function can't be called once @self has been used to request a
* channel.
*
- * Since: 0.19.UNRELEASED
+ * Since: 0.19.0
*/
void
tp_account_channel_request_set_target_contact (
@@ -1669,7 +1669,7 @@ tp_account_channel_request_set_target_contact (
* This function can't be called once @self has been used to request a
* channel.
*
- * Since: 0.19.UNRELEASED
+ * Since: 0.19.0
*/
void
tp_account_channel_request_set_target_id (
@@ -1710,7 +1710,7 @@ tp_account_channel_request_set_target_id (
*
* Returns: a new #TpAccountChannelRequest object
*
- * Since: 0.19.UNRELEASED
+ * Since: 0.19.0
*/
TpAccountChannelRequest *
tp_account_channel_request_new_text (
@@ -1769,7 +1769,7 @@ tp_account_channel_request_new_text (
* This function can't be called once @self has been used to request a
* channel.
*
- * Since: 0.19.UNRELEASED
+ * Since: 0.19.0
*/
void
tp_account_channel_request_set_request_property (
@@ -1828,7 +1828,7 @@ tp_account_channel_request_set_request_property (
*
* Returns: a new #TpAccountChannelRequest object
*
- * Since: 0.19.UNRELEASED
+ * Since: 0.19.0
*/
TpAccountChannelRequest *
tp_account_channel_request_new_audio_call (
@@ -1877,7 +1877,7 @@ tp_account_channel_request_new_audio_call (
*
* Returns: a new #TpAccountChannelRequest object
*
- * Since: 0.19.UNRELEASED
+ * Since: 0.19.0
*/
TpAccountChannelRequest *
tp_account_channel_request_new_audio_video_call (
@@ -1930,7 +1930,7 @@ tp_account_channel_request_new_audio_video_call (
*
* Returns: a new #TpAccountChannelRequest object
*
- * Since: 0.19.UNRELEASED
+ * Since: 0.19.0
*/
TpAccountChannelRequest *
tp_account_channel_request_new_file_transfer (
@@ -1984,7 +1984,7 @@ tp_account_channel_request_new_file_transfer (
* This function can't be called once @self has been used to request a
* channel.
*
- * Since: 0.19.UNRELEASED
+ * Since: 0.19.0
*/
void
tp_account_channel_request_set_file_transfer_description (
@@ -2032,7 +2032,7 @@ tp_account_channel_request_set_file_transfer_description (
* This function can't be called once @self has been used to request a
* channel.
*
- * Since: 0.19.UNRELEASED
+ * Since: 0.19.0
*/
void
tp_account_channel_request_set_file_transfer_uri (
@@ -2067,7 +2067,7 @@ tp_account_channel_request_set_file_transfer_uri (
* This function can't be called once @self has been used to request a
* channel.
*
- * Since: 0.19.UNRELEASED
+ * Since: 0.19.0
*/
void
tp_account_channel_request_set_file_transfer_timestamp (
@@ -2103,7 +2103,7 @@ tp_account_channel_request_set_file_transfer_timestamp (
* This function can't be called once @self has been used to request a
* channel.
*
- * Since: 0.19.UNRELEASED
+ * Since: 0.19.0
*/
void
tp_account_channel_request_set_file_transfer_initial_offset (
diff --git a/telepathy-glib/account.c b/telepathy-glib/account.c
index f085c9deb..466ecc3e0 100644
--- a/telepathy-glib/account.c
+++ b/telepathy-glib/account.c
@@ -465,6 +465,18 @@ OUT:
g_object_unref (self);
}
+static void _tp_account_set_connection (TpAccount *account, const gchar *path);
+
+static void
+connection_invalidated_cb (TpConnection *connection,
+ guint domain,
+ gint code,
+ gchar *message,
+ TpAccount *account)
+{
+ _tp_account_set_connection (account, "/");
+}
+
static void
_tp_account_set_connection (TpAccount *account,
const gchar *path)
@@ -474,14 +486,17 @@ _tp_account_set_connection (TpAccount *account,
gboolean have_public_connection;
GError *error = NULL;
- /* Do nothing if we already have a connection for the same path */
if (priv->connection != NULL)
{
const gchar *current;
+ /* Do nothing if we already have a connection for the same path */
current = tp_proxy_get_object_path (priv->connection);
if (!tp_strdiff (current, path))
return;
+
+ g_signal_handlers_disconnect_by_func (priv->connection,
+ connection_invalidated_cb, account);
}
had_public_connection = (priv->connection != NULL &&
@@ -514,6 +529,9 @@ _tp_account_set_connection (TpAccount *account,
}
else
{
+ tp_g_signal_connect_object (priv->connection, "invalidated",
+ G_CALLBACK (connection_invalidated_cb), account, 0);
+
_tp_connection_set_account (priv->connection, account);
if (tp_proxy_is_prepared (account, TP_ACCOUNT_FEATURE_CONNECTION))
{
@@ -1162,7 +1180,7 @@ _tp_account_dispose (GObject *object)
priv->dispose_has_run = TRUE;
- tp_clear_object (&self->priv->connection);
+ _tp_account_set_connection (self, "/");
/* release any references held by the object here */
if (G_OBJECT_CLASS (tp_account_parent_class)->dispose != NULL)
@@ -2777,20 +2795,16 @@ tp_account_update_parameters_vardict_async (TpAccount *account,
GAsyncReadyCallback callback,
gpointer user_data)
{
- GValue v = G_VALUE_INIT;
+ GHashTable *hash;
- g_return_if_fail (parameters != NULL);
- g_return_if_fail (g_variant_is_of_type (parameters, G_VARIANT_TYPE_VARDICT));
+ hash = _tp_asv_from_vardict (parameters);
g_variant_ref_sink (parameters);
- dbus_g_value_parse_g_variant (parameters, &v);
- g_assert (G_VALUE_HOLDS (&v, TP_HASH_TYPE_STRING_VARIANT_MAP));
-
- tp_account_update_parameters_async (account, g_value_get_boxed (&v),
+ tp_account_update_parameters_async (account, hash,
unset_parameters, callback, user_data);
- g_value_unset (&v);
g_variant_unref (parameters);
+ g_hash_table_unref (hash);
}
/**
diff --git a/telepathy-glib/base-connection.c b/telepathy-glib/base-connection.c
index 8bb894e0c..e7d15c2b0 100644
--- a/telepathy-glib/base-connection.c
+++ b/telepathy-glib/base-connection.c
@@ -227,6 +227,7 @@
#include <telepathy-glib/contacts-mixin.h>
#include <telepathy-glib/dbus-properties-mixin.h>
#include <telepathy-glib/dbus.h>
+#include <telepathy-glib/dbus-internal.h>
#include <telepathy-glib/exportable-channel.h>
#include <telepathy-glib/gtypes.h>
#include <telepathy-glib/interfaces.h>
@@ -1893,29 +1894,25 @@ tp_base_connection_disconnect_with_dbus_error_vardict (TpBaseConnection *self,
GVariant *details,
TpConnectionStatusReason reason)
{
- GValue value = G_VALUE_INIT;
+ GHashTable *hash;
g_return_if_fail (TP_IS_BASE_CONNECTION (self));
g_return_if_fail (tp_dbus_check_valid_interface_name (error_name, NULL));
- g_return_if_fail (g_variant_is_of_type (details, G_VARIANT_TYPE_VARDICT));
if (details == NULL)
{
- g_value_init (&value, TP_HASH_TYPE_STRING_VARIANT_MAP);
- g_value_take_boxed (&value, g_hash_table_new (g_str_hash, g_str_equal));
+ hash = g_hash_table_new (g_str_hash, g_str_equal);
}
else
{
- dbus_g_value_parse_g_variant (details, &value);
- g_assert (G_VALUE_TYPE (&value) == TP_HASH_TYPE_STRING_VARIANT_MAP);
+ hash = _tp_asv_from_vardict (details);
}
- tp_svc_connection_emit_connection_error (self, error_name,
- g_value_get_boxed (&value));
+ tp_svc_connection_emit_connection_error (self, error_name, hash);
tp_base_connection_change_status (self, TP_CONNECTION_STATUS_DISCONNECTED,
reason);
- g_value_unset (&value);
+ g_hash_table_unref (hash);
}
/**
diff --git a/telepathy-glib/capabilities.c b/telepathy-glib/capabilities.c
index 4913ceee6..633617da4 100644
--- a/telepathy-glib/capabilities.c
+++ b/telepathy-glib/capabilities.c
@@ -264,7 +264,7 @@ tp_capabilities_class_init (TpCapabilitiesClass *klass)
* tp_capabilities_supports_text_chats() are likely to be more useful to
* the majority of clients.
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
param_spec = g_param_spec_variant ("channel-classes-variant",
"GVariant of type a(a{sv}as)",
@@ -419,7 +419,7 @@ tp_capabilities_supports_text_chatrooms (TpCapabilities *self)
* #TP_PROP_CHANNEL_INTERFACE_SMS_SMS_CHANNEL set to %TRUE can be
* expected to work, %FALSE otherwise.
*
- * Since: 0.UNRELEASED
+ * Since: 0.19.0
*/
gboolean
tp_capabilities_supports_sms (TpCapabilities *self)
@@ -727,7 +727,7 @@ tp_capabilities_supports_file_transfer (TpCapabilities *self)
* tp_capabilities_supports_file_transfer() can also specify the outgoing
* file's URI
*
- * Since: 0.19.UNRELEASED
+ * Since: 0.19.0
*/
gboolean
tp_capabilities_supports_file_transfer_uri (TpCapabilities *self)
@@ -745,7 +745,7 @@ tp_capabilities_supports_file_transfer_uri (TpCapabilities *self)
* tp_capabilities_supports_file_transfer() can also specify the outgoing
* file's description
*
- * Since: 0.19.UNRELEASED
+ * Since: 0.19.0
*/
gboolean
tp_capabilities_supports_file_transfer_description (TpCapabilities *self)
@@ -765,7 +765,7 @@ tp_capabilities_supports_file_transfer_description (TpCapabilities *self)
* tp_capabilities_supports_file_transfer() can also specify an
* initial offset greater than 0
*
- * Since: 0.19.UNRELEASED
+ * Since: 0.19.0
*/
gboolean
tp_capabilities_supports_file_transfer_initial_offset (TpCapabilities *self)
@@ -783,7 +783,7 @@ tp_capabilities_supports_file_transfer_initial_offset (TpCapabilities *self)
* tp_capabilities_supports_file_transfer() can also specify the outgoing
* file's timestamp
*
- * Since: 0.19.UNRELEASED
+ * Since: 0.19.0
*/
gboolean
tp_capabilities_supports_file_transfer_timestamp (TpCapabilities *self)
@@ -1085,7 +1085,7 @@ tp_capabilities_supports_room_list (TpCapabilities *self,
* Returns: (transfer full): the value of the
* #TpCapabilities:channel-classes-variant property
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
GVariant *
tp_capabilities_dup_channel_classes_variant (TpCapabilities *self)
diff --git a/telepathy-glib/channel-contacts.c b/telepathy-glib/channel-contacts.c
index 1c79237e8..3e8cd50c5 100644
--- a/telepathy-glib/channel-contacts.c
+++ b/telepathy-glib/channel-contacts.c
@@ -341,6 +341,10 @@ process_contacts_queue (TpChannel *self)
features = tp_client_factory_dup_contact_features (
tp_proxy_get_factory (self->priv->connection), self->priv->connection);
+ /* We can't use upgrade_contacts_async() because we need compat with older
+ * CMs. by_id and by_handle are used only by TpTextChannel and are needed for
+ * older CMs that does not give both message-sender and message-sender-id */
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
if (item->contacts != NULL && item->contacts->len > 0)
{
g_assert (item->ids == NULL);
@@ -385,6 +389,7 @@ process_contacts_queue (TpChannel *self)
* without reentering mainloop first. */
g_idle_add (contacts_queue_item_idle_cb, self);
}
+ G_GNUC_END_IGNORE_DEPRECATIONS
g_array_unref (features);
}
@@ -600,7 +605,8 @@ _tp_channel_contacts_members_changed (TpChannel *self,
ids = tp_asv_get_boxed (details, "contact-ids",
TP_HASH_TYPE_HANDLE_IDENTIFIER_MAP);
- if (ids == NULL)
+ if (ids == NULL && (added->len > 0 || local_pending->len > 0 ||
+ remote_pending->len > 0 || actor != 0 ))
{
DEBUG ("CM did not give identifiers, can't create TpContact");
return;
diff --git a/telepathy-glib/channel.c b/telepathy-glib/channel.c
index 97af2acaa..faa5d2d5d 100644
--- a/telepathy-glib/channel.c
+++ b/telepathy-glib/channel.c
@@ -210,6 +210,7 @@ tp_channel_get_feature_quark_contacts (void)
* tp_proxy_prepare_async() function, and waiting for it to callback.
*
* Since: 0.11.3
+ * Deprecated: Use TP_TEXT_CHANNEL_FEATURE_CHAT_STATES instead.
*/
GQuark
@@ -490,6 +491,7 @@ tp_channel_get_property (GObject *object,
* Returns: the chat state for @contact, or %TP_CHANNEL_CHAT_STATE_INACTIVE
* if their chat state is not known
* Since: 0.11.3
+ * Deprecated: Use tp_text_channel_get_chat_state() instead.
*/
TpChannelChatState
tp_channel_get_chat_state (TpChannel *self,
@@ -696,9 +698,11 @@ tp_channel_chat_state_changed_cb (TpChannel *self,
g_hash_table_insert (self->priv->chat_states,
GUINT_TO_POINTER (contact), GUINT_TO_POINTER (state));
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
/* Don't emit the signal until we've had the initial state */
if (!tp_proxy_is_prepared (self, TP_CHANNEL_FEATURE_CHAT_STATES))
return;
+ G_GNUC_END_IGNORE_DEPRECATIONS
g_signal_emit (self, signals[SIGNAL_CHAT_STATE_CHANGED], 0, contact, state);
}
@@ -905,19 +909,19 @@ _tp_channel_prepare_connection (TpChannel *self)
}
static void
-upgrade_contacts_cb (TpConnection *connection,
- guint n_contacts,
- TpContact * const *contacts,
- const GError *error,
- gpointer user_data,
- GObject *weak_object)
+upgrade_contacts_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
{
- TpChannel *self = (TpChannel *) weak_object;
+ TpChannel *self = user_data;
+ TpConnection *connection = (TpConnection *) object;
+ GError *error = NULL;
- if (error != NULL)
+ if (!tp_connection_upgrade_contacts_finish (connection, result, NULL, &error))
{
_tp_channel_abort_introspection (self, "Upgrading contacts failed",
error);
+ g_clear_error (&error);
return;
}
@@ -985,10 +989,10 @@ _tp_channel_create_contacts (TpChannel *self)
tp_proxy_get_factory (self->priv->connection),
self->priv->connection);
- tp_connection_upgrade_contacts (self->priv->connection,
+ tp_connection_upgrade_contacts_async (self->priv->connection,
contacts->len, (TpContact **) contacts->pdata,
(GQuark *) features->data,
- upgrade_contacts_cb, NULL, NULL, (GObject *) self);
+ upgrade_contacts_cb, self);
g_array_unref (features);
}
@@ -1275,11 +1279,13 @@ tp_channel_list_features (TpProxyClass *cls G_GNUC_UNUSED)
features[FEAT_CONTACTS].prepare_async =
_tp_channel_contacts_prepare_async;
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
features[FEAT_CHAT_STATES].name = TP_CHANNEL_FEATURE_CHAT_STATES;
features[FEAT_CHAT_STATES].prepare_async =
tp_channel_prepare_chat_states_async;
need_chat_states[0] = TP_IFACE_QUARK_CHANNEL_INTERFACE_CHAT_STATE;
features[FEAT_CHAT_STATES].interfaces_needed = need_chat_states;
+ G_GNUC_END_IGNORE_DEPRECATIONS
features[FEAT_PASSWORD].name = TP_CHANNEL_FEATURE_PASSWORD;
features[FEAT_PASSWORD].prepare_async =
@@ -1526,6 +1532,7 @@ tp_channel_class_init (TpChannelClass *klass)
* has finished preparing the feature %TP_CHANNEL_FEATURE_CHAT_STATES.
*
* Since: 0.11.3
+ * Deprecated: Use #TpTextChannel::contact-chat-state-changed instead
*/
signals[SIGNAL_CHAT_STATE_CHANGED] = g_signal_new ("chat-state-changed",
G_OBJECT_CLASS_TYPE (klass),
diff --git a/telepathy-glib/channel.h b/telepathy-glib/channel.h
index 470c96620..73da1abe7 100644
--- a/telepathy-glib/channel.h
+++ b/telepathy-glib/channel.h
@@ -194,7 +194,10 @@ TpContact *tp_channel_group_get_contact_owner (TpChannel *self,
#define TP_CHANNEL_FEATURE_CHAT_STATES \
tp_channel_get_feature_quark_chat_states ()
+_TP_DEPRECATED_IN_0_20_FOR(tp_text_channel_get_feature_quark_chat_states)
GQuark tp_channel_get_feature_quark_chat_states (void) G_GNUC_CONST;
+
+_TP_DEPRECATED_IN_0_20_FOR(tp_text_channel_get_chat_state)
TpChannelChatState tp_channel_get_chat_state (TpChannel *self,
TpHandle contact);
diff --git a/telepathy-glib/cli-misc.h b/telepathy-glib/cli-misc.h
index 1dc079b8f..7c8bc9b63 100644
--- a/telepathy-glib/cli-misc.h
+++ b/telepathy-glib/cli-misc.h
@@ -32,6 +32,7 @@
#include <telepathy-glib/debug-client.h>
#include <telepathy-glib/protocol.h>
#include <telepathy-glib/proxy.h>
+#include <telepathy-glib/tls-certificate.h>
#include <telepathy-glib/_gen/tp-cli-account.h>
#include <telepathy-glib/_gen/tp-cli-account-manager.h>
@@ -44,6 +45,7 @@
#include <telepathy-glib/_gen/tp-cli-debug.h>
#include <telepathy-glib/_gen/tp-cli-generic.h>
#include <telepathy-glib/_gen/tp-cli-protocol.h>
+#include <telepathy-glib/_gen/tp-cli-tls-cert.h>
#endif
diff --git a/telepathy-glib/codegen.am b/telepathy-glib/codegen.am
index a7668b8ad..4135d16e4 100644
--- a/telepathy-glib/codegen.am
+++ b/telepathy-glib/codegen.am
@@ -66,6 +66,7 @@ nodist_gendbusinclude_HEADERS += \
_gen/tp-cli-debug.h \
_gen/tp-cli-generic.h \
_gen/tp-cli-protocol.h \
+ _gen/tp-cli-tls-cert.h \
_gen/tp-svc-account.h \
_gen/tp-svc-account-manager.h \
_gen/tp-svc-call-content.h \
@@ -117,6 +118,7 @@ nodist_libtelepathy_glib_dbus_internal_la_SOURCES += \
_gen/tp-cli-debug-body.h \
_gen/tp-cli-generic-body.h \
_gen/tp-cli-protocol-body.h \
+ _gen/tp-cli-tls-cert-body.h \
_gen/tp-svc-account.c \
_gen/tp-svc-account-manager.c \
_gen/tp-svc-call-content.c \
@@ -319,6 +321,10 @@ _gen/tp-cli-%-body.h: _gen/tp-spec-%.xml \
subclass=--subclass=TpDebugClient; \
subclass_assert=--subclass-assert=TP_IS_DEBUG_CLIENT; \
;; \
+ tls-cert) \
+ subclass=--subclass=TpTLSCertificate; \
+ subclass_assert=--subclass-assert=TP_IS_TLS_CERTIFICATE; \
+ ;; \
esac; \
$(PYTHON) $(tools_dir)/glib-client-gen.py \
$$subclass $$subclass_assert \
diff --git a/telepathy-glib/connection-contact-list.c b/telepathy-glib/connection-contact-list.c
index 965632beb..4cd8fcb14 100644
--- a/telepathy-glib/connection-contact-list.c
+++ b/telepathy-glib/connection-contact-list.c
@@ -136,16 +136,17 @@ contacts_changed_head_ready (TpConnection *self)
}
static void
-new_contacts_upgraded_cb (TpConnection *self,
- guint n_contacts,
- TpContact * const *contacts,
- const GError *error,
- gpointer user_data,
- GObject *weak_object)
+new_contacts_upgraded_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
{
- if (error != NULL)
+ TpConnection *self = (TpConnection *) object;
+ GError *error = NULL;
+
+ if (!tp_connection_upgrade_contacts_finish (self, result, NULL, &error))
{
DEBUG ("Error upgrading new roster contacts: %s", error->message);
+ g_clear_error (&error);
}
contacts_changed_head_ready (self);
@@ -191,10 +192,10 @@ process_queued_contacts_changed (TpConnection *self)
features = tp_client_factory_dup_contact_features (
tp_proxy_get_factory (self), self);
- tp_connection_upgrade_contacts (self,
+ tp_connection_upgrade_contacts_async (self,
item->new_contacts->len, (TpContact **) item->new_contacts->pdata,
(const GQuark *) features->data,
- new_contacts_upgraded_cb, NULL, NULL, NULL);
+ new_contacts_upgraded_cb, NULL);
g_array_unref (features);
}
@@ -1657,31 +1658,32 @@ blocked_changed_head_ready (TpConnection *self)
}
static void
-blocked_contacts_upgraded_cb (TpConnection *self,
- guint n_contacts,
- TpContact * const *contacts,
- const GError *error,
- gpointer user_data,
- GObject *weak_object)
+blocked_contacts_upgraded_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
{
+ TpConnection *self = (TpConnection *) object;
BlockedChangedItem *item;
guint i;
GPtrArray *added, *removed;
+ GPtrArray *contacts;
+ GError *error = NULL;
item = g_queue_peek_head (self->priv->blocked_changed_queue);
- if (error != NULL)
+ if (!tp_connection_upgrade_contacts_finish (self, result, &contacts, &error))
{
DEBUG ("Error upgrading blocked contacts: %s", error->message);
+ g_clear_error (&error);
goto out;
}
added = g_ptr_array_new ();
removed = g_ptr_array_new_with_free_func (g_object_unref);
- for (i = 0; i < n_contacts; i++)
+ for (i = 0; i < contacts->len; i++)
{
- TpContact *contact = contacts[i];
+ TpContact *contact = g_ptr_array_index (contacts, i);
TpHandle handle;
handle = tp_contact_get_handle (contact);
@@ -1720,6 +1722,7 @@ blocked_contacts_upgraded_cb (TpConnection *self,
g_ptr_array_unref (added);
g_ptr_array_unref (removed);
+ g_ptr_array_unref (contacts);
out:
blocked_changed_head_ready (self);
@@ -1784,10 +1787,10 @@ process_queued_blocked_changed (TpConnection *self)
features = tp_client_factory_dup_contact_features (
tp_proxy_get_factory (self), self);
- tp_connection_upgrade_contacts (self,
+ tp_connection_upgrade_contacts_async (self,
contacts->len, (TpContact **) contacts->pdata,
(const GQuark *) features->data,
- blocked_contacts_upgraded_cb, NULL, NULL, NULL);
+ blocked_contacts_upgraded_cb, NULL);
g_array_unref (features);
g_ptr_array_unref (contacts);
diff --git a/telepathy-glib/connection-manager.c b/telepathy-glib/connection-manager.c
index 375dddea5..0a41eaee3 100644
--- a/telepathy-glib/connection-manager.c
+++ b/telepathy-glib/connection-manager.c
@@ -2255,7 +2255,7 @@ tp_connection_manager_param_get_default (
* %G_VARIANT_TYPE_STRING.
*
* Returns: the default value, or %NULL if there is no default
- * Since: 0.19.UNRELEASED
+ * Since: 0.19.0
*/
GVariant *
tp_connection_manager_param_dup_default_variant (
diff --git a/telepathy-glib/connection.c b/telepathy-glib/connection.c
index 59e1470f5..6edc921ef 100644
--- a/telepathy-glib/connection.c
+++ b/telepathy-glib/connection.c
@@ -855,10 +855,12 @@ get_self_contact (TpConnection *self)
* require immortal-handles and spec change to give the self identifier. */
/* This relies on the special case in tp_connection_get_contacts_by_handle()
* which makes it start working slightly early. */
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
tp_connection_get_contacts_by_handle (self,
1, &self->priv->last_known_self_handle,
(GQuark *) features->data,
tp_connection_got_self_contact_cb, NULL, NULL, NULL);
+ G_GNUC_END_IGNORE_DEPRECATIONS
g_array_unref (features);
}
@@ -1292,7 +1294,10 @@ tp_connection_constructed (GObject *object)
tp_cli_dbus_properties_call_get_all (self, -1,
TP_IFACE_CONNECTION, _tp_connection_got_properties, NULL, NULL, NULL);
- g_signal_connect (self, "invalidated",
+ /* Give a chance to TpAccount to know about invalidated connection before we
+ * unref all roster contacts. This is to let applications properly remove all
+ * contacts at once instead of getting weak notify on each. */
+ g_signal_connect_after (self, "invalidated",
G_CALLBACK (tp_connection_invalidated), NULL);
}
@@ -2830,7 +2835,7 @@ tp_connection_get_detailed_error (TpConnection *self,
*
* Returns: (transfer full) (allow-none): a D-Bus error name, or %NULL.
*
- * Since: 0.19.UNRELEASED
+ * Since: 0.19.0
*/
gchar *
tp_connection_dup_detailed_error_vardict (TpConnection *self,
diff --git a/telepathy-glib/contact.c b/telepathy-glib/contact.c
index 2352dfaee..42ffa9369 100644
--- a/telepathy-glib/contact.c
+++ b/telepathy-glib/contact.c
@@ -116,7 +116,7 @@ tp_contact_get_feature_quark_alias (void)
* retrieved. In particular, the #TpContact:avatar-token property has
* been set.
*
- * Since: 0.UNRELEASED
+ * Since: 0.19.0
*/
GQuark
@@ -419,7 +419,7 @@ struct _TpContactPrivate {
* (it must be referenced with g_object_ref if it must remain valid
* longer than the contact)
*
- * Since: 0.UNRELEASED
+ * Since: 0.19.0
*/
TpAccount *
tp_contact_get_account (TpContact *self)
@@ -3606,6 +3606,7 @@ contacts_context_remove_common_features (ContactsContext *context)
* connection managers.
*
* Since: 0.7.18
+ * Deprecated: Use tp_client_factory_ensure_contact() instead.
*/
void
tp_connection_get_contacts_by_handle (TpConnection *self,
@@ -3686,6 +3687,7 @@ tp_connection_get_contacts_by_handle (TpConnection *self,
* connection managers.
*
* Since: 0.7.18
+ * Deprecated: Use tp_connection_upgrade_contacts_async() instead.
*/
void
tp_connection_upgrade_contacts (TpConnection *self,
@@ -3889,6 +3891,7 @@ contacts_requested_handles (TpConnection *connection,
* connection managers.
*
* Since: 0.7.18
+ * Deprecated: Use tp_connection_get_contact_by_id_async() instead.
*/
void
tp_connection_get_contacts_by_id (TpConnection *self,
@@ -3941,6 +3944,298 @@ tp_connection_get_contacts_by_id (TpConnection *self,
weak_object);
}
+typedef struct
+{
+ GSimpleAsyncResult *result;
+ ContactFeatureFlags features;
+} ContactsAsyncData;
+
+static ContactsAsyncData *
+contacts_async_data_new (GSimpleAsyncResult *result,
+ ContactFeatureFlags features)
+{
+ ContactsAsyncData *data;
+
+ data = g_slice_new0 (ContactsAsyncData);
+ data->result = g_object_ref (result);
+ data->features = features;
+
+ return data;
+}
+
+static void
+contacts_async_data_free (ContactsAsyncData *data)
+{
+ g_object_unref (data->result);
+ g_slice_free (ContactsAsyncData, data);
+}
+
+static void
+got_contact_by_id_cb (TpConnection *self,
+ TpHandle handle,
+ GHashTable *attributes,
+ const GError *error,
+ gpointer user_data,
+ GObject *weak_object)
+{
+ ContactsAsyncData *data = user_data;
+ TpContact *contact;
+ GError *e = NULL;
+
+ if (error != NULL)
+ {
+ g_simple_async_result_set_from_error (data->result, error);
+ g_simple_async_result_complete (data->result);
+ return;
+ }
+
+ /* set up the contact with its attributes */
+ contact = tp_contact_ensure (self, handle);
+ g_simple_async_result_set_op_res_gpointer (data->result,
+ contact, g_object_unref);
+
+ if (!tp_contact_set_attributes (contact, attributes, data->features, &e))
+ g_simple_async_result_take_error (data->result, e);
+
+ g_simple_async_result_complete (data->result);
+}
+
+/**
+ * tp_connection_dup_contact_by_id_async:
+ * @self: A connection, which must have the %TP_CONNECTION_FEATURE_CONNECTED
+ * feature prepared
+ * @id: A strings representing the desired contact by its
+ * identifier in the IM protocol (an XMPP JID, SIP URI, MSN Passport,
+ * AOL screen-name etc.)
+ * @features: (transfer-none) (array zero-terminated=1) (allow-none)
+ * (element-type GLib.Quark): An array of features that must be ready for
+ * @callback: A user callback to call when the contact is ready
+ * @user_data: Data to pass to the callback
+ *
+ * Create a #TpContact object and make any asynchronous method calls necessary
+ * to ensure that all the features specified in @features are ready for use
+ * (if they are supported at all).
+ *
+ * It is not an error to put features in @features even if the connection
+ * manager doesn't support them - users of this method should have a static
+ * list of features they would like to use if possible, and use it for all
+ * connection managers.
+ *
+ * Since: 0.19.0
+ */
+void
+tp_connection_dup_contact_by_id_async (TpConnection *self,
+ const gchar *id,
+ const GQuark *features,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ ContactsAsyncData *data;
+ GSimpleAsyncResult *result;
+ ContactFeatureFlags feature_flags = 0;
+ const gchar **supported_interfaces;
+
+ g_return_if_fail (tp_proxy_is_prepared (self,
+ TP_CONNECTION_FEATURE_CONNECTED));
+ g_return_if_fail (id != NULL);
+
+ if (features == NULL)
+ features = no_quarks;
+
+ if (!get_feature_flags (features, &feature_flags))
+ return;
+
+ supported_interfaces = contacts_bind_to_signals (self, feature_flags);
+
+ result = g_simple_async_result_new ((GObject *) self, callback, user_data,
+ tp_connection_dup_contact_by_id_async);
+
+ data = contacts_async_data_new (result, feature_flags);
+ tp_cli_connection_interface_contacts_call_get_contact_by_id (self, -1,
+ id, supported_interfaces, got_contact_by_id_cb,
+ data, (GDestroyNotify) contacts_async_data_free, NULL);
+
+ g_free (supported_interfaces);
+ g_object_unref (result);
+}
+
+/**
+ * tp_connection_dup_contact_by_id_finish:
+ * @self: a #TpConnection
+ * @result: a #GAsyncResult
+ * @error: a #GError to fill
+ *
+ * Finishes tp_connection_get_contact_by_id_async().
+ *
+ * Returns: (transfer full): a #TpContact or %NULL on error.
+ * Since: 0.19.0
+ */
+TpContact *
+tp_connection_dup_contact_by_id_finish (TpConnection *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ _tp_implement_finish_return_copy_pointer (self,
+ tp_connection_dup_contact_by_id_async, g_object_ref);
+}
+
+static void
+got_contact_attributes_cb (TpConnection *self,
+ GHashTable *attributes,
+ const GError *error,
+ gpointer user_data,
+ GObject *weak_object)
+{
+ ContactsAsyncData *data = user_data;
+ GHashTableIter iter;
+ gpointer key, value;
+
+ if (error != NULL)
+ {
+ g_simple_async_result_set_from_error (data->result, error);
+ g_simple_async_result_complete (data->result);
+ return;
+ }
+
+ g_hash_table_iter_init (&iter, attributes);
+ while (g_hash_table_iter_next (&iter, &key, &value))
+ {
+ TpHandle handle = GPOINTER_TO_UINT (key);
+ GHashTable *asv = value;
+ TpContact *contact;
+
+ /* set up the contact with its attributes */
+ contact = tp_contact_ensure (self, handle);
+ tp_contact_set_attributes (contact, asv, data->features, NULL);
+ g_object_unref (contact);
+ }
+
+ g_simple_async_result_complete (data->result);
+}
+
+/**
+ * tp_connection_upgrade_contacts_async:
+ * @self: A connection, which must have the %TP_CONNECTION_FEATURE_CONNECTED
+ * feature prepared
+ * @n_contacts: The number of contacts in @contacts (must be at least 1)
+ * @contacts: (array length=n_contacts): An array of #TpContact objects
+ * associated with @self
+ * @features: (transfer-none) (array zero-terminated=1) (allow-none)
+ * (element-type GLib.Quark): An array of features that must be ready for
+ * @callback: A user callback to call when the contacts are ready
+ * @user_data: Data to pass to the callback
+ *
+ * Given several #TpContact objects, make asynchronous method calls
+ * ensure that all the features specified in @features are ready for use
+ * (if they are supported at all).
+ *
+ * It is not an error to put features in @features even if the connection
+ * manager doesn't support them - users of this method should have a static
+ * list of features they would like to use if possible, and use it for all
+ * connection managers.
+ *
+ * Since: 0.19.0
+ */
+void
+tp_connection_upgrade_contacts_async (TpConnection *self,
+ guint n_contacts,
+ TpContact * const *contacts,
+ const GQuark *features,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ ContactsAsyncData *data;
+ GSimpleAsyncResult *result;
+ ContactFeatureFlags feature_flags = 0;
+ guint minimal_feature_flags = G_MAXUINT;
+ const gchar **supported_interfaces;
+ GPtrArray *contacts_array;
+ GArray *handles;
+ guint i;
+
+ g_return_if_fail (tp_proxy_is_prepared (self,
+ TP_CONNECTION_FEATURE_CONNECTED));
+ g_return_if_fail (n_contacts >= 1);
+ g_return_if_fail (contacts != NULL);
+
+ for (i = 0; i < n_contacts; i++)
+ {
+ g_return_if_fail (contacts[i]->priv->connection == self);
+ g_return_if_fail (contacts[i]->priv->identifier != NULL);
+ }
+
+ if (features == NULL)
+ features = no_quarks;
+
+ if (!get_feature_flags (features, &feature_flags))
+ return;
+
+ handles = g_array_sized_new (FALSE, FALSE, sizeof (TpHandle), n_contacts);
+ contacts_array = g_ptr_array_new_full (n_contacts, g_object_unref);
+ for (i = 0; i < n_contacts; i++)
+ {
+ /* feature flags that all contacts have */
+ minimal_feature_flags &= contacts[i]->priv->has_features;
+
+ /* Keep handles of contacts that does not already have all features */
+ if ((feature_flags & (~contacts[i]->priv->has_features)) != 0)
+ g_array_append_val (handles, contacts[i]->priv->handle);
+
+ /* Keep a ref on all contacts to ensure they do not disappear
+ * while upgrading them */
+ g_ptr_array_add (contacts_array, g_object_ref (contacts[i]));
+ }
+
+ /* Remove features that all contacts have */
+ feature_flags &= (~minimal_feature_flags);
+
+ supported_interfaces = contacts_bind_to_signals (self, feature_flags);
+
+ result = g_simple_async_result_new ((GObject *) self, callback, user_data,
+ tp_connection_upgrade_contacts_async);
+ g_simple_async_result_set_op_res_gpointer (result, contacts_array,
+ (GDestroyNotify) g_ptr_array_unref);
+
+ if (handles->len > 0 && supported_interfaces[0] != NULL)
+ {
+ data = contacts_async_data_new (result, feature_flags);
+ tp_cli_connection_interface_contacts_call_get_contact_attributes (self,
+ -1, handles, supported_interfaces, got_contact_attributes_cb,
+ data, (GDestroyNotify) contacts_async_data_free, NULL);
+ }
+ else
+ {
+ g_simple_async_result_complete_in_idle (result);
+ }
+
+ g_free (supported_interfaces);
+ g_object_unref (result);
+ g_array_unref (handles);
+}
+
+/**
+ * tp_connection_upgrade_contacts_finish:
+ * @self: a #TpConnection
+ * @result: a #GAsyncResult
+ * @contacts: (element-type TelepathyGLib.Contact) (transfer container) (out) (allow-none):
+ * a location to set a #GPtrArray of upgraded #TpContact, or %NULL.
+ * @error: a #GError to fill
+ *
+ * Finishes tp_connection_upgrade_contacts_async().
+ *
+ * Returns: %TRUE on success, %FALSE otherwise.
+ * Since: 0.19.0
+ */
+gboolean
+tp_connection_upgrade_contacts_finish (TpConnection *self,
+ GAsyncResult *result,
+ GPtrArray **contacts,
+ GError **error)
+{
+ _tp_implement_finish_copy_pointer (self,
+ tp_connection_upgrade_contacts_async, g_ptr_array_ref, contacts);
+}
+
void
_tp_contact_set_is_blocked (TpContact *self,
gboolean is_blocked)
diff --git a/telepathy-glib/contact.h b/telepathy-glib/contact.h
index 2910f1dc3..c089998b3 100644
--- a/telepathy-glib/contact.h
+++ b/telepathy-glib/contact.h
@@ -161,11 +161,13 @@ void tp_contact_set_contact_groups_async (TpContact *self,
gboolean tp_contact_set_contact_groups_finish (TpContact *self,
GAsyncResult *result, GError **error);
+#ifndef TP_DISABLE_DEPRECATED
typedef void (*TpConnectionContactsByHandleCb) (TpConnection *connection,
guint n_contacts, TpContact * const *contacts,
guint n_failed, const TpHandle *failed,
const GError *error, gpointer user_data, GObject *weak_object);
+_TP_DEPRECATED_IN_0_20
void tp_connection_get_contacts_by_handle (TpConnection *self,
guint n_handles, const TpHandle *handles,
const GQuark *features,
@@ -176,6 +178,7 @@ typedef void (*TpConnectionUpgradeContactsCb) (TpConnection *connection,
guint n_contacts, TpContact * const *contacts,
const GError *error, gpointer user_data, GObject *weak_object);
+_TP_DEPRECATED_IN_0_20_FOR(tp_connection_upgrade_contacts_async)
void tp_connection_upgrade_contacts (TpConnection *self,
guint n_contacts, TpContact * const *contacts,
const GQuark *features,
@@ -187,15 +190,41 @@ typedef void (*TpConnectionContactsByIdCb) (TpConnection *connection,
const gchar * const *requested_ids, GHashTable *failed_id_errors,
const GError *error, gpointer user_data, GObject *weak_object);
+_TP_DEPRECATED_IN_0_20_FOR(tp_connection_get_contact_by_id_async)
void tp_connection_get_contacts_by_id (TpConnection *self,
guint n_ids, const gchar * const *ids,
const GQuark *features,
TpConnectionContactsByIdCb callback,
gpointer user_data, GDestroyNotify destroy, GObject *weak_object);
+#endif
TpContact *tp_connection_dup_contact_if_possible (TpConnection *connection,
TpHandle handle, const gchar *identifier);
+_TP_AVAILABLE_IN_0_20
+void tp_connection_dup_contact_by_id_async (TpConnection *self,
+ const gchar *id,
+ const GQuark *features,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+_TP_AVAILABLE_IN_0_20
+TpContact *tp_connection_dup_contact_by_id_finish (TpConnection *self,
+ GAsyncResult *result,
+ GError **error);
+
+_TP_AVAILABLE_IN_0_20
+void tp_connection_upgrade_contacts_async (TpConnection *self,
+ guint n_contacts,
+ TpContact * const *contacts,
+ const GQuark *features,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+_TP_AVAILABLE_IN_0_20
+gboolean tp_connection_upgrade_contacts_finish (TpConnection *self,
+ GAsyncResult *result,
+ GPtrArray **contacts,
+ GError **error);
+
/* TP_CONTACT_FEATURE_CONTACT_BLOCKING */
_TP_AVAILABLE_IN_0_18
diff --git a/telepathy-glib/contacts-mixin.c b/telepathy-glib/contacts-mixin.c
index 12ced5e56..3dacef0ea 100644
--- a/telepathy-glib/contacts-mixin.c
+++ b/telepathy-glib/contacts-mixin.c
@@ -84,6 +84,11 @@ static TpDBusPropertiesMixinPropImpl known_contacts_props[] = {
{ NULL }
};
+static const gchar *always_included_interfaces[] = {
+ TP_IFACE_CONNECTION,
+ NULL
+};
+
static void
tp_presence_mixin_get_contacts_dbus_property (GObject *object,
GQuark interface,
@@ -365,15 +370,11 @@ tp_contacts_mixin_get_contact_attributes_impl (
{
TpBaseConnection *conn = TP_BASE_CONNECTION (iface);
GHashTable *result;
- const gchar *assumed_interfaces[] = {
- TP_IFACE_CONNECTION,
- NULL
- };
TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (conn, context);
result = tp_contacts_mixin_get_contact_attributes (G_OBJECT (conn),
- handles, interfaces, assumed_interfaces);
+ handles, interfaces, always_included_interfaces);
tp_svc_connection_interface_contacts_return_from_get_contact_attributes (
context, result);
@@ -381,6 +382,48 @@ tp_contacts_mixin_get_contact_attributes_impl (
g_hash_table_unref (result);
}
+static void
+tp_contacts_mixin_get_contact_by_id_impl (
+ TpSvcConnectionInterfaceContacts *iface,
+ const gchar *id,
+ const gchar **interfaces,
+ DBusGMethodInvocation *context)
+{
+ TpBaseConnection *conn = TP_BASE_CONNECTION (iface);
+ TpHandleRepoIface *contact_repo = tp_base_connection_get_handles (conn,
+ TP_HANDLE_TYPE_CONTACT);
+ TpHandle handle;
+ GArray *handles;
+ GHashTable *attributes;
+ GHashTable *result;
+ GError *error = NULL;
+
+ TP_BASE_CONNECTION_ERROR_IF_NOT_CONNECTED (conn, context);
+
+ handle = tp_handle_ensure (contact_repo, id, NULL, &error);
+ if (handle == 0)
+ {
+ dbus_g_method_return_error (context, error);
+ g_clear_error (&error);
+ return;
+ }
+
+ handles = g_array_new (FALSE, FALSE, sizeof (TpHandle));
+ g_array_append_val (handles, handle);
+
+ attributes = tp_contacts_mixin_get_contact_attributes (G_OBJECT (conn),
+ handles, interfaces, always_included_interfaces);
+
+ result = g_hash_table_lookup (attributes, GUINT_TO_POINTER (handle));
+ g_assert (result != NULL);
+
+ tp_svc_connection_interface_contacts_return_from_get_contact_by_id (context,
+ handle, result);
+
+ g_array_unref (handles);
+ g_hash_table_unref (attributes);
+}
+
/**
* tp_contacts_mixin_iface_init: (skip)
* @g_iface: A pointer to the #TpSvcConnectionInterfaceContacts in an object
@@ -403,6 +446,7 @@ tp_contacts_mixin_iface_init (gpointer g_iface, gpointer iface_data)
#define IMPLEMENT(x) tp_svc_connection_interface_contacts_implement_##x ( \
klass, tp_contacts_mixin_##x##_impl)
IMPLEMENT(get_contact_attributes);
+ IMPLEMENT(get_contact_by_id);
#undef IMPLEMENT
}
diff --git a/telepathy-glib/dbus-internal.h b/telepathy-glib/dbus-internal.h
index bbdf7bddf..0d68a44be 100644
--- a/telepathy-glib/dbus-internal.h
+++ b/telepathy-glib/dbus-internal.h
@@ -40,6 +40,8 @@ GVariant * _tp_boxed_to_variant (GType gtype,
const gchar *variant_type,
gpointer boxed);
+GHashTable * _tp_asv_from_vardict (GVariant *variant);
+
G_END_DECLS
#endif /* __TP_INTERNAL_DBUS_GLIB_H__ */
diff --git a/telepathy-glib/dbus.c b/telepathy-glib/dbus.c
index 5ba635200..553ea3e06 100644
--- a/telepathy-glib/dbus.c
+++ b/telepathy-glib/dbus.c
@@ -1886,3 +1886,29 @@ _tp_boxed_to_variant (GType gtype,
return g_variant_ref_sink (ret);
}
+
+/*
+ * _tp_asv_from_vardict:
+ * @variant: a #GVariant of type %G_VARIANT_TYPE_VARDICT
+ *
+ * Returns: (transfer full): a newly created #GHashTable of
+ * type #TP_HASH_TYPE_STRING_VARIANT_MAP
+ */
+GHashTable *
+_tp_asv_from_vardict (GVariant *variant)
+{
+ GValue v = G_VALUE_INIT;
+ GHashTable *result;
+
+ g_return_val_if_fail (variant != NULL, NULL);
+ g_return_val_if_fail (g_variant_is_of_type (variant, G_VARIANT_TYPE_VARDICT),
+ NULL);
+
+ dbus_g_value_parse_g_variant (variant, &v);
+ g_assert (G_VALUE_HOLDS (&v, TP_HASH_TYPE_STRING_VARIANT_MAP));
+
+ result = g_value_dup_boxed (&v);
+
+ g_value_unset (&v);
+ return result;
+}
diff --git a/telepathy-glib/debug-client.c b/telepathy-glib/debug-client.c
index bd4f8bf9d..b76fc978e 100644
--- a/telepathy-glib/debug-client.c
+++ b/telepathy-glib/debug-client.c
@@ -44,7 +44,7 @@
* This module provides access to the auxiliary objects used to
* implement #TpSvcDebug.
*
- * Since: 0.UNRELEASED
+ * Since: 0.19.0
*/
/**
@@ -52,7 +52,7 @@
*
* The class of a #TpDebugClient.
*
- * Since: 0.UNRELEASED
+ * Since: 0.19.0
*/
struct _TpDebugClientClass {
TpProxyClass parent_class;
@@ -65,7 +65,7 @@ struct _TpDebugClientClass {
*
* A proxy object for the debug interface of a Telepathy component.
*
- * Since: 0.UNRELEASED
+ * Since: 0.19.0
*/
struct _TpDebugClient {
TpProxy parent;
@@ -203,7 +203,7 @@ tp_debug_client_class_init (TpDebugClientClass *klass)
* This property is meaningless until the
* %TP_DEBUG_CLIENT_FEATURE_CORE feature has been prepared.
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
spec = g_param_spec_boolean ("enabled", "enabled",
"Enabled",
@@ -219,7 +219,7 @@ tp_debug_client_class_init (TpDebugClientClass *klass)
* Emitted when a #TpDebugMessage is generated if the TpDebugMessage:enabled
* property is set to %TRUE.
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
signals[SIG_NEW_DEBUG_MESSAGE] = g_signal_new ("new-debug-message",
G_OBJECT_CLASS_TYPE (klass),
@@ -328,7 +328,7 @@ tp_debug_client_list_features (TpProxyClass *klass)
* tp_proxy_or_subclass_hook_on_interface_add() with first argument
* %TP_TYPE_DEBUG_CLIENT.
*
- * Since: 0.UNRELEASED
+ * Since: 0.19.0
*/
void
tp_debug_client_init_known_interfaces (void)
@@ -360,7 +360,7 @@ tp_debug_client_init_known_interfaces (void)
*
* Returns: a new debug client proxy, or %NULL on invalid arguments
*
- * Since: 0.UNRELEASED
+ * Since: 0.19.0
*/
TpDebugClient *
tp_debug_client_new (
@@ -405,7 +405,7 @@ set_enabled_cb (
* Enable or disable publishing of debug messages on the bus by the component
* owning @self's bus name.
*
- * Since: 0.UNRELEASED
+ * Since: 0.19.0
*/
void
tp_debug_client_set_enabled_async (
@@ -434,7 +434,7 @@ tp_debug_client_set_enabled_async (
* Finishes tp_debug_client_set_enabled_async().
*
* Returns: %TRUE, if the operation suceeded, %FALSE otherwise
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
gboolean
tp_debug_client_set_enabled_finish (
@@ -453,7 +453,7 @@ tp_debug_client_set_enabled_finish (
*
* Returns: the value of #TpDebugClient:enabled property
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
gboolean
tp_debug_client_is_enabled (TpDebugClient *self)
@@ -512,7 +512,7 @@ out:
* use tp_debug_client_get_messages_finish() to retrieve the #TpDebugMessage
* objects.
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
void
tp_debug_client_get_messages_async (
@@ -538,7 +538,7 @@ tp_debug_client_get_messages_async (
* Returns: (transfer full) (type GLib.PtrArray) (element-type TelepathyGLib.DebugMessage):
* a #GPtrArray of #TpDebugMessage
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
GPtrArray *
tp_debug_client_get_messages_finish (TpDebugClient *self,
diff --git a/telepathy-glib/debug-internal.h b/telepathy-glib/debug-internal.h
index cea13dacf..4f8c0fea7 100644
--- a/telepathy-glib/debug-internal.h
+++ b/telepathy-glib/debug-internal.h
@@ -35,7 +35,8 @@ typedef enum
TP_DEBUG_ROOM_CONFIG = 1 << 17,
TP_DEBUG_CALL = 1 << 18,
/* Quis custodiet ipsos custodes? */
- TP_DEBUG_DEBUGGER = 1 << 19
+ TP_DEBUG_DEBUGGER = 1 << 19,
+ TP_DEBUG_TLS = 1 << 20
} TpDebugFlags;
gboolean _tp_debug_flag_is_set (TpDebugFlags flag);
diff --git a/telepathy-glib/debug-message.c b/telepathy-glib/debug-message.c
index ff947a7e4..284eef793 100644
--- a/telepathy-glib/debug-message.c
+++ b/telepathy-glib/debug-message.c
@@ -42,7 +42,7 @@
*
* Data structure representing a #TpDebugMessage.
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
/**
@@ -50,7 +50,7 @@
*
* The class of a #TpDebugMessage.
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
G_DEFINE_TYPE (TpDebugMessage, tp_debug_message, G_TYPE_OBJECT)
@@ -133,7 +133,7 @@ tp_debug_message_class_init (
*
* Timestamp of the debug message.
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
spec = g_param_spec_boxed ("time", "time",
"Time",
@@ -146,7 +146,7 @@ tp_debug_message_class_init (
*
* Domain of the debug message.
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
spec = g_param_spec_string ("domain", "domain",
"Domain",
@@ -159,7 +159,7 @@ tp_debug_message_class_init (
*
* Category of the debug message, or %NULL if none was specified.
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
spec = g_param_spec_string ("category", "category",
"Category",
@@ -172,7 +172,7 @@ tp_debug_message_class_init (
*
* A #GLogLevelFlags representing the level of the debug message.
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
spec = g_param_spec_uint ("level", "level",
"Level",
@@ -185,7 +185,7 @@ tp_debug_message_class_init (
*
* Text of the debug message, stripped from its trailing whitespaces.
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
spec = g_param_spec_string ("message", "message",
"Message",
@@ -271,7 +271,7 @@ _tp_debug_message_new (gdouble timestamp,
*
* Returns: (transfer none): the value of #TpDebugMessage:time property
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
GDateTime *
tp_debug_message_get_time (TpDebugMessage *self)
@@ -287,7 +287,7 @@ tp_debug_message_get_time (TpDebugMessage *self)
*
* Returns: the value of #TpDebugMessage:domain property
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
const gchar *
tp_debug_message_get_domain (TpDebugMessage *self)
@@ -303,7 +303,7 @@ tp_debug_message_get_domain (TpDebugMessage *self)
*
* Returns: the value of #TpDebugMessage:category property
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
const char *
tp_debug_message_get_category (TpDebugMessage *self)
@@ -319,7 +319,7 @@ tp_debug_message_get_category (TpDebugMessage *self)
*
* Returns: the value of #TpDebugMessage:level property
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
GLogLevelFlags
tp_debug_message_get_level (TpDebugMessage *self)
@@ -335,7 +335,7 @@ tp_debug_message_get_level (TpDebugMessage *self)
*
* Returns: the value of #TpDebugMessage:message property
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
const gchar *
tp_debug_message_get_message (TpDebugMessage *self)
diff --git a/telepathy-glib/debug.c b/telepathy-glib/debug.c
index 048cce8c1..36a673223 100644
--- a/telepathy-glib/debug.c
+++ b/telepathy-glib/debug.c
@@ -54,6 +54,8 @@
* <listitem><literal>contact-lists</literal> - the #TpBaseContactList
* (service)</listitem>
* <listitem><literal>debugger</literal> - #TpDebugClient objects</listitem>
+ * <listitem><literal>tls</literal> - #TpTLSCertificate objects
+ * (client)</listitem>
* <listitem><literal>all</literal> - all of the above</listitem>
* </itemizedlist>
*/
@@ -101,6 +103,7 @@ static GDebugKey keys[] = {
{ "room-config", TP_DEBUG_ROOM_CONFIG },
{ "call", TP_DEBUG_CALL },
{ "debugger", TP_DEBUG_DEBUGGER },
+ { "tls", TP_DEBUG_TLS },
{ 0, }
};
@@ -135,6 +138,7 @@ static DebugKeyToDomain key_to_domain[] = {
{ TP_DEBUG_SASL, G_LOG_DOMAIN "/sasl" },
{ TP_DEBUG_ROOM_CONFIG, G_LOG_DOMAIN "/room-config" },
{ TP_DEBUG_DEBUGGER, G_LOG_DOMAIN "/debugger" },
+ { TP_DEBUG_TLS, G_LOG_DOMAIN "/tls" },
{ 0, NULL }
};
diff --git a/telepathy-glib/defs.h b/telepathy-glib/defs.h
index df0405905..6b497b540 100644
--- a/telepathy-glib/defs.h
+++ b/telepathy-glib/defs.h
@@ -37,33 +37,25 @@ G_BEGIN_DECLS
#if (TP_MINOR_VERSION == 99)
/* special case for telepathy-glib 1.0 prereleases */
# define _TP_VERSION_CUR_STABLE (_TP_ENCODE_VERSION (TP_MAJOR_VERSION + 1, 0))
-# define _TP_VERSION_PREV_STABLE (_TP_ENCODE_VERSION (TP_MAJOR_VERSION + 1, 0))
#elif (TP_MINOR_VERSION == 0)
/* special case for telepathy-glib 1.0 itself */
# define _TP_VERSION_CUR_STABLE (_TP_ENCODE_VERSION (TP_MAJOR_VERSION, 0))
-# define _TP_VERSION_PREV_STABLE (_TP_ENCODE_VERSION (TP_MAJOR_VERSION, 0))
#elif (TP_MICRO_VERSION >= 99 && (TP_MINOR_VERSION % 2) == 0)
/* development branch about to start (0.18.999.1) */
# define _TP_VERSION_CUR_STABLE \
(_TP_ENCODE_VERSION (TP_MAJOR_VERSION, TP_MINOR_VERSION + 2))
-# define _TP_VERSION_PREV_STABLE \
- (_TP_ENCODE_VERSION (TP_MAJOR_VERSION, TP_MINOR_VERSION))
#elif (TP_MINOR_VERSION % 2)
/* development branch */
# define _TP_VERSION_CUR_STABLE \
(_TP_ENCODE_VERSION (TP_MAJOR_VERSION, TP_MINOR_VERSION + 1))
-# define _TP_VERSION_PREV_STABLE \
- (_TP_ENCODE_VERSION (TP_MAJOR_VERSION, TP_MINOR_VERSION - 1))
#else
/* stable branch */
# define _TP_VERSION_CUR_STABLE \
(_TP_ENCODE_VERSION (TP_MAJOR_VERSION, TP_MINOR_VERSION))
-# define _TP_VERSION_PREV_STABLE \
- (_TP_ENCODE_VERSION (TP_MAJOR_VERSION, TP_MINOR_VERSION - 2))
#endif
#ifndef TP_VERSION_MIN_REQUIRED
-# define TP_VERSION_MIN_REQUIRED (_TP_VERSION_PREV_STABLE)
+# define TP_VERSION_MIN_REQUIRED (_TP_VERSION_CUR_STABLE)
#endif
#ifndef TP_VERSION_MAX_ALLOWED
diff --git a/telepathy-glib/extra-gtkdoc.h b/telepathy-glib/extra-gtkdoc.h
index 0dbf4244a..cad2cd874 100644
--- a/telepathy-glib/extra-gtkdoc.h
+++ b/telepathy-glib/extra-gtkdoc.h
@@ -350,7 +350,7 @@
* @title: Version information
* @short_description: Checking the telepathy-glib version
*
- * Since 0.UNRELEASED, telepathy-glib provides version information similar
+ * Since 0.19.0, telepathy-glib provides version information similar
* to that used in GLib.
*
* Typical usage from configure.ac is similar to GLib's:
@@ -372,7 +372,7 @@
* ${TP_CFLAGS} ${TP_LIBS}
* ]|
*
- * This functionality was added in telepathy-glib 0.UNRELEASED, but it
+ * This functionality was added in telepathy-glib 0.19.0, but it
* is safe to define the TP_VERSION_MIN_REQUIRED and TP_VERSION_MAX_ALLOWED
* macros even for older versions of telepathy-glib, as long as you do
* not try to expand them.
diff --git a/telepathy-glib/introspection.am b/telepathy-glib/introspection.am
index 9b0f3e89c..b6bdcc569 100644
--- a/telepathy-glib/introspection.am
+++ b/telepathy-glib/introspection.am
@@ -72,6 +72,8 @@ TelepathyGLib_1_gir_FILES = \
$(srcdir)/channel-dispatcher.c $(srcdir)/channel-dispatcher.h \
$(srcdir)/debug-client.c $(srcdir)/debug-client.h \
$(srcdir)/debug-message.c $(srcdir)/debug-message.h \
+ $(srcdir)/tls-certificate.c $(srcdir)/tls-certificate.h \
+ $(srcdir)/tls-certificate-rejection.c $(srcdir)/tls-certificate-rejection.h \
$(srcdir)/errors.c $(srcdir)/errors.h \
$(srcdir)/room-list.c $(srcdir)/room-list.h \
$(srcdir)/room-info.c $(srcdir)/room-info.h \
diff --git a/telepathy-glib/message-mixin.c b/telepathy-glib/message-mixin.c
index eb416be02..c46efdda3 100644
--- a/telepathy-glib/message-mixin.c
+++ b/telepathy-glib/message-mixin.c
@@ -46,6 +46,15 @@
* tp_message_mixin_implement_sending() in the constructor function. If you do
* not, any attempt to send a message will fail with NotImplemented.
*
+ * To support chat state, you must call
+ * tp_message_mixin_implement_send_chat_state() in the constructor function, and
+ * include the following in the fourth argument of G_DEFINE_TYPE_WITH_CODE():
+ *
+ * <informalexample><programlisting>
+ * G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_CHANNEL_INTERFACE_CHAT_STATE,
+ * tp_message_mixin_chat_state_iface_init);
+ * </programlisting></informalexample>
+ *
* Since: 0.7.21
*/
@@ -97,6 +106,18 @@ struct _TpMessageMixinPrivate
/* Receiving */
guint recv_id;
GQueue *pending;
+
+ /* ChatState */
+
+ /* TpHandle -> TpChannelChatState */
+ GHashTable *chat_states;
+ TpMessageMixinSendChatStateImpl send_chat_state;
+ /* FALSE unless at least one chat state notification has been sent; <gone/>
+ * will only be sent when the channel closes if this is TRUE. This prevents
+ * opening a channel and closing it immediately sending a spurious <gone/> to
+ * the peer.
+ */
+ gboolean send_gone;
};
@@ -251,6 +272,185 @@ tp_message_mixin_implement_sending (GObject *object,
(gchar **) supported_content_types);
}
+static TpChannelChatState
+lookup_current_chat_state (TpMessageMixin *mixin,
+ TpHandle member)
+{
+ gpointer tmp;
+
+ if (g_hash_table_lookup_extended (mixin->priv->chat_states,
+ GUINT_TO_POINTER (member), NULL, &tmp))
+ {
+ return GPOINTER_TO_UINT (tmp);
+ }
+
+ return TP_CHANNEL_CHAT_STATE_INACTIVE;
+}
+
+/**
+ * tp_message_mixin_change_chat_state:
+ * @object: an instance of the implementation that uses this mixin
+ * @member: a member of this chat
+ * @state: the new state to set
+ *
+ * Change the current chat state of @member to be @state. This emits
+ * ChatStateChanged signal and update ChatStates property.
+ *
+ * Since: 0.19.0
+ */
+void
+tp_message_mixin_change_chat_state (GObject *object,
+ TpHandle member,
+ TpChannelChatState state)
+{
+ TpMessageMixin *mixin = TP_MESSAGE_MIXIN (object);
+
+ g_return_if_fail (state < TP_NUM_CHANNEL_CHAT_STATES);
+
+ if (state == lookup_current_chat_state (mixin, member))
+ return;
+
+ if (state == TP_CHANNEL_CHAT_STATE_INACTIVE ||
+ state == TP_CHANNEL_CHAT_STATE_GONE)
+ {
+ g_hash_table_remove (mixin->priv->chat_states,
+ GUINT_TO_POINTER (member));
+ }
+ else
+ {
+ g_hash_table_insert (mixin->priv->chat_states,
+ GUINT_TO_POINTER (member),
+ GUINT_TO_POINTER (state));
+ }
+
+ tp_svc_channel_interface_chat_state_emit_chat_state_changed (object,
+ member, state);
+}
+
+/**
+ * TpMessageMixinSendChatStateImpl:
+ * @object: an instance of the implementation that uses this mixin
+ * @state: a #TpChannelChatState to be send
+ * @error: a #GError to fill
+ *
+ * Signature of a virtual method which may be implemented to allow sending chat
+ * state.
+ *
+ * Returns: %TRUE on success, %FALSE otherwise.
+ * Since: 0.19.0
+ */
+
+/**
+ * tp_message_mixin_implement_send_chat_state:
+ * @object: an instance of the implementation that uses this mixin
+ * @send_chat_state: send our chat state
+ *
+ * Set the callback used to implement SetChatState. This must be called from the
+ * init, constructor or constructed callback, after tp_message_mixin_init(),
+ * and may only be called once per object.
+ *
+ * Since: 0.19.0
+ */
+void
+tp_message_mixin_implement_send_chat_state (GObject *object,
+ TpMessageMixinSendChatStateImpl send_chat_state)
+{
+ TpMessageMixin *mixin = TP_MESSAGE_MIXIN (object);
+
+ g_return_if_fail (mixin->priv->send_chat_state == NULL);
+
+ mixin->priv->send_chat_state = send_chat_state;
+}
+
+/**
+ * tp_message_mixin_maybe_send_gone:
+ * @object: An instance of the implementation that uses this mixin
+ *
+ * Send #TP_CHANNEL_CHAT_STATE_GONE if needed. This should be called on private
+ * chats when channel is closed.
+ *
+ * Since: 0.19.0
+ */
+void
+tp_message_mixin_maybe_send_gone (GObject *object)
+{
+ TpMessageMixin *mixin = TP_MESSAGE_MIXIN (object);
+
+ if (mixin->priv->send_gone && !TP_HAS_GROUP_MIXIN (object) &&
+ mixin->priv->send_chat_state != NULL)
+ {
+ mixin->priv->send_chat_state (object, TP_CHANNEL_CHAT_STATE_GONE, NULL);
+ }
+
+ mixin->priv->send_gone = FALSE;
+}
+
+/* FIXME: Use tp_base_channel_get_self_handle() when TpMessageMixin requires
+ * TpBaseChannel. See bug #49366 */
+static TpHandle
+get_self_handle (GObject *object)
+{
+ TpMessageMixin *mixin = TP_MESSAGE_MIXIN (object);
+
+ if (TP_HAS_GROUP_MIXIN (object))
+ {
+ guint ret = 0;
+
+ tp_group_mixin_get_self_handle (object, &ret, NULL);
+ if (ret != 0)
+ return ret;
+ }
+
+ return tp_base_connection_get_self_handle (mixin->priv->connection);
+}
+
+static void
+tp_message_mixin_set_chat_state_async (TpSvcChannelInterfaceChatState *iface,
+ guint state,
+ DBusGMethodInvocation *context)
+{
+ GObject *object = (GObject *) iface;
+ TpMessageMixin *mixin = TP_MESSAGE_MIXIN (object);
+ GError *error = NULL;
+
+ if (mixin->priv->send_chat_state == NULL)
+ {
+ tp_dbus_g_method_return_not_implemented (context);
+ return;
+ }
+
+ if (state >= TP_NUM_CHANNEL_CHAT_STATES)
+ {
+ DEBUG ("invalid chat state %u", state);
+
+ g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
+ "invalid state: %u", state);
+ goto error;
+ }
+
+ if (state == TP_CHANNEL_CHAT_STATE_GONE)
+ {
+ /* We cannot explicitly set the Gone state */
+ DEBUG ("you may not explicitly set the Gone state");
+
+ g_set_error (&error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
+ "you may not explicitly set the Gone state");
+ goto error;
+ }
+
+ if (!mixin->priv->send_chat_state (object, state, &error))
+ goto error;
+
+ mixin->priv->send_gone = TRUE;
+ tp_message_mixin_change_chat_state (object, get_self_handle (object), state);
+
+ tp_svc_channel_interface_chat_state_return_from_set_chat_state (context);
+ return;
+
+error:
+ dbus_g_method_return_error (context, error);
+ g_clear_error (&error);
+}
/**
* tp_message_mixin_init:
@@ -293,6 +493,8 @@ tp_message_mixin_init (GObject *obj,
mixin->priv->connection = g_object_ref (connection);
mixin->priv->supported_content_types = g_new0 (gchar *, 1);
+
+ mixin->priv->chat_states = g_hash_table_new (NULL, NULL);
}
@@ -339,6 +541,8 @@ tp_message_mixin_finalize (GObject *obj)
g_object_unref (mixin->priv->connection);
+ g_hash_table_unref (mixin->priv->chat_states);
+
g_slice_free (TpMessageMixinPrivate, mixin->priv);
}
@@ -560,7 +764,6 @@ struct _TpMessageMixinOutgoingMessagePrivate {
gboolean messages:1;
};
-
/**
* tp_message_mixin_sent:
* @object: An object implementing the Text interface with this mixin
@@ -611,21 +814,13 @@ tp_message_mixin_sent (GObject *object,
else
{
GHashTable *header = g_ptr_array_index (message->parts, 0);
- TpHandle self_handle = 0;
+
+ mixin->priv->send_gone = TRUE;
if (tp_asv_get_uint64 (header, "message-sent", NULL) == 0)
tp_message_set_uint64 (message, 0, "message-sent", time (NULL));
- if (TP_HAS_GROUP_MIXIN (object))
- {
- tp_group_mixin_get_self_handle (object, &self_handle, NULL);
- }
-
- if (self_handle == 0)
- self_handle = tp_base_connection_get_self_handle (
- mixin->priv->connection);
-
- tp_cm_message_set_sender (message, self_handle);
+ tp_cm_message_set_sender (message, get_self_handle (object));
/* emit Sent and MessageSent */
@@ -770,10 +965,18 @@ tp_message_mixin_init_dbus_properties (GObjectClass *cls)
{ "DeliveryReportingSupport", NULL, NULL },
{ NULL }
};
+ static TpDBusPropertiesMixinPropImpl chat_state_props[] = {
+ { "ChatStates", NULL, NULL },
+ { NULL }
+ };
tp_dbus_properties_mixin_implement_interface (cls,
TP_IFACE_QUARK_CHANNEL_TYPE_TEXT,
tp_message_mixin_get_dbus_property, NULL, props);
+
+ tp_dbus_properties_mixin_implement_interface (cls,
+ TP_IFACE_QUARK_CHANNEL_INTERFACE_CHAT_STATE,
+ tp_message_mixin_get_dbus_property, NULL, chat_state_props);
}
@@ -804,6 +1007,7 @@ tp_message_mixin_get_dbus_property (GObject *object,
static GQuark q_message_part_support_flags = 0;
static GQuark q_delivery_reporting_support_flags = 0;
static GQuark q_message_types = 0;
+ static GQuark q_chat_states = 0;
if (G_UNLIKELY (q_pending_messages == 0))
{
@@ -816,11 +1020,14 @@ tp_message_mixin_get_dbus_property (GObject *object,
g_quark_from_static_string ("DeliveryReportingSupport");
q_message_types =
g_quark_from_static_string ("MessageTypes");
+ q_chat_states =
+ g_quark_from_static_string ("ChatStates");
}
mixin = TP_MESSAGE_MIXIN (object);
- g_return_if_fail (interface == TP_IFACE_QUARK_CHANNEL_TYPE_TEXT);
+ g_return_if_fail (interface == TP_IFACE_QUARK_CHANNEL_TYPE_TEXT ||
+ interface == TP_IFACE_QUARK_CHANNEL_INTERFACE_CHAT_STATE);
g_return_if_fail (object != NULL);
g_return_if_fail (name != 0);
g_return_if_fail (value != NULL);
@@ -861,6 +1068,10 @@ tp_message_mixin_get_dbus_property (GObject *object,
{
g_value_set_boxed (value, mixin->priv->msg_types);
}
+ else if (name == q_chat_states)
+ {
+ g_value_set_boxed (value, mixin->priv->chat_states);
+ }
}
@@ -886,3 +1097,26 @@ tp_message_mixin_iface_init (gpointer g_iface,
IMPLEMENT (send_message);
#undef IMPLEMENT
}
+
+/**
+ * tp_message_mixin_chat_state_iface_init:
+ * @g_iface: A pointer to the #TpSvcChannelInterfaceChatStateClass in an object
+ * class
+ * @iface_data: Ignored
+ *
+ * Fill in this mixin's ChatState method implementations in the given interface
+ * vtable.
+ *
+ * Since: 0.19.0
+ */
+void
+tp_message_mixin_chat_state_iface_init (gpointer g_iface,
+ gpointer iface_data)
+{
+ TpSvcChannelInterfaceChatStateClass *klass = g_iface;
+
+#define IMPLEMENT(x) tp_svc_channel_interface_chat_state_implement_##x (\
+ klass, tp_message_mixin_##x##_async)
+ IMPLEMENT (set_chat_state);
+#undef IMPLEMENT
+}
diff --git a/telepathy-glib/message-mixin.h b/telepathy-glib/message-mixin.h
index 7c0ccbae0..4696f4feb 100644
--- a/telepathy-glib/message-mixin.h
+++ b/telepathy-glib/message-mixin.h
@@ -67,9 +67,28 @@ void tp_message_mixin_implement_sending (GObject *object,
TpDeliveryReportingSupportFlags delivery_reporting_support_flags,
const gchar * const * supported_content_types);
+/* ChatState */
+
+typedef gboolean (*TpMessageMixinSendChatStateImpl) (GObject *object,
+ TpChannelChatState state,
+ GError **error);
+
+_TP_AVAILABLE_IN_0_20
+void tp_message_mixin_change_chat_state (GObject *object,
+ TpHandle member,
+ TpChannelChatState state);
+
+_TP_AVAILABLE_IN_0_20
+void tp_message_mixin_implement_send_chat_state (GObject *object,
+ TpMessageMixinSendChatStateImpl send_chat_state);
+
+_TP_AVAILABLE_IN_0_20
+void tp_message_mixin_maybe_send_gone (GObject *object);
/* Initialization */
void tp_message_mixin_iface_init (gpointer g_iface, gpointer iface_data);
+void tp_message_mixin_chat_state_iface_init (gpointer g_iface,
+ gpointer iface_data);
void tp_message_mixin_init (GObject *obj, gsize offset,
TpBaseConnection *connection);
diff --git a/telepathy-glib/proxy.c b/telepathy-glib/proxy.c
index 4c3715871..739790638 100644
--- a/telepathy-glib/proxy.c
+++ b/telepathy-glib/proxy.c
@@ -108,7 +108,7 @@ tp_dbus_errors_quark (void)
*
* 1 more than the highest valid #TpDBusError at the time of compilation
*
- * Since: 0.UNRELEASED
+ * Since: 0.19.0
*/
/**
@@ -1990,6 +1990,9 @@ static void
prepare_feature (TpProxy *self,
const TpProxyFeature *feature)
{
+ /* If no function is set, then subclass is supposed to call
+ * _tp_proxy_set_feature_prepared() itself. This is used by features prepared
+ * from constructed. */
if (feature->prepare_async == NULL)
return;
diff --git a/telepathy-glib/room-info.c b/telepathy-glib/room-info.c
index 2412ee5f1..1843b1d0f 100644
--- a/telepathy-glib/room-info.c
+++ b/telepathy-glib/room-info.c
@@ -42,7 +42,7 @@
*
* Data structure representing a #TpRoomInfo.
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
/**
@@ -50,7 +50,7 @@
*
* The class of a #TpRoomInfo.
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
G_DEFINE_TYPE (TpRoomInfo, tp_room_info, G_TYPE_OBJECT)
@@ -127,7 +127,7 @@ _tp_room_info_new (GValueArray *dbus_struct)
*
* Returns: the #TpHandle of the room
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
TpHandle
tp_room_info_get_handle (TpRoomInfo *self)
@@ -144,7 +144,7 @@ tp_room_info_get_handle (TpRoomInfo *self)
* Returns: a string representing the D-Bus interface name of
* the channel type of the room
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
const gchar *
tp_room_info_get_channel_type (TpRoomInfo *self)
@@ -161,7 +161,7 @@ tp_room_info_get_channel_type (TpRoomInfo *self)
* Returns: the identifier of the room (as would be returned
* by inspecting the #TpHandle returned by tp_room_info_get_handle())
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
const gchar *
tp_room_info_get_handle_name (TpRoomInfo *self)
@@ -178,7 +178,7 @@ tp_room_info_get_handle_name (TpRoomInfo *self)
* Returns: the human-readable name of the room if different
* from the handle
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
const gchar *
tp_room_info_get_name (TpRoomInfo *self)
@@ -194,7 +194,7 @@ tp_room_info_get_name (TpRoomInfo *self)
*
* Returns: a description of the room's overall purpose
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
const gchar *
tp_room_info_get_description (TpRoomInfo *self)
@@ -210,7 +210,7 @@ tp_room_info_get_description (TpRoomInfo *self)
*
* Returns: the current subject of conversation in the room
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
const gchar *
tp_room_info_get_subject (TpRoomInfo *self)
@@ -228,7 +228,7 @@ tp_room_info_get_subject (TpRoomInfo *self)
*
* Returns: the number of members in the room
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
guint
tp_room_info_get_members_count (TpRoomInfo *self,
@@ -247,7 +247,7 @@ tp_room_info_get_members_count (TpRoomInfo *self,
*
* Returns: %TRUE if the room requires a password to enter
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
gboolean
tp_room_info_get_requires_password (TpRoomInfo *self,
@@ -266,7 +266,7 @@ tp_room_info_get_requires_password (TpRoomInfo *self,
*
* Returns: %TRUE if you cannot join the room, but must be invited
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
gboolean
tp_room_info_get_invite_only (TpRoomInfo *self,
@@ -283,7 +283,7 @@ tp_room_info_get_invite_only (TpRoomInfo *self,
*
* Returns: the human-readable identifier of the room
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
const gchar *
tp_room_info_get_room_id (TpRoomInfo *self)
@@ -299,7 +299,7 @@ tp_room_info_get_room_id (TpRoomInfo *self)
*
* Returns: the DNS name of the server hosting the room
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
const gchar *
tp_room_info_get_server (TpRoomInfo *self)
diff --git a/telepathy-glib/room-list.c b/telepathy-glib/room-list.c
index 3828672f3..98fd7e0e0 100644
--- a/telepathy-glib/room-list.c
+++ b/telepathy-glib/room-list.c
@@ -31,7 +31,7 @@
*
* Data structure representing a #TpRoomList.
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
/**
@@ -39,7 +39,7 @@
*
* The class of a #TpRoomList.
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
#include <config.h>
@@ -237,7 +237,7 @@ tp_room_list_class_init (TpRoomListClass *klass)
*
* The #TpAccount to use for the room listing.
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
param_spec = g_param_spec_object ("account", "account",
"TpAccount",
@@ -251,7 +251,7 @@ tp_room_list_class_init (TpRoomListClass *klass)
* The DNS name of the server whose rooms are listed by this channel, or
* %NULL.
*
- * Since: 0.UNRELEASED
+ * Since: 0.19.0
*/
param_spec = g_param_spec_string ("server", "Server",
"The server associated with the channel",
@@ -267,7 +267,7 @@ tp_room_list_class_init (TpRoomListClass *klass)
* This property is meaningless until the
* %TP_ROOM_LIST_FEATURE_LISTING feature has been prepared.
*
- * Since: 0.UNRELEASED
+ * Since: 0.19.0
*/
param_spec = g_param_spec_boolean ("listing", "Listing",
"TRUE if the channel is listing rooms",
@@ -285,7 +285,7 @@ tp_room_list_class_init (TpRoomListClass *klass)
* User should take his own reference on @room if he plans to
* continue using it once the signal callback has returned.
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
signals[SIG_GOT_ROOM] = g_signal_new ("got-room",
G_OBJECT_CLASS_TYPE (klass),
@@ -302,7 +302,7 @@ tp_room_list_class_init (TpRoomListClass *klass)
* Fired when something goes wrong while listing the channels; see @error
* for details.
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
signals[SIG_FAILED] = g_signal_new ("failed",
G_OBJECT_CLASS_TYPE (klass),
@@ -329,7 +329,7 @@ tp_room_list_init (TpRoomList *self)
*
* Returns: (transfer none): the value of #TpRoomList:account property
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
TpAccount *
tp_room_list_get_account (TpRoomList *self)
@@ -345,7 +345,7 @@ tp_room_list_get_account (TpRoomList *self)
*
* Returns: the value of #TpRoomList:server property
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
const gchar *
tp_room_list_get_server (TpRoomList *self)
@@ -361,7 +361,7 @@ tp_room_list_get_server (TpRoomList *self)
*
* Returns: the value of #TpRoomList:listing property
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
gboolean
tp_room_list_is_listing (TpRoomList *self)
@@ -391,7 +391,7 @@ list_rooms_cb (TpChannel *channel,
* signal to get the rooms found.
* Errors will be reported using the TpRoomList::failed signal.
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
void
tp_room_list_start (TpRoomList *self)
@@ -558,7 +558,7 @@ async_initable_iface_init (GAsyncInitableIface *iface)
*
* <!-- -->
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
void
tp_room_list_new_async (TpAccount *account,
@@ -585,7 +585,7 @@ tp_room_list_new_async (TpAccount *account,
* Returns: (transfer full): a new #TpRoomList object, or %NULL
* in case of error.
*
- * Since: UNRELEASED
+ * Since: 0.19.0
*/
TpRoomList *
tp_room_list_new_finish (GAsyncResult *result,
diff --git a/telepathy-glib/stream-tube-channel.c b/telepathy-glib/stream-tube-channel.c
index c41f380cd..d74e7f435 100644
--- a/telepathy-glib/stream-tube-channel.c
+++ b/telepathy-glib/stream-tube-channel.c
@@ -1035,12 +1035,15 @@ connection_identified (TpStreamTubeChannel *self,
features = tp_client_factory_dup_contact_features (
tp_proxy_get_factory (connection), connection);
+ /* Spec does not give the id with the handle */
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
/* Pass the ref on tube_conn to the function */
tp_connection_get_contacts_by_handle (connection,
1, &handle,
(const GQuark *) features->data,
_new_remote_connection_with_contact,
tube_conn, g_object_unref, G_OBJECT (self));
+ G_GNUC_END_IGNORE_DEPRECATIONS
g_array_unref (features);
}
diff --git a/telepathy-glib/telepathy-glib.h b/telepathy-glib/telepathy-glib.h
index 0e3ac96de..7d72c3d43 100644
--- a/telepathy-glib/telepathy-glib.h
+++ b/telepathy-glib/telepathy-glib.h
@@ -107,6 +107,7 @@
#include <telepathy-glib/stream-tube-channel.h>
#include <telepathy-glib/stream-tube-connection.h>
#include <telepathy-glib/text-channel.h>
+#include <telepathy-glib/tls-certificate.h>
#undef __TP_IN_GLIB_H__
#endif /* __TP_GLIB_H__ */
diff --git a/telepathy-glib/text-channel.c b/telepathy-glib/text-channel.c
index 3325b061d..95688a929 100644
--- a/telepathy-glib/text-channel.c
+++ b/telepathy-glib/text-channel.c
@@ -105,6 +105,7 @@ enum /* signals */
SIG_MESSAGE_RECEIVED,
SIG_PENDING_MESSAGE_REMOVED,
SIG_MESSAGE_SENT,
+ SIG_CONTACT_CHAT_STATE_CHANGED,
LAST_SIGNAL
};
@@ -357,6 +358,42 @@ message_sent_cb (TpChannel *channel,
}
static void
+chat_state_changed_cb (TpTextChannel *self,
+ TpHandle handle,
+ TpChannelChatState state)
+{
+ TpConnection *conn;
+ TpContact *contact;
+
+ /* We have only an handle, but since we guarantee "contact-chat-state-changed"
+ * to be emitted only if TP_CHANNEL_FEATURE_GROUP and
+ * TP_CHANNEL_FEATURE_CONTACTS has been prepared, we should already have its
+ * TpContact. If the TpContact does not exist, telling its chat state is
+ * useless anyway. */
+ conn = tp_channel_borrow_connection ((TpChannel *) self);
+ contact = tp_connection_dup_contact_if_possible (conn, handle, NULL);
+ if (contact == NULL)
+ return;
+
+ g_signal_emit (self, signals[SIG_CONTACT_CHAT_STATE_CHANGED], 0,
+ contact, state);
+
+ g_object_unref (contact);
+}
+
+static void
+tp_text_channel_prepare_chat_states_async (TpProxy *proxy,
+ const TpProxyFeature *feature,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ /* This feature depends on TP_CHANNEL_FEATURE_CHAT_STATES so it's already
+ * prepared. */
+ tp_simple_async_report_success_in_idle ((GObject *) proxy,
+ callback, user_data, tp_text_channel_prepare_chat_states_async);
+}
+
+static void
tp_text_channel_constructed (GObject *obj)
{
TpTextChannel *self = (TpTextChannel *) obj;
@@ -383,6 +420,11 @@ tp_text_channel_constructed (GObject *obj)
return;
}
+ /* Forward TpChannel::chat-state-changed as
+ * TpTextChannel::contact-chat-state-changed */
+ g_signal_connect (self, "chat-state-changed",
+ G_CALLBACK (chat_state_changed_cb), NULL);
+
props = tp_channel_borrow_immutable_properties (TP_CHANNEL (self));
self->priv->supported_content_types = (GStrv) tp_asv_get_strv (props,
@@ -786,6 +828,7 @@ tp_text_channel_prepare_sms_async (TpProxy *proxy,
enum {
FEAT_PENDING_MESSAGES,
FEAT_SMS,
+ FEAT_CHAT_STATES,
N_FEAT
};
@@ -794,6 +837,7 @@ tp_text_channel_list_features (TpProxyClass *cls G_GNUC_UNUSED)
{
static TpProxyFeature features[N_FEAT + 1] = { { 0 } };
static GQuark need_sms[2] = {0, 0};
+ static GQuark depends_chat_state[2] = {0, 0};
if (G_LIKELY (features[0].name != 0))
return features;
@@ -810,6 +854,15 @@ tp_text_channel_list_features (TpProxyClass *cls G_GNUC_UNUSED)
need_sms[0] = TP_IFACE_QUARK_CHANNEL_INTERFACE_SMS;
features[FEAT_SMS].interfaces_needed = need_sms;
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+ features[FEAT_CHAT_STATES].name =
+ TP_TEXT_CHANNEL_FEATURE_CHAT_STATES;
+ features[FEAT_CHAT_STATES].prepare_async =
+ tp_text_channel_prepare_chat_states_async;
+ depends_chat_state[0] = TP_CHANNEL_FEATURE_CHAT_STATES;
+ features[FEAT_CHAT_STATES].depends_on = depends_chat_state;
+ G_GNUC_END_IGNORE_DEPRECATIONS
+
/* assert that the terminator at the end is there */
g_assert (features[N_FEAT].name == 0);
@@ -1009,6 +1062,26 @@ tp_text_channel_class_init (TpTextChannelClass *klass)
3, TP_TYPE_SIGNALLED_MESSAGE, G_TYPE_UINT, G_TYPE_STRING);
g_type_class_add_private (gobject_class, sizeof (TpTextChannelPrivate));
+
+ /**
+ * TpTextChannel::contact-chat-state-changed:
+ * @self: a channel
+ * @contact: a #TpContact for the local user or another contact
+ * @state: the new #TpChannelChatState for the contact
+ *
+ * Emitted when a contact's chat state changes after tp_proxy_prepare_async()
+ * has finished preparing features %TP_TEXT_CHANNEL_FEATURE_CHAT_STATES,
+ * %TP_CHANNEL_FEATURE_GROUP and %TP_CHANNEL_FEATURE_CONTACTS.
+ *
+ * Since: 0.19.0
+ */
+ signals[SIG_CONTACT_CHAT_STATE_CHANGED] = g_signal_new (
+ "contact-chat-state-changed",
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ 0,
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 2, TP_TYPE_CONTACT, G_TYPE_UINT);
}
static void
@@ -1478,6 +1551,53 @@ tp_text_channel_ack_message_finish (TpTextChannel *self,
_tp_implement_finish_void (self, tp_text_channel_ack_message_async)
}
+/**
+ * TP_TEXT_CHANNEL_FEATURE_CHAT_STATES:
+ *
+ * Expands to a call to a function that returns a quark representing the
+ * chat states feature on a #TpTextChannel.
+ *
+ * When this feature is prepared, tp_text_channel_get_chat_state() and the
+ * #TpTextChannel::contact-chat-state-changed signal become useful.
+ *
+ * One can ask for a feature to be prepared using the
+ * tp_proxy_prepare_async() function, and waiting for it to callback.
+ *
+ * Since: 0.19.0
+ */
+
+GQuark
+tp_text_channel_get_feature_quark_chat_states (void)
+{
+ return g_quark_from_static_string ("tp-text-channel-feature-chat-states");
+}
+
+/**
+ * tp_text_channel_get_chat_state:
+ * @self: a channel
+ * @contact: a #TpContact
+ *
+ * Return the chat state for the given contact. If tp_proxy_is_prepared()
+ * would return %FALSE for the feature %TP_TEXT_CHANNEL_FEATURE_CHAT_STATES,
+ * the result will always be %TP_CHANNEL_CHAT_STATE_INACTIVE.
+ *
+ * Returns: the chat state for @contact, or %TP_CHANNEL_CHAT_STATE_INACTIVE
+ * if their chat state is not known
+ * Since: 0.19.0
+ */
+TpChannelChatState
+tp_text_channel_get_chat_state (TpTextChannel *self,
+ TpContact *contact)
+{
+ g_return_val_if_fail (TP_IS_TEXT_CHANNEL (self), 0);
+
+ /* Use the deprecated function internally to avoid duplicated introspection */
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+ return tp_channel_get_chat_state ((TpChannel *) self,
+ tp_contact_get_handle (contact));
+ G_GNUC_END_IGNORE_DEPRECATIONS
+}
+
static void
set_chat_state_cb (TpChannel *proxy,
const GError *error,
diff --git a/telepathy-glib/text-channel.h b/telepathy-glib/text-channel.h
index beb5e718a..828def48d 100644
--- a/telepathy-glib/text-channel.h
+++ b/telepathy-glib/text-channel.h
@@ -121,6 +121,15 @@ gboolean tp_text_channel_ack_all_pending_messages_finish (TpTextChannel *self,
GAsyncResult *result,
GError **error);
+#define TP_TEXT_CHANNEL_FEATURE_CHAT_STATES \
+ tp_text_channel_get_feature_quark_chat_states ()
+_TP_AVAILABLE_IN_0_20
+GQuark tp_text_channel_get_feature_quark_chat_states (void) G_GNUC_CONST;
+
+_TP_AVAILABLE_IN_0_20
+TpChannelChatState tp_text_channel_get_chat_state (TpTextChannel *self,
+ TpContact *contact);
+
void tp_text_channel_set_chat_state_async (TpTextChannel *self,
TpChannelChatState state,
GAsyncReadyCallback callback,
diff --git a/telepathy-glib/tls-certificate-rejection-internal.h b/telepathy-glib/tls-certificate-rejection-internal.h
new file mode 100644
index 000000000..f4f747984
--- /dev/null
+++ b/telepathy-glib/tls-certificate-rejection-internal.h
@@ -0,0 +1,30 @@
+/*
+ * tls-certificate-rejection-internal.h
+ *
+ * Copyright (C) 2012 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * 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
+ */
+
+#ifndef __TP_TLS_CERTIFICATE_REJECTION_INTERNAL_H__
+#define __TP_TLS_CERTIFICATE_REJECTION_INTERNAL_H__
+
+TpTLSCertificateRejection * _tp_tls_certificate_rejection_new (
+ GError *error,
+ TpTLSCertificateRejectReason reason,
+ const gchar *dbus_error,
+ GVariant *details);
+
+#endif
diff --git a/telepathy-glib/tls-certificate-rejection.c b/telepathy-glib/tls-certificate-rejection.c
new file mode 100644
index 000000000..173234602
--- /dev/null
+++ b/telepathy-glib/tls-certificate-rejection.c
@@ -0,0 +1,339 @@
+/*
+ * tls-certificate-rejection.c
+ *
+ * Copyright (C) 2012 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+
+#include "config.h"
+
+#include "tls-certificate-rejection.h"
+#include "tls-certificate-rejection-internal.h"
+
+/**
+ * SECTION: tls-certificate-rejection
+ * @title: TpTLSCertificateRejection
+ * @short_description: a certificate rejection
+ *
+ * TpTLSCertificateRejection is a small object used by
+ * #TpTLSCertificate to represent the rejection of a
+ * certificate.
+ */
+
+/**
+ * TpTLSCertificateRejection:
+ *
+ * Data structure representing a #TpTLSCertificateRejection.
+ *
+ * Since: 0.19.0
+ */
+
+/**
+ * TpTLSCertificateRejectionClass:
+ *
+ * The class of a #TpTLSCertificateRejection.
+ *
+ * Since: 0.19.0
+ */
+
+G_DEFINE_TYPE (TpTLSCertificateRejection, tp_tls_certificate_rejection,
+ G_TYPE_OBJECT)
+
+enum
+{
+ PROP_REASON = 1,
+ PROP_DBUS_ERROR,
+ PROP_DETAILS,
+ PROP_ERROR,
+ N_PROPS
+};
+
+struct _TpTLSCertificateRejectionPriv {
+ TpTLSCertificateRejectReason reason;
+ gchar *dbus_error;
+ GVariant *details;
+ GError *error;
+};
+
+static void
+tp_tls_certificate_rejection_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ TpTLSCertificateRejection *self = TP_TLS_CERTIFICATE_REJECTION (object);
+
+ switch (property_id)
+ {
+ case PROP_REASON:
+ g_value_set_uint (value, self->priv->reason);
+ break;
+ case PROP_DBUS_ERROR:
+ g_value_set_string (value, self->priv->dbus_error);
+ break;
+ case PROP_DETAILS:
+ g_value_set_variant (value, self->priv->details);
+ break;
+ case PROP_ERROR:
+ g_value_set_boxed (value, self->priv->error);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+tp_tls_certificate_rejection_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ TpTLSCertificateRejection *self = TP_TLS_CERTIFICATE_REJECTION (object);
+
+ switch (property_id)
+ {
+ case PROP_REASON:
+ self->priv->reason = g_value_get_uint (value);
+ break;
+ case PROP_DBUS_ERROR:
+ g_assert (self->priv->dbus_error == NULL); /* construct only */
+ self->priv->dbus_error = g_value_dup_string (value);
+ break;
+ case PROP_DETAILS:
+ self->priv->details = g_value_dup_variant (value);
+ break;
+ case PROP_ERROR:
+ self->priv->error = g_value_dup_boxed (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+tp_tls_certificate_rejection_dispose (GObject *object)
+{
+ TpTLSCertificateRejection *self = TP_TLS_CERTIFICATE_REJECTION (object);
+ void (*chain_up) (GObject *) =
+ ((GObjectClass *) tp_tls_certificate_rejection_parent_class)->dispose;
+
+ g_variant_unref (self->priv->details);
+
+ if (chain_up != NULL)
+ chain_up (object);
+}
+
+static void
+tp_tls_certificate_rejection_finalize (GObject *object)
+{
+ TpTLSCertificateRejection *self = TP_TLS_CERTIFICATE_REJECTION (object);
+ void (*chain_up) (GObject *) =
+ ((GObjectClass *) tp_tls_certificate_rejection_parent_class)->finalize;
+
+ g_free (self->priv->dbus_error);
+
+ if (chain_up != NULL)
+ chain_up (object);
+}
+
+static void
+tp_tls_certificate_rejection_class_init (
+ TpTLSCertificateRejectionClass *klass)
+{
+ GObjectClass *oclass = G_OBJECT_CLASS (klass);
+ GParamSpec *spec;
+
+ oclass->get_property = tp_tls_certificate_rejection_get_property;
+ oclass->set_property = tp_tls_certificate_rejection_set_property;
+ oclass->dispose = tp_tls_certificate_rejection_dispose;
+ oclass->finalize = tp_tls_certificate_rejection_finalize;
+
+ /**
+ * TpTLSCertificateRejection:reason:
+ *
+ * #TpTLSCertificateRejectReason representing the reason of the rejection
+ *
+ * Since: 0.19.0
+ */
+ spec = g_param_spec_uint ("reason", "reason",
+ "TpTLSCertificateRejectReason",
+ TP_TLS_CERTIFICATE_REJECT_REASON_UNKNOWN,
+ TP_NUM_TLS_CERTIFICATE_REJECT_REASONS,
+ TP_TLS_CERTIFICATE_REJECT_REASON_UNKNOWN,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (oclass, PROP_REASON, spec);
+
+ /**
+ * TpTLSCertificateRejection:dbus-error:
+ *
+ * The D-Bus error name of the rejection
+ *
+ * Since: 0.19.0
+ */
+ spec = g_param_spec_string ("dbus-error", "dbus-error",
+ "DBus error",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (oclass, PROP_DBUS_ERROR, spec);
+
+ /**
+ * TpTLSCertificateRejection:details:
+ *
+ * A #G_VARIANT_TYPE_VARDICT containing the details of the rejection
+ *
+ * Since: 0.19.0
+ */
+ spec = g_param_spec_variant ("details", "details",
+ "GVariant",
+ G_VARIANT_TYPE_VARDICT, NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (oclass, PROP_DETAILS, spec);
+
+ /**
+ * TpTLSCertificateRejection:error:
+ *
+ * a #GError (likely to be in the %TP_ERROR domain) indicating the reason
+ * of the rejection
+ *
+ * Since: 0.19.0
+ */
+ spec = g_param_spec_boxed ("error", "error",
+ "GError",
+ G_TYPE_ERROR,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (oclass, PROP_ERROR, spec);
+
+ g_type_class_add_private (klass, sizeof (TpTLSCertificateRejectionPriv));
+}
+
+static void
+tp_tls_certificate_rejection_init (TpTLSCertificateRejection *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ TP_TYPE_TLS_CERTIFICATE_REJECTION, TpTLSCertificateRejectionPriv);
+}
+
+/* @details is sinked if it's a floating reference */
+TpTLSCertificateRejection *
+_tp_tls_certificate_rejection_new (
+ GError *error,
+ TpTLSCertificateRejectReason reason,
+ const gchar *dbus_error,
+ GVariant *details)
+{
+ TpTLSCertificateRejection *ret;
+
+ g_variant_ref_sink (details);
+
+ ret = g_object_new (TP_TYPE_TLS_CERTIFICATE_REJECTION,
+ "error", error,
+ "reason", reason,
+ "dbus-error", dbus_error,
+ "details", details,
+ NULL);
+
+ g_variant_unref (details);
+ return ret;
+}
+
+/**
+ * tp_tls_certificate_rejection_get_error:
+ * @self: a #TpTLSCertificateRejection
+ *
+ * Return the #TpTLSCertificateRejection:error property
+ *
+ * Returns: the value of #TpTLSCertificateRejection:error property
+ *
+ * Since: 0.19.0
+ */
+const GError *
+tp_tls_certificate_rejection_get_error (TpTLSCertificateRejection *self)
+{
+ return self->priv->error;
+}
+
+/**
+ * tp_tls_certificate_rejection_get_reason:
+ * @self: a #TpTLSCertificateRejection
+ *
+ * Return the #TpTLSCertificateRejection:reason property
+ *
+ * Returns: the value of #TpTLSCertificateRejection:reason property
+ *
+ * Since: 0.19.0
+ */
+TpTLSCertificateRejectReason
+tp_tls_certificate_rejection_get_reason (TpTLSCertificateRejection *self)
+{
+ return self->priv->reason;
+}
+
+/**
+ * tp_tls_certificate_rejection_get_dbus_error:
+ * @self: a #TpTLSCertificateRejection
+ *
+ * Return the #TpTLSCertificateRejection:dbus-error property
+ *
+ * Returns: the value of #TpTLSCertificateRejection:dbus-error property
+ *
+ * Since: 0.19.0
+ */
+const gchar *
+tp_tls_certificate_rejection_get_dbus_error (TpTLSCertificateRejection *self)
+{
+ return self->priv->dbus_error;
+}
+
+/**
+ * tp_tls_certificate_rejection_get_details:
+ * @self: a #TpTLSCertificateRejection
+ *
+ * Return the #TpTLSCertificateRejection:details property
+ *
+ * Returns: the value of #TpTLSCertificateRejection:details property
+ *
+ * Since: 0.19.0
+ */
+GVariant *
+tp_tls_certificate_rejection_get_details (TpTLSCertificateRejection *self)
+{
+ return self->priv->details;
+}
+
+/**
+ * tp_tls_certificate_rejection_raise_error:
+ * @self: a #TpTLSCertificateRejection
+ * @error: (out) (allow-none) (transfer full): a #GError to fill
+ *
+ * Convenient function to raise the #TpTLSCertificateRejection:error
+ * property in language binding supporting this feature.
+ *
+ * Returns: %FALSE
+ *
+ * Since: 0.19.0
+ */
+gboolean
+tp_tls_certificate_rejection_raise_error (TpTLSCertificateRejection *self,
+ GError **error)
+{
+ if (error != NULL)
+ *error = g_error_copy (self->priv->error);
+
+ return FALSE;
+}
diff --git a/telepathy-glib/tls-certificate-rejection.h b/telepathy-glib/tls-certificate-rejection.h
new file mode 100644
index 000000000..50f5199a9
--- /dev/null
+++ b/telepathy-glib/tls-certificate-rejection.h
@@ -0,0 +1,92 @@
+/*
+ * tls-certificate-rejection.h
+ *
+ * Copyright (C) 2012 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * 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
+ */
+
+
+#ifndef __TP_TLS_CERTIFICATE_REJECTION_H__
+#define __TP_TLS_CERTIFICATE_REJECTION_H__
+
+#include <glib-object.h>
+
+#include <telepathy-glib/defs.h>
+#include <telepathy-glib/enums.h>
+
+G_BEGIN_DECLS
+
+typedef struct _TpTLSCertificateRejection TpTLSCertificateRejection;
+typedef struct _TpTLSCertificateRejectionClass TpTLSCertificateRejectionClass;
+typedef struct _TpTLSCertificateRejectionPriv TpTLSCertificateRejectionPriv;
+
+struct _TpTLSCertificateRejectionClass {
+ /*<private>*/
+ GObjectClass parent_class;
+};
+
+struct _TpTLSCertificateRejection {
+ /*<private>*/
+ GObject parent;
+ TpTLSCertificateRejectionPriv *priv;
+};
+
+_TP_AVAILABLE_IN_0_20
+GType tp_tls_certificate_rejection_get_type (void);
+
+/* TYPE MACROS */
+#define TP_TYPE_TLS_CERTIFICATE_REJECTION \
+ (tp_tls_certificate_rejection_get_type ())
+#define TP_TLS_CERTIFICATE_REJECTION(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), \
+ TP_TYPE_TLS_CERTIFICATE_REJECTION, \
+ TpTLSCertificateRejection))
+#define TP_TLS_CERTIFICATE_REJECTION_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), \
+ TP_TYPE_TLS_CERTIFICATE_REJECTION, \
+ TpTLSCertificateRejectionClass))
+#define TP_IS_TLS_CERTIFICATE_REJECTION(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), \
+ TP_TYPE_TLS_CERTIFICATE_REJECTION))
+#define TP_IS_TLS_CERTIFICATE_REJECTION_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), \
+ TP_TYPE_TLS_CERTIFICATE_REJECTION))
+#define TP_TLS_CERTIFICATE_REJECTION_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ TP_TYPE_TLS_CERTIFICATE_REJECTION, \
+ TpTLSCertificateRejectionClass))
+
+_TP_AVAILABLE_IN_0_20
+const GError * tp_tls_certificate_rejection_get_error (
+ TpTLSCertificateRejection *self);
+_TP_AVAILABLE_IN_0_20
+TpTLSCertificateRejectReason tp_tls_certificate_rejection_get_reason (
+ TpTLSCertificateRejection *self);
+_TP_AVAILABLE_IN_0_20
+const gchar * tp_tls_certificate_rejection_get_dbus_error (
+ TpTLSCertificateRejection *self);
+_TP_AVAILABLE_IN_0_20
+GVariant * tp_tls_certificate_rejection_get_details (
+ TpTLSCertificateRejection *self);
+
+_TP_AVAILABLE_IN_0_20
+gboolean tp_tls_certificate_rejection_raise_error (
+ TpTLSCertificateRejection *self,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* #ifndef __TP_TLS_CERTIFICATE_REJECTION_H__*/
diff --git a/telepathy-glib/tls-certificate.c b/telepathy-glib/tls-certificate.c
new file mode 100644
index 000000000..46374c127
--- /dev/null
+++ b/telepathy-glib/tls-certificate.c
@@ -0,0 +1,923 @@
+/*
+ * TpTLSCertificate - a TpProxy for TLS certificates
+ * Copyright © 2010 Collabora Ltd.
+ *
+ * Based on EmpathyTLSCertificate:
+ * @author Cosimo Cecchi <cosimo.cecchi@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <config.h>
+#include "telepathy-glib/tls-certificate.h"
+
+#include <glib/gstdio.h>
+
+#include <telepathy-glib/cli-misc.h>
+#include <telepathy-glib/dbus.h>
+#include <telepathy-glib/dbus-internal.h>
+#include <telepathy-glib/enums.h>
+#include <telepathy-glib/gtypes.h>
+#include <telepathy-glib/interfaces.h>
+#include <telepathy-glib/proxy-internal.h>
+#include <telepathy-glib/proxy-subclass.h>
+#include <telepathy-glib/util.h>
+#include <telepathy-glib/util-internal.h>
+#include <telepathy-glib/tls-certificate-rejection-internal.h>
+
+#define DEBUG_FLAG TP_DEBUG_TLS
+#include "debug-internal.h"
+
+/**
+ * SECTION:tls-certificate
+ * @title: TpTLSCertificate
+ * @short_description: proxy object for a server or peer's TLS certificate
+ *
+ * #TpTLSCertificate is a #TpProxy subclass for TLSCertificate objects,
+ * used in Channel.Type.ServerTLSConnection.
+ *
+ * Since: 0.19.0
+ */
+
+/**
+ * TpTLSCertificate:
+ *
+ * A #TpProxy subclass representing a server or peer's TLS certificate
+ * being presented for acceptance/rejection.
+ *
+ * Since: 0.19.0
+ */
+
+/**
+ * TpTLSCertificateClass:
+ *
+ * The class of a #TpTLSCertificate.
+ *
+ * Since: 0.19.0
+ */
+
+enum {
+ /* proxy properties */
+ PROP_CERT_TYPE = 1,
+ PROP_CERT_DATA,
+ PROP_STATE,
+ PROP_PARENT,
+ N_PROPS
+};
+
+struct _TpTLSCertificatePrivate {
+ TpProxy *parent;
+
+ /* TLSCertificate properties */
+ gchar *cert_type;
+ GPtrArray *cert_data;
+ TpTLSCertificateState state;
+ /* array of TpTLSCertificateRejection received from the CM */
+ GPtrArray *rejections;
+ /* GPtrArray of TP_STRUCT_TYPE_TLS_CERTIFICATE_REJECTION to send to CM */
+ GPtrArray *pending_rejections;
+};
+
+G_DEFINE_TYPE (TpTLSCertificate, tp_tls_certificate,
+ TP_TYPE_PROXY)
+
+/**
+ * TP_TLS_CERTIFICATE_FEATURE_CORE:
+ *
+ * Expands to a call to a function that returns a quark representing the
+ * core functionality of a #TpTLSCertificate.
+ *
+ * When this feature is prepared, the basic properties of the
+ * object have been retrieved and are available for use:
+ *
+ * <itemizedlist>
+ * <listitem>#TpTLSCertificate:cert-type</listitem>
+ * <listitem>#TpTLSCertificate:cert-data</listitem>
+ * <listitem>#TpTLSCertificate:state</listitem>
+ * </itemizedlist>
+ *
+ * In addition, #GObject::notify::state will be emitted if the state changes.
+ *
+ * One can ask for a feature to be prepared using the
+ * tp_proxy_prepare_async() function, and waiting for it to callback.
+ *
+ * Since: 0.19.0
+ */
+
+GQuark
+tp_tls_certificate_get_feature_quark_core (void)
+{
+ return g_quark_from_static_string ("tp-tls-certificate-feature-core");
+}
+
+static void
+tp_tls_certificate_accepted_cb (TpTLSCertificate *self,
+ gpointer unused G_GNUC_UNUSED,
+ GObject *unused_object G_GNUC_UNUSED)
+{
+ tp_clear_pointer (&self->priv->rejections, g_ptr_array_unref);
+ self->priv->state = TP_TLS_CERTIFICATE_STATE_ACCEPTED;
+ g_object_notify ((GObject *) self, "state");
+}
+
+static void
+tp_tls_certificate_rejected_cb (TpTLSCertificate *self,
+ const GPtrArray *rejections,
+ gpointer unused G_GNUC_UNUSED,
+ GObject *unused_object G_GNUC_UNUSED)
+{
+ self->priv->state = TP_TLS_CERTIFICATE_STATE_REJECTED;
+
+ tp_clear_pointer (&self->priv->rejections, g_ptr_array_unref);
+ self->priv->rejections = g_ptr_array_new_with_free_func (g_object_unref);
+
+ if (rejections == NULL || rejections->len == 0)
+ {
+ TpTLSCertificateRejection *rej;
+ GVariantBuilder builder;
+ GError *error = g_error_new_literal (TP_ERROR, TP_ERROR_CERT_INVALID,
+ "Rejected, no reason given");
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
+
+ rej = _tp_tls_certificate_rejection_new (error,
+ TP_TLS_CERTIFICATE_REJECT_REASON_UNKNOWN, TP_ERROR_STR_CERT_INVALID,
+ g_variant_builder_end (&builder));
+
+ g_ptr_array_add (self->priv->rejections, rej);
+ g_error_free (error);
+ }
+ else
+ {
+ guint i;
+
+ for (i = 0; i < rejections->len; i++)
+ {
+ TpTLSCertificateRejection *rej;
+ GValueArray *va = g_ptr_array_index (rejections, i);
+ const gchar *error_name;
+ const GHashTable *details;
+ TpTLSCertificateRejectReason reason;
+ GError *error = NULL;
+ GVariant *vardict;
+
+ tp_value_array_unpack (va, 3,
+ &reason,
+ &error_name,
+ &details);
+
+ tp_proxy_dbus_error_to_gerror (self, error_name,
+ tp_asv_get_string (details, "debug-message"), &error);
+
+ vardict = _tp_asv_to_vardict (details);
+
+ rej = _tp_tls_certificate_rejection_new (error,
+ reason, error_name, vardict);
+
+ g_ptr_array_add (self->priv->rejections, rej);
+
+ g_error_free (error);
+ g_variant_unref (vardict);
+ }
+ }
+
+ g_object_notify ((GObject *) self, "state");
+}
+
+static void
+tls_certificate_got_all_cb (TpProxy *proxy,
+ GHashTable *properties,
+ const GError *error,
+ gpointer user_data,
+ GObject *weak_object)
+{
+ GPtrArray *cert_data;
+ TpTLSCertificate *self = TP_TLS_CERTIFICATE (proxy);
+ guint state;
+ guint i;
+
+ if (error != NULL)
+ {
+ tp_proxy_invalidate (proxy, error);
+ return;
+ }
+
+ self->priv->cert_type = g_strdup (tp_asv_get_string (properties,
+ "CertificateType"));
+
+ state = tp_asv_get_uint32 (properties, "State", NULL);
+
+ switch (state)
+ {
+ case TP_TLS_CERTIFICATE_STATE_PENDING:
+ break;
+
+ case TP_TLS_CERTIFICATE_STATE_ACCEPTED:
+ tp_tls_certificate_accepted_cb (self, NULL, NULL);
+ break;
+
+ case TP_TLS_CERTIFICATE_STATE_REJECTED:
+ tp_tls_certificate_rejected_cb (self,
+ tp_asv_get_boxed (properties, "Rejections",
+ TP_ARRAY_TYPE_TLS_CERTIFICATE_REJECTION_LIST),
+ NULL, NULL);
+ break;
+
+ default:
+ {
+ GError e = { TP_DBUS_ERRORS, TP_DBUS_ERROR_INCONSISTENT,
+ "Invalid State" };
+
+ DEBUG ("Invalid state '%u' on %s", state,
+ tp_proxy_get_object_path (self));
+ tp_proxy_invalidate (proxy, &e);
+ }
+ }
+
+ cert_data = tp_asv_get_boxed (properties, "CertificateChainData",
+ TP_ARRAY_TYPE_UCHAR_ARRAY_LIST);
+ g_assert (cert_data != NULL);
+
+ self->priv->cert_data = g_ptr_array_new_with_free_func (
+ (GDestroyNotify) g_bytes_unref);
+
+ for (i = 0; i < cert_data->len; i++)
+ {
+ GArray *arr = g_ptr_array_index (cert_data, i);
+ GBytes *bytes;
+
+ bytes = g_bytes_new (arr->data, arr->len);
+ g_ptr_array_add (self->priv->cert_data, bytes);
+ }
+
+ DEBUG ("Got a certificate chain long %u, of type %s",
+ self->priv->cert_data->len, self->priv->cert_type);
+
+ _tp_proxy_set_feature_prepared (proxy, TP_TLS_CERTIFICATE_FEATURE_CORE,
+ TRUE);
+}
+
+static void
+parent_invalidated_cb (TpProxy *parent,
+ guint domain,
+ gint code,
+ gchar *message,
+ TpTLSCertificate *self)
+{
+ GError e = { domain, code, message };
+
+ tp_clear_object (&self->priv->parent);
+
+ tp_proxy_invalidate ((TpProxy *) self, &e);
+ g_object_notify ((GObject *) self, "parent");
+}
+
+static void
+tp_tls_certificate_constructed (GObject *object)
+{
+ TpTLSCertificate *self = TP_TLS_CERTIFICATE (object);
+ void (*constructed) (GObject *) =
+ G_OBJECT_CLASS (tp_tls_certificate_parent_class)->constructed;
+
+ if (constructed != NULL)
+ constructed (object);
+
+ g_return_if_fail (self->priv->parent == NULL ||
+ TP_IS_CHANNEL (self->priv->parent) ||
+ TP_IS_CONNECTION (self->priv->parent));
+
+ if (self->priv->parent != NULL)
+ {
+ if (self->priv->parent->invalidated != NULL)
+ {
+ GError *invalidated = self->priv->parent->invalidated;
+
+ parent_invalidated_cb (self->priv->parent, invalidated->domain,
+ invalidated->code, invalidated->message, self);
+ }
+ else
+ {
+ tp_g_signal_connect_object (self->priv->parent,
+ "invalidated", G_CALLBACK (parent_invalidated_cb), self, 0);
+ }
+ }
+
+ tp_cli_authentication_tls_certificate_connect_to_accepted (self,
+ tp_tls_certificate_accepted_cb, NULL, NULL, NULL, NULL);
+ tp_cli_authentication_tls_certificate_connect_to_rejected (self,
+ tp_tls_certificate_rejected_cb, NULL, NULL, NULL, NULL);
+
+ tp_cli_dbus_properties_call_get_all (self,
+ -1, TP_IFACE_AUTHENTICATION_TLS_CERTIFICATE,
+ tls_certificate_got_all_cb, NULL, NULL, NULL);
+}
+
+static void
+tp_tls_certificate_finalize (GObject *object)
+{
+ TpTLSCertificate *self = TP_TLS_CERTIFICATE (object);
+ TpTLSCertificatePrivate *priv = self->priv;
+
+ DEBUG ("%p", object);
+
+ tp_clear_pointer (&self->priv->rejections, g_ptr_array_unref);
+ g_free (priv->cert_type);
+ if (priv->cert_data != NULL)
+ g_ptr_array_unref (priv->cert_data);
+ tp_clear_boxed (TP_ARRAY_TYPE_TLS_CERTIFICATE_REJECTION_LIST,
+ &self->priv->pending_rejections);
+
+ G_OBJECT_CLASS (tp_tls_certificate_parent_class)->finalize (object);
+}
+
+static void
+tp_tls_certificate_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ TpTLSCertificate *self = TP_TLS_CERTIFICATE (object);
+ TpTLSCertificatePrivate *priv = self->priv;
+
+ switch (property_id)
+ {
+ case PROP_CERT_TYPE:
+ g_value_set_string (value, priv->cert_type);
+ break;
+
+ case PROP_CERT_DATA:
+ g_value_set_boxed (value, priv->cert_data);
+ break;
+
+ case PROP_STATE:
+ g_value_set_uint (value, priv->state);
+ break;
+
+ case PROP_PARENT:
+ g_value_set_object (value, priv->parent);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+tp_tls_certificate_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ TpTLSCertificate *self = TP_TLS_CERTIFICATE (object);
+
+ switch (property_id)
+ {
+ case PROP_PARENT:
+ self->priv->parent = TP_PROXY (g_value_dup_object (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+tp_tls_certificate_init (TpTLSCertificate *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ TP_TYPE_TLS_CERTIFICATE, TpTLSCertificatePrivate);
+}
+
+enum {
+ FEAT_CORE,
+ N_FEAT
+};
+
+static const TpProxyFeature *
+tp_tls_certificate_list_features (TpProxyClass *cls G_GNUC_UNUSED)
+{
+ static TpProxyFeature features[N_FEAT + 1] = { { 0 } };
+
+ if (G_LIKELY (features[0].name != 0))
+ return features;
+
+ features[FEAT_CORE].name = TP_TLS_CERTIFICATE_FEATURE_CORE;
+ features[FEAT_CORE].core = TRUE;
+
+ g_assert (features[N_FEAT].name == 0);
+ return features;
+}
+
+static void
+tp_tls_certificate_class_init (TpTLSCertificateClass *klass)
+{
+ GParamSpec *pspec;
+ GObjectClass *oclass = G_OBJECT_CLASS (klass);
+ TpProxyClass *pclass = TP_PROXY_CLASS (klass);
+
+ tp_tls_certificate_init_known_interfaces ();
+
+ oclass->get_property = tp_tls_certificate_get_property;
+ oclass->set_property = tp_tls_certificate_set_property;
+ oclass->constructed = tp_tls_certificate_constructed;
+ oclass->finalize = tp_tls_certificate_finalize;
+
+ pclass->interface = TP_IFACE_QUARK_AUTHENTICATION_TLS_CERTIFICATE;
+ pclass->must_have_unique_name = TRUE;
+ pclass->list_features = tp_tls_certificate_list_features;
+
+ g_type_class_add_private (klass, sizeof (TpTLSCertificatePrivate));
+
+ /**
+ * TpTLSCertificate:cert-type:
+ *
+ * The type of the certificate, typically either "x509" or "pgp".
+ *
+ * Since: 0.19.0
+ */
+ pspec = g_param_spec_string ("cert-type", "Certificate type",
+ "The type of this certificate.",
+ NULL,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (oclass, PROP_CERT_TYPE, pspec);
+
+ /**
+ * TpTLSCertificate:cert-data:
+ *
+ * The raw data of the certificate or certificate chain, represented
+ * as a #GPtrArray of #GBytes. It should be interpreted
+ * according to #TpTLSCertificate:cert-type.
+ *
+ * The first certificate in this array is the server's certificate,
+ * followed by its issuer, followed by the issuer's issuer and so on.
+ *
+ * For "x509" certificates, each certificate is an X.509 certificate in
+ * binary (DER) format.
+ *
+ * For "pgp" certificates, each certificate is a binary OpenPGP key.
+ *
+ * Since: 0.19.0
+ */
+ pspec = g_param_spec_boxed ("cert-data", "Certificate chain data",
+ "The raw DER-encoded certificate chain data.",
+ G_TYPE_PTR_ARRAY,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (oclass, PROP_CERT_DATA, pspec);
+
+ /**
+ * TpTLSCertificate:state:
+ *
+ * The state of this TLS certificate as a #TpTLSCertificateState,
+ * initially %TP_TLS_CERTIFICATE_STATE_PENDING.
+ *
+ * #GObject::notify::state will be emitted when this changes.
+ *
+ * Since: 0.19.0
+ */
+ pspec = g_param_spec_uint ("state", "State",
+ "The state of this certificate.",
+ 0, TP_NUM_TLS_CERTIFICATE_STATES - 1, TP_TLS_CERTIFICATE_STATE_PENDING,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (oclass, PROP_STATE, pspec);
+
+ /**
+ * TpTLSCertificate:parent:
+ *
+ * A #TpConnection or #TpChannel which owns this TLS certificate. If the
+ * parent object is invalidated, the certificate is also invalidated, and
+ * this property is set to %NULL.
+ *
+ * Since: 0.19.0
+ */
+ pspec = g_param_spec_object ("parent", "Parent",
+ "The TpConnection or TpChannel to which this belongs", TP_TYPE_PROXY,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (oclass, PROP_PARENT, pspec);
+}
+
+static void
+cert_proxy_accept_cb (TpTLSCertificate *self,
+ const GError *error,
+ gpointer user_data,
+ GObject *unused_object G_GNUC_UNUSED)
+{
+ GSimpleAsyncResult *accept_result = user_data;
+
+ DEBUG ("Callback for accept(), error %p", error);
+
+ if (error != NULL)
+ {
+ DEBUG ("Error was %s", error->message);
+ g_simple_async_result_set_from_error (accept_result, error);
+ }
+
+ g_simple_async_result_complete (accept_result);
+}
+
+static void
+cert_proxy_reject_cb (TpTLSCertificate *self,
+ const GError *error,
+ gpointer user_data,
+ GObject *unused_object G_GNUC_UNUSED)
+{
+ GSimpleAsyncResult *reject_result = user_data;
+
+ DEBUG ("Callback for reject(), error %p", error);
+
+ if (error != NULL)
+ {
+ DEBUG ("Error was %s", error->message);
+ g_simple_async_result_set_from_error (reject_result, error);
+ }
+
+ g_simple_async_result_complete (reject_result);
+}
+
+static const gchar *
+reject_reason_get_dbus_error (TpTLSCertificateRejectReason reason)
+{
+ const gchar *retval = NULL;
+
+ switch (reason)
+ {
+#define EASY_CASE(x) \
+ case TP_TLS_CERTIFICATE_REJECT_REASON_ ## x: \
+ retval = tp_error_get_dbus_name (TP_ERROR_CERT_ ## x); \
+ break
+ EASY_CASE (UNTRUSTED);
+ EASY_CASE (EXPIRED);
+ EASY_CASE (NOT_ACTIVATED);
+ EASY_CASE (FINGERPRINT_MISMATCH);
+ EASY_CASE (HOSTNAME_MISMATCH);
+ EASY_CASE (SELF_SIGNED);
+ EASY_CASE (REVOKED);
+ EASY_CASE (INSECURE);
+ EASY_CASE (LIMIT_EXCEEDED);
+#undef EASY_CASE
+
+ case TP_TLS_CERTIFICATE_REJECT_REASON_UNKNOWN:
+ default:
+ retval = tp_error_get_dbus_name (TP_ERROR_CERT_INVALID);
+ break;
+ }
+
+ return retval;
+}
+
+/**
+ * tp_tls_certificate_new:
+ * @conn_or_chan: a #TpConnection or #TpChannel parent for this object, whose
+ * invalidation will also result in invalidation of the returned object
+ * @object_path: the object path of this TLS certificate
+ * @error: a #GError used to return an error if %NULL is returned, or %NULL
+ *
+ * <!-- -->
+ *
+ * Returns: (transfer full): a new TLS certificate proxy. Prepare the
+ * feature %TP_TLS_CERTIFICATE_FEATURE_CORE to make it useful.
+ * Since: 0.19.0
+ */
+TpTLSCertificate *
+tp_tls_certificate_new (TpProxy *conn_or_chan,
+ const gchar *object_path,
+ GError **error)
+{
+ TpTLSCertificate *retval = NULL;
+
+ g_return_val_if_fail (TP_IS_CONNECTION (conn_or_chan) ||
+ TP_IS_CHANNEL (conn_or_chan), NULL);
+
+ if (!tp_dbus_check_valid_object_path (object_path, error))
+ goto finally;
+
+ retval = g_object_new (TP_TYPE_TLS_CERTIFICATE,
+ "parent", conn_or_chan,
+ "dbus-daemon", conn_or_chan->dbus_daemon,
+ "bus-name", conn_or_chan->bus_name,
+ "object-path", object_path,
+ NULL);
+
+finally:
+ return retval;
+}
+
+/**
+ * tp_tls_certificate_accept_async:
+ * @self: a TLS certificate
+ * @callback: called on success or failure
+ * @user_data: user data for the callback
+ *
+ * Accept this certificate, asynchronously. In or after @callback,
+ * you may call tp_tls_certificate_accept_finish() to check the result.
+ *
+ * #GObject::notify::state will also be emitted when the connection manager
+ * signals that the certificate has been accepted.
+ * Since: 0.19.0
+ */
+void
+tp_tls_certificate_accept_async (TpTLSCertificate *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *accept_result;
+
+ g_assert (TP_IS_TLS_CERTIFICATE (self));
+
+ DEBUG ("Accepting TLS certificate");
+
+ accept_result = g_simple_async_result_new (G_OBJECT (self),
+ callback, user_data, tp_tls_certificate_accept_async);
+
+ tp_cli_authentication_tls_certificate_call_accept (self,
+ -1, cert_proxy_accept_cb,
+ accept_result, g_object_unref, NULL);
+}
+
+/**
+ * tp_tls_certificate_accept_finish:
+ * @self: a TLS certificate
+ * @result: the result passed to the callback by
+ * tp_tls_certificate_accept_async()
+ * @error: used to raise an error if %FALSE is returned
+ *
+ * Check the result of tp_tls_certificate_accept_async().
+ *
+ * Returns: %TRUE if acceptance was successful
+ * Since: 0.19.0
+ */
+gboolean
+tp_tls_certificate_accept_finish (TpTLSCertificate *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ _tp_implement_finish_void (self, tp_tls_certificate_accept_async)
+}
+
+/**
+ * tp_tls_certificate_add_rejection:
+ * @self: a TLS certificate
+ * @reason: the reason for rejection
+ * @dbus_error: a D-Bus error name such as %TP_ERROR_STR_CERT_REVOKED, or
+ * %NULL to derive one from @reason
+ * @details: (transfer none) (allow-none): a variant of type
+ * %G_VARIANT_TYPE_VARDICT containing the details of the rejection, or %NULL
+ *
+ * Add a pending reason for rejection. The first call to this method is
+ * considered "most important". After calling this method as many times
+ * as are required, call tp_tls_certificate_reject_async() to reject the
+ * certificate.
+ *
+ * If @details is a floating reference (see g_variant_ref_sink()),
+ * ownership of @details is taken by this function. This means
+ * you can pass the result of g_variant_new() or g_variant_new_parsed()
+ * directly to this function without additional reference-count management.
+ *
+ * Since: 0.19.0
+ */
+void
+tp_tls_certificate_add_rejection (TpTLSCertificate *self,
+ TpTLSCertificateRejectReason reason,
+ const gchar *dbus_error,
+ GVariant *details)
+{
+ GValueArray *rejection;
+ GHashTable *hash;
+
+ g_return_if_fail (dbus_error == NULL ||
+ tp_dbus_check_valid_interface_name (dbus_error, NULL));
+ g_return_if_fail (details == NULL ||
+ g_variant_is_of_type (details, G_VARIANT_TYPE_VARDICT));
+
+ if (self->priv->pending_rejections == NULL)
+ self->priv->pending_rejections = g_ptr_array_new ();
+
+ if (dbus_error == NULL)
+ dbus_error = reject_reason_get_dbus_error (reason);
+
+ if (details == NULL)
+ {
+ hash = g_hash_table_new (NULL, NULL);
+ }
+ else
+ {
+ hash = _tp_asv_from_vardict (details);
+ g_variant_ref_sink (details);
+ }
+
+ rejection = tp_value_array_build (3,
+ G_TYPE_UINT, reason,
+ G_TYPE_STRING, dbus_error,
+ TP_HASH_TYPE_STRING_VARIANT_MAP, hash,
+ NULL);
+
+ g_ptr_array_add (self->priv->pending_rejections, rejection);
+
+ g_hash_table_unref (hash);
+
+ if (details != NULL)
+ g_variant_unref (details);
+}
+
+/**
+ * tp_tls_certificate_reject_async:
+ * @self: a TLS certificate
+ * @callback: called on success or failure
+ * @user_data: user data for the callback
+ *
+ * Reject this certificate, asynchronously.
+ *
+ * Before calling this method, you must call
+ * tp_tls_certificate_add_rejection() at least once, to set the reason(s)
+ * for rejection (for instance, a certificate might be both self-signed and
+ * expired).
+ *
+ * In or after @callback,
+ * you may call tp_tls_certificate_reject_finish() to check the result.
+ *
+ * #GObject::notify::state will also be emitted when the connection manager
+ * signals that the certificate has been rejected.
+ * Since: 0.19.0
+ */
+void
+tp_tls_certificate_reject_async (TpTLSCertificate *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *reject_result;
+
+ g_return_if_fail (TP_IS_TLS_CERTIFICATE (self));
+ g_return_if_fail (self->priv->pending_rejections != NULL);
+ g_return_if_fail (self->priv->pending_rejections->len >= 1);
+
+ reject_result = g_simple_async_result_new (G_OBJECT (self),
+ callback, user_data, tp_tls_certificate_reject_async);
+
+ tp_cli_authentication_tls_certificate_call_reject (self,
+ -1, self->priv->pending_rejections, cert_proxy_reject_cb,
+ reject_result, g_object_unref, NULL);
+
+ tp_clear_boxed (TP_ARRAY_TYPE_TLS_CERTIFICATE_REJECTION_LIST,
+ &self->priv->pending_rejections);
+}
+
+/**
+ * tp_tls_certificate_reject_finish:
+ * @self: a TLS certificate
+ * @result: the result passed to the callback by
+ * tp_tls_certificate_reject_async()
+ * @error: used to raise an error if %FALSE is returned
+ *
+ * Check the result of tp_tls_certificate_reject_async().
+ *
+ * Returns: %TRUE if rejection was successful
+ * Since: 0.19.0
+ */
+gboolean
+tp_tls_certificate_reject_finish (TpTLSCertificate *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ _tp_implement_finish_void (self, tp_tls_certificate_reject_async)
+}
+
+#include <telepathy-glib/_gen/tp-cli-tls-cert-body.h>
+
+/**
+ * tp_tls_certificate_init_known_interfaces:
+ *
+ * Ensure that the known interfaces for TpTLSCertificate have been set up.
+ * This is done automatically when necessary, but for correct
+ * overriding of library interfaces by local extensions, you should
+ * call this function before calling
+ * tp_proxy_or_subclass_hook_on_interface_add() with first argument
+ * %TP_TYPE_TLS_CERTIFICATE.
+ *
+ * Since: 0.19.0
+ */
+void
+tp_tls_certificate_init_known_interfaces (void)
+{
+ static gsize once = 0;
+
+ if (g_once_init_enter (&once))
+ {
+ GType tp_type = TP_TYPE_TLS_CERTIFICATE;
+
+ tp_proxy_init_known_interfaces ();
+ tp_proxy_or_subclass_hook_on_interface_add (tp_type,
+ tp_cli_tls_cert_add_signals);
+ tp_proxy_subclass_add_error_mapping (tp_type,
+ TP_ERROR_PREFIX, TP_ERROR, TP_TYPE_ERROR);
+
+ g_once_init_leave (&once, 1);
+ }
+}
+
+/**
+ * tp_tls_certificate_get_rejection:
+ * @self: a TLS certificate
+ *
+ * If this certificate has been rejected, return a #TpTLSCertificateRejection
+ * indicating the first rejection reason (by convention,
+ * the most important).
+ *
+ * If you want to list all the things that are wrong with the certificate
+ * (for instance, it might be self-signed and also have expired)
+ * you can call tp_tls_certificate_get_nth_rejection(), increasing @n until
+ * it returns %NULL.
+ *
+ * Returns: (transfer none) (allow-none): a #TpTLSCertificateRejection, or %NULL
+ * Since: 0.19.0
+ */
+TpTLSCertificateRejection *
+tp_tls_certificate_get_rejection (TpTLSCertificate *self)
+{
+ return tp_tls_certificate_get_nth_rejection (self, 0);
+}
+
+/**
+ * tp_tls_certificate_get_nth_rejection:
+ * @self: a TLS certificate
+ * @n: the rejection reason to return; if 0, return the same thing as
+ * tp_tls_certificate_get_detailed_rejection()
+ *
+ * If this certificate has been rejected and @n is less than the number of
+ * rejection reasons, return a #TpTLSCertificateRejection representing the
+ * @n<!---->th rejection reason (starting from 0).
+ *
+ * With @n == 0 this is equivalent to tp_tls_certificate_get_rejection().
+ *
+ * Returns: (transfer none) (allow-none): a #TpTLSCertificateRejection, or %NULL
+ * Since: 0.19.0
+ */
+TpTLSCertificateRejection *
+tp_tls_certificate_get_nth_rejection (TpTLSCertificate *self,
+ guint n)
+{
+ if (self->priv->rejections == NULL || n >= self->priv->rejections->len)
+ return NULL;
+
+ return g_ptr_array_index (self->priv->rejections, n);
+}
+
+/**
+ * tp_tls_certificate_get_cert_type:
+ * @self: a #TpTLSCertificate
+ *
+ * Return the #TpTLSCertificate:cert-type property
+ *
+ * Returns: the value of #TpTLSCertificate:cert-type property
+ *
+ * Since: 0.19.0
+ */
+const gchar *
+tp_tls_certificate_get_cert_type (TpTLSCertificate *self)
+{
+ return self->priv->cert_type;
+}
+
+/**
+ * tp_tls_certificate_get_cert_data:
+ * @self: a #TpTLSCertificate
+ *
+ * Return the #TpTLSCertificate:cert-data property
+ *
+ * Returns: (transfer none) (type GLib.PtrArray) (element-type GLib.Bytes): the value of #TpTLSCertificate:cert-data property
+ *
+ * Since: 0.19.0
+ */
+GPtrArray *
+tp_tls_certificate_get_cert_data (TpTLSCertificate *self)
+{
+ return self->priv->cert_data;
+}
+
+/**
+ * tp_tls_certificate_get_state:
+ * @self: a #TpTLSCertificate
+ *
+ * Return the #TpTLSCertificate:state property
+ *
+ * Returns: the value of #TpTLSCertificate:state property
+ *
+ * Since: 0.19.0
+ */
+TpTLSCertificateState
+tp_tls_certificate_get_state (TpTLSCertificate *self)
+{
+ return self->priv->state;
+}
diff --git a/telepathy-glib/tls-certificate.h b/telepathy-glib/tls-certificate.h
new file mode 100644
index 000000000..72b1c018d
--- /dev/null
+++ b/telepathy-glib/tls-certificate.h
@@ -0,0 +1,127 @@
+/*
+ * TpTLSCertificate - a TpProxy for TLS certificates
+ * Copyright © 2010 Collabora Ltd.
+ *
+ * Based on EmpathyTLSCertificate:
+ * @author Cosimo Cecchi <cosimo.cecchi@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * 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
+ */
+
+#ifndef __TP_TLS_CERTIFICATE_H__
+#define __TP_TLS_CERTIFICATE_H__
+
+#include <glib-object.h>
+#include <gio/gio.h>
+
+#include <telepathy-glib/channel.h>
+#include <telepathy-glib/enums.h>
+#include <telepathy-glib/proxy.h>
+#include <telepathy-glib/tls-certificate-rejection.h>
+
+G_BEGIN_DECLS
+
+typedef struct _TpTLSCertificate TpTLSCertificate;
+typedef struct _TpTLSCertificateClass TpTLSCertificateClass;
+typedef struct _TpTLSCertificatePrivate TpTLSCertificatePrivate;
+typedef struct _TpTLSCertificateClassPrivate TpTLSCertificateClassPrivate;
+
+struct _TpTLSCertificateClass {
+ /*<private>*/
+ TpProxyClass parent_class;
+ GCallback _future[3];
+ TpTLSCertificateClassPrivate *priv;
+};
+
+struct _TpTLSCertificate {
+ /*<private>*/
+ TpProxy parent;
+ TpTLSCertificatePrivate *priv;
+};
+
+_TP_AVAILABLE_IN_0_20
+GType tp_tls_certificate_get_type (void);
+
+#define TP_TYPE_TLS_CERTIFICATE \
+ (tp_tls_certificate_get_type ())
+#define TP_TLS_CERTIFICATE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), TP_TYPE_TLS_CERTIFICATE, \
+ TpTLSCertificate))
+#define TP_TLS_CERTIFICATE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), TP_TYPE_TLS_CERTIFICATE, \
+ TpTLSCertificateClass))
+#define TP_IS_TLS_CERTIFICATE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TP_TYPE_TLS_CERTIFICATE))
+#define TP_IS_TLS_CERTIFICATE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), TP_TYPE_TLS_CERTIFICATE))
+#define TP_TLS_CERTIFICATE_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TYPE_TLS_CERTIFICATE, \
+ TpTLSCertificateClass))
+
+_TP_AVAILABLE_IN_0_20
+GQuark tp_tls_certificate_get_feature_quark_core (void);
+#define TP_TLS_CERTIFICATE_FEATURE_CORE \
+ (tp_tls_certificate_get_feature_quark_core ())
+
+_TP_AVAILABLE_IN_0_20
+TpTLSCertificate *tp_tls_certificate_new (TpProxy *conn_or_chan,
+ const gchar *object_path,
+ GError **error);
+
+_TP_AVAILABLE_IN_0_20
+TpTLSCertificateRejection *tp_tls_certificate_get_rejection (
+ TpTLSCertificate *self);
+
+_TP_AVAILABLE_IN_0_20
+TpTLSCertificateRejection *tp_tls_certificate_get_nth_rejection (
+ TpTLSCertificate *self,
+ guint n);
+
+_TP_AVAILABLE_IN_0_20
+void tp_tls_certificate_accept_async (TpTLSCertificate *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+_TP_AVAILABLE_IN_0_20
+gboolean tp_tls_certificate_accept_finish (TpTLSCertificate *self,
+ GAsyncResult *result,
+ GError **error);
+
+_TP_AVAILABLE_IN_0_20
+void tp_tls_certificate_add_rejection (TpTLSCertificate *self,
+ TpTLSCertificateRejectReason reason,
+ const gchar *dbus_error,
+ GVariant *details);
+_TP_AVAILABLE_IN_0_20
+void tp_tls_certificate_reject_async (TpTLSCertificate *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+_TP_AVAILABLE_IN_0_20
+gboolean tp_tls_certificate_reject_finish (TpTLSCertificate *self,
+ GAsyncResult *result,
+ GError **error);
+
+_TP_AVAILABLE_IN_0_20
+void tp_tls_certificate_init_known_interfaces (void);
+
+_TP_AVAILABLE_IN_0_20
+const gchar * tp_tls_certificate_get_cert_type (TpTLSCertificate *self);
+_TP_AVAILABLE_IN_0_20
+GPtrArray * tp_tls_certificate_get_cert_data (TpTLSCertificate *self);
+_TP_AVAILABLE_IN_0_20
+TpTLSCertificateState tp_tls_certificate_get_state (TpTLSCertificate *self);
+
+G_END_DECLS
+
+#endif /* multiple-inclusion guard */
diff --git a/telepathy-glib/versions/0.19.0.abi b/telepathy-glib/versions/0.19.0.abi
new file mode 100644
index 000000000..069e86ec3
--- /dev/null
+++ b/telepathy-glib/versions/0.19.0.abi
@@ -0,0 +1,97 @@
+Version: TELEPATHY_GLIB_0.19.0
+Extends: TELEPATHY_GLIB_0.18.0
+Release: 0.19.0
+
+tp_room_info_get_subject
+tp_debug_message_get_category
+tp_room_info_get_requires_password
+tp_account_channel_request_new_audio_video_call
+tp_debug_client_init_known_interfaces
+tp_room_info_get_handle
+tp_account_channel_request_set_request_property
+tp_room_info_get_server
+tp_cli_authentication_tls_certificate_call_reject
+tp_tls_certificate_get_rejection
+tp_capabilities_supports_file_transfer_uri
+tp_room_list_start
+tp_tls_certificate_add_rejection
+tp_svc_connection_interface_contacts_implement_get_contact_by_id
+tp_tls_certificate_rejection_get_error
+tp_debug_client_get_type
+tp_capabilities_supports_file_transfer_initial_offset
+tp_room_info_get_description
+tp_tls_certificate_rejection_raise_error
+tp_cli_debug_connect_to_new_debug_message
+tp_tls_certificate_rejection_get_type
+tp_capabilities_supports_sms
+tp_debug_client_set_enabled_finish
+tp_room_info_get_type
+tp_connection_manager_param_dup_default_variant
+tp_room_info_get_invite_only
+tp_tls_certificate_rejection_get_details
+tp_connection_dup_contact_by_id_async
+tp_tls_certificate_init_known_interfaces
+tp_account_channel_request_set_target_id
+tp_debug_client_new
+tp_tls_certificate_new
+tp_connection_upgrade_contacts_finish
+tp_tls_certificate_get_feature_quark_core
+tp_tls_certificate_get_cert_data
+tp_room_info_get_handle_name
+tp_tls_certificate_rejection_get_reason
+tp_tls_certificate_get_type
+tp_room_list_get_account
+tp_tls_certificate_reject_finish
+tp_cli_connection_interface_contacts_call_get_contact_by_id
+tp_capabilities_supports_file_transfer_timestamp
+tp_room_info_get_channel_type
+tp_tls_certificate_get_nth_rejection
+tp_debug_client_set_enabled_async
+tp_capabilities_dup_channel_classes_variant
+tp_connection_dup_contact_by_id_finish
+tp_debug_client_get_feature_quark_core
+tp_room_info_get_name
+tp_account_channel_request_set_target_contact
+tp_connection_dup_detailed_error_vardict
+tp_tls_certificate_get_cert_type
+tp_cli_authentication_tls_certificate_call_accept
+tp_tls_certificate_rejection_get_dbus_error
+tp_tls_certificate_accept_async
+tp_debug_client_is_enabled
+tp_account_channel_request_new_audio_call
+tp_debug_message_get_domain
+tp_debug_client_get_messages_finish
+tp_room_info_get_members_count
+tp_account_channel_request_set_file_transfer_timestamp
+tp_debug_message_get_type
+tp_tls_certificate_get_state
+tp_debug_message_get_time
+tp_debug_client_get_messages_async
+tp_cli_authentication_tls_certificate_connect_to_accepted
+tp_contact_get_account
+tp_connection_upgrade_contacts_async
+tp_account_channel_request_set_file_transfer_initial_offset
+tp_debug_message_get_message
+tp_tls_certificate_accept_finish
+tp_debug_message_get_level
+tp_room_list_get_server
+tp_account_channel_request_new_text
+tp_cli_debug_call_get_messages
+tp_account_channel_request_set_file_transfer_description
+tp_room_list_get_type
+tp_room_list_new_async
+tp_room_list_is_listing
+tp_room_list_new_finish
+tp_room_info_get_room_id
+tp_base_connection_disconnect_with_dbus_error_vardict
+tp_account_channel_request_new_file_transfer
+tp_cli_authentication_tls_certificate_connect_to_rejected
+tp_account_channel_request_set_file_transfer_uri
+tp_capabilities_supports_file_transfer_description
+tp_tls_certificate_reject_async
+tp_text_channel_get_feature_quark_chat_states
+tp_text_channel_get_chat_state
+tp_message_mixin_chat_state_iface_init
+tp_message_mixin_maybe_send_gone
+tp_message_mixin_change_chat_state
+tp_message_mixin_implement_send_chat_state
diff --git a/tests/dbus/Makefile.am b/tests/dbus/Makefile.am
index c111112a3..53c198656 100644
--- a/tests/dbus/Makefile.am
+++ b/tests/dbus/Makefile.am
@@ -55,6 +55,7 @@ tests_list = \
test-stream-tube \
test-text-channel \
test-text-respawn \
+ test-tls-certificate \
test-unsupported-interface
if ENABLE_INSTALLED_TESTS
@@ -248,6 +249,8 @@ test_debug_client_SOURCES = debug-client.c
test_room_list_SOURCES = room-list.c
+test_tls_certificate_SOURCES = tls-certificate.c
+
check_c_sources = *.c
include $(top_srcdir)/tools/check-coding-style.mk
check-local: check-coding-style
diff --git a/tests/dbus/text-channel.c b/tests/dbus/text-channel.c
index 32ccde569..fca77954e 100644
--- a/tests/dbus/text-channel.c
+++ b/tests/dbus/text-channel.c
@@ -966,6 +966,81 @@ test_receive_muc_delivery (Test *test,
g_ptr_array_unref (parts);
}
+static void
+set_chat_state_cb (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ Test *test = user_data;
+
+ tp_text_channel_set_chat_state_finish (TP_TEXT_CHANNEL (source), result,
+ &test->error);
+
+ test->wait--;
+ if (test->wait <= 0)
+ g_main_loop_quit (test->mainloop);
+}
+
+static void
+contact_chat_state_changed_cb (TpTextChannel *channel,
+ TpContact *contact,
+ TpChannelChatState state,
+ Test *test)
+{
+ test->wait--;
+ if (test->wait <= 0)
+ g_main_loop_quit (test->mainloop);
+}
+
+static void
+test_chat_state (Test *test,
+ gconstpointer data G_GNUC_UNUSED)
+{
+ GQuark features[] = {
+ TP_CHANNEL_FEATURE_CONTACTS,
+ TP_TEXT_CHANNEL_FEATURE_CHAT_STATES,
+ 0 };
+ TpContact *contact;
+ TpChannelChatState state;
+
+ /* Set an initial chat state, prepare the channel, and verify target contact
+ * has that state */
+ tp_message_mixin_change_chat_state (G_OBJECT (test->chan_service),
+ test->bob, TP_CHANNEL_CHAT_STATE_COMPOSING);
+
+ tp_tests_proxy_run_until_prepared (test->channel, features);
+
+ contact = tp_channel_get_target_contact ((TpChannel *) test->channel);
+ state = tp_text_channel_get_chat_state (test->channel, contact);
+ g_assert_cmpuint (state, ==, TP_CHANNEL_CHAT_STATE_COMPOSING);
+
+ /* Test setting invalid chat state */
+ tp_text_channel_set_chat_state_async (test->channel, -1,
+ set_chat_state_cb, test);
+ g_main_loop_run (test->mainloop);
+ g_assert_error (test->error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT);
+ g_clear_error (&test->error);
+
+ tp_text_channel_set_chat_state_async (test->channel,
+ TP_CHANNEL_CHAT_STATE_GONE, set_chat_state_cb, test);
+ g_main_loop_run (test->mainloop);
+ g_assert_error (test->error, TP_ERROR, TP_ERROR_INVALID_ARGUMENT);
+ g_clear_error (&test->error);
+
+ /* Now set a valid chat state and verify self contact has that state */
+ tp_text_channel_set_chat_state_async (test->channel,
+ TP_CHANNEL_CHAT_STATE_COMPOSING, set_chat_state_cb, test);
+ g_signal_connect (test->channel, "contact-chat-state-changed",
+ G_CALLBACK (contact_chat_state_changed_cb), test);
+ test->wait = 2;
+ g_main_loop_run (test->mainloop);
+ g_assert_no_error (test->error);
+
+ contact = tp_connection_get_self_contact (test->connection);
+ state = tp_text_channel_get_chat_state (test->channel, contact);
+ g_assert_cmpuint (state, ==, TP_CHANNEL_CHAT_STATE_COMPOSING);
+}
+
int
main (int argc,
char **argv)
@@ -1001,6 +1076,8 @@ main (int argc,
test_sent_with_no_sender, teardown);
g_test_add ("/text-channel/receive-muc-delivery", Test, NULL, setup,
test_receive_muc_delivery, teardown);
+ g_test_add ("/text-channel/chat-state", Test, NULL, setup,
+ test_chat_state, teardown);
return g_test_run ();
}
diff --git a/tests/dbus/tls-certificate.c b/tests/dbus/tls-certificate.c
new file mode 100644
index 000000000..752ea6d30
--- /dev/null
+++ b/tests/dbus/tls-certificate.c
@@ -0,0 +1,355 @@
+/* Tests of TpTLSCertificate
+ *
+ * Copyright © 2012 Collabora Ltd. <http://www.collabora.co.uk/>
+ *
+ * Copying and distribution of this file, with or without modification,
+ * are permitted in any medium without royalty provided the copyright
+ * notice and this notice are preserved.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <telepathy-glib/telepathy-glib.h>
+
+#include "tests/lib/contacts-conn.h"
+#include "tests/lib/tls-certificate.h"
+#include "tests/lib/util.h"
+
+typedef struct {
+ GMainLoop *mainloop;
+ TpDBusDaemon *dbus;
+
+ /* Service side objects */
+ TpBaseConnection *base_connection;
+ TpTestsTLSCertificate *service_cert;
+
+ /* Client side objects */
+ TpConnection *connection;
+ TpTLSCertificate *cert;
+
+ GError *error /* initialized where needed */;
+ gint wait;
+} Test;
+
+
+static void
+setup (Test *test,
+ gconstpointer data)
+{
+ gchar *path;
+ GPtrArray *chain_data;
+ GArray *cert;
+
+ test->mainloop = g_main_loop_new (NULL, FALSE);
+ test->dbus = tp_tests_dbus_daemon_dup_or_die ();
+
+ test->error = NULL;
+
+ /* Create (service and client sides) connection objects */
+ tp_tests_create_and_connect_conn (TP_TESTS_TYPE_CONTACTS_CONNECTION,
+ "me@test.com", &test->base_connection, &test->connection);
+
+ path = g_strdup_printf ("%s/TlsCertificate",
+ tp_proxy_get_object_path (test->connection));
+
+ chain_data = g_ptr_array_new_with_free_func ((GDestroyNotify) g_array_unref);
+
+ cert = g_array_new (TRUE, TRUE, sizeof (guchar));
+ g_array_append_vals (cert, "BADGER", 6);
+ g_ptr_array_add (chain_data, cert);
+
+ test->service_cert = g_object_new (TP_TESTS_TYPE_TLS_CERTIFICATE,
+ "object-path", path,
+ "certificate-type", "x509",
+ "certificate-chain-data", chain_data,
+ "dbus-daemon", test->dbus,
+ NULL);
+
+ g_ptr_array_unref (chain_data);
+
+ test->cert = tp_tls_certificate_new (TP_PROXY (test->connection), path,
+ &test->error);
+ g_assert_no_error (test->error);
+
+ g_free (path);
+}
+
+static void
+disconnect_conn (Test *test)
+{
+ if (test->connection == NULL)
+ return;
+
+ tp_tests_connection_assert_disconnect_succeeds (test->connection);
+ tp_clear_object (&test->connection);
+ tp_clear_object (&test->base_connection);
+}
+
+static void
+teardown (Test *test,
+ gconstpointer data)
+{
+ g_clear_error (&test->error);
+
+ tp_clear_object (&test->dbus);
+ g_main_loop_unref (test->mainloop);
+ test->mainloop = NULL;
+
+ tp_clear_object (&test->service_cert);
+ tp_clear_object (&test->cert);
+
+ disconnect_conn (test);
+}
+
+static void
+test_creation (Test *test,
+ gconstpointer data G_GNUC_UNUSED)
+{
+ g_assert (TP_IS_TLS_CERTIFICATE (test->cert));
+}
+
+static void
+proxy_prepare_cb (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ Test *test = user_data;
+
+ tp_proxy_prepare_finish (source, result, &test->error);
+
+ test->wait--;
+ if (test->wait <= 0)
+ g_main_loop_quit (test->mainloop);
+}
+
+static void
+prepare_cert (Test *test,
+ TpTLSCertificate *cert)
+{
+ GQuark features[] = { TP_TLS_CERTIFICATE_FEATURE_CORE, 0 };
+
+ tp_proxy_prepare_async (cert, features, proxy_prepare_cb, test);
+
+ test->wait = 1;
+ g_main_loop_run (test->mainloop);
+ g_assert_no_error (test->error);
+}
+
+static void
+test_core (Test *test,
+ gconstpointer data G_GNUC_UNUSED)
+{
+ GPtrArray *cert_data;
+ GBytes *d;
+
+ /* Properties are not valid yet */
+ g_assert_cmpstr (tp_tls_certificate_get_cert_type (test->cert), ==, NULL);
+ g_assert (tp_tls_certificate_get_cert_data (test->cert) == NULL);
+ g_assert_cmpuint (tp_tls_certificate_get_state (test->cert), ==,
+ TP_TLS_CERTIFICATE_STATE_PENDING);
+
+ prepare_cert (test, test->cert);
+
+ g_assert_cmpstr (tp_tls_certificate_get_cert_type (test->cert), ==, "x509");
+ g_assert_cmpuint (tp_tls_certificate_get_state (test->cert), ==,
+ TP_TLS_CERTIFICATE_STATE_PENDING);
+
+ cert_data = tp_tls_certificate_get_cert_data (test->cert);
+ g_assert (cert_data != NULL);
+ g_assert_cmpuint (cert_data->len, ==, 1);
+ d = g_ptr_array_index (cert_data, 0);
+ g_assert_cmpstr (g_bytes_get_data (d, NULL), ==, "BADGER");
+}
+
+static void
+notify_cb (GObject *object,
+ GParamSpec *spec,
+ Test *test)
+{
+ test->wait--;
+ if (test->wait <= 0)
+ g_main_loop_quit (test->mainloop);
+}
+
+static void
+accept_cb (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ Test *test = user_data;
+
+ tp_tls_certificate_accept_finish (TP_TLS_CERTIFICATE (source), result,
+ &test->error);
+
+ test->wait--;
+ if (test->wait <= 0)
+ g_main_loop_quit (test->mainloop);
+}
+
+static void
+test_accept (Test *test,
+ gconstpointer data G_GNUC_UNUSED)
+{
+ g_signal_connect (test->cert, "notify::state",
+ G_CALLBACK (notify_cb), test);
+
+ tp_tls_certificate_accept_async (test->cert, accept_cb, test);
+
+ test->wait = 2;
+ g_main_loop_run (test->mainloop);
+ g_assert_no_error (test->error);
+
+ g_assert_cmpuint (tp_tls_certificate_get_state (test->cert), ==,
+ TP_TLS_CERTIFICATE_STATE_ACCEPTED);
+}
+
+static void
+reject_cb (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ Test *test = user_data;
+
+ tp_tls_certificate_reject_finish (TP_TLS_CERTIFICATE (source), result,
+ &test->error);
+
+ test->wait--;
+ if (test->wait <= 0)
+ g_main_loop_quit (test->mainloop);
+}
+
+static void
+test_reject (Test *test,
+ gconstpointer data G_GNUC_UNUSED)
+{
+ GVariant *details;
+ const GError *error;
+ TpTLSCertificateRejectReason reason;
+ const gchar *dbus_error;
+ gboolean enabled;
+ TpTLSCertificate *cert;
+ TpTLSCertificateRejection *rej;
+ GError *err = NULL;
+
+ g_signal_connect (test->cert, "notify::state",
+ G_CALLBACK (notify_cb), test);
+
+
+ tp_tls_certificate_add_rejection (test->cert,
+ TP_TLS_CERTIFICATE_REJECT_REASON_REVOKED, NULL,
+ g_variant_new_parsed ("{ 'user-requested': <%b> }", TRUE));
+ tp_tls_certificate_add_rejection (test->cert,
+ TP_TLS_CERTIFICATE_REJECT_REASON_UNKNOWN,
+ TP_ERROR_STR_CAPTCHA_NOT_SUPPORTED, NULL);
+
+ tp_tls_certificate_reject_async (test->cert, reject_cb, test);
+
+ test->wait = 2;
+ g_main_loop_run (test->mainloop);
+ g_assert_no_error (test->error);
+
+ g_assert_cmpuint (tp_tls_certificate_get_state (test->cert), ==,
+ TP_TLS_CERTIFICATE_STATE_REJECTED);
+
+ rej = tp_tls_certificate_get_rejection (test->cert);
+ g_assert (TP_IS_TLS_CERTIFICATE_REJECTION (rej));
+ error = tp_tls_certificate_rejection_get_error (rej);
+ dbus_error = tp_tls_certificate_rejection_get_dbus_error (rej);
+ reason = tp_tls_certificate_rejection_get_reason (rej);
+ details = tp_tls_certificate_rejection_get_details (rej);
+
+ g_assert_error (error, TP_ERROR, TP_ERROR_CERT_REVOKED);
+ g_assert_cmpstr (dbus_error, ==, TP_ERROR_STR_CERT_REVOKED);
+ g_assert_cmpuint (reason, ==, TP_TLS_CERTIFICATE_REJECT_REASON_REVOKED);
+ g_assert (g_variant_is_of_type (details, G_VARIANT_TYPE_VARDICT));
+ g_assert_cmpuint (g_variant_n_children (details), ==, 1);
+ g_assert (g_variant_lookup (details, "user-requested", "b", &enabled));
+ g_assert (enabled);
+
+ g_assert (!tp_tls_certificate_rejection_raise_error (rej, &err));
+ g_assert_error (err, TP_ERROR, TP_ERROR_CERT_REVOKED);
+ g_error_free (err);
+
+ rej = tp_tls_certificate_get_nth_rejection (test->cert, 1);
+ g_assert (TP_IS_TLS_CERTIFICATE_REJECTION (rej));
+ error = tp_tls_certificate_rejection_get_error (rej);
+ dbus_error = tp_tls_certificate_rejection_get_dbus_error (rej);
+ details = tp_tls_certificate_rejection_get_details (rej);
+
+ g_assert_error (error, TP_ERROR, TP_ERROR_CAPTCHA_NOT_SUPPORTED);
+ g_assert_cmpstr (dbus_error, ==, TP_ERROR_STR_CAPTCHA_NOT_SUPPORTED);
+ g_assert (g_variant_is_of_type (details, G_VARIANT_TYPE_VARDICT));
+ g_assert_cmpuint (g_variant_n_children (details), ==, 0);
+
+ /* Test if we cope with an empty rejections list */
+ tp_tests_tls_certificate_clear_rejection (test->service_cert);
+
+ cert = tp_tls_certificate_new (TP_PROXY (test->connection),
+ tp_proxy_get_object_path (test->cert), &test->error);
+ g_assert_no_error (test->error);
+
+ prepare_cert (test, cert);
+
+ rej = tp_tls_certificate_get_rejection (cert);
+ g_assert (TP_IS_TLS_CERTIFICATE_REJECTION (rej));
+ error = tp_tls_certificate_rejection_get_error (rej);
+ dbus_error = tp_tls_certificate_rejection_get_dbus_error (rej);
+ details = tp_tls_certificate_rejection_get_details (rej);
+
+ g_assert_error (error, TP_ERROR, TP_ERROR_CERT_INVALID);
+ g_assert_cmpstr (dbus_error, ==, TP_ERROR_STR_CERT_INVALID);
+ g_assert (g_variant_is_of_type (details, G_VARIANT_TYPE_VARDICT));
+ g_assert_cmpuint (g_variant_n_children (details), ==, 0);
+
+ g_object_unref (cert);
+}
+
+static void
+invalidated_cb (TpProxy *cert,
+ guint domain,
+ gint code,
+ const gchar *message,
+ Test *test)
+{
+ g_clear_error (&test->error);
+ test->error = g_error_new_literal (domain, code, message);
+
+ test->wait--;
+ if (test->wait <= 0)
+ g_main_loop_quit (test->mainloop);
+}
+
+static void
+test_invalidated (Test *test,
+ gconstpointer data G_GNUC_UNUSED)
+{
+ g_signal_connect (test->cert, "invalidated",
+ G_CALLBACK (invalidated_cb), test);
+
+ disconnect_conn (test);
+
+ g_assert_error (test->error, TP_ERROR, TP_ERROR_CANCELLED);
+}
+
+int
+main (int argc,
+ char **argv)
+{
+ tp_tests_init (&argc, &argv);
+ g_test_bug_base ("http://bugs.freedesktop.org/show_bug.cgi?id=");
+
+ g_test_add ("/tls-certificate/creation", Test, NULL, setup,
+ test_creation, teardown);
+ g_test_add ("/tls-certificate/core", Test, NULL, setup,
+ test_core, teardown);
+ g_test_add ("/tls-certificate/accept", Test, NULL, setup,
+ test_accept, teardown);
+ g_test_add ("/tls-certificate/reject", Test, NULL, setup,
+ test_reject, teardown);
+ g_test_add ("/tls-certificate/invalidated", Test, NULL, setup,
+ test_invalidated, teardown);
+
+ return g_test_run ();
+}
diff --git a/tests/lib/Makefile.am b/tests/lib/Makefile.am
index c63d2e332..75b8c005a 100644
--- a/tests/lib/Makefile.am
+++ b/tests/lib/Makefile.am
@@ -69,6 +69,8 @@ libtp_glib_tests_la_SOURCES = \
textchan-null.h \
textchan-group.c \
textchan-group.h \
+ tls-certificate.h \
+ tls-certificate.c \
util.c \
util.h
libtp_glib_tests_internal_la_SOURCES = $(libtp_glib_tests_la_SOURCES)
diff --git a/tests/lib/tls-certificate.c b/tests/lib/tls-certificate.c
new file mode 100644
index 000000000..e61b2dd1c
--- /dev/null
+++ b/tests/lib/tls-certificate.c
@@ -0,0 +1,353 @@
+/*
+ * tls-certificate.c - Source for TpTestsTLSCertificate
+ * Copyright (C) 2010 Collabora Ltd.
+ * @author Cosimo Cecchi <cosimo.cecchi@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+#include "tls-certificate.h"
+
+#include <telepathy-glib/gtypes.h>
+#include <telepathy-glib/interfaces.h>
+#include <telepathy-glib/telepathy-glib.h>
+#include <telepathy-glib/svc-generic.h>
+#include <telepathy-glib/svc-tls.h>
+
+#define DEBUG_FLAG TP_TESTS_DEBUG_TLS
+#include "debug.h"
+
+static void
+tls_certificate_iface_init (gpointer g_iface, gpointer iface_data);
+
+G_DEFINE_TYPE_WITH_CODE (TpTestsTLSCertificate,
+ tp_tests_tls_certificate,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_AUTHENTICATION_TLS_CERTIFICATE,
+ tls_certificate_iface_init);
+ G_IMPLEMENT_INTERFACE (TP_TYPE_SVC_DBUS_PROPERTIES,
+ tp_dbus_properties_mixin_iface_init);)
+
+struct _TpTestsTLSCertificatePrivate {
+ gchar *object_path;
+
+ gchar *cert_type;
+ TpTLSCertificateState cert_state;
+
+ GPtrArray *rejections;
+ GPtrArray *cert_data;
+
+ TpDBusDaemon *daemon;
+
+ gboolean dispose_has_run;
+};
+
+enum {
+ PROP_OBJECT_PATH = 1,
+ PROP_STATE,
+ PROP_REJECTIONS,
+ PROP_CERTIFICATE_TYPE,
+ PROP_CERTIFICATE_CHAIN_DATA,
+
+ /* not exported */
+ PROP_DBUS_DAEMON,
+
+ NUM_PROPERTIES
+};
+
+static void
+tp_tests_tls_certificate_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ TpTestsTLSCertificate *self = TP_TESTS_TLS_CERTIFICATE (object);
+
+ switch (property_id)
+ {
+ case PROP_OBJECT_PATH:
+ g_value_set_string (value, self->priv->object_path);
+ break;
+ case PROP_STATE:
+ g_value_set_uint (value, self->priv->cert_state);
+ break;
+ case PROP_REJECTIONS:
+ g_value_set_boxed (value, self->priv->rejections);
+ break;
+ case PROP_CERTIFICATE_TYPE:
+ g_value_set_string (value, self->priv->cert_type);
+ break;
+ case PROP_CERTIFICATE_CHAIN_DATA:
+ g_value_set_boxed (value, self->priv->cert_data);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+tp_tests_tls_certificate_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ TpTestsTLSCertificate *self = TP_TESTS_TLS_CERTIFICATE (object);
+
+ switch (property_id)
+ {
+ case PROP_OBJECT_PATH:
+ self->priv->object_path = g_value_dup_string (value);
+ break;
+ case PROP_CERTIFICATE_TYPE:
+ self->priv->cert_type = g_value_dup_string (value);
+ break;
+ case PROP_CERTIFICATE_CHAIN_DATA:
+ self->priv->cert_data = g_value_dup_boxed (value);
+ break;
+ case PROP_DBUS_DAEMON:
+ self->priv->daemon = g_value_dup_object (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, value);
+ break;
+ }
+}
+
+static void
+tp_tests_tls_certificate_finalize (GObject *object)
+{
+ TpTestsTLSCertificate *self = TP_TESTS_TLS_CERTIFICATE (object);
+
+ tp_clear_boxed (TP_ARRAY_TYPE_TLS_CERTIFICATE_REJECTION_LIST,
+ &self->priv->rejections);
+
+ g_free (self->priv->object_path);
+ g_free (self->priv->cert_type);
+ g_ptr_array_unref (self->priv->cert_data);
+
+ G_OBJECT_CLASS (tp_tests_tls_certificate_parent_class)->finalize (object);
+}
+
+static void
+tp_tests_tls_certificate_dispose (GObject *object)
+{
+ TpTestsTLSCertificate *self = TP_TESTS_TLS_CERTIFICATE (object);
+
+ if (self->priv->dispose_has_run)
+ return;
+
+ self->priv->dispose_has_run = TRUE;
+
+ tp_clear_object (&self->priv->daemon);
+
+ G_OBJECT_CLASS (tp_tests_tls_certificate_parent_class)->dispose (object);
+}
+
+static void
+tp_tests_tls_certificate_constructed (GObject *object)
+{
+ TpTestsTLSCertificate *self = TP_TESTS_TLS_CERTIFICATE (object);
+ void (*chain_up) (GObject *) =
+ G_OBJECT_CLASS (tp_tests_tls_certificate_parent_class)->constructed;
+
+ if (chain_up != NULL)
+ chain_up (object);
+
+ /* register the certificate on the bus */
+ tp_dbus_daemon_register_object (self->priv->daemon,
+ self->priv->object_path, self);
+}
+
+static void
+tp_tests_tls_certificate_init (TpTestsTLSCertificate *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ TP_TESTS_TYPE_TLS_CERTIFICATE, TpTestsTLSCertificatePrivate);
+ self->priv->rejections = g_ptr_array_new ();
+}
+
+static void
+tp_tests_tls_certificate_class_init (TpTestsTLSCertificateClass *klass)
+{
+ static TpDBusPropertiesMixinPropImpl object_props[] = {
+ { "State", "state", NULL },
+ { "Rejections", "rejections", NULL },
+ { "CertificateType", "certificate-type", NULL },
+ { "CertificateChainData", "certificate-chain-data", NULL },
+ { NULL }
+ };
+ static TpDBusPropertiesMixinIfaceImpl prop_interfaces[] = {
+ { TP_IFACE_AUTHENTICATION_TLS_CERTIFICATE,
+ tp_dbus_properties_mixin_getter_gobject_properties,
+ NULL,
+ object_props,
+ },
+ { NULL }
+ };
+ GObjectClass *oclass = G_OBJECT_CLASS (klass);
+ GParamSpec *pspec;
+
+ g_type_class_add_private (klass, sizeof (TpTestsTLSCertificatePrivate));
+
+ oclass->finalize = tp_tests_tls_certificate_finalize;
+ oclass->dispose = tp_tests_tls_certificate_dispose;
+ oclass->set_property = tp_tests_tls_certificate_set_property;
+ oclass->get_property = tp_tests_tls_certificate_get_property;
+ oclass->constructed = tp_tests_tls_certificate_constructed;
+
+ pspec = 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_STRINGS);
+ g_object_class_install_property (oclass, PROP_OBJECT_PATH, pspec);
+
+ pspec = g_param_spec_uint ("state",
+ "State of this certificate",
+ "The state of this TLS certificate.",
+ 0, TP_NUM_TLS_CERTIFICATE_STATES - 1,
+ TP_TLS_CERTIFICATE_STATE_PENDING,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (oclass, PROP_STATE, pspec);
+
+ pspec = g_param_spec_boxed ("rejections",
+ "The reject reasons",
+ "The reasons why this TLS certificate has been rejected",
+ TP_ARRAY_TYPE_TLS_CERTIFICATE_REJECTION_LIST,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (oclass, PROP_REJECTIONS, pspec);
+
+ pspec = g_param_spec_string ("certificate-type",
+ "The certificate type",
+ "The type of this certificate.",
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (oclass, PROP_CERTIFICATE_TYPE, pspec);
+
+ pspec = g_param_spec_boxed ("certificate-chain-data",
+ "The certificate chain data",
+ "The raw PEM-encoded trust chain of this certificate.",
+ TP_ARRAY_TYPE_UCHAR_ARRAY_LIST,
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (oclass, PROP_CERTIFICATE_CHAIN_DATA, pspec);
+
+ pspec = g_param_spec_object ("dbus-daemon",
+ "The DBus daemon connection",
+ "The connection to the DBus daemon owning the CM",
+ TP_TYPE_DBUS_DAEMON,
+ G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
+ g_object_class_install_property (oclass, PROP_DBUS_DAEMON, pspec);
+
+ klass->dbus_props_class.interfaces = prop_interfaces;
+ tp_dbus_properties_mixin_class_init (oclass,
+ G_STRUCT_OFFSET (TpTestsTLSCertificateClass, dbus_props_class));
+}
+
+static void
+tp_tests_tls_certificate_accept (TpSvcAuthenticationTLSCertificate *cert,
+ DBusGMethodInvocation *context)
+{
+ TpTestsTLSCertificate *self = TP_TESTS_TLS_CERTIFICATE (cert);
+
+ DEBUG ("Accept() called on the TLS certificate; current state %u",
+ self->priv->cert_state);
+
+ if (self->priv->cert_state != TP_TLS_CERTIFICATE_STATE_PENDING)
+ {
+ GError error =
+ { TP_ERROR,
+ TP_ERROR_INVALID_ARGUMENT,
+ "Calling Accept() on a certificate with state != PENDING "
+ "doesn't make sense."
+ };
+
+ dbus_g_method_return_error (context, &error);
+ return;
+ }
+
+ self->priv->cert_state = TP_TLS_CERTIFICATE_STATE_ACCEPTED;
+ tp_svc_authentication_tls_certificate_emit_accepted (self);
+
+ tp_svc_authentication_tls_certificate_return_from_accept (context);
+}
+
+static void
+tp_tests_tls_certificate_reject (TpSvcAuthenticationTLSCertificate *cert,
+ const GPtrArray *rejections,
+ DBusGMethodInvocation *context)
+{
+ TpTestsTLSCertificate *self = TP_TESTS_TLS_CERTIFICATE (cert);
+
+ DEBUG ("Reject() called on the TLS certificate with rejections %p, "
+ "length %u; current state %u", rejections, rejections->len,
+ self->priv->cert_state);
+
+ if (rejections->len < 1)
+ {
+ GError error = { TP_ERROR, TP_ERROR_INVALID_ARGUMENT,
+ "Calling Reject() with a zero-length rejection list." };
+
+ dbus_g_method_return_error (context, &error);
+ return;
+ }
+
+ if (self->priv->cert_state != TP_TLS_CERTIFICATE_STATE_PENDING)
+ {
+ GError error =
+ { TP_ERROR,
+ TP_ERROR_INVALID_ARGUMENT,
+ "Calling Reject() on a certificate with state != PENDING "
+ "doesn't make sense."
+ };
+
+ dbus_g_method_return_error (context, &error);
+ return;
+ }
+
+ tp_clear_boxed (TP_ARRAY_TYPE_TLS_CERTIFICATE_REJECTION_LIST,
+ &self->priv->rejections);
+
+ self->priv->rejections =
+ g_boxed_copy (TP_ARRAY_TYPE_TLS_CERTIFICATE_REJECTION_LIST,
+ rejections);
+ self->priv->cert_state = TP_TLS_CERTIFICATE_STATE_REJECTED;
+
+ tp_svc_authentication_tls_certificate_emit_rejected (
+ self, self->priv->rejections);
+
+ tp_svc_authentication_tls_certificate_return_from_reject (context);
+}
+
+static void
+tls_certificate_iface_init (gpointer g_iface,
+ gpointer iface_data)
+{
+ TpSvcAuthenticationTLSCertificateClass *klass = g_iface;
+
+#define IMPLEMENT(x) \
+ tp_svc_authentication_tls_certificate_implement_##x ( \
+ klass, tp_tests_tls_certificate_##x)
+ IMPLEMENT (accept);
+ IMPLEMENT (reject);
+#undef IMPLEMENT
+}
+
+void
+tp_tests_tls_certificate_clear_rejection (TpTestsTLSCertificate *self)
+{
+ g_ptr_array_set_size (self->priv->rejections, 0);
+}
diff --git a/tests/lib/tls-certificate.h b/tests/lib/tls-certificate.h
new file mode 100644
index 000000000..7ce0cf4aa
--- /dev/null
+++ b/tests/lib/tls-certificate.h
@@ -0,0 +1,68 @@
+/*
+ * tls-certificate.h - Header for TpTestsTLSCertificate
+ * Copyright (C) 2010 Collabora Ltd.
+ * @author Cosimo Cecchi <cosimo.cecchi@collabora.co.uk>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * 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
+ */
+
+#ifndef __TP_TESTS_TLS_CERTIFICATE_H__
+#define __TP_TESTS_TLS_CERTIFICATE_H__
+
+#include <glib-object.h>
+
+#include <telepathy-glib/dbus-properties-mixin.h>
+
+G_BEGIN_DECLS
+
+typedef struct _TpTestsTLSCertificate TpTestsTLSCertificate;
+typedef struct _TpTestsTLSCertificateClass TpTestsTLSCertificateClass;
+typedef struct _TpTestsTLSCertificatePrivate TpTestsTLSCertificatePrivate;
+
+struct _TpTestsTLSCertificateClass {
+ GObjectClass parent_class;
+
+ TpDBusPropertiesMixinClass dbus_props_class;
+};
+
+struct _TpTestsTLSCertificate {
+ GObject parent;
+
+ TpTestsTLSCertificatePrivate *priv;
+};
+
+GType tp_tests_tls_certificate_get_type (void);
+
+#define TP_TESTS_TYPE_TLS_CERTIFICATE \
+ (tp_tests_tls_certificate_get_type ())
+#define TP_TESTS_TLS_CERTIFICATE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj), TP_TESTS_TYPE_TLS_CERTIFICATE, \
+ TpTestsTLSCertificate))
+#define TP_TESTS_TLS_CERTIFICATE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), TP_TESTS_TYPE_TLS_CERTIFICATE, \
+ TpTestsTLSCertificateClass))
+#define TP_TESTS_IS_TLS_CERTIFICATE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj), TP_TESTS_TYPE_TLS_CERTIFICATE))
+#define TP_TESTS_IS_TLS_CERTIFICATE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), TP_TESTS_TYPE_TLS_CERTIFICATE))
+#define TP_TESTS_TLS_CERTIFICATE_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), TP_TESTS_TYPE_TLS_CERTIFICATE, \
+ TpTestsTLSCertificateClass))
+
+void tp_tests_tls_certificate_clear_rejection (TpTestsTLSCertificate *self);
+
+G_END_DECLS
+
+#endif /* #ifndef __TP_TESTS_TLS_CERTIFICATE_H__*/
diff --git a/tests/lib/util.c b/tests/lib/util.c
index 3a0c8768c..976029c8f 100644
--- a/tests/lib/util.c
+++ b/tests/lib/util.c
@@ -477,24 +477,19 @@ tp_tests_connection_assert_disconnect_succeeds (TpConnection *connection)
}
static void
-one_contact_cb (TpConnection *connection,
- guint n_contacts,
- TpContact * const *contacts,
- const gchar * const *good_ids,
- GHashTable *bad_ids,
- const GError *error,
- gpointer user_data,
- GObject *weak_object)
+one_contact_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
{
+ TpConnection *connection = (TpConnection *) object;
TpContact **contact_loc = user_data;
+ GError *error = NULL;
- g_assert_no_error (error);
- g_assert_cmpuint (g_hash_table_size (bad_ids), ==, 0);
- g_assert_cmpuint (n_contacts, ==, 1);
- g_assert_cmpstr (good_ids[0], !=, NULL);
- g_assert (contacts[0] != NULL);
+ *contact_loc = tp_connection_dup_contact_by_id_finish (connection, result,
+ &error);
- *contact_loc = g_object_ref (contacts[0]);
+ g_assert_no_error (error);
+ g_assert (TP_IS_CONTACT (*contact_loc));
}
TpContact *
@@ -504,8 +499,8 @@ tp_tests_connection_run_until_contact_by_id (TpConnection *connection,
{
TpContact *contact = NULL;
- tp_connection_get_contacts_by_id (connection, 1, &id, features,
- one_contact_cb, &contact, NULL, NULL);
+ tp_connection_dup_contact_by_id_async (connection, id, features,
+ one_contact_cb, &contact);
while (contact == NULL)
g_main_context_iteration (NULL, TRUE);
diff --git a/tools/check-c-style.sh b/tools/check-c-style.sh
index 4330b1479..55834207a 100644
--- a/tools/check-c-style.sh
+++ b/tools/check-c-style.sh
@@ -3,13 +3,6 @@ fail=0
( . "${tools_dir}"/check-misc.sh ) || fail=$?
-if grep -n '^ *GError *\*[[:alpha:]_][[:alnum:]_]* *;' "$@"
-then
- echo "^^^ The above files contain uninitialized GError*s - they should be"
- echo " initialized to NULL"
- fail=1
-fi
-
# The first regex finds function calls like foo() (as opposed to foo ()).
# It attempts to ignore string constants (may cause false negatives).
# The second and third ignore block comments (gtkdoc uses foo() as markup).