]> git.0d.be Git - empathy.git/commitdiff
Merge branch 'irc-command'
authorXavier Claessens <xclaesse@gmail.com>
Tue, 3 Nov 2009 16:15:50 +0000 (17:15 +0100)
committerXavier Claessens <xclaesse@gmail.com>
Tue, 3 Nov 2009 16:15:50 +0000 (17:15 +0100)
1  2 
libempathy-gtk/empathy-chat.c

index b2fefee5fad2471e515a67668e3d077aa767cfd3,cfeb0073b62cca0440d5d17a9b8d17f8d9fbd1f7..e96c02db240e07d240e823125228b8b319c75932
@@@ -530,54 -367,305 +530,344 @@@ chat_input_history_get_prev (EmpathyCha
                return NULL;
        }
  
 -      if (priv->sent_messages_index >= 0) {
 -              priv->sent_messages_index--;
 +      if (priv->input_history_current == NULL)
 +      {
 +              return NULL;
 +      }
 +      else if ((item = g_list_previous (priv->input_history_current)) == NULL)
 +      {
 +              item = priv->input_history_current;
        }
  
 -      DEBUG ("Returning last message index:%d", priv->sent_messages_index);
 +      msg = chat_input_history_entry_get_text (item->data);
  
 -      return g_slist_nth_data (priv->sent_messages, priv->sent_messages_index);
 +      DEBUG ("Returning previous entry: '%s'", msg);
 +
 +      priv->input_history_current = item;
 +
 +      return msg;
 +}
 +
 +static void
 +chat_input_history_update (EmpathyChat *chat,
 +                           GtkTextBuffer *buffer)
 +{
 +      EmpathyChatPriv      *priv;
 +      GtkTextIter           start, end;
 +      gchar                *text;
 +      InputHistoryEntry    *entry;
 +
 +      priv = GET_PRIV (chat);
 +
 +      gtk_text_buffer_get_bounds (buffer, &start, &end);
 +      text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
 +
 +      if (priv->input_history_current == NULL) {
 +              /* Add the current text temporarily to the history */
 +              chat_input_history_add (chat, text, TRUE);
 +              g_free (text);
 +              return;
 +      }
 +
 +      /* Save the changes in the history */
 +      entry = priv->input_history_current->data;
 +      if (tp_strdiff (chat_input_history_entry_get_text (entry), text)) {
 +              chat_input_history_entry_update_text (entry, text);
 +      }
 +
 +      g_free (text);
  }
  
+ 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)
  
        priv = GET_PRIV (chat);
  
 -      chat_sent_message_add (chat, msg);
 +      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