From d9344b00fe6d3c77d8e935b7029ac11587e5001f Mon Sep 17 00:00:00 2001 From: James Booth Date: Sun, 3 Apr 2016 22:30:24 +0100 Subject: [PATCH 1/3] Added prof_strstr function --- src/common.c | 72 ++++++++++++--- src/common.h | 3 +- src/event/server_events.c | 14 +-- tests/unittests/test_common.c | 167 ++++++++++++++++++++++------------ tests/unittests/test_common.h | 1 + tests/unittests/unittests.c | 10 +- 6 files changed, 177 insertions(+), 90 deletions(-) diff --git a/src/common.c b/src/common.c index ad66015f..c6ead0ba 100644 --- a/src/common.c +++ b/src/common.c @@ -199,18 +199,6 @@ str_replace(const char *string, const char *substr, return newstr; } -gboolean -str_contains_str(const char *const searchstr, const char *const substr) -{ - if (!searchstr) { - return FALSE; - } - if (!substr) { - return FALSE; - } - return g_strrstr(searchstr, substr) != NULL; -} - int str_contains(const char str[], int size, char ch) { @@ -669,3 +657,63 @@ is_notify_enabled(void) return notify_enabled; } + +gboolean +prof_strstr(const char *const needle, const char *const haystack, gboolean case_sensitive, gboolean whole_word) +{ + if (needle == NULL || haystack == NULL) { + return FALSE; + } + + char *needle_str = case_sensitive ? strdup(needle) : g_utf8_strdown(needle, -1); + char *haystack_str = case_sensitive ? strdup(haystack) : g_utf8_strdown(haystack, -1); + + if (whole_word) { + if (g_strcmp0(needle_str, haystack_str) == 0) { + free(needle_str); + free(haystack_str); + return TRUE; + } + + char *pos = g_strrstr(haystack_str, needle_str); + if (pos == NULL) { + free(needle_str); + free(haystack_str); + return FALSE; + } + + gboolean at_start = g_str_has_prefix(haystack_str, needle_str); + gboolean at_end = g_str_has_suffix(haystack_str, needle_str); + + if (at_start) { + char *next = g_utf8_next_char(pos + strlen(needle_str) - 1); + gunichar nextu = g_utf8_get_char(next); + gboolean result = g_unichar_isalnum(nextu) ? FALSE : TRUE; + free(needle_str); + free(haystack_str); + return result; + } else if (at_end) { + char *prev = g_utf8_prev_char(pos); + gunichar prevu = g_utf8_get_char(prev); + gboolean result = g_unichar_isalnum(prevu) ? FALSE : TRUE; + free(needle_str); + free(haystack_str); + return result; + } else { + char *prev = g_utf8_prev_char(pos); + char *next = g_utf8_next_char(pos + strlen(needle_str) - 1); + gunichar prevu = g_utf8_get_char(prev); + gunichar nextu = g_utf8_get_char(next); + gboolean result = g_unichar_isalnum(prevu) || g_unichar_isalnum(nextu) ? FALSE : TRUE; + free(needle_str); + free(haystack_str); + return result; + } + } else { + gboolean result = g_strrstr(haystack_str, needle_str) != NULL ? TRUE : FALSE; + free(needle_str); + free(haystack_str); + return result; + } +} + diff --git a/src/common.h b/src/common.h index 21e9c4e2..284a096e 100644 --- a/src/common.h +++ b/src/common.h @@ -103,7 +103,6 @@ gboolean p_hash_table_contains(GHashTable *hash_table, gconstpointer key); gboolean create_dir(char *name); gboolean mkdir_recursive(const char *dir); char* str_replace(const char *string, const char *substr, const char *replacement); -gboolean str_contains_str(const char *const searchstr, const char *const substr); int str_contains(const char str[], int size, char ch); gboolean strtoi_range(char *str, int *saveptr, int min, int max, char **err_msg); int utf8_display_len(const char *const str); @@ -129,4 +128,6 @@ char* get_file_or_linked(char *loc, char *basedir); char* strip_arg_quotes(const char *const input); gboolean is_notify_enabled(void); +gboolean prof_strstr(const char *const needle, const char *const haystack, gboolean case_sensitive, gboolean whole_word); + #endif diff --git a/src/event/server_events.c b/src/event/server_events.c index 48e79d3b..2712ba56 100644 --- a/src/event/server_events.c +++ b/src/event/server_events.c @@ -251,15 +251,11 @@ sv_ev_room_message(const char *const room_jid, const char *const nick, const cha char *new_message = plugins_pre_room_message_display(room_jid, nick, message); char *mynick = muc_nick(mucwin->roomjid); - gboolean mention = FALSE; - char *message_lower = g_utf8_strdown(new_message, -1); - char *mynick_lower = g_utf8_strdown(mynick, -1); - if (g_strrstr(message_lower, mynick_lower)) { - mention = TRUE; - } - g_free(message_lower); - g_free(mynick_lower); - +// gboolean case_sensitive = prefs_get_boolean(PREF_MENTION_CASE_SENSITIVE); +// gboolean whole_word = prefs_get_boolean(PREF_MENTION_WHOLE_WORD); + gboolean case_sensitive = FALSE; + gboolean whole_word = FALSE; + gboolean mention = prof_strstr(mynick, new_message, case_sensitive, whole_word); GList *triggers = prefs_message_get_triggers(new_message); mucwin_message(mucwin, nick, new_message, mention, triggers); diff --git a/tests/unittests/test_common.c b/tests/unittests/test_common.c index 0e26b704..e80edb1c 100644 --- a/tests/unittests/test_common.c +++ b/tests/unittests/test_common.c @@ -631,66 +631,113 @@ void strip_quotes_strips_both(void **state) free(result); } -void str_not_contains_str(void **state) +void prof_strstr_contains(void **state) { - char *main = "somestring"; - char *occur = "not"; + assert_true(prof_strstr(NULL, "some string", FALSE, FALSE) == FALSE); + assert_true(prof_strstr("boothj5", NULL, FALSE, FALSE) == FALSE); + assert_true(prof_strstr(NULL, NULL, FALSE, FALSE) == FALSE); - assert_false(str_contains_str(main, occur)); -} - -void str_contains_str_at_start(void **state) -{ - char *main = "somestring"; - char *occur = "some"; - - assert_true(str_contains_str(main, occur)); -} - -void str_contains_str_at_end(void **state) -{ - char *main = "somestring"; - char *occur = "string"; - - assert_true(str_contains_str(main, occur)); -} - -void str_contains_str_in_middle(void **state) -{ - char *main = "somestring"; - char *occur = "str"; - - assert_true(str_contains_str(main, occur)); -} - -void str_contains_str_whole(void **state) -{ - char *main = "somestring"; - char *occur = "somestring"; - - assert_true(str_contains_str(main, occur)); -} - -void str_empty_not_contains_str(void **state) -{ - char *main = NULL; - char *occur = "str"; - - assert_false(str_contains_str(main, occur)); -} - -void str_not_contains_str_empty(void **state) -{ - char *main = "somestring"; - char *occur = NULL; - - assert_false(str_contains_str(main, occur)); -} - -void str_empty_not_contains_str_empty(void **state) -{ - char *main = NULL; - char *occur = NULL; - - assert_false(str_contains_str(main, occur)); + assert_true(prof_strstr("boothj5", "boothj5", FALSE, FALSE) == TRUE); + assert_true(prof_strstr("boothj5", "boothj5 hello", FALSE, FALSE) == TRUE); + assert_true(prof_strstr("boothj5", "hello boothj5", FALSE, FALSE) == TRUE); + assert_true(prof_strstr("boothj5", "hello boothj5 there", FALSE, FALSE) == TRUE); + assert_true(prof_strstr("boothj5", "helloboothj5test", FALSE, FALSE) == TRUE); + + assert_true(prof_strstr("boothj5", "BoothJ5", FALSE, FALSE) == TRUE); + assert_true(prof_strstr("boothj5", "BoothJ5 hello", FALSE, FALSE) == TRUE); + assert_true(prof_strstr("boothj5", "hello BoothJ5", FALSE, FALSE) == TRUE); + assert_true(prof_strstr("boothj5", "hello BoothJ5 there", FALSE, FALSE) == TRUE); + assert_true(prof_strstr("boothj5", "helloBoothJ5test", FALSE, FALSE) == TRUE); + + assert_true(prof_strstr("BoothJ5", "boothj5", FALSE, FALSE) == TRUE); + assert_true(prof_strstr("BoothJ5", "boothj5 hello", FALSE, FALSE) == TRUE); + assert_true(prof_strstr("BoothJ5", "hello boothj5", FALSE, FALSE) == TRUE); + assert_true(prof_strstr("BoothJ5", "hello boothj5 there", FALSE, FALSE) == TRUE); + assert_true(prof_strstr("BoothJ5", "helloboothj5test", FALSE, FALSE) == TRUE); + + assert_true(prof_strstr("boothj5", "BoothJ5", TRUE, FALSE) == FALSE); + assert_true(prof_strstr("boothj5", "BoothJ5 hello", TRUE, FALSE) == FALSE); + assert_true(prof_strstr("boothj5", "hello BoothJ5", TRUE, FALSE) == FALSE); + assert_true(prof_strstr("boothj5", "hello BoothJ5 there", TRUE, FALSE) == FALSE); + assert_true(prof_strstr("boothj5", "helloBoothJ5test", TRUE, FALSE) == FALSE); + + assert_true(prof_strstr("BoothJ5", "boothj5", TRUE, FALSE) == FALSE); + assert_true(prof_strstr("BoothJ5", "boothj5 hello", TRUE, FALSE) == FALSE); + assert_true(prof_strstr("BoothJ5", "hello boothj5", TRUE, FALSE) == FALSE); + assert_true(prof_strstr("BoothJ5", "hello boothj5 there", TRUE, FALSE) == FALSE); + assert_true(prof_strstr("BoothJ5", "helloboothj5test", TRUE, FALSE) == FALSE); + + assert_true(prof_strstr("boothj5", "boothj5", FALSE, TRUE) == TRUE); + assert_true(prof_strstr("boothj5", "boothj5 hello", FALSE, TRUE) == TRUE); + assert_true(prof_strstr("boothj5", "hello boothj5", FALSE, TRUE) == TRUE); + assert_true(prof_strstr("boothj5", "hello boothj5 there", FALSE, TRUE) == TRUE); + assert_true(prof_strstr("boothj5", "boothj5test", FALSE, TRUE) == FALSE); + assert_true(prof_strstr("boothj5", "helloboothj5", FALSE, TRUE) == FALSE); + assert_true(prof_strstr("boothj5", "helloboothj5test", FALSE, TRUE) == FALSE); + + assert_true(prof_strstr("boothj5", "BoothJ5", TRUE, TRUE) == FALSE); + assert_true(prof_strstr("boothj5", "BoothJ5 hello", TRUE, TRUE) == FALSE); + assert_true(prof_strstr("boothj5", "hello BoothJ5", TRUE, TRUE) == FALSE); + assert_true(prof_strstr("boothj5", "hello BoothJ5 there", TRUE, TRUE) == FALSE); + assert_true(prof_strstr("boothj5", "BoothJ5test", TRUE, TRUE) == FALSE); + assert_true(prof_strstr("boothj5", "helloBoothJ5", TRUE, TRUE) == FALSE); + assert_true(prof_strstr("boothj5", "helloBoothJ5test", TRUE, TRUE) == FALSE); + + assert_true(prof_strstr("BoothJ5", "boothj5", TRUE, TRUE) == FALSE); + assert_true(prof_strstr("BoothJ5", "boothj5 hello", TRUE, TRUE) == FALSE); + assert_true(prof_strstr("BoothJ5", "hello boothj5", TRUE, TRUE) == FALSE); + assert_true(prof_strstr("BoothJ5", "hello boothj5 there", TRUE, TRUE) == FALSE); + assert_true(prof_strstr("BoothJ5", "boothj5test", TRUE, TRUE) == FALSE); + assert_true(prof_strstr("BoothJ5", "helloboothj5", TRUE, TRUE) == FALSE); + assert_true(prof_strstr("BoothJ5", "helloboothj5test", TRUE, TRUE) == FALSE); + + assert_true(prof_strstr("boothj5", "boothj5:", FALSE, TRUE) == TRUE); + assert_true(prof_strstr("boothj5", "boothj5,", FALSE, TRUE) == TRUE); + assert_true(prof_strstr("boothj5", "boothj5-", FALSE, TRUE) == TRUE); + assert_true(prof_strstr("boothj5", ":boothj5", FALSE, TRUE) == TRUE); + assert_true(prof_strstr("boothj5", ",boothj5", FALSE, TRUE) == TRUE); + assert_true(prof_strstr("boothj5", "-boothj5", FALSE, TRUE) == TRUE); + assert_true(prof_strstr("boothj5", ":boothj5:", FALSE, TRUE) == TRUE); + assert_true(prof_strstr("boothj5", ",boothj5,", FALSE, TRUE) == TRUE); + assert_true(prof_strstr("boothj5", "-boothj5-", FALSE, TRUE) == TRUE); + + assert_true(prof_strstr("boothj5", "BoothJ5:", FALSE, TRUE) == TRUE); + assert_true(prof_strstr("boothj5", "BoothJ5,", FALSE, TRUE) == TRUE); + assert_true(prof_strstr("boothj5", "BoothJ5-", FALSE, TRUE) == TRUE); + assert_true(prof_strstr("boothj5", ":BoothJ5", FALSE, TRUE) == TRUE); + assert_true(prof_strstr("boothj5", ",BoothJ5", FALSE, TRUE) == TRUE); + assert_true(prof_strstr("boothj5", "-BoothJ5", FALSE, TRUE) == TRUE); + assert_true(prof_strstr("boothj5", ":BoothJ5:", FALSE, TRUE) == TRUE); + assert_true(prof_strstr("boothj5", ",BoothJ5,", FALSE, TRUE) == TRUE); + assert_true(prof_strstr("boothj5", "-BoothJ5-", FALSE, TRUE) == TRUE); + + assert_true(prof_strstr("boothj5", "BoothJ5:", TRUE, TRUE) == FALSE); + assert_true(prof_strstr("boothj5", "BoothJ5,", TRUE, TRUE) == FALSE); + assert_true(prof_strstr("boothj5", "BoothJ5-", TRUE, TRUE) == FALSE); + assert_true(prof_strstr("boothj5", ":BoothJ5", TRUE, TRUE) == FALSE); + assert_true(prof_strstr("boothj5", ",BoothJ5", TRUE, TRUE) == FALSE); + assert_true(prof_strstr("boothj5", "-BoothJ5", TRUE, TRUE) == FALSE); + assert_true(prof_strstr("boothj5", ":BoothJ5:", TRUE, TRUE) == FALSE); + assert_true(prof_strstr("boothj5", ",BoothJ5,", TRUE, TRUE) == FALSE); + assert_true(prof_strstr("boothj5", "-BoothJ5-", TRUE, TRUE) == FALSE); + + assert_true(prof_strstr("K", "don't know", FALSE, FALSE) == TRUE); + assert_true(prof_strstr("K", "don't know", TRUE, FALSE) == FALSE); + assert_true(prof_strstr("K", "don't know", FALSE, TRUE) == FALSE); + assert_true(prof_strstr("K", "don't know", TRUE, TRUE) == FALSE); + + assert_true(prof_strstr("K", "don't Know", FALSE, FALSE) == TRUE); + assert_true(prof_strstr("K", "don't Know", TRUE, FALSE) == TRUE); + assert_true(prof_strstr("K", "don't Know", FALSE, TRUE) == FALSE); + assert_true(prof_strstr("K", "don't Know", TRUE, TRUE) == FALSE); + + assert_true(prof_strstr("K", "backwards", FALSE, FALSE) == TRUE); + assert_true(prof_strstr("K", "backwards", TRUE, FALSE) == FALSE); + assert_true(prof_strstr("K", "backwards", FALSE, TRUE) == FALSE); + assert_true(prof_strstr("K", "backwards", TRUE, TRUE) == FALSE); + + assert_true(prof_strstr("K", "BACKWARDS", FALSE, FALSE) == TRUE); + assert_true(prof_strstr("K", "BACKWARDS", TRUE, FALSE) == TRUE); + assert_true(prof_strstr("K", "BACKWARDS", FALSE, TRUE) == FALSE); + assert_true(prof_strstr("K", "BACKWARDS", TRUE, TRUE) == FALSE); } diff --git a/tests/unittests/test_common.h b/tests/unittests/test_common.h index 6f3f1698..f0e901a7 100644 --- a/tests/unittests/test_common.h +++ b/tests/unittests/test_common.h @@ -64,3 +64,4 @@ void str_contains_str_whole(void **state); void str_empty_not_contains_str(void **state); void str_not_contains_str_empty(void **state); void str_empty_not_contains_str_empty(void **state); +void prof_strstr_contains(void **state); diff --git a/tests/unittests/unittests.c b/tests/unittests/unittests.c index 6b26cb29..8826f2ec 100644 --- a/tests/unittests/unittests.c +++ b/tests/unittests/unittests.c @@ -94,14 +94,6 @@ int main(int argc, char* argv[]) { unit_test(strip_quotes_strips_first), unit_test(strip_quotes_strips_last), unit_test(strip_quotes_strips_both), - unit_test(str_not_contains_str), - unit_test(str_contains_str_at_start), - unit_test(str_contains_str_at_end), - unit_test(str_contains_str_in_middle), - unit_test(str_contains_str_whole), - unit_test(str_empty_not_contains_str), - unit_test(str_not_contains_str_empty), - unit_test(str_empty_not_contains_str_empty), unit_test(clear_empty), unit_test(reset_after_create), @@ -624,6 +616,8 @@ int main(int argc, char* argv[]) { unit_test_setup_teardown(clears_chat_sessions, load_preferences, close_preferences), + + unit_test(prof_strstr_contains), }; return run_tests(all_tests); From afa2c0f5ba5e38c2234c15191ebb0aee41e5833a Mon Sep 17 00:00:00 2001 From: James Booth Date: Sun, 3 Apr 2016 23:33:21 +0100 Subject: [PATCH 2/3] Added mention match preferences --- src/config/preferences.c | 8 ++++++++ src/config/preferences.h | 2 ++ src/event/server_events.c | 6 ++---- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/config/preferences.c b/src/config/preferences.c index 968787e3..ce40a321 100644 --- a/src/config/preferences.c +++ b/src/config/preferences.c @@ -1230,6 +1230,8 @@ _get_group(preference_t pref) case PREF_NOTIFY_ROOM_TEXT: case PREF_NOTIFY_INVITE: case PREF_NOTIFY_SUB: + case PREF_MENTION_CASE_SENSITIVE: + case PREF_MENTION_WHOLE_WORD: return PREF_GROUP_NOTIFICATIONS; case PREF_CHLOG: case PREF_GRLOG: @@ -1332,6 +1334,10 @@ _get_key(preference_t pref) return "invite"; case PREF_NOTIFY_SUB: return "sub"; + case PREF_MENTION_CASE_SENSITIVE: + return "room.mention.casesensitive"; + case PREF_MENTION_WHOLE_WORD: + return "room.mention.wholeword"; case PREF_CHLOG: return "chlog"; case PREF_GRLOG: @@ -1488,6 +1494,8 @@ _get_default_boolean(preference_t pref) case PREF_ROSTER_ROOMS: case PREF_TLS_SHOW: case PREF_LASTACTIVITY: + case PREF_MENTION_CASE_SENSITIVE: + case PREF_MENTION_WHOLE_WORD: return TRUE; default: return FALSE; diff --git a/src/config/preferences.h b/src/config/preferences.h index 1ab18d31..7165079b 100644 --- a/src/config/preferences.h +++ b/src/config/preferences.h @@ -113,6 +113,8 @@ typedef enum { PREF_NOTIFY_ROOM_TEXT, PREF_NOTIFY_INVITE, PREF_NOTIFY_SUB, + PREF_MENTION_CASE_SENSITIVE, + PREF_MENTION_WHOLE_WORD, PREF_CHLOG, PREF_GRLOG, PREF_AUTOAWAY_CHECK, diff --git a/src/event/server_events.c b/src/event/server_events.c index 2712ba56..11252dab 100644 --- a/src/event/server_events.c +++ b/src/event/server_events.c @@ -251,10 +251,8 @@ sv_ev_room_message(const char *const room_jid, const char *const nick, const cha char *new_message = plugins_pre_room_message_display(room_jid, nick, message); char *mynick = muc_nick(mucwin->roomjid); -// gboolean case_sensitive = prefs_get_boolean(PREF_MENTION_CASE_SENSITIVE); -// gboolean whole_word = prefs_get_boolean(PREF_MENTION_WHOLE_WORD); - gboolean case_sensitive = FALSE; - gboolean whole_word = FALSE; + gboolean case_sensitive = prefs_get_boolean(PREF_MENTION_CASE_SENSITIVE); + gboolean whole_word = prefs_get_boolean(PREF_MENTION_WHOLE_WORD); gboolean mention = prof_strstr(mynick, new_message, case_sensitive, whole_word); GList *triggers = prefs_message_get_triggers(new_message); From f243e333fcb6740ff8d09cc04db27d88040f5f7d Mon Sep 17 00:00:00 2001 From: James Booth Date: Thu, 7 Apr 2016 01:01:27 +0100 Subject: [PATCH 3/3] Added whole word matches for room mention --- src/command/command.c | 64 ++++++---- src/command/commands.c | 12 ++ src/common.c | 67 +++------- src/common.h | 3 +- src/config/preferences.c | 12 +- src/config/preferences.h | 4 +- src/event/server_events.c | 16 ++- src/ui/console.c | 10 ++ src/ui/mucwin.c | 51 ++++---- src/ui/ui.h | 2 +- tests/unittests/test_common.c | 231 +++++++++++++++++++--------------- tests/unittests/test_common.h | 3 +- tests/unittests/ui/stub_ui.c | 2 +- tests/unittests/unittests.c | 3 +- 14 files changed, 263 insertions(+), 217 deletions(-) diff --git a/src/command/command.c b/src/command/command.c index 5aa86a90..bf323a02 100644 --- a/src/command/command.c +++ b/src/command/command.c @@ -1179,6 +1179,8 @@ static struct cmd_t command_defs[] = "/notify chat text on|off", "/notify room on|off", "/notify room mention on|off", + "/notify room mention case_sensitive|case_insensitive", + "/notify room mention word_whole|word_part", "/notify room current on|off", "/notify room text on|off", "/notify room trigger add ", @@ -1197,26 +1199,30 @@ static struct cmd_t command_defs[] = CMD_DESC( "Settings for various kinds of desktop notifications.") CMD_ARGS( - { "chat on|off", "Notifications for regular chat messages." }, - { "chat current on|off", "Whether to show regular chat message notifications when the window is focussed." }, - { "chat text on|off", "Show message text in regular message notifications." }, - { "room on|off", "Notifications for all chat room messages, 'mention' only notifies when your nick is mentioned." }, - { "room mention on|off", "Notifications for all chat room messages when your nick is mentioned." }, - { "room current on|off", "Whether to show all chat room messages notifications when the window is focussed." }, - { "room text on|off", "Show message text in chat room message notifications." }, - { "room trigger add ", "Notify when specified text included in all chat room messages." }, - { "room trigger remove ", "Remove chat room notification trigger." }, - { "room trigger list", "List all chat room triggers." }, - { "room trigger on|off", "Enable or disable all chat room notification triggers." }, - { "on|off", "Override the global message setting for the current chat room." }, - { "mention on|off", "Override the global 'mention' setting for the current chat room." }, - { "trigger on|off", "Override the global 'trigger' setting for the current chat room." }, - { "reset", "Reset to global notification settings for the current chat room." }, - { "remind ", "Notification reminder period for unread messages, use 0 to disable." }, - { "typing on|off", "Notifications when contacts are typing." }, - { "typing current on|off", "Whether typing notifications are triggered for the current window." }, - { "invite on|off", "Notifications for chat room invites." }, - { "sub on|off", "Notifications for subscription requests." }) + { "chat on|off", "Notifications for regular chat messages." }, + { "chat current on|off", "Whether to show regular chat message notifications when the window is focussed." }, + { "chat text on|off", "Show message text in regular message notifications." }, + { "room on|off", "Notifications for all chat room messages, 'mention' only notifies when your nick is mentioned." }, + { "room mention on|off", "Notifications for all chat room messages when your nick is mentioned." }, + { "room mention case_sensitive", "Set room mention notifications as case sensitive." }, + { "room mention case_insensitive", "Set room mention notifications as case insensitive." }, + { "room mention word_whole", "Set room mention notifications only on whole word match, i.e. when nickname is not part of a larger word." }, + { "room mention word_part", "Set room mention notifications on partial word match, i.e. nickname may be part of a larger word." }, + { "room current on|off", "Whether to show all chat room messages notifications when the window is focussed." }, + { "room text on|off", "Show message text in chat room message notifications." }, + { "room trigger add ", "Notify when specified text included in all chat room messages." }, + { "room trigger remove ", "Remove chat room notification trigger." }, + { "room trigger list", "List all chat room triggers." }, + { "room trigger on|off", "Enable or disable all chat room notification triggers." }, + { "on|off", "Override the global message setting for the current chat room." }, + { "mention on|off", "Override the global 'mention' setting for the current chat room." }, + { "trigger on|off", "Override the global 'trigger' setting for the current chat room." }, + { "reset", "Reset to global notification settings for the current chat room." }, + { "remind ", "Notification reminder period for unread messages, use 0 to disable." }, + { "typing on|off", "Notifications when contacts are typing." }, + { "typing current on|off", "Whether typing notifications are triggered for the current window." }, + { "invite on|off", "Notifications for chat room invites." }, + { "sub on|off", "Notifications for subscription requests." }) CMD_EXAMPLES( "/notify chat on", "/notify chat text on", @@ -1943,6 +1949,7 @@ static Autocomplete notify_ac; static Autocomplete notify_chat_ac; static Autocomplete notify_room_ac; static Autocomplete notify_typing_ac; +static Autocomplete notify_mention_ac; static Autocomplete notify_trigger_ac; static Autocomplete prefs_ac; static Autocomplete sub_ac; @@ -2111,6 +2118,14 @@ cmd_init(void) autocomplete_add(notify_typing_ac, "off"); autocomplete_add(notify_typing_ac, "current"); + notify_mention_ac = autocomplete_new(); + autocomplete_add(notify_mention_ac, "on"); + autocomplete_add(notify_mention_ac, "off"); + autocomplete_add(notify_mention_ac, "case_sensitive"); + autocomplete_add(notify_mention_ac, "case_insensitive"); + autocomplete_add(notify_mention_ac, "word_whole"); + autocomplete_add(notify_mention_ac, "word_part"); + notify_trigger_ac = autocomplete_new(); autocomplete_add(notify_trigger_ac, "add"); autocomplete_add(notify_trigger_ac, "remove"); @@ -2571,6 +2586,7 @@ cmd_uninit(void) autocomplete_free(notify_chat_ac); autocomplete_free(notify_room_ac); autocomplete_free(notify_typing_ac); + autocomplete_free(notify_mention_ac); autocomplete_free(notify_trigger_ac); autocomplete_free(sub_ac); autocomplete_free(titlebar_ac); @@ -2788,6 +2804,7 @@ cmd_reset_autocomplete(ProfWin *window) autocomplete_reset(notify_chat_ac); autocomplete_reset(notify_room_ac); autocomplete_reset(notify_typing_ac); + autocomplete_reset(notify_mention_ac); autocomplete_reset(notify_trigger_ac); autocomplete_reset(sub_ac); @@ -3491,7 +3508,7 @@ _notify_autocomplete(ProfWin *window, const char *const input) } gchar *boolean_choices1[] = { "/notify room current", "/notify chat current", "/notify typing current", - "/notify room text", "/notify room mention", "/notify chat text" }; + "/notify room text", "/notify chat text" }; for (i = 0; i < ARRAY_SIZE(boolean_choices1); i++) { result = autocomplete_param_with_func(input, boolean_choices1[i], prefs_autocomplete_boolean_choice); if (result) { @@ -3499,6 +3516,11 @@ _notify_autocomplete(ProfWin *window, const char *const input) } } + result = autocomplete_param_with_ac(input, "/notify room mention", notify_mention_ac, TRUE); + if (result) { + return result; + } + result = autocomplete_param_with_ac(input, "/notify room trigger", notify_trigger_ac, TRUE); if (result) { return result; diff --git a/src/command/commands.c b/src/command/commands.c index da6fdec8..538a62ae 100644 --- a/src/command/commands.c +++ b/src/command/commands.c @@ -4855,6 +4855,18 @@ cmd_notify(ProfWin *window, const char *const command, gchar **args) } else if (g_strcmp0(args[2], "off") == 0) { cons_show("Room notifications with mention disabled."); prefs_set_boolean(PREF_NOTIFY_ROOM_MENTION, FALSE); + } else if (g_strcmp0(args[2], "case_sensitive") == 0) { + cons_show("Room mention matching set to case sensitive."); + prefs_set_boolean(PREF_NOTIFY_MENTION_CASE_SENSITIVE, TRUE); + } else if (g_strcmp0(args[2], "case_insensitive") == 0) { + cons_show("Room mention matching set to case insensitive."); + prefs_set_boolean(PREF_NOTIFY_MENTION_CASE_SENSITIVE, FALSE); + } else if (g_strcmp0(args[2], "word_whole") == 0) { + cons_show("Room mention matching set to whole word."); + prefs_set_boolean(PREF_NOTIFY_MENTION_WHOLE_WORD, TRUE); + } else if (g_strcmp0(args[2], "word_part") == 0) { + cons_show("Room mention matching set to partial word."); + prefs_set_boolean(PREF_NOTIFY_MENTION_WHOLE_WORD, FALSE); } else { cons_show("Usage: /notify room mention on|off"); } diff --git a/src/common.c b/src/common.c index c6ead0ba..a8282fe7 100644 --- a/src/common.c +++ b/src/common.c @@ -658,62 +658,31 @@ is_notify_enabled(void) return notify_enabled; } -gboolean -prof_strstr(const char *const needle, const char *const haystack, gboolean case_sensitive, gboolean whole_word) +GSList* +prof_occurrences(const char *const needle, const char *const haystack, int offset, gboolean whole_word, GSList **result) { if (needle == NULL || haystack == NULL) { - return FALSE; + return *result; } - char *needle_str = case_sensitive ? strdup(needle) : g_utf8_strdown(needle, -1); - char *haystack_str = case_sensitive ? strdup(haystack) : g_utf8_strdown(haystack, -1); - - if (whole_word) { - if (g_strcmp0(needle_str, haystack_str) == 0) { - free(needle_str); - free(haystack_str); - return TRUE; - } - - char *pos = g_strrstr(haystack_str, needle_str); - if (pos == NULL) { - free(needle_str); - free(haystack_str); - return FALSE; - } - - gboolean at_start = g_str_has_prefix(haystack_str, needle_str); - gboolean at_end = g_str_has_suffix(haystack_str, needle_str); - - if (at_start) { - char *next = g_utf8_next_char(pos + strlen(needle_str) - 1); - gunichar nextu = g_utf8_get_char(next); - gboolean result = g_unichar_isalnum(nextu) ? FALSE : TRUE; - free(needle_str); - free(haystack_str); - return result; - } else if (at_end) { - char *prev = g_utf8_prev_char(pos); + if (g_str_has_prefix(&haystack[offset], needle)) { + if (whole_word) { + char *prev = g_utf8_prev_char(&haystack[offset]); + char *next = g_utf8_next_char(&haystack[offset] + strlen(needle) - 1); gunichar prevu = g_utf8_get_char(prev); - gboolean result = g_unichar_isalnum(prevu) ? FALSE : TRUE; - free(needle_str); - free(haystack_str); - return result; + gunichar nextu = g_utf8_get_char(next); + if (!g_unichar_isalnum(prevu) && !g_unichar_isalnum(nextu)) { + *result = g_slist_append(*result, GINT_TO_POINTER(offset)); + } } else { - char *prev = g_utf8_prev_char(pos); - char *next = g_utf8_next_char(pos + strlen(needle_str) - 1); - gunichar prevu = g_utf8_get_char(prev); - gunichar nextu = g_utf8_get_char(next); - gboolean result = g_unichar_isalnum(prevu) || g_unichar_isalnum(nextu) ? FALSE : TRUE; - free(needle_str); - free(haystack_str); - return result; + *result = g_slist_append(*result, GINT_TO_POINTER(offset)); } - } else { - gboolean result = g_strrstr(haystack_str, needle_str) != NULL ? TRUE : FALSE; - free(needle_str); - free(haystack_str); - return result; } + + if (haystack[offset+1] != '\0') { + *result = prof_occurrences(needle, haystack, offset+1, whole_word, result); + } + + return *result; } diff --git a/src/common.h b/src/common.h index 284a096e..c67b1460 100644 --- a/src/common.h +++ b/src/common.h @@ -128,6 +128,7 @@ char* get_file_or_linked(char *loc, char *basedir); char* strip_arg_quotes(const char *const input); gboolean is_notify_enabled(void); -gboolean prof_strstr(const char *const needle, const char *const haystack, gboolean case_sensitive, gboolean whole_word); +GSList* prof_occurrences(const char *const needle, const char *const haystack, int offset, gboolean whole_word, + GSList **result); #endif diff --git a/src/config/preferences.c b/src/config/preferences.c index ce40a321..4957a600 100644 --- a/src/config/preferences.c +++ b/src/config/preferences.c @@ -1230,8 +1230,8 @@ _get_group(preference_t pref) case PREF_NOTIFY_ROOM_TEXT: case PREF_NOTIFY_INVITE: case PREF_NOTIFY_SUB: - case PREF_MENTION_CASE_SENSITIVE: - case PREF_MENTION_WHOLE_WORD: + case PREF_NOTIFY_MENTION_CASE_SENSITIVE: + case PREF_NOTIFY_MENTION_WHOLE_WORD: return PREF_GROUP_NOTIFICATIONS; case PREF_CHLOG: case PREF_GRLOG: @@ -1334,9 +1334,9 @@ _get_key(preference_t pref) return "invite"; case PREF_NOTIFY_SUB: return "sub"; - case PREF_MENTION_CASE_SENSITIVE: + case PREF_NOTIFY_MENTION_CASE_SENSITIVE: return "room.mention.casesensitive"; - case PREF_MENTION_WHOLE_WORD: + case PREF_NOTIFY_MENTION_WHOLE_WORD: return "room.mention.wholeword"; case PREF_CHLOG: return "chlog"; @@ -1494,8 +1494,8 @@ _get_default_boolean(preference_t pref) case PREF_ROSTER_ROOMS: case PREF_TLS_SHOW: case PREF_LASTACTIVITY: - case PREF_MENTION_CASE_SENSITIVE: - case PREF_MENTION_WHOLE_WORD: + case PREF_NOTIFY_MENTION_CASE_SENSITIVE: + case PREF_NOTIFY_MENTION_WHOLE_WORD: return TRUE; default: return FALSE; diff --git a/src/config/preferences.h b/src/config/preferences.h index 7165079b..8f18149c 100644 --- a/src/config/preferences.h +++ b/src/config/preferences.h @@ -113,8 +113,8 @@ typedef enum { PREF_NOTIFY_ROOM_TEXT, PREF_NOTIFY_INVITE, PREF_NOTIFY_SUB, - PREF_MENTION_CASE_SENSITIVE, - PREF_MENTION_WHOLE_WORD, + PREF_NOTIFY_MENTION_CASE_SENSITIVE, + PREF_NOTIFY_MENTION_WHOLE_WORD, PREF_CHLOG, PREF_GRLOG, PREF_AUTOAWAY_CHECK, diff --git a/src/event/server_events.c b/src/event/server_events.c index 11252dab..76c649cd 100644 --- a/src/event/server_events.c +++ b/src/event/server_events.c @@ -251,12 +251,20 @@ sv_ev_room_message(const char *const room_jid, const char *const nick, const cha char *new_message = plugins_pre_room_message_display(room_jid, nick, message); char *mynick = muc_nick(mucwin->roomjid); - gboolean case_sensitive = prefs_get_boolean(PREF_MENTION_CASE_SENSITIVE); - gboolean whole_word = prefs_get_boolean(PREF_MENTION_WHOLE_WORD); - gboolean mention = prof_strstr(mynick, new_message, case_sensitive, whole_word); + gboolean whole_word = prefs_get_boolean(PREF_NOTIFY_MENTION_WHOLE_WORD); + gboolean case_sensitive = prefs_get_boolean(PREF_NOTIFY_MENTION_CASE_SENSITIVE); + char *message_search = case_sensitive ? strdup(new_message) : g_utf8_strdown(new_message, -1); + char *mynick_search = case_sensitive ? strdup(mynick) : g_utf8_strdown(mynick, -1); + + GSList *mentions = NULL; + mentions = prof_occurrences(mynick_search, message_search, 0, whole_word, &mentions); + gboolean mention = g_slist_length(mentions) > 0; + g_free(message_search); + g_free(mynick_search); + GList *triggers = prefs_message_get_triggers(new_message); - mucwin_message(mucwin, nick, new_message, mention, triggers); + mucwin_message(mucwin, nick, new_message, mentions, triggers); ProfWin *window = (ProfWin*)mucwin; int num = wins_get_num(window); diff --git a/src/ui/console.c b/src/ui/console.c index 69984333..c104e21b 100644 --- a/src/ui/console.c +++ b/src/ui/console.c @@ -1550,6 +1550,16 @@ cons_notify_setting(void) else cons_show("Room mention (/notify room) : OFF"); + if (prefs_get_boolean(PREF_NOTIFY_MENTION_CASE_SENSITIVE)) + cons_show("Room mention case (/notify room) : Case sensitive"); + else + cons_show("Room mention case (/notify room) : Case insensitive"); + + if (prefs_get_boolean(PREF_NOTIFY_MENTION_WHOLE_WORD)) + cons_show("Room mention word (/notify room) : Whole word only"); + else + cons_show("Room mention word (/notify room) : Part of word"); + if (prefs_get_boolean(PREF_NOTIFY_ROOM_TRIGGER)) cons_show("Room trigger (/notify room) : ON"); else diff --git a/src/ui/mucwin.c b/src/ui/mucwin.c index 4d323ef1..0b3c65f7 100644 --- a/src/ui/mucwin.c +++ b/src/ui/mucwin.c @@ -359,33 +359,30 @@ mucwin_history(ProfMucWin *mucwin, const char *const nick, GDateTime *timestamp, } static void -_mucwin_print_mention(ProfWin *window, const char *const message, const char *const my_nick) +_mucwin_print_mention(ProfWin *window, const char *const message, const char *const nick, GSList *mentions) { - char *mynick_lower = g_utf8_strdown(my_nick, -1); - char *message_lower = g_utf8_strdown(message, -1); - char message_section[strlen(message) + 1]; + int last_pos = 0; + int pos = 0; + GSList *curr = mentions; + while (curr) { + pos = GPOINTER_TO_INT(curr->data); - int i = 0; - while(!g_str_has_prefix(&message_lower[i], mynick_lower) && i < strlen(message)) { - message_section[i] = message[i]; - i++; + char *before_str = g_strndup(message + last_pos, pos - last_pos); + win_print(window, '-', 0, NULL, NO_DATE | NO_ME | NO_EOL, THEME_ROOMMENTION, "", before_str); + g_free(before_str); + char *nick_str = g_strndup(message + pos, strlen(nick)); + win_print(window, '-', 0, NULL, NO_DATE | NO_ME | NO_EOL, THEME_ROOMMENTION_TERM, "", nick_str); + g_free(nick_str); + + last_pos = pos + strlen(nick); + + curr = g_slist_next(curr); } - message_section[i] = '\0'; - - char *mention_section = strndup(&message[i], strlen(my_nick)); - int used = strlen(message_section) + strlen(mention_section); - - win_print(window, '-', 0, NULL, NO_DATE | NO_ME | NO_EOL, THEME_ROOMMENTION, "", message_section); - if (strlen(message) > used) { - win_print(window, '-', 0, NULL, NO_DATE | NO_ME | NO_EOL, THEME_ROOMMENTION_TERM, "", mention_section); - _mucwin_print_mention(window, &message[used], my_nick); + if (last_pos < strlen(message)) { + win_print(window, '-', 0, NULL, NO_DATE | NO_ME, THEME_ROOMMENTION, "", &message[last_pos]); } else { - win_print(window, '-', 0, NULL, NO_DATE | NO_ME, THEME_ROOMMENTION_TERM, "", mention_section); + win_print(window, '-', 0, NULL, NO_DATE | NO_ME, THEME_ROOMMENTION, "", ""); } - - free(mention_section); - g_free(mynick_lower); - g_free(message_lower); } gint @@ -472,17 +469,17 @@ _mucwin_print_triggers(ProfWin *window, const char *const message, GList *trigge } void -mucwin_message(ProfMucWin *mucwin, const char *const nick, const char *const message, gboolean mention, GList *triggers) +mucwin_message(ProfMucWin *mucwin, const char *const nick, const char *const message, GSList *mentions, GList *triggers) { assert(mucwin != NULL); ProfWin *window = (ProfWin*)mucwin; - char *my_nick = muc_nick(mucwin->roomjid); + char *mynick = muc_nick(mucwin->roomjid); - if (g_strcmp0(nick, my_nick) != 0) { - if (mention) { + if (g_strcmp0(nick, mynick) != 0) { + if (g_slist_length(mentions) > 0) { win_print(window, '-', 0, NULL, NO_ME | NO_EOL, THEME_ROOMMENTION, nick, ""); - _mucwin_print_mention(window, message, my_nick); + _mucwin_print_mention(window, message, mynick, mentions); } else if (triggers) { win_print(window, '-', 0, NULL, NO_ME | NO_EOL, THEME_ROOMTRIGGER, nick, ""); _mucwin_print_triggers(window, message, triggers); diff --git a/src/ui/ui.h b/src/ui/ui.h index ab42f4d1..924ba33c 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -157,7 +157,7 @@ void mucwin_occupant_role_and_affiliation_change(ProfMucWin *mucwin, const char const char *const role, const char *const affiliation, const char *const actor, const char *const reason); void mucwin_roster(ProfMucWin *mucwin, GList *occupants, const char *const presence); void mucwin_history(ProfMucWin *mucwin, const char *const nick, GDateTime *timestamp, const char *const message); -void mucwin_message(ProfMucWin *mucwin, const char *const nick, const char *const message, gboolean mention, GList *triggers); +void mucwin_message(ProfMucWin *mucwin, const char *const nick, const char *const message, GSList *mentions, GList *triggers); void mucwin_subject(ProfMucWin *mucwin, const char *const nick, const char *const subject); void mucwin_requires_config(ProfMucWin *mucwin); void mucwin_info(ProfMucWin *mucwin); diff --git a/tests/unittests/test_common.c b/tests/unittests/test_common.c index e80edb1c..76128edf 100644 --- a/tests/unittests/test_common.c +++ b/tests/unittests/test_common.c @@ -631,113 +631,138 @@ void strip_quotes_strips_both(void **state) free(result); } -void prof_strstr_contains(void **state) +gboolean +_lists_equal(GSList *a, GSList *b) { - assert_true(prof_strstr(NULL, "some string", FALSE, FALSE) == FALSE); - assert_true(prof_strstr("boothj5", NULL, FALSE, FALSE) == FALSE); - assert_true(prof_strstr(NULL, NULL, FALSE, FALSE) == FALSE); + if (g_slist_length(a) != g_slist_length(b)) { + return FALSE; + } - assert_true(prof_strstr("boothj5", "boothj5", FALSE, FALSE) == TRUE); - assert_true(prof_strstr("boothj5", "boothj5 hello", FALSE, FALSE) == TRUE); - assert_true(prof_strstr("boothj5", "hello boothj5", FALSE, FALSE) == TRUE); - assert_true(prof_strstr("boothj5", "hello boothj5 there", FALSE, FALSE) == TRUE); - assert_true(prof_strstr("boothj5", "helloboothj5test", FALSE, FALSE) == TRUE); + GSList *curra = a; + GSList *currb = b; - assert_true(prof_strstr("boothj5", "BoothJ5", FALSE, FALSE) == TRUE); - assert_true(prof_strstr("boothj5", "BoothJ5 hello", FALSE, FALSE) == TRUE); - assert_true(prof_strstr("boothj5", "hello BoothJ5", FALSE, FALSE) == TRUE); - assert_true(prof_strstr("boothj5", "hello BoothJ5 there", FALSE, FALSE) == TRUE); - assert_true(prof_strstr("boothj5", "helloBoothJ5test", FALSE, FALSE) == TRUE); + while (curra) { + int aval = GPOINTER_TO_INT(curra->data); + int bval = GPOINTER_TO_INT(currb->data); - assert_true(prof_strstr("BoothJ5", "boothj5", FALSE, FALSE) == TRUE); - assert_true(prof_strstr("BoothJ5", "boothj5 hello", FALSE, FALSE) == TRUE); - assert_true(prof_strstr("BoothJ5", "hello boothj5", FALSE, FALSE) == TRUE); - assert_true(prof_strstr("BoothJ5", "hello boothj5 there", FALSE, FALSE) == TRUE); - assert_true(prof_strstr("BoothJ5", "helloboothj5test", FALSE, FALSE) == TRUE); + if (aval != bval) { + return FALSE; + } - assert_true(prof_strstr("boothj5", "BoothJ5", TRUE, FALSE) == FALSE); - assert_true(prof_strstr("boothj5", "BoothJ5 hello", TRUE, FALSE) == FALSE); - assert_true(prof_strstr("boothj5", "hello BoothJ5", TRUE, FALSE) == FALSE); - assert_true(prof_strstr("boothj5", "hello BoothJ5 there", TRUE, FALSE) == FALSE); - assert_true(prof_strstr("boothj5", "helloBoothJ5test", TRUE, FALSE) == FALSE); + curra = g_list_next(curra); + currb = g_list_next(currb); + } - assert_true(prof_strstr("BoothJ5", "boothj5", TRUE, FALSE) == FALSE); - assert_true(prof_strstr("BoothJ5", "boothj5 hello", TRUE, FALSE) == FALSE); - assert_true(prof_strstr("BoothJ5", "hello boothj5", TRUE, FALSE) == FALSE); - assert_true(prof_strstr("BoothJ5", "hello boothj5 there", TRUE, FALSE) == FALSE); - assert_true(prof_strstr("BoothJ5", "helloboothj5test", TRUE, FALSE) == FALSE); - - assert_true(prof_strstr("boothj5", "boothj5", FALSE, TRUE) == TRUE); - assert_true(prof_strstr("boothj5", "boothj5 hello", FALSE, TRUE) == TRUE); - assert_true(prof_strstr("boothj5", "hello boothj5", FALSE, TRUE) == TRUE); - assert_true(prof_strstr("boothj5", "hello boothj5 there", FALSE, TRUE) == TRUE); - assert_true(prof_strstr("boothj5", "boothj5test", FALSE, TRUE) == FALSE); - assert_true(prof_strstr("boothj5", "helloboothj5", FALSE, TRUE) == FALSE); - assert_true(prof_strstr("boothj5", "helloboothj5test", FALSE, TRUE) == FALSE); - - assert_true(prof_strstr("boothj5", "BoothJ5", TRUE, TRUE) == FALSE); - assert_true(prof_strstr("boothj5", "BoothJ5 hello", TRUE, TRUE) == FALSE); - assert_true(prof_strstr("boothj5", "hello BoothJ5", TRUE, TRUE) == FALSE); - assert_true(prof_strstr("boothj5", "hello BoothJ5 there", TRUE, TRUE) == FALSE); - assert_true(prof_strstr("boothj5", "BoothJ5test", TRUE, TRUE) == FALSE); - assert_true(prof_strstr("boothj5", "helloBoothJ5", TRUE, TRUE) == FALSE); - assert_true(prof_strstr("boothj5", "helloBoothJ5test", TRUE, TRUE) == FALSE); - - assert_true(prof_strstr("BoothJ5", "boothj5", TRUE, TRUE) == FALSE); - assert_true(prof_strstr("BoothJ5", "boothj5 hello", TRUE, TRUE) == FALSE); - assert_true(prof_strstr("BoothJ5", "hello boothj5", TRUE, TRUE) == FALSE); - assert_true(prof_strstr("BoothJ5", "hello boothj5 there", TRUE, TRUE) == FALSE); - assert_true(prof_strstr("BoothJ5", "boothj5test", TRUE, TRUE) == FALSE); - assert_true(prof_strstr("BoothJ5", "helloboothj5", TRUE, TRUE) == FALSE); - assert_true(prof_strstr("BoothJ5", "helloboothj5test", TRUE, TRUE) == FALSE); - - assert_true(prof_strstr("boothj5", "boothj5:", FALSE, TRUE) == TRUE); - assert_true(prof_strstr("boothj5", "boothj5,", FALSE, TRUE) == TRUE); - assert_true(prof_strstr("boothj5", "boothj5-", FALSE, TRUE) == TRUE); - assert_true(prof_strstr("boothj5", ":boothj5", FALSE, TRUE) == TRUE); - assert_true(prof_strstr("boothj5", ",boothj5", FALSE, TRUE) == TRUE); - assert_true(prof_strstr("boothj5", "-boothj5", FALSE, TRUE) == TRUE); - assert_true(prof_strstr("boothj5", ":boothj5:", FALSE, TRUE) == TRUE); - assert_true(prof_strstr("boothj5", ",boothj5,", FALSE, TRUE) == TRUE); - assert_true(prof_strstr("boothj5", "-boothj5-", FALSE, TRUE) == TRUE); - - assert_true(prof_strstr("boothj5", "BoothJ5:", FALSE, TRUE) == TRUE); - assert_true(prof_strstr("boothj5", "BoothJ5,", FALSE, TRUE) == TRUE); - assert_true(prof_strstr("boothj5", "BoothJ5-", FALSE, TRUE) == TRUE); - assert_true(prof_strstr("boothj5", ":BoothJ5", FALSE, TRUE) == TRUE); - assert_true(prof_strstr("boothj5", ",BoothJ5", FALSE, TRUE) == TRUE); - assert_true(prof_strstr("boothj5", "-BoothJ5", FALSE, TRUE) == TRUE); - assert_true(prof_strstr("boothj5", ":BoothJ5:", FALSE, TRUE) == TRUE); - assert_true(prof_strstr("boothj5", ",BoothJ5,", FALSE, TRUE) == TRUE); - assert_true(prof_strstr("boothj5", "-BoothJ5-", FALSE, TRUE) == TRUE); - - assert_true(prof_strstr("boothj5", "BoothJ5:", TRUE, TRUE) == FALSE); - assert_true(prof_strstr("boothj5", "BoothJ5,", TRUE, TRUE) == FALSE); - assert_true(prof_strstr("boothj5", "BoothJ5-", TRUE, TRUE) == FALSE); - assert_true(prof_strstr("boothj5", ":BoothJ5", TRUE, TRUE) == FALSE); - assert_true(prof_strstr("boothj5", ",BoothJ5", TRUE, TRUE) == FALSE); - assert_true(prof_strstr("boothj5", "-BoothJ5", TRUE, TRUE) == FALSE); - assert_true(prof_strstr("boothj5", ":BoothJ5:", TRUE, TRUE) == FALSE); - assert_true(prof_strstr("boothj5", ",BoothJ5,", TRUE, TRUE) == FALSE); - assert_true(prof_strstr("boothj5", "-BoothJ5-", TRUE, TRUE) == FALSE); - - assert_true(prof_strstr("K", "don't know", FALSE, FALSE) == TRUE); - assert_true(prof_strstr("K", "don't know", TRUE, FALSE) == FALSE); - assert_true(prof_strstr("K", "don't know", FALSE, TRUE) == FALSE); - assert_true(prof_strstr("K", "don't know", TRUE, TRUE) == FALSE); - - assert_true(prof_strstr("K", "don't Know", FALSE, FALSE) == TRUE); - assert_true(prof_strstr("K", "don't Know", TRUE, FALSE) == TRUE); - assert_true(prof_strstr("K", "don't Know", FALSE, TRUE) == FALSE); - assert_true(prof_strstr("K", "don't Know", TRUE, TRUE) == FALSE); - - assert_true(prof_strstr("K", "backwards", FALSE, FALSE) == TRUE); - assert_true(prof_strstr("K", "backwards", TRUE, FALSE) == FALSE); - assert_true(prof_strstr("K", "backwards", FALSE, TRUE) == FALSE); - assert_true(prof_strstr("K", "backwards", TRUE, TRUE) == FALSE); - - assert_true(prof_strstr("K", "BACKWARDS", FALSE, FALSE) == TRUE); - assert_true(prof_strstr("K", "BACKWARDS", TRUE, FALSE) == TRUE); - assert_true(prof_strstr("K", "BACKWARDS", FALSE, TRUE) == FALSE); - assert_true(prof_strstr("K", "BACKWARDS", TRUE, TRUE) == FALSE); + return TRUE; +} + +void prof_partial_occurrences_tests(void **state) +{ + GSList *actual = NULL; + GSList *expected = NULL; + assert_true(_lists_equal(prof_occurrences(NULL, NULL, 0, FALSE, &actual), expected)); + g_slist_free(actual); actual = NULL; + + assert_true(_lists_equal(prof_occurrences(NULL, "some string", 0, FALSE, &actual), expected)); g_slist_free(actual); actual = NULL; + assert_true(_lists_equal(prof_occurrences("boothj5", NULL, 0, FALSE, &actual), expected)); g_slist_free(actual); actual = NULL; + assert_true(_lists_equal(prof_occurrences(NULL, NULL, 0, FALSE, &actual), expected)); g_slist_free(actual); actual = NULL; + assert_true(_lists_equal(prof_occurrences("boothj5", "Boothj5", 0, FALSE, &actual), expected)); g_slist_free(actual); actual = NULL; + assert_true(_lists_equal(prof_occurrences("Boothj5", "boothj5", 0, FALSE, &actual), expected)); g_slist_free(actual); actual = NULL; + + expected = g_slist_append(expected, GINT_TO_POINTER(0)); + assert_true(_lists_equal(prof_occurrences("boothj5", "boothj5", 0, FALSE, &actual), expected)); g_slist_free(actual); actual = NULL; + assert_true(_lists_equal(prof_occurrences("boothj5", "boothj5hello", 0, FALSE, &actual), expected)); g_slist_free(actual); actual = NULL; + assert_true(_lists_equal(prof_occurrences("boothj5", "boothj5 hello", 0, FALSE, &actual), expected)); g_slist_free(actual); actual = NULL; + g_slist_free(expected); expected = NULL; + + expected = g_slist_append(expected, GINT_TO_POINTER(5)); + assert_true(_lists_equal(prof_occurrences("boothj5", "helloboothj5", 0, FALSE, &actual), expected)); g_slist_free(actual); actual = NULL; + assert_true(_lists_equal(prof_occurrences("boothj5", "helloboothj5hello", 0, FALSE, &actual), expected)); g_slist_free(actual); actual = NULL; + g_slist_free(expected); expected = NULL; + + expected = g_slist_append(expected, GINT_TO_POINTER(6)); + assert_true(_lists_equal(prof_occurrences("boothj5", "hello boothj5", 0, FALSE, &actual), expected)); g_slist_free(actual); actual = NULL; + assert_true(_lists_equal(prof_occurrences("boothj5", "hello boothj5 hello", 0, FALSE, &actual), expected)); g_slist_free(actual); actual = NULL; + g_slist_free(expected); expected = NULL; + + expected = g_slist_append(expected, GINT_TO_POINTER(0)); + expected = g_slist_append(expected, GINT_TO_POINTER(7)); + assert_true(_lists_equal(prof_occurrences("boothj5", "boothj5boothj5", 0, FALSE, &actual), expected)); g_slist_free(actual); actual = NULL; + g_slist_free(expected); expected = NULL; + + expected = g_slist_append(expected, GINT_TO_POINTER(0)); + expected = g_slist_append(expected, GINT_TO_POINTER(12)); + assert_true(_lists_equal(prof_occurrences("boothj5", "boothj5helloboothj5", 0, FALSE, &actual), expected)); g_slist_free(actual); actual = NULL; + g_slist_free(expected); expected = NULL; + + expected = g_slist_append(expected, GINT_TO_POINTER(0)); + expected = g_slist_append(expected, GINT_TO_POINTER(14)); + assert_true(_lists_equal(prof_occurrences("boothj5", "boothj5 hello boothj5", 0, FALSE, &actual), expected)); g_slist_free(actual); actual = NULL; + g_slist_free(expected); expected = NULL; + + expected = g_slist_append(expected, GINT_TO_POINTER(2)); + expected = g_slist_append(expected, GINT_TO_POINTER(16)); + expected = g_slist_append(expected, GINT_TO_POINTER(29)); + assert_true(_lists_equal(prof_occurrences("boothj5", "hiboothj5 hello boothj5there boothj5s", 0, FALSE, &actual), expected)); g_slist_free(actual); actual = NULL; + g_slist_free(expected); expected = NULL; +} + +void prof_whole_occurrences_tests(void **state) +{ + GSList *actual = NULL; + GSList *expected = NULL; + assert_true(_lists_equal(prof_occurrences(NULL, NULL, 0, FALSE, &actual), expected)); + g_slist_free(actual); actual = NULL; + + expected = g_slist_append(expected, GINT_TO_POINTER(0)); + assert_true(_lists_equal(prof_occurrences("boothj5", "boothj5", 0, TRUE, &actual), expected)); g_slist_free(actual); actual = NULL; + assert_true(_lists_equal(prof_occurrences("boothj5", "boothj5 hi", 0, TRUE, &actual), expected)); g_slist_free(actual); actual = NULL; + assert_true(_lists_equal(prof_occurrences("boothj5", "boothj5: hi", 0, TRUE, &actual), expected)); g_slist_free(actual); actual = NULL; + assert_true(_lists_equal(prof_occurrences("boothj5", "boothj5, hi", 0, TRUE, &actual), expected)); g_slist_free(actual); actual = NULL; + g_slist_free(expected); expected = NULL; + + expected = g_slist_append(expected, GINT_TO_POINTER(6)); + assert_true(_lists_equal(prof_occurrences("boothj5", "hello boothj5", 0, TRUE, &actual), expected)); g_slist_free(actual); actual = NULL; + assert_true(_lists_equal(prof_occurrences("boothj5", "hello boothj5 there", 0, TRUE, &actual), expected)); g_slist_free(actual); actual = NULL; + assert_true(_lists_equal(prof_occurrences("boothj5", "heyy @boothj5, there", 0, TRUE, &actual), expected)); g_slist_free(actual); actual = NULL; + g_slist_free(expected); expected = NULL; + + expected = g_slist_append(expected, GINT_TO_POINTER(6)); + expected = g_slist_append(expected, GINT_TO_POINTER(26)); + assert_true(_lists_equal(prof_occurrences("boothj5", "hello boothj5 some more a boothj5 stuff", 0, TRUE, &actual), expected)); g_slist_free(actual); actual = NULL; + assert_true(_lists_equal(prof_occurrences("boothj5", "hello boothj5 there ands #boothj5", 0, TRUE, &actual), expected)); g_slist_free(actual); actual = NULL; + assert_true(_lists_equal(prof_occurrences("boothj5", "heyy @boothj5, there hows boothj5?", 0, TRUE, &actual), expected)); g_slist_free(actual); actual = NULL; + g_slist_free(expected); expected = NULL; + + expected = g_slist_append(expected, GINT_TO_POINTER(6)); + assert_true(_lists_equal(prof_occurrences("p", "ppppp p", 0, TRUE, &actual), expected)); g_slist_free(actual); actual = NULL; + g_slist_free(expected); expected = NULL; + + expected = g_slist_append(expected, GINT_TO_POINTER(0)); + assert_true(_lists_equal(prof_occurrences("p", "p ppppp", 0, TRUE, &actual), expected)); g_slist_free(actual); actual = NULL; + g_slist_free(expected); expected = NULL; + + expected = g_slist_append(expected, GINT_TO_POINTER(4)); + assert_true(_lists_equal(prof_occurrences("p", "ppp p ppp", 0, TRUE, &actual), expected)); g_slist_free(actual); actual = NULL; + g_slist_free(expected); expected = NULL; + + expected = NULL; + assert_true(_lists_equal(prof_occurrences("boothj5", "boothj5hello", 0, TRUE, &actual), expected)); g_slist_free(actual); actual = NULL; + assert_true(_lists_equal(prof_occurrences("boothj5", "heyboothj5", 0, TRUE, &actual), expected)); g_slist_free(actual); actual = NULL; + assert_true(_lists_equal(prof_occurrences("boothj5", "heyboothj5hithere", 0, TRUE, &actual), expected)); g_slist_free(actual); actual = NULL; + assert_true(_lists_equal(prof_occurrences("boothj5", "hey boothj5hithere", 0, TRUE, &actual), expected)); g_slist_free(actual); actual = NULL; + assert_true(_lists_equal(prof_occurrences("boothj5", "hey @boothj5hithere", 0, TRUE, &actual), expected)); g_slist_free(actual); actual = NULL; + assert_true(_lists_equal(prof_occurrences("boothj5", "heyboothj5 hithere", 0, TRUE, &actual), expected)); g_slist_free(actual); actual = NULL; + assert_true(_lists_equal(prof_occurrences("boothj5", "heyboothj5, hithere", 0, TRUE, &actual), expected)); g_slist_free(actual); actual = NULL; + assert_true(_lists_equal(prof_occurrences("boothj5", "boothj5boothj5", 0, TRUE, &actual), expected)); g_slist_free(actual); actual = NULL; + assert_true(_lists_equal(prof_occurrences("boothj5", "boothj5fillboothj5", 0, TRUE, &actual), expected)); g_slist_free(actual); actual = NULL; + assert_true(_lists_equal(prof_occurrences("k", "dont know", 0, TRUE, &actual), expected)); g_slist_free(actual); actual = NULL; + assert_true(_lists_equal(prof_occurrences("k", "kick", 0, TRUE, &actual), expected)); g_slist_free(actual); actual = NULL; + assert_true(_lists_equal(prof_occurrences("k", "kick kick", 0, TRUE, &actual), expected)); g_slist_free(actual); actual = NULL; + assert_true(_lists_equal(prof_occurrences("k", "kick kickk", 0, TRUE, &actual), expected)); g_slist_free(actual); actual = NULL; + assert_true(_lists_equal(prof_occurrences("k", "kic", 0, TRUE, &actual), expected)); g_slist_free(actual); actual = NULL; + assert_true(_lists_equal(prof_occurrences("k", "ick", 0, TRUE, &actual), expected)); g_slist_free(actual); actual = NULL; + assert_true(_lists_equal(prof_occurrences("k", "kk", 0, TRUE, &actual), expected)); g_slist_free(actual); actual = NULL; + assert_true(_lists_equal(prof_occurrences("k", "kkkkkkk", 0, TRUE, &actual), expected)); g_slist_free(actual); actual = NULL; + g_slist_free(expected); expected = NULL; } diff --git a/tests/unittests/test_common.h b/tests/unittests/test_common.h index f0e901a7..3a790017 100644 --- a/tests/unittests/test_common.h +++ b/tests/unittests/test_common.h @@ -64,4 +64,5 @@ void str_contains_str_whole(void **state); void str_empty_not_contains_str(void **state); void str_not_contains_str_empty(void **state); void str_empty_not_contains_str_empty(void **state); -void prof_strstr_contains(void **state); +void prof_partial_occurrences_tests(void **state); +void prof_whole_occurrences_tests(void **state); diff --git a/tests/unittests/ui/stub_ui.c b/tests/unittests/ui/stub_ui.c index 4881d831..f9de0859 100644 --- a/tests/unittests/ui/stub_ui.c +++ b/tests/unittests/ui/stub_ui.c @@ -193,7 +193,7 @@ void mucwin_occupant_role_and_affiliation_change(ProfMucWin *mucwin, const char const char * const affiliation, const char * const actor, const char * const reason) {} void mucwin_roster(ProfMucWin *mucwin, GList *occupants, const char * const presence) {} void mucwin_history(ProfMucWin *mucwin, const char * const nick, GDateTime *timestamp, const char * const message) {} -void mucwin_message(ProfMucWin *mucwin, const char * const nick, const char * const message, gboolean mention, GList *triggers) {} +void mucwin_message(ProfMucWin *mucwin, const char *const nick, const char *const message, GSList *mentions, GList *triggers) {} void mucwin_subject(ProfMucWin *mucwin, const char * const nick, const char * const subject) {} void mucwin_requires_config(ProfMucWin *mucwin) {} void ui_room_destroy(const char * const roomjid) {} diff --git a/tests/unittests/unittests.c b/tests/unittests/unittests.c index 8826f2ec..572d1a4f 100644 --- a/tests/unittests/unittests.c +++ b/tests/unittests/unittests.c @@ -617,7 +617,8 @@ int main(int argc, char* argv[]) { load_preferences, close_preferences), - unit_test(prof_strstr_contains), + unit_test(prof_partial_occurrences_tests), + unit_test(prof_whole_occurrences_tests), }; return run_tests(all_tests);