From e98c7a31f74356590b5093d2108f100a661cfda1 Mon Sep 17 00:00:00 2001 From: Will Thompson Date: Tue, 10 May 2011 16:36:00 +0100 Subject: Add empathy_duration_to_string() This is based on the body of empathy_time_to_string_relative(); it takes a duration in seconds, rather than a timestamp. --- libempathy/empathy-time.c | 64 ++++++++++++++++++++++++++--------------------- libempathy/empathy-time.h | 1 + 2 files changed, 36 insertions(+), 29 deletions(-) diff --git a/libempathy/empathy-time.c b/libempathy/empathy-time.c index f33152d97..5144fa4d8 100644 --- a/libempathy/empathy-time.c +++ b/libempathy/empathy-time.c @@ -81,6 +81,40 @@ empathy_time_to_string_local (gint64 t, return result; } +gchar * +empathy_duration_to_string (guint seconds) +{ + if (seconds < 60) { + return g_strdup_printf (ngettext ("%d second ago", + "%d seconds ago", seconds), seconds); + } + else if (seconds < (60 * 60)) { + seconds /= 60; + return g_strdup_printf (ngettext ("%d minute ago", + "%d minutes ago", seconds), seconds); + } + else if (seconds < (60 * 60 * 24)) { + seconds /= 60 * 60; + return g_strdup_printf (ngettext ("%d hour ago", + "%d hours ago", seconds), seconds); + } + else if (seconds < (60 * 60 * 24 * 7)) { + seconds /= 60 * 60 * 24; + return g_strdup_printf (ngettext ("%d day ago", + "%d days ago", seconds), seconds); + } + else if (seconds < (60 * 60 * 24 * 30)) { + seconds /= 60 * 60 * 24 * 7; + return g_strdup_printf (ngettext ("%d week ago", + "%d weeks ago", seconds), seconds); + } + else { + seconds /= 60 * 60 * 24 * 30; + return g_strdup_printf (ngettext ("%d month ago", + "%d months ago", seconds), seconds); + } +} + gchar * empathy_time_to_string_relative (gint64 t) { @@ -96,35 +130,7 @@ empathy_time_to_string_relative (gint64 t) seconds = delta / G_TIME_SPAN_SECOND; if (seconds > 0) { - if (seconds < 60) { - result = g_strdup_printf (ngettext ("%d second ago", - "%d seconds ago", seconds), seconds); - } - else if (seconds < (60 * 60)) { - seconds /= 60; - result = g_strdup_printf (ngettext ("%d minute ago", - "%d minutes ago", seconds), seconds); - } - else if (seconds < (60 * 60 * 24)) { - seconds /= 60 * 60; - result = g_strdup_printf (ngettext ("%d hour ago", - "%d hours ago", seconds), seconds); - } - else if (seconds < (60 * 60 * 24 * 7)) { - seconds /= 60 * 60 * 24; - result = g_strdup_printf (ngettext ("%d day ago", - "%d days ago", seconds), seconds); - } - else if (seconds < (60 * 60 * 24 * 30)) { - seconds /= 60 * 60 * 24 * 7; - result = g_strdup_printf (ngettext ("%d week ago", - "%d weeks ago", seconds), seconds); - } - else { - seconds /= 60 * 60 * 24 * 30; - result = g_strdup_printf (ngettext ("%d month ago", - "%d months ago", seconds), seconds); - } + result = empathy_duration_to_string (seconds); } else { result = g_strdup (_("in the future")); diff --git a/libempathy/empathy-time.h b/libempathy/empathy-time.h index 7fac48221..3a22adeee 100644 --- a/libempathy/empathy-time.h +++ b/libempathy/empathy-time.h @@ -45,6 +45,7 @@ gchar *empathy_time_to_string_utc (gint64 t, gchar *empathy_time_to_string_local (gint64 t, const gchar *format); gchar *empathy_time_to_string_relative (gint64 t); +gchar *empathy_duration_to_string (guint seconds); G_END_DECLS -- cgit v1.2.3 From e92e9e9c411ec02dacc1bb11f15aa4682fd64cdf Mon Sep 17 00:00:00 2001 From: Will Thompson Date: Tue, 10 May 2011 17:14:16 +0100 Subject: ContactWidget: show IRC channel list. Very recent versions of Idle expose the list of channels provided in WHOIS replies. The data is provided as a bunch of x-irc-channel fields with a single value, namely the name of the channel. Here we expose that data to the user as a comma-separated list of links; clicking a link ensures that channel. https://bugzilla.gnome.org/show_bug.cgi?id=592795 --- libempathy-gtk/empathy-contact-widget.c | 74 +++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/libempathy-gtk/empathy-contact-widget.c b/libempathy-gtk/empathy-contact-widget.c index c4e3748b4..4f37ccb01 100644 --- a/libempathy-gtk/empathy-contact-widget.c +++ b/libempathy-gtk/empathy-contact-widget.c @@ -526,12 +526,73 @@ contact_widget_details_update_edit (EmpathyContactWidget *information) return n_rows; } +static gboolean +channel_name_activated_cb ( + GtkLabel *label, + gchar *uri, + EmpathyContactWidget *information) +{ + TpAccount *account = empathy_contact_get_account (information->contact); + + empathy_join_muc (account, uri, empathy_get_current_action_time ()); + return TRUE; +} + +static void +add_channel_list ( + EmpathyContactWidget *information, + GPtrArray *channels, + guint row) +{ + GtkWidget *w; + GString *label_markup = g_string_new (""); + guint i; + + w = gtk_label_new (_("Channels:")); + gtk_table_attach (GTK_TABLE (information->table_details), + w, 0, 1, row, row + 1, GTK_FILL, 0, 0, 0); + gtk_misc_set_alignment (GTK_MISC (w), 0, 0.5); + gtk_widget_show (w); + + for (i = 0; i < channels->len; i++) + { + const gchar *channel_name = g_ptr_array_index (channels, i); + /* We abuse the URI of the link to hold the channel name. It seems to + * be okay to just use it essentially verbatim, rather than trying to + * ensure it's actually a valid URI. g_string_append_uri_escaped() + * escapes way more than we actually need to; so we're just using + * g_markup_escape_text directly. + */ + gchar *escaped = g_markup_escape_text (channel_name, -1); + + if (i > 0) + g_string_append (label_markup, ", "); + + g_string_append_printf (label_markup, "%s", + escaped, channel_name); + g_free (escaped); + } + + w = gtk_label_new (NULL); + gtk_label_set_markup (GTK_LABEL (w), label_markup->str); + gtk_label_set_line_wrap (GTK_LABEL (w), TRUE); + g_signal_connect (w, "activate-link", + (GCallback) channel_name_activated_cb, information); + gtk_table_attach_defaults (GTK_TABLE (information->table_details), + w, 1, 2, row, row + 1); + gtk_misc_set_alignment (GTK_MISC (w), 0, 0.5); + gtk_widget_show (w); + + g_string_free (label_markup, TRUE); +} + static guint contact_widget_details_update_show (EmpathyContactWidget *information) { TpContact *contact; GList *info, *l; guint n_rows = 0; + GPtrArray *channels = g_ptr_array_new (); contact = empathy_contact_get_tp_contact (information->contact); info = tp_contact_get_contact_info (contact); @@ -548,6 +609,12 @@ contact_widget_details_update_show (EmpathyContactWidget *information) value = field->field_value[0]; + if (!tp_strdiff (field->field_name, "x-irc-channel")) + { + g_ptr_array_add (channels, (gpointer) value); + continue; + } + field_data = find_info_field_data (field->field_name); if (field_data == NULL) { @@ -585,6 +652,13 @@ contact_widget_details_update_show (EmpathyContactWidget *information) } g_list_free (info); + if (channels->len > 0) + { + add_channel_list (information, channels, n_rows); + n_rows++; + } + + g_ptr_array_unref (channels); return n_rows; } -- cgit v1.2.3 From 3e99c2d9e8b4f5a36507722c8bd681086c3220c4 Mon Sep 17 00:00:00 2001 From: Will Thompson Date: Tue, 10 May 2011 17:27:04 +0100 Subject: ContactWidget: generalize linkifying values Many of the new fields exposed by Idle need more processing than just bunging the first string into a label. Let's start by generalizing linkifying the first string. I speculatively allow the format functions to fail. --- libempathy-gtk/empathy-contact-widget.c | 40 ++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/libempathy-gtk/empathy-contact-widget.c b/libempathy-gtk/empathy-contact-widget.c index 4f37ccb01..f8f7b268b 100644 --- a/libempathy-gtk/empathy-contact-widget.c +++ b/libempathy-gtk/empathy-contact-widget.c @@ -283,20 +283,28 @@ contact_widget_bday_changed_cb (GtkCalendar *calendar, static void contact_widget_details_notify_cb (EmpathyContactWidget *information); +typedef gchar * (* FieldFormatFunc) (GStrv); + typedef struct { const gchar *field_name; const gchar *title; - gboolean linkify; + FieldFormatFunc format; } InfoFieldData; +static gchar * +linkify_first_value (GStrv values) +{ + return empathy_add_link_markup (values[0]); +} + static InfoFieldData info_field_datas[] = { - { "fn", N_("Full name:"), FALSE }, - { "tel", N_("Phone number:"), FALSE }, - { "email", N_("E-mail address:"), TRUE }, - { "url", N_("Website:"), TRUE }, - { "bday", N_("Birthday:"), FALSE }, + { "fn", N_("Full name:"), NULL }, + { "tel", N_("Phone number:"), NULL }, + { "email", N_("E-mail address:"), linkify_first_value }, + { "url", N_("Website:"), linkify_first_value }, + { "bday", N_("Birthday:"), NULL }, { NULL, NULL } }; @@ -602,6 +610,7 @@ contact_widget_details_update_show (EmpathyContactWidget *information) TpContactInfoField *field = l->data; InfoFieldData *field_data; const gchar *value; + gchar *markup = NULL; GtkWidget *w; if (field->field_value == NULL || field->field_value[0] == NULL) @@ -611,7 +620,7 @@ contact_widget_details_update_show (EmpathyContactWidget *information) if (!tp_strdiff (field->field_name, "x-irc-channel")) { - g_ptr_array_add (channels, (gpointer) value); + g_ptr_array_add (channels, (gpointer) field->field_value[0]); continue; } @@ -622,6 +631,18 @@ contact_widget_details_update_show (EmpathyContactWidget *information) continue; } + if (field_data->format != NULL) + { + markup = field_data->format (field->field_value); + + if (markup == NULL) + { + DEBUG ("Invalid value for field '%s' (first element was '%s')", + field->field_name, field->field_value[0]); + continue; + } + } + /* Add Title */ w = gtk_label_new (_(field_data->title)); gtk_table_attach (GTK_TABLE (information->table_details), @@ -631,11 +652,8 @@ contact_widget_details_update_show (EmpathyContactWidget *information) /* Add Value */ w = gtk_label_new (value); - if (field_data->linkify) + if (markup != NULL) { - gchar *markup; - - markup = empathy_add_link_markup (value); gtk_label_set_markup (GTK_LABEL (w), markup); g_free (markup); } -- cgit v1.2.3 From 5eb74b177084b3cd03e412ea3b7f55b41542a9fe Mon Sep 17 00:00:00 2001 From: Will Thompson Date: Tue, 10 May 2011 17:35:20 +0100 Subject: ContactWidget: support Idle's x-idle-time field. --- libempathy-gtk/empathy-contact-widget.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/libempathy-gtk/empathy-contact-widget.c b/libempathy-gtk/empathy-contact-widget.c index f8f7b268b..1b2570de2 100644 --- a/libempathy-gtk/empathy-contact-widget.c +++ b/libempathy-gtk/empathy-contact-widget.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -298,6 +299,18 @@ linkify_first_value (GStrv values) return empathy_add_link_markup (values[0]); } +static gchar * +format_idle_time (GStrv values) +{ + const gchar *value = values[0]; + int duration = strtol (value, NULL, 10); + + if (duration <= 0) + return NULL; + + return empathy_duration_to_string (duration); +} + static InfoFieldData info_field_datas[] = { { "fn", N_("Full name:"), NULL }, @@ -305,6 +318,12 @@ static InfoFieldData info_field_datas[] = { "email", N_("E-mail address:"), linkify_first_value }, { "url", N_("Website:"), linkify_first_value }, { "bday", N_("Birthday:"), NULL }, + + /* Note to translators: this is the caption for a string of the form "5 + * minutes ago", and refers to the time since the contact last interacted + * with their IM client. + */ + { "x-idle-time", N_("Last seen:"), format_idle_time }, { NULL, NULL } }; -- cgit v1.2.3 From d5ddca2ac157b52b04b418d51530505d378b3dd5 Mon Sep 17 00:00:00 2001 From: Will Thompson Date: Tue, 10 May 2011 17:40:25 +0100 Subject: ContactWidget: support IRC server and host info --- libempathy-gtk/empathy-contact-widget.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/libempathy-gtk/empathy-contact-widget.c b/libempathy-gtk/empathy-contact-widget.c index 1b2570de2..39bac969c 100644 --- a/libempathy-gtk/empathy-contact-widget.c +++ b/libempathy-gtk/empathy-contact-widget.c @@ -311,6 +311,17 @@ format_idle_time (GStrv values) return empathy_duration_to_string (duration); } +static gchar * +format_server (GStrv values) +{ + g_assert (values[0] != NULL); + + if (values[1] == NULL) + return g_markup_escape_text (values[0], -1); + else + return g_markup_printf_escaped ("%s (%s)", values[0], values[1]); +} + static InfoFieldData info_field_datas[] = { { "fn", N_("Full name:"), NULL }, @@ -324,6 +335,9 @@ static InfoFieldData info_field_datas[] = * with their IM client. */ { "x-idle-time", N_("Last seen:"), format_idle_time }, + { "x-irc-server", N_("Server:"), format_server }, + { "x-host", N_("Connected from:"), format_server }, + { NULL, NULL } }; -- cgit v1.2.3 From af9646511992294411549884521130056f34f455 Mon Sep 17 00:00:00 2001 From: Will Thompson Date: Tue, 10 May 2011 17:44:03 +0100 Subject: ContactWidget: expose IRC presence information This is basically just a temporary hack until Idle implements SimplePresence. --- libempathy-gtk/empathy-contact-widget.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/libempathy-gtk/empathy-contact-widget.c b/libempathy-gtk/empathy-contact-widget.c index 39bac969c..14042bf61 100644 --- a/libempathy-gtk/empathy-contact-widget.c +++ b/libempathy-gtk/empathy-contact-widget.c @@ -322,6 +322,15 @@ format_server (GStrv values) return g_markup_printf_escaped ("%s (%s)", values[0], values[1]); } +static gchar * +presence_hack (GStrv values) +{ + if (tp_str_empty (values[0])) + return NULL; + + return g_markup_escape_text (values[0], -1); +} + static InfoFieldData info_field_datas[] = { { "fn", N_("Full name:"), NULL }, @@ -338,6 +347,11 @@ static InfoFieldData info_field_datas[] = { "x-irc-server", N_("Server:"), format_server }, { "x-host", N_("Connected from:"), format_server }, + /* FIXME: once Idle implements SimplePresence using this information, we can + * and should bin this. + */ + { "x-presence-status-message", N_("Away message:"), presence_hack }, + { NULL, NULL } }; -- cgit v1.2.3 From 9c42c7ae5d46bf3bf2aa4aab8e4d615876982eca Mon Sep 17 00:00:00 2001 From: Will Thompson Date: Thu, 12 May 2011 13:13:32 +0100 Subject: Add a /whois command. https://bugzilla.gnome.org/show_bug.cgi?id=571631 --- libempathy-gtk/empathy-chat.c | 82 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/libempathy-gtk/empathy-chat.c b/libempathy-gtk/empathy-chat.c index 8ce698f02..8c41849f3 100644 --- a/libempathy-gtk/empathy-chat.c +++ b/libempathy-gtk/empathy-chat.c @@ -48,6 +48,7 @@ #include "empathy-chat.h" #include "empathy-spell.h" +#include "empathy-contact-dialogs.h" #include "empathy-contact-list-store.h" #include "empathy-contact-list-view.h" #include "empathy-contact-menu.h" @@ -930,6 +931,84 @@ chat_command_say (EmpathyChat *chat, g_object_unref (message); } +static void +whois_got_contact_cb (TpConnection *connection, + guint n_contacts, + TpContact * const *contacts, + const gchar * const *requested_ids, + GHashTable *failed_id_errors, + const GError *error, + gpointer user_data, + GObject *weak_object) +{ + EmpathyChat *chat = EMPATHY_CHAT (weak_object); + + g_return_if_fail (n_contacts <= 1); + + if (n_contacts == 0) { + GHashTableIter iter; + gpointer key = NULL, value = NULL; + gchar *id; + GError *id_error; + + /* tp-glib guarantees that the contacts you requested will be + * in failed_id_errors regardless of whether the individual + * contact was invalid or the whole operation failed. + */ + g_hash_table_iter_init (&iter, failed_id_errors); + g_hash_table_iter_next (&iter, &key, &value); + id = key; + id_error = value; + + DEBUG ("Error getting TpContact for '%s': %s %u %s", + id, g_quark_to_string (id_error->domain), + id_error->code, id_error->message); + + if (error == NULL) { + /* The specific ID failed. */ + gchar *event = g_strdup_printf ( + _("“%s” is not a valid contact ID"), id); + empathy_chat_view_append_event (chat->view, event); + g_free (event); + } + /* Otherwise we're disconnected or something; so the window + * will already say ‘Disconnected’, so let's not show anything. + */ + } else { + EmpathyContact *empathy_contact; + GtkWidget *window; + + g_return_if_fail (contacts[0] != NULL); + empathy_contact = empathy_contact_dup_from_tp_contact ( + contacts[0]); + + window = gtk_widget_get_toplevel (GTK_WIDGET (chat)); + /* If we're alive and this command is running, we'd better be + * in a window. */ + g_return_if_fail (window != NULL); + g_return_if_fail (gtk_widget_is_toplevel (window)); + empathy_contact_information_dialog_show (empathy_contact, + GTK_WINDOW (window)); + g_object_unref (empathy_contact); + } +} + +static void +chat_command_whois (EmpathyChat *chat, + GStrv strv) +{ + EmpathyChatPriv *priv = GET_PRIV (chat); + TpConnection *conn; + + conn = empathy_tp_chat_get_connection (priv->tp_chat); + tp_connection_get_contacts_by_id (conn, + /* Element 0 of 'strv' is "whois"; element 1 is the contact ID + * entered by the user (including spaces, if any). */ + 1, (const gchar * const *) strv + 1, + 0, NULL, + whois_got_contact_cb, NULL, NULL, G_OBJECT (chat)); +} + static void chat_command_help (EmpathyChat *chat, GStrv strv); typedef void (*ChatCommandFunc) (EmpathyChat *chat, GStrv strv); @@ -980,6 +1059,9 @@ static ChatCommandItem commands[] = { "This is used to send a message starting with a '/'. For example: " "\"/say /join is used to join a new chat room\"")}, + {"whois", 2, 2, chat_command_whois, NULL, + N_("/whois : display information about a contact")}, + {"help", 1, 2, chat_command_help, NULL, N_("/help []: show all supported commands. " "If is defined, show its usage.")}, -- cgit v1.2.3