diff options
author | Xavier Claessens <xclaesse@gmail.com> | 2009-11-04 00:15:50 +0800 |
---|---|---|
committer | Xavier Claessens <xclaesse@gmail.com> | 2009-11-04 00:15:50 +0800 |
commit | 22c06bcfd832f65fe2de6e44657e22decf2f523d (patch) | |
tree | 78a97f274bae9b135d27796187e856cd5f22905e | |
parent | 2fdf42815677e4e7f41a73f77997af87d5ae5eb2 (diff) | |
parent | e31c0e3f3b9a12dcf280a1ec05fc58463a020d71 (diff) | |
download | gsoc2013-empathy-22c06bcfd832f65fe2de6e44657e22decf2f523d.tar gsoc2013-empathy-22c06bcfd832f65fe2de6e44657e22decf2f523d.tar.gz gsoc2013-empathy-22c06bcfd832f65fe2de6e44657e22decf2f523d.tar.bz2 gsoc2013-empathy-22c06bcfd832f65fe2de6e44657e22decf2f523d.tar.lz gsoc2013-empathy-22c06bcfd832f65fe2de6e44657e22decf2f523d.tar.xz gsoc2013-empathy-22c06bcfd832f65fe2de6e44657e22decf2f523d.tar.zst gsoc2013-empathy-22c06bcfd832f65fe2de6e44657e22decf2f523d.zip |
Merge branch 'irc-command'
-rw-r--r-- | libempathy-gtk/empathy-chat.c | 378 | ||||
-rw-r--r-- | libempathy/empathy-message.c | 56 | ||||
-rw-r--r-- | libempathy/empathy-message.h | 1 | ||||
-rw-r--r-- | libempathy/empathy-tp-chat.c | 73 | ||||
-rw-r--r-- | libempathy/empathy-tp-chat.h | 11 |
5 files changed, 424 insertions, 95 deletions
diff --git a/libempathy-gtk/empathy-chat.c b/libempathy-gtk/empathy-chat.c index b2fefee5f..e96c02db2 100644 --- a/libempathy-gtk/empathy-chat.c +++ b/libempathy-gtk/empathy-chat.c @@ -579,11 +579,302 @@ chat_input_history_update (EmpathyChat *chat, } static void +chat_command_join_cb (EmpathyDispatchOperation *dispatch, + const GError *error, + gpointer user_data) +{ + EmpathyChat *chat = user_data; + + if (error != NULL) { + DEBUG ("Error: %s", error->message); + empathy_chat_view_append_event (chat->view, + _("Failed to join chatroom")); + } +} + +typedef struct { + EmpathyChat *chat; + gchar *message; +} ChatCommandMsgData; + +static void +chat_command_msg_cb (EmpathyDispatchOperation *dispatch, + const GError *error, + gpointer user_data) +{ + ChatCommandMsgData *data = user_data; + + if (error != NULL) { + empathy_chat_view_append_event (data->chat->view, + _("Failed to open private chat")); + goto OUT; + } + + if (!EMP_STR_EMPTY (data->message)) { + EmpathyTpChat *tpchat; + EmpathyMessage *message; + + tpchat = EMPATHY_TP_CHAT ( + empathy_dispatch_operation_get_channel_wrapper (dispatch)); + + message = empathy_message_new (data->message); + empathy_tp_chat_send (tpchat, message); + g_object_unref (message); + } + +OUT: + g_free (data->message); + g_slice_free (ChatCommandMsgData, data); +} + +static void +chat_command_clear (EmpathyChat *chat, + GStrv strv) +{ + empathy_chat_view_clear (chat->view); +} + +static void +chat_command_topic (EmpathyChat *chat, + GStrv strv) +{ + EmpathyChatPriv *priv = GET_PRIV (chat); + EmpathyTpChatProperty *property; + GValue value = {0, }; + + property = empathy_tp_chat_get_property (priv->tp_chat, "subject"); + if (property == NULL) { + empathy_chat_view_append_event (chat->view, + _("Topic not supported on this conversation")); + return; + } + + if (!(property->flags & TP_PROPERTY_FLAG_WRITE)) { + empathy_chat_view_append_event (chat->view, + _("You are not allowed to change the topic")); + return; + } + + g_value_init (&value, G_TYPE_STRING); + g_value_set_string (&value, strv[1]); + empathy_tp_chat_set_property (priv->tp_chat, "subject", &value); + g_value_unset (&value); +} + +static void +chat_command_join (EmpathyChat *chat, + GStrv strv) +{ + EmpathyChatPriv *priv = GET_PRIV (chat); + TpConnection *connection; + + connection = empathy_tp_chat_get_connection (priv->tp_chat); + empathy_dispatcher_join_muc (connection, strv[1], + chat_command_join_cb, + chat); +} + +static void +chat_command_msg_internal (EmpathyChat *chat, + const gchar *contact_id, + const gchar *message) +{ + EmpathyChatPriv *priv = GET_PRIV (chat); + TpConnection *connection; + ChatCommandMsgData *data; + + /* FIXME: We should probably search in members alias. But this + * is enough for IRC */ + data = g_slice_new (ChatCommandMsgData); + data->chat = chat; + data->message = g_strdup (message); + connection = empathy_tp_chat_get_connection (priv->tp_chat); + empathy_dispatcher_chat_with_contact_id (connection, contact_id, + chat_command_msg_cb, + data); +} + +static void +chat_command_query (EmpathyChat *chat, + GStrv strv) +{ + /* If <message> part is not defined, + * strv[2] will be the terminal NULL */ + chat_command_msg_internal (chat, strv[1], strv[2]); +} + +static void +chat_command_msg (EmpathyChat *chat, + GStrv strv) +{ + chat_command_msg_internal (chat, strv[1], strv[2]); +} + +static void +chat_command_me (EmpathyChat *chat, + GStrv strv) +{ + EmpathyChatPriv *priv = GET_PRIV (chat); + EmpathyMessage *message; + + message = empathy_message_new (strv[1]); + empathy_message_set_tptype (message, TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION); + empathy_tp_chat_send (priv->tp_chat, message); + g_object_unref (message); +} + +static void +chat_command_say (EmpathyChat *chat, + GStrv strv) +{ + EmpathyChatPriv *priv = GET_PRIV (chat); + EmpathyMessage *message; + + message = empathy_message_new (strv[1]); + empathy_tp_chat_send (priv->tp_chat, message); + g_object_unref (message); +} + +static void chat_command_help (EmpathyChat *chat, GStrv strv); + +typedef void (*ChatCommandFunc) (EmpathyChat *chat, GStrv strv); + +typedef struct { + const gchar *prefix; + guint min_parts; + guint max_parts; + ChatCommandFunc func; + const gchar *help; +} ChatCommandItem; + +static ChatCommandItem commands[] = { + {"clear", 1, 1, chat_command_clear, + N_("/clear, clear all messages from the current conversation")}, + + {"topic", 2, 2, chat_command_topic, + N_("/topic <topic>, set the topic of the current conversation")}, + + {"join", 2, 2, chat_command_join, + N_("/join <chatroom id>, join a new chatroom")}, + + {"j", 2, 2, chat_command_join, + N_("/j <chatroom id>, join a new chatroom")}, + + {"query", 2, 3, chat_command_query, + N_("/query <contact id> [<message>], open a private chat")}, + + {"msg", 3, 3, chat_command_msg, + N_("/msg <contact id> <message>, open a private chat")}, + + {"me", 2, 2, chat_command_me, + N_("/me <message>, send an ACTION message to the current conversation")}, + + {"say", 2, 2, chat_command_say, + N_("/say <message>, send <message> to the current conversation. " + "This is used to send a message starting with a '/'. For example: " + "\"/say /join is used to join a new chatroom\"")}, + + {"help", 1, 2, chat_command_help, + N_("/help [<command>], show all supported commands. " + "If <command> is defined, show its usage.")}, +}; + +static void +chat_command_show_help (EmpathyChat *chat, + ChatCommandItem *item) +{ + gchar *str; + + str = g_strdup_printf (_("Usage: %s"), _(item->help)); + empathy_chat_view_append_event (chat->view, str); + g_free (str); +} + +static void +chat_command_help (EmpathyChat *chat, + GStrv strv) +{ + guint i; + + /* If <command> part is not defined, + * strv[1] will be the terminal NULL */ + if (strv[1] == NULL) { + for (i = 0; i < G_N_ELEMENTS (commands); i++) { + empathy_chat_view_append_event (chat->view, + _(commands[i].help)); + } + return; + } + + for (i = 0; i < G_N_ELEMENTS (commands); i++) { + if (g_ascii_strcasecmp (strv[1], commands[i].prefix) == 0) { + chat_command_show_help (chat, &commands[i]); + return; + } + } +} + +static GStrv +chat_command_parse (const gchar *text, guint max_parts) +{ + GPtrArray *array; + gchar *item; + + DEBUG ("Parse command, parts=%d text=\"%s\":", max_parts, text); + + array = g_ptr_array_sized_new (max_parts + 1); + while (max_parts > 1) { + const gchar *end; + + /* Skip white spaces */ + while (g_ascii_isspace (*text)) { + text++; + } + + /* Search the end of this part, until first space. */ + for (end = text; *end != '\0' && !g_ascii_isspace (*end); end++) + /* Do nothing */; + if (*end == '\0') { + break; + } + + item = g_strndup (text, end - text); + g_ptr_array_add (array, item); + DEBUG ("\tITEM: \"%s\"", item); + + text = end; + max_parts--; + } + + /* Append last part if not empty */ + item = g_strstrip (g_strdup (text)); + if (!EMP_STR_EMPTY (item)) { + g_ptr_array_add (array, item); + DEBUG ("\tITEM: \"%s\"", item); + } else { + g_free (item); + } + + /* Make the array NULL-terminated */ + g_ptr_array_add (array, NULL); + + return (GStrv) g_ptr_array_free (array, FALSE); +} + +static gboolean +has_prefix_case (const gchar *s, + const gchar *prefix) +{ + return g_ascii_strncasecmp (s, prefix, strlen (prefix)) == 0; +} + +static void chat_send (EmpathyChat *chat, const gchar *msg) { EmpathyChatPriv *priv; EmpathyMessage *message; + guint i; if (EMP_STR_EMPTY (msg)) { return; @@ -593,20 +884,59 @@ chat_send (EmpathyChat *chat, chat_input_history_add (chat, msg, FALSE); - if (strcmp (msg, "/clear") == 0) { - empathy_chat_view_clear (chat->view); - return; - } + if (msg[0] == '/') { + gboolean second_slash = FALSE; + const gchar *iter = msg + 1; - message = empathy_message_new_from_entry (msg); + for (i = 0; i < G_N_ELEMENTS (commands); i++) { + GStrv strv; + guint strv_len; - if (message == NULL) { - empathy_chat_view_append_event (chat->view, - _("Unsupported command")); - } else { - empathy_tp_chat_send (priv->tp_chat, message); - g_object_unref (message); + if (!has_prefix_case (msg + 1, commands[i].prefix) || + !g_ascii_isspace (msg + 1 + strlen (commands[i].prefix))) { + continue; + } + + /* We can't use g_strsplit here because it does + * not deal correctly if we have more than one space + * between args */ + strv = chat_command_parse (msg + 1, commands[i].max_parts); + + strv_len = g_strv_length (strv); + if (strv_len < commands[i].min_parts || + strv_len > commands[i].max_parts) { + chat_command_show_help (chat, &commands[i]); + g_strfreev (strv); + return; + } + + commands[i].func (chat, strv); + g_strfreev (strv); + return; + } + + /* Also allow messages with two slashes before the + * first space, so it is possible to send a /unix/path. + * This heuristic is kind of crap. */ + while (*iter != '\0' && !g_ascii_isspace (*iter)) { + if (*iter == '/') { + second_slash = TRUE; + break; + } + iter++; + } + + if (!second_slash) { + empathy_chat_view_append_event (chat->view, + _("Unknown command, see /help for the available" + " commands")); + return; + } } + + message = empathy_message_new (msg); + empathy_tp_chat_send (priv->tp_chat, message); + g_object_unref (message); } static void @@ -1654,9 +1984,6 @@ chat_create_ui (EmpathyChat *chat) chat->input_text_view); gtk_widget_show (chat->input_text_view); - /* Create contact list */ - chat_update_contacts_visibility (chat); - /* Initialy hide the topic, will be shown if not empty */ gtk_widget_hide (priv->hbox_topic); @@ -1790,7 +2117,6 @@ chat_constructed (GObject *object) { EmpathyChat *chat = EMPATHY_CHAT (object); - chat_create_ui (chat); chat_add_logs (chat); show_pending_messages (chat); } @@ -1956,6 +2282,8 @@ empathy_chat_init (EmpathyChat *chat) /* Add nick name completion */ priv->completion = g_completion_new ((GCompletionFunc) empathy_contact_get_name); g_completion_set_compare (priv->completion, chat_contacts_completion_func); + + chat_create_ui (chat); } EmpathyChat * @@ -1980,6 +2308,7 @@ empathy_chat_set_tp_chat (EmpathyChat *chat, { EmpathyChatPriv *priv = GET_PRIV (chat); TpConnection *connection; + GPtrArray *properties; g_return_if_fail (EMPATHY_IS_CHAT (chat)); g_return_if_fail (EMPATHY_IS_TP_CHAT (tp_chat)); @@ -2019,6 +2348,25 @@ empathy_chat_set_tp_chat (EmpathyChat *chat, G_CALLBACK (chat_remote_contact_changed_cb), chat); + /* Get initial value of properties */ + properties = empathy_tp_chat_get_properties (priv->tp_chat); + if (properties != NULL) { + guint i; + + for (i = 0; i < properties->len; i++) { + EmpathyTpChatProperty *property; + + property = g_ptr_array_index (properties, i); + if (property->value == NULL) + continue; + + chat_property_changed_cb (priv->tp_chat, + property->name, + property->value, + chat); + } + } + chat_remote_contact_changed_cb (chat); if (chat->input_text_view) { diff --git a/libempathy/empathy-message.c b/libempathy/empathy-message.c index a403766e4..705bd224b 100644 --- a/libempathy/empathy-message.c +++ b/libempathy/empathy-message.c @@ -234,62 +234,6 @@ message_set_property (GObject *object, }; } -static gboolean -has_prefix_case (const gchar *s, - const gchar *prefix) -{ - return g_ascii_strncasecmp (s, prefix, strlen (prefix)) == 0; -} - -/* - * Constructs an EmpathyMessage based on user input, which may include "/me" - * and friends. - * - * Returns: an #EmpathyMessage if @message could be parsed, or %NULL if - * @message was an unknown command. - */ -EmpathyMessage * -empathy_message_new_from_entry (const gchar *message) -{ - TpChannelTextMessageType t = TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL; - - g_return_val_if_fail (message != NULL, NULL); - - if (message[0] == '/') { - if (g_ascii_strcasecmp (message, "/me") == 0) { - message = ""; - t = TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION; - } else if (has_prefix_case (message, "/me ")) { - message += strlen ("/me "); - t = TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION; - } else if (has_prefix_case (message, "/say ")) { - message += strlen ("/say "); - } else { - /* Also allow messages with two slashes before the - * first space, so it is possible to send a /unix/path. - * This heuristic is kind of crap. - */ - gboolean second_slash = FALSE; - const gchar *m = message + 1; - - while (!second_slash && *m != '\0' && *m != ' ') { - if (*m == '/') - second_slash = TRUE; - - m++; - } - - if (!second_slash) - return NULL; - } - } - - return g_object_new (EMPATHY_TYPE_MESSAGE, - "type", t, - "body", message, - NULL); -} - EmpathyMessage * empathy_message_new (const gchar *body) { diff --git a/libempathy/empathy-message.h b/libempathy/empathy-message.h index 7ca624031..09175e625 100644 --- a/libempathy/empathy-message.h +++ b/libempathy/empathy-message.h @@ -52,7 +52,6 @@ struct _EmpathyMessageClass { }; GType empathy_message_get_type (void) G_GNUC_CONST; -EmpathyMessage * empathy_message_new_from_entry (const gchar *message); EmpathyMessage * empathy_message_new (const gchar *body); TpChannelTextMessageType empathy_message_get_tptype (EmpathyMessage *message); void empathy_message_set_tptype (EmpathyMessage *message, diff --git a/libempathy/empathy-tp-chat.c b/libempathy/empathy-tp-chat.c index 09077538a..83faaff39 100644 --- a/libempathy/empathy-tp-chat.c +++ b/libempathy/empathy-tp-chat.c @@ -58,13 +58,6 @@ typedef struct { gboolean ready; } EmpathyTpChatPriv; -typedef struct { - gchar *name; - guint id; - TpPropertyFlags flags; - GValue *value; -} TpChatProperty; - static void tp_chat_iface_init (EmpathyContactListIface *iface); enum { @@ -493,10 +486,10 @@ tp_chat_property_flags_changed_cb (TpProxy *proxy, } for (i = 0; i < properties->len; i++) { - GValueArray *prop_struct; - TpChatProperty *property; - guint id; - guint flags; + GValueArray *prop_struct; + EmpathyTpChatProperty *property; + guint id; + guint flags; prop_struct = g_ptr_array_index (properties, i); id = g_value_get_uint (g_value_array_get_nth (prop_struct, 0)); @@ -531,10 +524,10 @@ tp_chat_properties_changed_cb (TpProxy *proxy, } for (i = 0; i < properties->len; i++) { - GValueArray *prop_struct; - TpChatProperty *property; - guint id; - GValue *src_value; + GValueArray *prop_struct; + EmpathyTpChatProperty *property; + guint id; + GValue *src_value; prop_struct = g_ptr_array_index (properties, i); id = g_value_get_uint (g_value_array_get_nth (prop_struct, 0)); @@ -597,11 +590,11 @@ tp_chat_list_properties_cb (TpProxy *proxy, ids = g_array_sized_new (FALSE, FALSE, sizeof (guint), properties->len); priv->properties = g_ptr_array_sized_new (properties->len); for (i = 0; i < properties->len; i++) { - GValueArray *prop_struct; - TpChatProperty *property; + GValueArray *prop_struct; + EmpathyTpChatProperty *property; prop_struct = g_ptr_array_index (properties, i); - property = g_slice_new0 (TpChatProperty); + property = g_slice_new0 (EmpathyTpChatProperty); property->id = g_value_get_uint (g_value_array_get_nth (prop_struct, 0)); property->name = g_value_dup_string (g_value_array_get_nth (prop_struct, 1)); property->flags = g_value_get_uint (g_value_array_get_nth (prop_struct, 3)); @@ -628,9 +621,13 @@ empathy_tp_chat_set_property (EmpathyTpChat *chat, const gchar *name, const GValue *value) { - EmpathyTpChatPriv *priv = GET_PRIV (chat); - TpChatProperty *property; - guint i; + EmpathyTpChatPriv *priv = GET_PRIV (chat); + EmpathyTpChatProperty *property; + guint i; + + if (!priv->had_properties_list) { + return; + } for (i = 0; i < priv->properties->len; i++) { property = g_ptr_array_index (priv->properties, i); @@ -672,6 +669,36 @@ empathy_tp_chat_set_property (EmpathyTpChat *chat, } } +EmpathyTpChatProperty * +empathy_tp_chat_get_property (EmpathyTpChat *chat, + const gchar *name) +{ + EmpathyTpChatPriv *priv = GET_PRIV (chat); + EmpathyTpChatProperty *property; + guint i; + + if (!priv->had_properties_list) { + return NULL; + } + + for (i = 0; i < priv->properties->len; i++) { + property = g_ptr_array_index (priv->properties, i); + if (!tp_strdiff (property->name, name)) { + return property; + } + } + + return NULL; +} + +GPtrArray * +empathy_tp_chat_get_properties (EmpathyTpChat *chat) +{ + EmpathyTpChatPriv *priv = GET_PRIV (chat); + + return priv->properties; +} + static void tp_chat_dispose (GObject *object) { @@ -727,14 +754,14 @@ tp_chat_finalize (GObject *object) if (priv->properties) { for (i = 0; i < priv->properties->len; i++) { - TpChatProperty *property; + EmpathyTpChatProperty *property; property = g_ptr_array_index (priv->properties, i); g_free (property->name); if (property->value) { tp_g_value_slice_free (property->value); } - g_slice_free (TpChatProperty, property); + g_slice_free (EmpathyTpChatProperty, property); } g_ptr_array_free (priv->properties, TRUE); } diff --git a/libempathy/empathy-tp-chat.h b/libempathy/empathy-tp-chat.h index f7d2b58a1..f07f0648f 100644 --- a/libempathy/empathy-tp-chat.h +++ b/libempathy/empathy-tp-chat.h @@ -52,6 +52,13 @@ struct _EmpathyTpChatClass { GObjectClass parent_class; }; +typedef struct { + gchar *name; + guint id; + TpPropertyFlags flags; + GValue *value; +} EmpathyTpChatProperty; + GType empathy_tp_chat_get_type (void) G_GNUC_CONST; EmpathyTpChat *empathy_tp_chat_new (TpChannel *channel); void empathy_tp_chat_close (EmpathyTpChat *chat); @@ -67,6 +74,10 @@ void empathy_tp_chat_set_state (EmpathyTpChat *chat, void empathy_tp_chat_set_property (EmpathyTpChat *chat, const gchar *name, const GValue *value); +EmpathyTpChatProperty * + empathy_tp_chat_get_property (EmpathyTpChat *chat, + const gchar *name); +GPtrArray * empathy_tp_chat_get_properties (EmpathyTpChat *chat); /* Returns a read-only list of pending messages (should be a copy maybe ?) */ const GList * empathy_tp_chat_get_pending_messages (EmpathyTpChat *chat); |