From fd472762b9cd552d59edc5e4b187173d3a9db95a Mon Sep 17 00:00:00 2001 From: Guillaume Desmottes Date: Fri, 20 May 2011 10:34:12 +0200 Subject: [PATCH] TpTextChannel: add TP_TEXT_CHANNEL_FEATURE_SMS (#37358) --- docs/reference/telepathy-glib-sections.txt | 4 + telepathy-glib/text-channel.c | 199 ++++++++++++++++++++++++++++ telepathy-glib/text-channel.h | 8 + tests/dbus/text-channel.c | 88 ++++++++++++- 4 files changed, 298 insertions(+), 1 deletions(-) diff --git a/docs/reference/telepathy-glib-sections.txt b/docs/reference/telepathy-glib-sections.txt index 0e72f6a..8bc621e 100644 --- a/docs/reference/telepathy-glib-sections.txt +++ b/docs/reference/telepathy-glib-sections.txt @@ -5596,6 +5596,9 @@ tp_text_channel_ack_message_finish tp_text_channel_set_chat_state_async tp_text_channel_set_chat_state_finish tp_text_channel_supports_message_type +TP_TEXT_CHANNEL_FEATURE_SMS +tp_text_channel_is_sms +tp_text_channel_get_sms_flash TP_IS_TEXT_CHANNEL TP_IS_TEXT_CHANNEL_CLASS @@ -5607,4 +5610,5 @@ tp_text_channel_get_type TpTextChannelPrivate tp_text_channel_get_feature_quark_incoming_messages +tp_text_channel_get_feature_quark_sms diff --git a/telepathy-glib/text-channel.c b/telepathy-glib/text-channel.c index 5cf4242..7e74b18 100644 --- a/telepathy-glib/text-channel.c +++ b/telepathy-glib/text-channel.c @@ -80,6 +80,9 @@ struct _TpTextChannelPrivate /* queue of owned TpSignalledMessage */ GQueue *pending_messages; gboolean got_initial_messages; + + gboolean is_sms; + gboolean sms_flash; }; enum @@ -88,6 +91,8 @@ enum PROP_MESSAGE_PART_SUPPORT_FLAGS, PROP_DELIVERY_REPORTING_SUPPORT, PROP_MESSAGE_TYPES, + PROP_IS_SMS, + PROP_SMS_FLASH, }; enum /* signals */ @@ -144,6 +149,14 @@ tp_text_channel_get_property (GObject *object, tp_text_channel_get_message_types (self)); break; + case PROP_IS_SMS: + g_value_set_boolean (value, tp_text_channel_is_sms (self)); + break; + + case PROP_SMS_FLASH: + g_value_set_boolean (value, tp_text_channel_get_sms_flash (self)); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; @@ -335,6 +348,10 @@ tp_text_channel_constructed (GObject *obj) tp_proxy_get_object_path (self), err->message); g_error_free (err); } + + /* SMS */ + self->priv->sms_flash = tp_asv_get_boolean (props, + TP_PROP_CHANNEL_INTERFACE_SMS_FLASH, NULL); } static void @@ -828,8 +845,91 @@ fail: g_object_unref (result); } +static void +get_sms_channel_cb (TpProxy *proxy, + const GValue *value, + const GError *error, + gpointer user_data, + GObject *weak_object) +{ + TpTextChannel *self = (TpTextChannel *) proxy; + GSimpleAsyncResult *result = user_data; + + if (error != NULL) + { + DEBUG ("Failed to get SMSChannel property: %s", error->message); + + g_simple_async_result_set_error (result, error->domain, error->code, + "Failed to get SMSChannel property: %s", error->message); + goto out; + } + + if (!G_VALUE_HOLDS (value, G_TYPE_BOOLEAN)) + { + DEBUG ("SMSChannel property is of the wrong type"); + + g_simple_async_result_set_error (result, TP_ERRORS, TP_ERROR_CONFUSED, + "SMSChannel property is of the wrong type"); + goto out; + } + + self->priv->is_sms = g_value_get_boolean (value); + + /* self->priv->is_sms is set to FALSE by default, so only notify the + * property change is it is now set to TRUE. */ + if (self->priv->is_sms) + g_object_notify (G_OBJECT (self), "is-sms"); + +out: + g_simple_async_result_complete (result); + g_object_unref (result); +} + +static void +sms_channel_changed_cb (TpChannel *proxy, + gboolean sms, + gpointer user_data, + GObject *weak_object) +{ + TpTextChannel *self = (TpTextChannel *) proxy; + + if (self->priv->is_sms == sms) + return; + + self->priv->is_sms = sms; + g_object_notify (weak_object, "is-sms"); +} + +static void +tp_text_channel_prepare_sms_async (TpProxy *proxy, + const TpProxyFeature *feature, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSimpleAsyncResult *result; + GError *error = NULL; + + result = g_simple_async_result_new ((GObject *) proxy, callback, user_data, + tp_text_channel_prepare_sms_async); + + tp_cli_channel_interface_sms_connect_to_sms_channel_changed ( + (TpChannel *) proxy, sms_channel_changed_cb, NULL, NULL, + G_OBJECT (proxy), &error); + if (error != NULL) + { + WARNING ("Failed to connect to SMS.SMSChannelChanged: %s", + error->message); + g_error_free (error); + } + + tp_cli_dbus_properties_call_get (proxy, -1, + TP_IFACE_CHANNEL_INTERFACE_SMS, "SMSChannel", + get_sms_channel_cb, result, NULL, G_OBJECT (proxy)); +} + enum { FEAT_PENDING_MESSAGES, + FEAT_SMS, N_FEAT }; @@ -837,6 +937,7 @@ static const TpProxyFeature * tp_text_channel_list_features (TpProxyClass *cls G_GNUC_UNUSED) { static TpProxyFeature features[N_FEAT + 1] = { { 0 } }; + static GQuark need_sms[2] = {0, 0}; if (G_LIKELY (features[0].name != 0)) return features; @@ -846,6 +947,13 @@ tp_text_channel_list_features (TpProxyClass *cls G_GNUC_UNUSED) features[FEAT_PENDING_MESSAGES].prepare_async = tp_text_channel_prepare_pending_messages_async; + features[FEAT_SMS].name = + TP_TEXT_CHANNEL_FEATURE_SMS; + features[FEAT_SMS].prepare_async = + tp_text_channel_prepare_sms_async; + need_sms[0] = TP_IFACE_QUARK_CHANNEL_INTERFACE_SMS; + features[FEAT_SMS].interfaces_needed = need_sms; + /* assert that the terminator at the end is there */ g_assert (features[N_FEAT].name == 0); @@ -929,6 +1037,41 @@ tp_text_channel_class_init (TpTextChannelClass *klass) g_object_class_install_property (gobject_class, PROP_MESSAGE_TYPES, param_spec); + /** + * TpTextChannel:is-sms: + * + * %TRUE if messages sent and received on this channel are transmitted + * via SMS. + * + * This property is not guaranteed to have a meaningful value until + * TP_TEXT_CHANNEL_FEATURE_SMS has been prepared. + * + * Since: 0.15.UNRELEASED + */ + param_spec = g_param_spec_boolean ("is-sms", + "is SMS", + "The SMS.SMSChannel property of the channel", + FALSE, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (gobject_class, PROP_IS_SMS, param_spec); + + /** + * TpTextChannel:sms-flash: + * + * %TRUE if this channel is exclusively for receiving class 0 SMSes + * (and no SMSes can be sent using tp_text_channel_send_message_async() + * on this channel). If %FALSE, no incoming class 0 SMSes will appear + * on this channel. + * + * Since: 0.15.UNRELEASED + */ + param_spec = g_param_spec_boolean ("sms-flash", + "SMS flash", + "The SMS.Flash property of the channel", + FALSE, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_class_install_property (gobject_class, PROP_SMS_FLASH, param_spec); + /** * TpTextChannel::message-received * @self: the #TpTextChannel @@ -1535,3 +1678,59 @@ tp_text_channel_supports_message_type (TpTextChannel *self, return FALSE; } + +/** + * TP_TEXT_CHANNEL_FEATURE_SMS: + * + * Expands to a call to a function that returns a quark representing the + * SMS feature of a #TpTextChannel. + * + * When this feature is prepared, the TpTextChannel:is-sms property will have + * a meaningful value and will be updated when needed. + * + * One can ask for a feature to be prepared using the + * tp_proxy_prepare_async() function, and waiting for it to callback. + * + * Since: 0.15.UNRELEASED + */ +GQuark +tp_text_channel_get_feature_quark_sms (void) +{ + return g_quark_from_static_string ("tp-text-channel-feature-sms"); +} + +/** + * tp_text_channel_is_sms: + * @self: a #TpTextChannel + * + * Return the #TpTextChannel:is-sms property + * + * Returns: the value of #TpTextChannel:is-sms property + * + * Since: 0.15.UNRELEASED + */ +gboolean +tp_text_channel_is_sms (TpTextChannel *self) +{ + g_return_val_if_fail (TP_IS_TEXT_CHANNEL (self), FALSE); + + return self->priv->is_sms; +} + +/** + * tp_text_channel_get_sms_flash: + * @self: a #TpTextChannel + * + * Return the #TpTextChannel:sms-flash property + * + * Returns: the value of #TpTextChannel:sms-flash property + * + * Since: 0.15.UNRELEASED + */ +gboolean +tp_text_channel_get_sms_flash (TpTextChannel *self) +{ + g_return_val_if_fail (TP_IS_TEXT_CHANNEL (self), FALSE); + + return self->priv->sms_flash; +} diff --git a/telepathy-glib/text-channel.h b/telepathy-glib/text-channel.h index 492cc86..a6d9e6a 100644 --- a/telepathy-glib/text-channel.h +++ b/telepathy-glib/text-channel.h @@ -119,6 +119,14 @@ gboolean tp_text_channel_set_chat_state_finish (TpTextChannel *self, GAsyncResult *result, GError **error); +#define TP_TEXT_CHANNEL_FEATURE_SMS \ + tp_text_channel_get_feature_quark_sms () +GQuark tp_text_channel_get_feature_quark_sms (void) G_GNUC_CONST; + +gboolean tp_text_channel_is_sms (TpTextChannel *self); + +gboolean tp_text_channel_get_sms_flash (TpTextChannel *self); + G_END_DECLS #endif diff --git a/tests/dbus/text-channel.c b/tests/dbus/text-channel.c index 88f6e75..8319f8f 100644 --- a/tests/dbus/text-channel.c +++ b/tests/dbus/text-channel.c @@ -23,11 +23,13 @@ typedef struct { /* Service side objects */ TpBaseConnection *base_connection; ExampleEcho2Channel *chan_service; + ExampleEcho2Channel *sms_chan_service; TpHandleRepoIface *contact_repo; /* Client side objects */ TpConnection *connection; TpTextChannel *channel; + TpTextChannel *sms_channel; TpMessage *received_msg; TpMessage *removed_msg; @@ -48,6 +50,7 @@ create_contact_chan (Test *test) GHashTable *props; tp_clear_object (&test->chan_service); + tp_clear_object (&test->sms_chan_service); /* Create service-side tube channel object */ chan_path = g_strdup_printf ("%s/Channel", @@ -81,9 +84,32 @@ create_contact_chan (Test *test) g_assert_no_error (test->error); g_free (chan_path); + g_hash_table_unref (props); - tp_handle_unref (test->contact_repo, handle); + /* Register channel implementing SMS */ + chan_path = g_strdup_printf ("%s/ChannelSMS", + tp_proxy_get_object_path (test->connection)); + + test->sms_chan_service = g_object_new ( + EXAMPLE_TYPE_ECHO_2_CHANNEL, + "connection", test->base_connection, + "handle", handle, + "object-path", chan_path, + "sms", TRUE, + NULL); + + g_object_get (test->chan_service, + "channel-properties", &props, + NULL); + + test->sms_channel = tp_text_channel_new (test->connection, chan_path, + props, &test->error); + g_assert_no_error (test->error); + + g_free (chan_path); g_hash_table_unref (props); + + tp_handle_unref (test->contact_repo, handle); } static void @@ -113,6 +139,7 @@ teardown (Test *test, test->mainloop = NULL; tp_clear_object (&test->chan_service); + tp_clear_object (&test->sms_chan_service); tp_cli_connection_run_disconnect (test->connection, -1, &test->error, NULL); g_assert_no_error (test->error); @@ -127,6 +154,7 @@ teardown (Test *test, tp_clear_pointer (&test->sent_token, g_free); tp_clear_object (&test->channel); + tp_clear_object (&test->sms_channel); } static void @@ -600,6 +628,62 @@ test_message_sent (Test *test, g_assert (test->sent_token == NULL); } +static void +notify_cb (GObject *object, + GParamSpec *spec, + Test *test) +{ + test->wait--; + if (test->wait <= 0) + g_main_loop_quit (test->mainloop); +} + + +static void +test_sms_feature (Test *test, + gconstpointer data G_GNUC_UNUSED) +{ + gboolean is_sms; + GQuark features[] = { TP_TEXT_CHANNEL_FEATURE_SMS, 0 }; + + g_assert (tp_text_channel_get_sms_flash (test->sms_channel)); + + /* SMS feature is not prepared yet */ + g_assert (!tp_text_channel_is_sms (test->sms_channel)); + + g_object_get (test->sms_channel, "is-sms", &is_sms, NULL); + g_assert (!is_sms); + + test->wait++; + tp_proxy_prepare_async (test->sms_channel, features, + proxy_prepare_cb, test); + + test->wait++; + g_signal_connect (test->sms_channel, "notify::is-sms", + G_CALLBACK (notify_cb), test); + + g_main_loop_run (test->mainloop); + g_assert_no_error (test->error); + + /* Feature has been prepared */ + g_assert (tp_text_channel_is_sms (test->sms_channel)); + + g_object_get (test->sms_channel, "is-sms", &is_sms, NULL); + g_assert (is_sms); + + /* Property is changed */ + example_echo_2_channel_set_sms (test->sms_chan_service, FALSE); + + test->wait++; + g_main_loop_run (test->mainloop); + g_assert_no_error (test->error); + + g_assert (!tp_text_channel_is_sms (test->sms_channel)); + + g_object_get (test->sms_channel, "is-sms", &is_sms, NULL); + g_assert (!is_sms); +} + int main (int argc, char **argv) @@ -621,6 +705,8 @@ main (int argc, test_ack_message, teardown); g_test_add ("/text-channel/message-sent", Test, NULL, setup, test_message_sent, teardown); + g_test_add ("/text-channel/sms-feature", Test, NULL, setup, + test_sms_feature, teardown); return g_test_run (); } -- 1.7.4.1