about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--Makefile.am1
-rw-r--r--src/command/command.c2
-rw-r--r--src/command/commands.c43
-rw-r--r--src/config/preferences.c89
-rw-r--r--src/config/preferences.h11
-rw-r--r--src/ui/console.c16
-rw-r--r--src/ui/ui.h1
-rw-r--r--tests/test_cmd_alias.c150
-rw-r--r--tests/test_cmd_alias.h8
-rw-r--r--tests/testsuite.c22
-rw-r--r--tests/ui/mock_ui.c19
-rw-r--r--tests/ui/mock_ui.h3
12 files changed, 356 insertions, 9 deletions
diff --git a/Makefile.am b/Makefile.am
index 933a44f6..5d5e3fba 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -77,6 +77,7 @@ test_sources = \
 	tests/test_cmd_account.c \
 	tests/test_cmd_rooms.c \
 	tests/test_cmd_sub.c \
+	tests/test_cmd_alias.c \
 	tests/test_cmd_statuses.c \
 	tests/test_history.c \
 	tests/test_jid.c \
diff --git a/src/command/command.c b/src/command/command.c
index 76f237cb..87161c4f 100644
--- a/src/command/command.c
+++ b/src/command/command.c
@@ -547,7 +547,7 @@ static struct cmd_t command_defs[] =
           NULL } } },
 
     { "/alias",
-        cmd_alias, parse_args, 1, 3, &cons_alias_setting,
+        cmd_alias, parse_args_with_freetext, 1, 3, &cons_alias_setting,
         { "/alias add|remove|list [name value]", "Add your own command aliases.",
         { "/alias add|remove|list [name value]",
           "-----------------------------------",
diff --git a/src/command/commands.c b/src/command/commands.c
index 712d39d8..c4390966 100644
--- a/src/command/commands.c
+++ b/src/command/commands.c
@@ -1821,8 +1821,47 @@ cmd_nick(gchar **args, struct cmd_help_t help)
 gboolean
 cmd_alias(gchar **args, struct cmd_help_t help)
 {
-    cons_show("Alias command TODO");
-    return TRUE;
+    char *subcmd = args[0];
+
+    if (strcmp(subcmd, "add") == 0) {
+        char *alias = args[1];
+        if (alias == NULL) {
+            cons_show("Usage: %s", help.usage);
+            return TRUE;
+        } else {
+            char *value = args[2];
+            if (value == NULL) {
+                cons_show("Usage: %s", help.usage);
+                return TRUE;
+            } else {
+                prefs_add_alias(alias, value);
+                cons_show("Command alias added /%s -> %s", alias, value);
+                return TRUE;
+            }
+        }
+    } else if (strcmp(subcmd, "remove") == 0) {
+        char *alias = args[1];
+        if (alias == NULL) {
+            cons_show("Usage: %s", help.usage);
+            return TRUE;
+        } else {
+            gboolean removed = prefs_remove_alias(alias);
+            if (!removed) {
+                cons_show("No such command alias /%s", alias);
+            } else {
+                cons_show("Command alias removed -> /%s", alias);
+            }
+            return TRUE;
+        }
+    } else if (strcmp(subcmd, "list") == 0) {
+        GList *aliases = prefs_get_aliases();
+        cons_show_aliases(aliases);
+        prefs_free_aliases(aliases);
+        return TRUE;
+    } else {
+        cons_show("Usage: %s", help.usage);
+        return TRUE;
+    }
 }
 
 gboolean
diff --git a/src/config/preferences.c b/src/config/preferences.c
index 3d5c9325..88e267f4 100644
--- a/src/config/preferences.c
+++ b/src/config/preferences.c
@@ -44,6 +44,7 @@
 #define PREF_GROUP_NOTIFICATIONS "notifications"
 #define PREF_GROUP_PRESENCE "presence"
 #define PREF_GROUP_CONNECTION "connection"
+#define PREF_GROUP_ALIAS "alias"
 
 static gchar *prefs_loc;
 static GKeyFile *prefs;
@@ -259,6 +260,82 @@ prefs_set_autoaway_time(gint value)
     _save_prefs();
 }
 
+void
+prefs_add_alias(const char * const name, const char * const value)
+{
+    g_key_file_set_string(prefs, PREF_GROUP_ALIAS, name, value);
+    _save_prefs();
+}
+
+char *
+prefs_get_alias(const char * const name)
+{
+    return g_key_file_get_string(prefs, PREF_GROUP_ALIAS, name, NULL);
+
+}
+
+gboolean
+prefs_remove_alias(const char * const name)
+{
+    if (!g_key_file_has_key(prefs, PREF_GROUP_ALIAS, name, NULL)) {
+        return FALSE;
+    } else {
+        g_key_file_remove_key(prefs, PREF_GROUP_ALIAS, name, NULL);
+        _save_prefs();
+        return TRUE;
+    }
+}
+
+static gint
+_alias_cmp(gconstpointer *p1, gconstpointer *p2)
+{
+    ProfAlias *alias1 = (ProfAlias*)p1;
+    ProfAlias *alias2 = (ProfAlias*)p2;
+
+    return strcmp(alias1->name, alias2->name);
+}
+
+GList *
+prefs_get_aliases(void)
+{
+    if (!g_key_file_has_group(prefs, PREF_GROUP_ALIAS)) {
+        return NULL;
+    } else {
+        GList *result = NULL;
+        gsize len;
+        gchar **keys = g_key_file_get_keys(prefs, PREF_GROUP_ALIAS, &len, NULL);
+        int i;
+        for (i = 0; i < len; i++) {
+            char *name = keys[i];
+            char *value = g_key_file_get_string(prefs, PREF_GROUP_ALIAS, name, NULL);
+
+            ProfAlias *alias = malloc(sizeof(struct prof_alias_t));
+            alias->name = strdup(name);
+            alias->value = strdup(value);
+
+            result = g_list_insert_sorted(result, alias, (GCompareFunc)_alias_cmp);
+        }
+
+        g_strfreev(keys);
+
+        return result;
+    }
+}
+
+void
+_free_alias(ProfAlias *alias)
+{
+    FREE_SET_NULL(alias->name);
+    FREE_SET_NULL(alias->value);
+    FREE_SET_NULL(alias);
+}
+
+void
+prefs_free_aliases(GList *aliases)
+{
+    g_list_free_full(aliases, (GDestroyNotify)_free_alias);
+}
+
 static void
 _save_prefs(void)
 {
@@ -299,25 +376,25 @@ _get_group(preference_t pref)
         case PREF_STATUSES_CHAT:
         case PREF_STATUSES_MUC:
         case PREF_OTR_WARN:
-            return "ui";
+            return PREF_GROUP_UI;
         case PREF_STATES:
         case PREF_OUTTYPE:
-            return "chatstates";
+            return PREF_GROUP_CHATSTATES;
         case PREF_NOTIFY_TYPING:
         case PREF_NOTIFY_MESSAGE:
         case PREF_NOTIFY_INVITE:
         case PREF_NOTIFY_SUB:
-            return "notifications";
+            return PREF_GROUP_NOTIFICATIONS;
         case PREF_CHLOG:
         case PREF_GRLOG:
         case PREF_OTR_LOG:
-            return "logging";
+            return PREF_GROUP_LOGGING;
         case PREF_AUTOAWAY_CHECK:
         case PREF_AUTOAWAY_MODE:
         case PREF_AUTOAWAY_MESSAGE:
-            return "presence";
+            return PREF_GROUP_PRESENCE;
         case PREF_CONNECT_ACCOUNT:
-            return "connection";
+            return PREF_GROUP_CONNECTION;
         default:
             return NULL;
     }
diff --git a/src/config/preferences.h b/src/config/preferences.h
index cc9d63e1..22a175d4 100644
--- a/src/config/preferences.h
+++ b/src/config/preferences.h
@@ -65,6 +65,11 @@ typedef enum {
     PREF_OTR_WARN
 } preference_t;
 
+typedef struct prof_alias_t {
+    gchar *name;
+    gchar *value;
+} ProfAlias;
+
 void prefs_load(void);
 void prefs_close(void);
 
@@ -92,6 +97,12 @@ void prefs_set_autoaway_time(gint value);
 
 void prefs_add_login(const char *jid);
 
+void prefs_add_alias(const char * const name, const char * const value);
+gboolean prefs_remove_alias(const char * const name);
+char* prefs_get_alias(const char * const name);
+GList* prefs_get_aliases(void);
+void prefs_free_aliases(GList *aliases);
+
 gboolean prefs_get_boolean(preference_t pref);
 void prefs_set_boolean(preference_t pref, gboolean value);
 char * prefs_get_string(preference_t pref);
diff --git a/src/ui/console.c b/src/ui/console.c
index a79f438e..0a8b3be2 100644
--- a/src/ui/console.c
+++ b/src/ui/console.c
@@ -903,6 +903,21 @@ _cons_show_account(ProfAccount *account)
 }
 
 static void
+_cons_show_aliases(GList *aliases)
+{
+    GList *curr = aliases;
+    if (curr != NULL) {
+        cons_show("Command aliases:");
+    }
+    while (curr != NULL) {
+        ProfAlias *alias = curr->data;
+        cons_show("  /%s -> %s", alias->name, alias->value);
+        curr = g_list_next(curr);
+    }
+    cons_show("");
+}
+
+static void
 _cons_alias_setting(void)
 {
     cons_show("Alias setting TODO");
@@ -1645,4 +1660,5 @@ console_init_module(void)
     cons_alert = _cons_alert;
     cons_show_contact_online = _cons_show_contact_online;
     cons_show_contact_offline = _cons_show_contact_offline;
+    cons_show_aliases = _cons_show_aliases;
 }
diff --git a/src/ui/ui.h b/src/ui/ui.h
index 00d284f3..cdd25ced 100644
--- a/src/ui/ui.h
+++ b/src/ui/ui.h
@@ -183,6 +183,7 @@ void (*cons_show_status)(const char * const barejid);
 void (*cons_show_info)(PContact pcontact);
 void (*cons_show_caps)(const char * const contact, Resource *resource);
 void (*cons_show_themes)(GSList *themes);
+void (*cons_show_aliases)(GList *aliases);
 void (*cons_show_login_success)(ProfAccount *account);
 void (*cons_show_software_version)(const char * const jid,
     const char * const presence, const char * const name,
diff --git a/tests/test_cmd_alias.c b/tests/test_cmd_alias.c
new file mode 100644
index 00000000..bdb16ede
--- /dev/null
+++ b/tests/test_cmd_alias.c
@@ -0,0 +1,150 @@
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+
+#include "xmpp/xmpp.h"
+#include "xmpp/mock_xmpp.h"
+
+#include "ui/ui.h"
+#include "ui/mock_ui.h"
+
+#include "config/preferences.h"
+
+#include "command/commands.h"
+
+void cmd_alias_add_shows_usage_when_no_args(void **state)
+{
+    mock_cons_show();
+    CommandHelp *help = malloc(sizeof(CommandHelp));
+    help->usage = "some usage";
+    gchar *args[] = { "add", NULL };
+
+    expect_cons_show("Usage: some usage");
+
+    gboolean result = cmd_alias(args, *help);
+    assert_true(result);
+
+    free(help);
+}
+
+void cmd_alias_add_shows_usage_when_no_value(void **state)
+{
+    mock_cons_show();
+    CommandHelp *help = malloc(sizeof(CommandHelp));
+    help->usage = "some usage";
+    gchar *args[] = { "add", "alias", NULL };
+
+    expect_cons_show("Usage: some usage");
+
+    gboolean result = cmd_alias(args, *help);
+    assert_true(result);
+
+    free(help);
+}
+
+void cmd_alias_remove_shows_usage_when_no_args(void **state)
+{
+    mock_cons_show();
+    CommandHelp *help = malloc(sizeof(CommandHelp));
+    help->usage = "some usage";
+    gchar *args[] = { "remove", NULL };
+
+    expect_cons_show("Usage: some usage");
+
+    gboolean result = cmd_alias(args, *help);
+    assert_true(result);
+
+    free(help);
+}
+
+void cmd_alias_show_usage_when_invalid_subcmd(void **state)
+{
+    mock_cons_show();
+    CommandHelp *help = malloc(sizeof(CommandHelp));
+    help->usage = "some usage";
+    gchar *args[] = { "blah", NULL };
+
+    expect_cons_show("Usage: some usage");
+
+    gboolean result = cmd_alias(args, *help);
+    assert_true(result);
+
+    free(help);
+}
+
+void cmd_alias_add_adds_alias(void **state)
+{
+    mock_cons_show();
+    CommandHelp *help = malloc(sizeof(CommandHelp));
+    gchar *args[] = { "add", "hc", "/help commands", NULL };
+
+    expect_cons_show("Command alias added /hc -> /help commands");
+
+    gboolean result = cmd_alias(args, *help);
+
+    char *returned_val = prefs_get_alias("hc");
+
+    assert_true(result);
+    assert_string_equal("/help commands", returned_val);
+
+    free(help);
+}
+
+void cmd_alias_remove_removes_alias(void **state)
+{
+    mock_cons_show();
+    CommandHelp *help = malloc(sizeof(CommandHelp));
+    gchar *args[] = { "remove", "hn", NULL };
+
+    prefs_add_alias("hn", "/help navigation");
+
+    expect_cons_show("Command alias removed -> /hn");
+
+    gboolean result = cmd_alias(args, *help);
+
+    char *returned_val = prefs_get_alias("hn");
+
+    assert_true(result);
+    assert_null(returned_val);
+
+    free(help);
+}
+
+void cmd_alias_remove_shows_message_when_no_alias(void **state)
+{
+    mock_cons_show();
+    CommandHelp *help = malloc(sizeof(CommandHelp));
+    gchar *args[] = { "remove", "hn", NULL };
+
+    expect_cons_show("No such command alias /hn");
+
+    gboolean result = cmd_alias(args, *help);
+    assert_true(result);
+
+    free(help);
+}
+
+void cmd_alias_list_shows_all_aliases(void **state)
+{
+    mock_cons_show_aliases();
+    CommandHelp *help = malloc(sizeof(CommandHelp));
+    gchar *args[] = { "list", NULL };
+
+    prefs_add_alias("vy", "/vercheck on");
+    prefs_add_alias("q", "/quit");
+    prefs_add_alias("hn", "/help navigation");
+    prefs_add_alias("hc", "/help commands");
+    prefs_add_alias("vn", "/vercheck off");
+
+    // write a custom checker to check the correct list is passed
+    expect_cons_show_aliases();
+
+    gboolean result = cmd_alias(args, *help);
+    assert_true(result);
+
+    free(help);
+}
diff --git a/tests/test_cmd_alias.h b/tests/test_cmd_alias.h
new file mode 100644
index 00000000..1f2df5cd
--- /dev/null
+++ b/tests/test_cmd_alias.h
@@ -0,0 +1,8 @@
+void cmd_alias_add_shows_usage_when_no_args(void **state);
+void cmd_alias_add_shows_usage_when_no_value(void **state);
+void cmd_alias_remove_shows_usage_when_no_args(void **state);
+void cmd_alias_show_usage_when_invalid_subcmd(void **state);
+void cmd_alias_add_adds_alias(void **state);
+void cmd_alias_remove_removes_alias(void **state);
+void cmd_alias_remove_shows_message_when_no_alias(void **state);
+void cmd_alias_list_shows_all_aliases(void **state);
diff --git a/tests/testsuite.c b/tests/testsuite.c
index 94a06a87..af42fe7c 100644
--- a/tests/testsuite.c
+++ b/tests/testsuite.c
@@ -21,6 +21,7 @@
 #include "test_roster_list.h"
 #include "test_preferences.h"
 #include "test_server_events.h"
+#include "test_cmd_alias.h"
 
 #define PROF_RUN_TESTS(name) fprintf(stderr, "\n-> Running %s\n", #name); \
     fflush(stderr); \
@@ -390,6 +391,26 @@ int main(int argc, char* argv[]) {
 //            delete_config_file),
     };
 
+    const UnitTest cmd_alias_tests[] = {
+        unit_test(cmd_alias_add_shows_usage_when_no_args),
+        unit_test(cmd_alias_add_shows_usage_when_no_value),
+        unit_test(cmd_alias_remove_shows_usage_when_no_args),
+        unit_test(cmd_alias_show_usage_when_invalid_subcmd),
+        unit_test_setup_teardown(cmd_alias_add_adds_alias,
+            create_config_file,
+            delete_config_file),
+        unit_test_setup_teardown(cmd_alias_remove_removes_alias,
+            create_config_file,
+            delete_config_file),
+        unit_test_setup_teardown(cmd_alias_remove_shows_message_when_no_alias,
+            create_config_file,
+            delete_config_file),
+        unit_test_setup_teardown(cmd_alias_list_shows_all_aliases,
+            create_config_file,
+            delete_config_file),
+    };
+
+
     int bak, new;
     fflush(stdout);
     bak = dup(1);
@@ -413,6 +434,7 @@ int main(int argc, char* argv[]) {
     PROF_RUN_TESTS(cmd_statuses_tests);
     PROF_RUN_TESTS(preferences_tests);
     PROF_RUN_TESTS(server_events_tests);
+    PROF_RUN_TESTS(cmd_alias_tests);
 
     fflush(stdout);
     dup2(bak, 1);
diff --git a/tests/ui/mock_ui.c b/tests/ui/mock_ui.c
index cd6c62ff..e03b77c5 100644
--- a/tests/ui/mock_ui.c
+++ b/tests/ui/mock_ui.c
@@ -69,6 +69,12 @@ void _mock_cons_show_account(ProfAccount *account)
 }
 
 static
+void _mock_cons_show_aliases(GList *aliases)
+{
+    check_expected(aliases);
+}
+
+static
 void _mock_cons_show_account_list(gchar **accounts)
 {
     check_expected(accounts);
@@ -123,6 +129,12 @@ mock_cons_show_account(void)
 }
 
 void
+mock_cons_show_aliases(void)
+{
+    cons_show_aliases = _mock_cons_show_aliases;
+}
+
+void
 mock_cons_show_account_list(void)
 {
     cons_show_account_list = _mock_cons_show_account_list;
@@ -190,6 +202,13 @@ expect_cons_show_contact_online(PContact contact, Resource *resource, GDateTime
 }
 
 void
+expect_cons_show_aliases()
+{
+    // write a custom checker for the list
+    expect_any(_mock_cons_show_aliases, aliases);
+}
+
+void
 mock_ui_ask_password_returns(char *password)
 {
     will_return(_mock_ui_ask_password, strdup(password));
diff --git a/tests/ui/mock_ui.h b/tests/ui/mock_ui.h
index 6f6d34d7..b0a5a80d 100644
--- a/tests/ui/mock_ui.h
+++ b/tests/ui/mock_ui.h
@@ -21,6 +21,9 @@ void expect_cons_show_error(char *output);
 void mock_cons_show_account(void);
 void expect_cons_show_account(ProfAccount *account);
 
+void mock_cons_show_aliases(void);
+void expect_cons_show_aliases(void);
+
 void mock_cons_show_account_list(void);
 void expect_cons_show_account_list(gchar **accounts);