diff options
Diffstat (limited to 'src/fe-common/core')
-rw-r--r-- | src/fe-common/core/Makefile.am | 5 | ||||
-rw-r--r-- | src/fe-common/core/chat-completion.c | 49 | ||||
-rw-r--r-- | src/fe-common/core/completion.c | 77 | ||||
-rw-r--r-- | src/fe-common/core/fe-channels.c | 118 | ||||
-rw-r--r-- | src/fe-common/core/fe-common-core.c | 11 | ||||
-rw-r--r-- | src/fe-common/core/fe-core-commands.c | 3 | ||||
-rw-r--r-- | src/fe-common/core/fe-exec.c | 15 | ||||
-rw-r--r-- | src/fe-common/core/fe-ignore.c | 8 | ||||
-rw-r--r-- | src/fe-common/core/fe-log.c | 2 | ||||
-rw-r--r-- | src/fe-common/core/fe-messages.c | 5 | ||||
-rw-r--r-- | src/fe-common/core/fe-server.c | 24 | ||||
-rw-r--r-- | src/fe-common/core/fe-settings.c | 27 | ||||
-rw-r--r-- | src/fe-common/core/formats.c | 28 | ||||
-rw-r--r-- | src/fe-common/core/hilight-text.c | 149 | ||||
-rw-r--r-- | src/fe-common/core/hilight-text.h | 1 | ||||
-rw-r--r-- | src/fe-common/core/module-formats.c | 2 | ||||
-rw-r--r-- | src/fe-common/core/module-formats.h | 2 | ||||
-rw-r--r-- | src/fe-common/core/module.h | 2 | ||||
-rw-r--r-- | src/fe-common/core/themes.c | 2 | ||||
-rw-r--r-- | src/fe-common/core/utf8.c | 26 | ||||
-rw-r--r-- | src/fe-common/core/utf8.h | 17 | ||||
-rw-r--r-- | src/fe-common/core/wcwidth.c | 220 |
22 files changed, 332 insertions, 461 deletions
diff --git a/src/fe-common/core/Makefile.am b/src/fe-common/core/Makefile.am index e755b510..63f91fa6 100644 --- a/src/fe-common/core/Makefile.am +++ b/src/fe-common/core/Makefile.am @@ -24,8 +24,6 @@ libfe_common_core_a_SOURCES = \ fe-queries.c \ fe-server.c \ fe-settings.c \ - utf8.c \ - wcwidth.c \ formats.c \ hilight-text.c \ keyboard.c \ @@ -62,6 +60,3 @@ pkginc_fe_common_core_HEADERS = \ window-items.h \ windows-layout.h \ fe-windows.h - -noinst_HEADERS = \ - utf8.h diff --git a/src/fe-common/core/chat-completion.c b/src/fe-common/core/chat-completion.c index c37c77cd..3e144602 100644 --- a/src/fe-common/core/chat-completion.c +++ b/src/fe-common/core/chat-completion.c @@ -38,11 +38,18 @@ #include "chat-completion.h" #include "window-items.h" +enum { + COMPLETE_MCASE_NEVER = 0, + COMPLETE_MCASE_ALWAYS, + COMPLETE_MCASE_AUTO, +}; + static int keep_privates_count, keep_publics_count; static int completion_lowercase; static char *completion_char, *cmdchars; static GSList *global_lastmsgs; static int completion_auto, completion_strict; +static int completion_match_case; #define SERVER_LAST_MSG_ADD(server, nick) \ last_msg_add(&((MODULE_SERVER_REC *) MODULE_DATA(server))->lastmsgs, \ @@ -52,6 +59,18 @@ static int completion_auto, completion_strict; last_msg_add(&((MODULE_CHANNEL_REC *) MODULE_DATA(channel))->lastmsgs, \ nick, own, keep_publics_count) +static gboolean contains_uppercase(const char *s1) +{ + const char *ch; + + for (ch = s1; *ch != '\0'; ch++) { + if (g_ascii_isupper(*ch)) + return TRUE; + } + + return FALSE; +} + static LAST_MSG_REC *last_msg_find(GSList *list, const char *nick) { while (list != NULL) { @@ -336,7 +355,8 @@ GList *completion_msg(SERVER_REC *win_server, } static void complete_from_nicklist(GList **outlist, CHANNEL_REC *channel, - const char *nick, const char *suffix) + const char *nick, const char *suffix, + const int match_case) { MODULE_CHANNEL_REC *mchannel; GSList *tmp; @@ -352,8 +372,10 @@ static void complete_from_nicklist(GList **outlist, CHANNEL_REC *channel, for (tmp = mchannel->lastmsgs; tmp != NULL; tmp = tmp->next) { LAST_MSG_REC *rec = tmp->data; - if (g_ascii_strncasecmp(rec->nick, nick, len) == 0 && - glist_find_icase_string(*outlist, rec->nick) == NULL) { + if ((match_case? strncmp(rec->nick, nick, len) + : g_ascii_strncasecmp(rec->nick, nick, len)) == 0 && + (match_case? glist_find_string(*outlist, rec->nick) + : glist_find_icase_string(*outlist, rec->nick)) == NULL) { str = g_strconcat(rec->nick, suffix, NULL); if (completion_lowercase) ascii_strdown(str); if (rec->own) @@ -368,7 +390,8 @@ static void complete_from_nicklist(GList **outlist, CHANNEL_REC *channel, static GList *completion_nicks_nonstrict(CHANNEL_REC *channel, const char *nick, - const char *suffix) + const char *suffix, + const int match_case) { GSList *nicks, *tmp; GList *list; @@ -404,7 +427,8 @@ static GList *completion_nicks_nonstrict(CHANNEL_REC *channel, *out = '\0'; /* add to list if 'cleaned' nick matches */ - if (g_ascii_strncasecmp(str, nick, len) == 0) { + if ((match_case? strncmp(str, nick, len) + : g_ascii_strncasecmp(str, nick, len)) == 0) { tnick = g_strconcat(rec->nick, suffix, NULL); if (completion_lowercase) ascii_strdown(tnick); @@ -428,7 +452,7 @@ static GList *completion_channel_nicks(CHANNEL_REC *channel, const char *nick, GSList *nicks, *tmp; GList *list; char *str; - int len; + int len, match_case; g_return_val_if_fail(channel != NULL, NULL); g_return_val_if_fail(nick != NULL, NULL); @@ -437,9 +461,12 @@ static GList *completion_channel_nicks(CHANNEL_REC *channel, const char *nick, if (suffix != NULL && *suffix == '\0') suffix = NULL; + match_case = completion_match_case == COMPLETE_MCASE_ALWAYS || + (completion_match_case == COMPLETE_MCASE_AUTO && contains_uppercase(nick)); + /* put first the nicks who have recently said something */ list = NULL; - complete_from_nicklist(&list, channel, nick, suffix); + complete_from_nicklist(&list, channel, nick, suffix, match_case); /* and add the rest of the nicks too */ len = strlen(nick); @@ -447,7 +474,8 @@ static GList *completion_channel_nicks(CHANNEL_REC *channel, const char *nick, for (tmp = nicks; tmp != NULL; tmp = tmp->next) { NICK_REC *rec = tmp->data; - if (g_ascii_strncasecmp(rec->nick, nick, len) == 0 && + if ((match_case? strncmp(rec->nick, nick, len) + : g_ascii_strncasecmp(rec->nick, nick, len)) == 0 && rec != channel->ownnick) { str = g_strconcat(rec->nick, suffix, NULL); if (completion_lowercase) @@ -463,7 +491,7 @@ static GList *completion_channel_nicks(CHANNEL_REC *channel, const char *nick, /* remove non alphanum chars from nick and search again in case list is still NULL ("foo<tab>" would match "_foo_" f.e.) */ if (!completion_strict) - list = g_list_concat(list, completion_nicks_nonstrict(channel, nick, suffix)); + list = g_list_concat(list, completion_nicks_nonstrict(channel, nick, suffix, match_case)); return list; } @@ -1130,6 +1158,8 @@ static void read_settings(void) completion_auto = settings_get_bool("completion_auto"); completion_strict = settings_get_bool("completion_strict"); + completion_match_case = settings_get_choice("completion_nicks_match_case"); + g_free_not_null(completion_char); completion_char = g_strdup(settings_get_str("completion_char")); @@ -1150,6 +1180,7 @@ void chat_completion_init(void) settings_add_int("completion", "completion_keep_privates", 10); settings_add_bool("completion", "completion_nicks_lowercase", FALSE); settings_add_bool("completion", "completion_strict", FALSE); + settings_add_choice("completion", "completion_nicks_match_case", COMPLETE_MCASE_AUTO, "never;always;auto"); settings_add_bool("lookandfeel", "expand_escapes", FALSE); diff --git a/src/fe-common/core/completion.c b/src/fe-common/core/completion.c index 4461de92..76dfbb79 100644 --- a/src/fe-common/core/completion.c +++ b/src/fe-common/core/completion.c @@ -37,8 +37,11 @@ static int last_want_space, last_line_pos; #define isseparator_notspace(c) \ ((c) == ',') +#define isseparator_space(c) \ + ((c) == ' ') + #define isseparator(c) \ - ((c) == ' ' || isseparator_notspace(c)) + (isseparator_space(c) || isseparator_notspace(c)) void chat_completion_init(void); void chat_completion_deinit(void); @@ -153,20 +156,23 @@ char *word_complete(WINDOW_REC *window, const char *line, int *pos, int erase, i word = NULL; linestart = NULL; } else { + char* old_wordstart; + /* get the word we want to complete */ word = get_word_at(line, *pos, &wordstart); + old_wordstart = wordstart; + startpos = (int) (wordstart-line); wordlen = strlen(word); - /* get the start of line until the word we're completing */ - if (isseparator(*line)) { - /* empty space at the start of line */ - if (wordstart == line) - wordstart += strlen(wordstart); - } else { - while (wordstart > line && isseparator(wordstart[-1])) - wordstart--; - } + /* remove trailing spaces from linestart */ + while (wordstart > line && isseparator_space(wordstart[-1])) + wordstart--; + + /* unless everything was spaces */ + if (old_wordstart > line && wordstart == line) + wordstart = old_wordstart - 1; + linestart = g_strndup(line, (int) (wordstart-line)); /* completions usually add space after the word, that makes @@ -175,19 +181,24 @@ char *word_complete(WINDOW_REC *window, const char *line, int *pos, int erase, i BUT if we start completion with "/msg "<tab>, we don't want to complete the /msg word, but instead complete empty word with /msg being in linestart. */ - if (!erase && *pos > 0 && line[*pos-1] == ' ' && - (*linestart == '\0' || wordstart[-1] != ' ')) { + if (!erase && *pos > 0 && isseparator_space(line[*pos-1]) && + (*linestart == '\0' || !isseparator_space(wordstart[-1]))) { char *old; - old = linestart; + old = linestart; linestart = *linestart == '\0' ? g_strdup(word) : - g_strconcat(linestart, " ", word, NULL); + g_strdup_printf("%s%c%s", + /* do not accidentally duplicate the word separator */ + line == wordstart - 1 ? "" : linestart, + wordstart[-1], word); g_free(old); g_free(word); word = g_strdup(""); - startpos = strlen(linestart)+1; + + startpos = *linestart == '\0' ? 0 : + strlen(linestart)+1; wordlen = 0; } @@ -217,6 +228,11 @@ char *word_complete(WINDOW_REC *window, const char *line, int *pos, int erase, i want_space = TRUE; signal_emit("complete word", 5, &complist, window, word, linestart, &want_space); last_want_space = want_space; + + if (complist != NULL) { + /* Remove all nulls (from the signal) before doing further processing */ + complist = g_list_remove_all(g_list_first(complist), NULL); + } } g_free(linestart); @@ -329,7 +345,9 @@ GList *filename_complete(const char *path, const char *default_path) (dp->d_name[1] == '.' && dp->d_name[2] == '\0')) continue; /* skip . and .. */ - if (basename[0] != '.') + /* Skip the dotfiles unless the user explicitly asked us + * to do so. Basename might be './', beware of that */ + if (basename[0] != '.' || basename[1] == '\0') continue; } @@ -392,7 +410,8 @@ static GList *completion_get_aliases(const char *alias, char cmdchar) continue; if (g_ascii_strncasecmp(node->key, alias, len) == 0) { - word = g_strdup_printf("%c%s", cmdchar, node->key); + word = cmdchar == '\0' ? g_strdup(node->key) : + g_strdup_printf("%c%s", cmdchar, node->key); /* add matching alias to completion list, aliases will be appended after command completions and kept in uppercase to show it's an alias */ @@ -584,13 +603,19 @@ static void sig_complete_word(GList **list, WINDOW_REC *window, /* command completion? */ cmdchars = settings_get_str("cmdchars"); - if (*word != '\0' && *linestart == '\0' && strchr(cmdchars, *word)) { + if (*word != '\0' && ((*linestart == '\0' && strchr(cmdchars, *word)) || + (*linestart != '\0' && linestart[1] == '\0' && + strchr(cmdchars, *linestart)))) { + gboolean skip = *linestart == '\0' ? TRUE : FALSE; + /* complete /command */ - *list = completion_get_commands(word+1, *word); + *list = completion_get_commands(word + (skip ? 1 : 0), + skip ? *word : '\0'); /* complete aliases, too */ *list = g_list_concat(*list, - completion_get_aliases(word+1, *word)); + completion_get_aliases(word + (skip ? 1 : 0), + skip ? *word : '\0')); if (*list != NULL) signal_stop(); return; @@ -686,8 +711,20 @@ static void sig_complete_set(GList **list, WINDOW_REC *window, SETTINGS_REC *rec = settings_get_record(line); if (rec != NULL) { char *value = settings_get_print(rec); + + /* show the current option first */ if (value != NULL) *list = g_list_append(*list, value); + + /* show the whole list of valid options */ + if (rec->type == SETTING_TYPE_CHOICE) { + char **tmp; + + for (tmp = rec->choices; *tmp; tmp++) { + if (g_ascii_strcasecmp(*tmp, value) != 0) + *list = g_list_append(*list, g_strdup(*tmp)); + } + } } } diff --git a/src/fe-common/core/fe-channels.c b/src/fe-common/core/fe-channels.c index 046d641a..00aac885 100644 --- a/src/fe-common/core/fe-channels.c +++ b/src/fe-common/core/fe-channels.c @@ -26,6 +26,8 @@ #include "levels.h" #include "misc.h" #include "settings.h" +#include "special-vars.h" +#include "utf8.h" #include "chat-protocols.h" #include "chatnets.h" @@ -246,9 +248,7 @@ static void cmd_channel(const char *data, SERVER_REC *server, WI_ITEM_REC *item) } } -/* SYNTAX: CHANNEL ADD [-auto | -noauto] [-bots <masks>] [-botcmd <command>] - <channel> <network> [<password>] */ -static void cmd_channel_add(const char *data) +static void cmd_channel_add_modify(const char *data, gboolean add) { GHashTable *optlist; CHATNET_REC *chatnetrec; @@ -257,18 +257,19 @@ static void cmd_channel_add(const char *data) void *free_arg; if (!cmd_get_params(data, &free_arg, 3 | PARAM_FLAG_OPTIONS, - "channel add", &optlist, &channel, &chatnet, &password)) + "channel add", &optlist, &channel, &chatnet, &password)) return; - if (*chatnet == '\0' || *channel == '\0') + if (*chatnet == '\0' || *channel == '\0') { cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); + } chatnetrec = chatnet_find(chatnet); if (chatnetrec == NULL) { printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, - TXT_UNKNOWN_CHATNET, chatnet); + TXT_UNKNOWN_CHATNET, chatnet); cmd_params_free(free_arg); - return; + return; } botarg = g_hash_table_lookup(optlist, "bots"); @@ -276,6 +277,13 @@ static void cmd_channel_add(const char *data) rec = channel_setup_find(channel, chatnet); if (rec == NULL) { + if (add == FALSE) { + cmd_params_free(free_arg); + printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, + TXT_CHANSETUP_NOT_FOUND, channel, chatnet); + return; + } + rec = CHAT_PROTOCOL(chatnetrec)->create_channel_setup(); rec->name = g_strdup(channel); rec->chatnet = g_strdup(chatnet); @@ -299,6 +307,18 @@ static void cmd_channel_add(const char *data) cmd_params_free(free_arg); } +/* SYNTAX: CHANNEL ADD|MODIFY [-auto | -noauto] [-bots <masks>] [-botcmd <command>] + <channel> <network> [<password>] */ +static void cmd_channel_add(const char *data) +{ + cmd_channel_add_modify(data, TRUE); +} + +static void cmd_channel_modify(const char *data) +{ + cmd_channel_add_modify(data, FALSE); +} + /* SYNTAX: CHANNEL REMOVE <channel> <network> */ static void cmd_channel_remove(const char *data) { @@ -323,40 +343,40 @@ static void cmd_channel_remove(const char *data) static int get_nick_length(void *data) { - return strlen(((NICK_REC *) data)->nick); + return string_width(((NICK_REC *) data)->nick, -1); } static void display_sorted_nicks(CHANNEL_REC *channel, GSList *nicklist) { - WINDOW_REC *window; + WINDOW_REC *window; TEXT_DEST_REC dest; GString *str; GSList *tmp; - char *format, *stripped, *prefix_format; - char *linebuf, nickmode[2] = { 0, 0 }; + char *format, *stripped, *prefix_format; + char *aligned_nick, nickmode[2] = { 0, 0 }; int *columns, cols, rows, last_col_rows, col, row, max_width; - int item_extra, linebuf_size, formatnum; + int item_extra, formatnum; window = window_find_closest(channel->server, channel->visible_name, - MSGLEVEL_CLIENTCRAP); - max_width = window->width; + MSGLEVEL_CLIENTCRAP); + max_width = window->width; - /* get the length of item extra stuff ("[ ] ") */ + /* get the length of item extra stuff ("[ ] ") */ format = format_get_text(MODULE_NAME, NULL, - channel->server, channel->visible_name, - TXT_NAMES_NICK, " ", ""); + channel->server, channel->visible_name, + TXT_NAMES_NICK, " ", ""); stripped = strip_codes(format); item_extra = strlen(stripped); - g_free(stripped); + g_free(stripped); g_free(format); if (settings_get_int("names_max_width") > 0 && settings_get_int("names_max_width") < max_width) max_width = settings_get_int("names_max_width"); - /* remove width of the timestamp from max_width */ + /* remove width of the timestamp from max_width */ format_create_dest(&dest, channel->server, channel->visible_name, - MSGLEVEL_CLIENTCRAP, NULL); + MSGLEVEL_CLIENTCRAP, NULL); format = format_get_line_start(current_theme, &dest, time(NULL)); if (format != NULL) { stripped = strip_codes(format); @@ -365,11 +385,11 @@ static void display_sorted_nicks(CHANNEL_REC *channel, GSList *nicklist) g_free(format); } - /* remove width of the prefix from max_width */ + /* remove width of the prefix from max_width */ prefix_format = format_get_text(MODULE_NAME, NULL, - channel->server, channel->visible_name, - TXT_NAMES_PREFIX, - channel->visible_name); + channel->server, channel->visible_name, + TXT_NAMES_PREFIX, + channel->visible_name); if (prefix_format != NULL) { stripped = strip_codes(prefix_format); max_width -= strlen(stripped); @@ -384,19 +404,18 @@ static void display_sorted_nicks(CHANNEL_REC *channel, GSList *nicklist) /* calculate columns */ cols = get_max_column_count(nicklist, get_nick_length, max_width, - settings_get_int("names_max_columns"), - item_extra, 3, &columns, &rows); + settings_get_int("names_max_columns"), + item_extra, 3, &columns, &rows); nicklist = columns_sort_list(nicklist, rows); - /* rows in last column */ + /* rows in last column */ last_col_rows = rows-(cols*rows-g_slist_length(nicklist)); if (last_col_rows == 0) - last_col_rows = rows; + last_col_rows = rows; str = g_string_new(prefix_format); - linebuf_size = max_width+1; linebuf = g_malloc(linebuf_size); - col = 0; row = 0; + col = 0; row = 0; for (tmp = nicklist; tmp != NULL; tmp = tmp->next) { NICK_REC *rec = tmp->data; @@ -405,48 +424,44 @@ static void display_sorted_nicks(CHANNEL_REC *channel, GSList *nicklist) else nickmode[0] = ' '; - if (linebuf_size < columns[col]-item_extra+1) { - linebuf_size = (columns[col]-item_extra+1)*2; - linebuf = g_realloc(linebuf, linebuf_size); - } - memset(linebuf, ' ', columns[col]-item_extra); - linebuf[columns[col]-item_extra] = '\0'; - memcpy(linebuf, rec->nick, strlen(rec->nick)); - - formatnum = rec->op ? TXT_NAMES_NICK_OP : - rec->halfop ? TXT_NAMES_NICK_HALFOP : - rec->voice ? TXT_NAMES_NICK_VOICE : - TXT_NAMES_NICK; + aligned_nick = get_alignment(rec->nick, + columns[col]-item_extra, + ALIGN_PAD, ' '); + + formatnum = rec->op ? TXT_NAMES_NICK_OP : + rec->halfop ? TXT_NAMES_NICK_HALFOP : + rec->voice ? TXT_NAMES_NICK_VOICE : + TXT_NAMES_NICK; format = format_get_text(MODULE_NAME, NULL, - channel->server, - channel->visible_name, - formatnum, nickmode, linebuf); + channel->server, + channel->visible_name, + formatnum, nickmode, aligned_nick); g_string_append(str, format); + g_free(aligned_nick); g_free(format); if (++col == cols) { printtext(channel->server, channel->visible_name, - MSGLEVEL_CLIENTCRAP, "%s", str->str); + MSGLEVEL_CLIENTCRAP, "%s", str->str); g_string_truncate(str, 0); if (prefix_format != NULL) - g_string_assign(str, prefix_format); + g_string_assign(str, prefix_format); col = 0; row++; if (row == last_col_rows) - cols--; + cols--; } } if (str->len > strlen(prefix_format)) { printtext(channel->server, channel->visible_name, - MSGLEVEL_CLIENTCRAP, "%s", str->str); + MSGLEVEL_CLIENTCRAP, "%s", str->str); } g_slist_free(nicklist); g_string_free(str, TRUE); g_free_not_null(columns); g_free_not_null(prefix_format); - g_free(linebuf); } void fe_channels_nicklist(CHANNEL_REC *channel, int flags) @@ -622,12 +637,14 @@ void fe_channels_init(void) command_bind("join", NULL, (SIGNAL_FUNC) cmd_join); command_bind("channel", NULL, (SIGNAL_FUNC) cmd_channel); command_bind("channel add", NULL, (SIGNAL_FUNC) cmd_channel_add); + command_bind("channel modify", NULL, (SIGNAL_FUNC) cmd_channel_modify); command_bind("channel remove", NULL, (SIGNAL_FUNC) cmd_channel_remove); command_bind("channel list", NULL, (SIGNAL_FUNC) cmd_channel_list); command_bind("names", NULL, (SIGNAL_FUNC) cmd_names); command_bind("cycle", NULL, (SIGNAL_FUNC) cmd_cycle); command_set_options("channel add", "auto noauto -bots -botcmd"); + command_set_options("channel modify", "auto noauto -bots -botcmd"); command_set_options("names", "count ops halfops voices normal"); command_set_options("join", "invite window"); } @@ -643,6 +660,7 @@ void fe_channels_deinit(void) command_unbind("join", (SIGNAL_FUNC) cmd_join); command_unbind("channel", (SIGNAL_FUNC) cmd_channel); command_unbind("channel add", (SIGNAL_FUNC) cmd_channel_add); + command_unbind("channel modify", (SIGNAL_FUNC) cmd_channel_modify); command_unbind("channel remove", (SIGNAL_FUNC) cmd_channel_remove); command_unbind("channel list", (SIGNAL_FUNC) cmd_channel_list); command_unbind("names", (SIGNAL_FUNC) cmd_names); diff --git a/src/fe-common/core/fe-common-core.c b/src/fe-common/core/fe-common-core.c index ee7f9424..1b2ab1e2 100644 --- a/src/fe-common/core/fe-common-core.c +++ b/src/fe-common/core/fe-common-core.c @@ -459,15 +459,24 @@ gboolean strarray_find_dest(char **array, const TEXT_DEST_REC *dest) { g_return_val_if_fail(array != NULL, FALSE); + if (strarray_find(array, "*") != -1) + return TRUE; + if (strarray_find(array, dest->target) != -1) return TRUE; if (dest->server_tag != NULL) { - char *tagtarget = g_strdup_printf("%s/%s", dest->server_tag, dest->target); + char *tagtarget = g_strdup_printf("%s/%s", dest->server_tag, "*"); int ret = strarray_find(array, tagtarget); g_free(tagtarget); if (ret != -1) return TRUE; + + tagtarget = g_strdup_printf("%s/%s", dest->server_tag, dest->target); + ret = strarray_find(array, tagtarget); + g_free(tagtarget); + if (ret != -1) + return TRUE; } return FALSE; } diff --git a/src/fe-common/core/fe-core-commands.c b/src/fe-common/core/fe-core-commands.c index 7b1d7b94..97a246ec 100644 --- a/src/fe-common/core/fe-core-commands.c +++ b/src/fe-common/core/fe-core-commands.c @@ -51,7 +51,8 @@ static int ret_texts[] = { TXT_INVALID_TIME, TXT_INVALID_CHARSET, TXT_EVAL_MAX_RECURSE, - TXT_PROGRAM_NOT_FOUND + TXT_PROGRAM_NOT_FOUND, + TXT_NO_SERVER_DEFINED, }; int command_hide_output; diff --git a/src/fe-common/core/fe-exec.c b/src/fe-common/core/fe-exec.c index b5f289ce..36990866 100644 --- a/src/fe-common/core/fe-exec.c +++ b/src/fe-common/core/fe-exec.c @@ -237,22 +237,13 @@ static int signal_name_to_id(const char *name) static int cmd_options_get_signal(const char *cmd, GHashTable *optlist) { - GSList *list, *tmp, *next; + GList *list; char *signame; int signum; /* get all the options, then remove the known ones. there should be only one left - the signal */ - list = hashtable_get_keys(optlist); - if (cmd != NULL) { - for (tmp = list; tmp != NULL; tmp = next) { - char *option = tmp->data; - next = tmp->next; - - if (command_have_option(cmd, option)) - list = g_slist_remove(list, option); - } - } + list = optlist_remove_known(cmd, optlist); if (list == NULL) return -1; @@ -272,7 +263,7 @@ static int cmd_options_get_signal(const char *cmd, return -2; } - g_slist_free(list); + g_list_free(list); return signum; } diff --git a/src/fe-common/core/fe-ignore.c b/src/fe-common/core/fe-ignore.c index a809ac91..52b11e6b 100644 --- a/src/fe-common/core/fe-ignore.c +++ b/src/fe-common/core/fe-ignore.c @@ -215,7 +215,7 @@ static void cmd_unignore(const char *data) { IGNORE_REC *rec; GSList *tmp; - char *mask; + char *mask, *mask_orig; void *free_arg; if (!cmd_get_params(data, &free_arg, 1, &mask)) @@ -224,6 +224,10 @@ static void cmd_unignore(const char *data) if (*mask == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); + /* Save the mask string here since it might be modified in the code + * below and we need it to print meaningful error messages. */ + mask_orig = mask; + if (is_numeric(mask, ' ')) { /* with index number */ tmp = g_slist_nth(ignores, atoi(mask)-1); @@ -248,7 +252,7 @@ static void cmd_unignore(const char *data) ignore_update_rec(rec); } else { printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, - TXT_IGNORE_NOT_FOUND, mask); + TXT_IGNORE_NOT_FOUND, mask_orig); } cmd_params_free(free_arg); } diff --git a/src/fe-common/core/fe-log.c b/src/fe-common/core/fe-log.c index f2c4c014..5bc5c4e1 100644 --- a/src/fe-common/core/fe-log.c +++ b/src/fe-common/core/fe-log.c @@ -453,7 +453,7 @@ static void autolog_open(SERVER_REC *server, const char *server_tag, log_item_add(log, LOG_ITEM_TARGET, target, server_tag); dir = g_path_get_dirname(log->real_fname); - mkpath(dir, log_dir_create_mode); + g_mkdir_with_parents(dir, log_dir_create_mode); g_free(dir); log->temp = TRUE; diff --git a/src/fe-common/core/fe-messages.c b/src/fe-common/core/fe-messages.c index 8ad83753..487a5754 100644 --- a/src/fe-common/core/fe-messages.c +++ b/src/fe-common/core/fe-messages.c @@ -175,6 +175,7 @@ static void sig_message_public(SERVER_REC *server, const char *msg, int for_me, print_channel, level; char *nickmode, *color, *freemsg = NULL; HILIGHT_REC *hilight; + TEXT_DEST_REC dest; /* NOTE: this may return NULL if some channel is just closed with /WINDOW CLOSE and server still sends the few last messages */ @@ -214,7 +215,6 @@ static void sig_message_public(SERVER_REC *server, const char *msg, if (printnick == NULL) printnick = nick; - TEXT_DEST_REC dest; format_create_dest(&dest, server, target, level, NULL); dest.address = address; dest.nick = nick; @@ -396,8 +396,9 @@ static void sig_message_quit(SERVER_REC *server, const char *nick, count = 0; windows = NULL; chans = g_string_new(NULL); for (tmp = server->channels; tmp != NULL; tmp = tmp->next) { + CHANNEL_REC *rec; level = MSGLEVEL_QUITS; - CHANNEL_REC *rec = tmp->data; + rec = tmp->data; if (!nicklist_find(rec, nick)) continue; diff --git a/src/fe-common/core/fe-server.c b/src/fe-common/core/fe-server.c index 429e6dac..468cb707 100644 --- a/src/fe-common/core/fe-server.c +++ b/src/fe-common/core/fe-server.c @@ -104,7 +104,7 @@ static SERVER_SETUP_REC *create_server_setup(GHashTable *optlist) return server; } -static void cmd_server_add(const char *data) +static void cmd_server_add_modify(const char *data, gboolean add) { GHashTable *optlist; SERVER_SETUP_REC *rec; @@ -113,7 +113,7 @@ static void cmd_server_add(const char *data) int port; if (!cmd_get_params(data, &free_arg, 3 | PARAM_FLAG_OPTIONS, - "server add", &optlist, &addr, &portstr, &password)) + "server add", &optlist, &addr, &portstr, &password)) return; if (*addr == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); @@ -124,6 +124,13 @@ static void cmd_server_add(const char *data) rec = server_setup_find(addr, port, chatnet); if (rec == NULL) { + if (add == FALSE) { + cmd_params_free(free_arg); + printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, + TXT_SETUPSERVER_NOT_FOUND, addr, port); + return; + } + rec = create_server_setup(optlist); if (rec == NULL) { cmd_params_free(free_arg); @@ -205,6 +212,16 @@ static void cmd_server_add(const char *data) cmd_params_free(free_arg); } +static void cmd_server_add(const char *data) +{ + cmd_server_add_modify(data, TRUE); +} + +static void cmd_server_modify(const char *data) +{ + cmd_server_add_modify(data, FALSE); +} + /* SYNTAX: SERVER REMOVE <address> [<port>] [<network>] */ static void cmd_server_remove(const char *data) { @@ -388,10 +405,12 @@ void fe_server_init(void) command_bind("server", NULL, (SIGNAL_FUNC) cmd_server); command_bind("server connect", NULL, (SIGNAL_FUNC) cmd_server_connect); command_bind("server add", NULL, (SIGNAL_FUNC) cmd_server_add); + command_bind("server modify", NULL, (SIGNAL_FUNC) cmd_server_modify); command_bind("server remove", NULL, (SIGNAL_FUNC) cmd_server_remove); command_bind_first("server", NULL, (SIGNAL_FUNC) server_command); command_bind_first("disconnect", NULL, (SIGNAL_FUNC) server_command); command_set_options("server add", "4 6 !! ssl +ssl_cert +ssl_pkey +ssl_pass ssl_verify +ssl_cafile +ssl_capath +ssl_ciphers auto noauto proxy noproxy -host -port noautosendcmd"); + command_set_options("server modify", "4 6 !! ssl +ssl_cert +ssl_pkey +ssl_pass ssl_verify +ssl_cafile +ssl_capath +ssl_ciphers auto noauto proxy noproxy -host -port noautosendcmd"); signal_add("server looking", (SIGNAL_FUNC) sig_server_looking); signal_add("server connecting", (SIGNAL_FUNC) sig_server_connecting); @@ -412,6 +431,7 @@ void fe_server_deinit(void) command_unbind("server", (SIGNAL_FUNC) cmd_server); command_unbind("server connect", (SIGNAL_FUNC) cmd_server_connect); command_unbind("server add", (SIGNAL_FUNC) cmd_server_add); + command_unbind("server modify", (SIGNAL_FUNC) cmd_server_modify); command_unbind("server remove", (SIGNAL_FUNC) cmd_server_remove); command_unbind("server", (SIGNAL_FUNC) server_command); command_unbind("disconnect", (SIGNAL_FUNC) server_command); diff --git a/src/fe-common/core/fe-settings.c b/src/fe-common/core/fe-settings.c index b689cbf9..abbd45a8 100644 --- a/src/fe-common/core/fe-settings.c +++ b/src/fe-common/core/fe-settings.c @@ -67,6 +67,7 @@ static void set_print_pattern(const char *pattern) static void set_boolean(const char *key, const char *value) { char *stripped_value; + stripped_value = g_strdup(value); g_strstrip(stripped_value); @@ -79,7 +80,7 @@ static void set_boolean(const char *key, const char *value) else printformat(NULL, NULL, MSGLEVEL_CLIENTERROR, TXT_NOT_TOGGLE); - g_free(stripped_value); + g_free(stripped_value); } static void set_int(const char *key, const char *value) @@ -99,6 +100,24 @@ static void set_int(const char *key, const char *value) settings_set_int(key, (int)longval); } +static void set_choice(const char *key, const char *value) +{ + char *stripped_value; + + stripped_value = g_strdup(value); + g_strstrip(stripped_value); + + if (settings_set_choice(key, stripped_value) == FALSE) { + SETTINGS_REC *rec = settings_get_record(key); + char *msg = g_strjoinv(", ", rec->choices); + + printformat(NULL, NULL, MSGLEVEL_CLIENTERROR, TXT_INVALID_CHOICE, msg); + g_free(msg); + } + + g_free(stripped_value); +} + /* SYNTAX: SET [-clear | -default] [<key> [<value>]] */ static void cmd_set(char *data) { @@ -142,6 +161,12 @@ static void cmd_set(char *data) else set_int(key, value); break; + case SETTING_TYPE_CHOICE: + if (clear || set_default) + settings_set_choice(key, rec->choices[rec->default_value.v_int]); + else + set_choice(key, value); + break; case SETTING_TYPE_STRING: settings_set_str(key, clear ? "" : set_default ? rec->default_value.v_string : diff --git a/src/fe-common/core/formats.c b/src/fe-common/core/formats.c index d9a51201..9aa7698d 100644 --- a/src/fe-common/core/formats.c +++ b/src/fe-common/core/formats.c @@ -422,33 +422,17 @@ void format_create_dest_tag(TEXT_DEST_REC *dest, void *server, window_find_closest(server, target, level); } -static int advance (char const **str, gboolean utf8) -{ - if (utf8) { - gunichar c; - - c = g_utf8_get_char(*str); - *str = g_utf8_next_char(*str); - - return unichar_isprint(c) ? mk_wcwidth(c) : 1; - } else { - *str += 1; - - return 1; - } -} - /* Return length of text part in string (ie. without % codes) */ int format_get_length(const char *str) { GString *tmp; int len; - gboolean utf8; + int utf8; int adv = 0; g_return_val_if_fail(str != NULL, 0); - utf8 = is_utf8() && g_utf8_validate(str, -1, NULL); + utf8 = string_policy(str); tmp = g_string_new(NULL); len = 0; @@ -467,7 +451,7 @@ int format_get_length(const char *str) len++; } - len += advance(&str, utf8); + len += string_advance(&str, utf8); } g_string_free(tmp, TRUE); @@ -482,12 +466,12 @@ int format_real_length(const char *str, int len) GString *tmp; const char *start; const char *oldstr; - gboolean utf8; + int utf8; int adv = 0; g_return_val_if_fail(str != NULL, 0); g_return_val_if_fail(len >= 0, 0); - utf8 = is_utf8() && g_utf8_validate(str, -1, NULL); + utf8 = string_policy(str); start = str; tmp = g_string_new(NULL); @@ -509,7 +493,7 @@ int format_real_length(const char *str, int len) } oldstr = str; - len -= advance(&str, utf8); + len -= string_advance(&str, utf8); if (len < 0) str = oldstr; } diff --git a/src/fe-common/core/hilight-text.c b/src/fe-common/core/hilight-text.c index b746f636..4691a708 100644 --- a/src/fe-common/core/hilight-text.c +++ b/src/fe-common/core/hilight-text.c @@ -49,7 +49,7 @@ static void reset_level_cache(void) HILIGHT_REC *rec = tmp->data; if (never_hilight_level & rec->level) - never_hilight_level &= ~rec->level; + never_hilight_level &= ~rec->level; } } @@ -68,17 +68,18 @@ static void hilight_add_config(HILIGHT_REC *rec) node = iconfig_node_traverse("(hilights", TRUE); node = iconfig_node_section(node, NULL, NODE_TYPE_BLOCK); - iconfig_node_set_str(node, "text", rec->text); - if (rec->level > 0) iconfig_node_set_int(node, "level", rec->level); - if (rec->color) iconfig_node_set_str(node, "color", rec->color); - if (rec->act_color) iconfig_node_set_str(node, "act_color", rec->act_color); - if (rec->priority > 0) iconfig_node_set_int(node, "priority", rec->priority); - iconfig_node_set_bool(node, "nick", rec->nick); - iconfig_node_set_bool(node, "word", rec->word); - if (rec->nickmask) iconfig_node_set_bool(node, "mask", TRUE); - if (rec->fullword) iconfig_node_set_bool(node, "fullword", TRUE); - if (rec->regexp) iconfig_node_set_bool(node, "regexp", TRUE); - if (rec->servertag) iconfig_node_set_str(node, "servertag", rec->servertag); + iconfig_node_set_str(node, "text", rec->text); + if (rec->level > 0) iconfig_node_set_int(node, "level", rec->level); + if (rec->color) iconfig_node_set_str(node, "color", rec->color); + if (rec->act_color) iconfig_node_set_str(node, "act_color", rec->act_color); + if (rec->priority > 0) iconfig_node_set_int(node, "priority", rec->priority); + iconfig_node_set_bool(node, "nick", rec->nick); + iconfig_node_set_bool(node, "word", rec->word); + if (rec->nickmask) iconfig_node_set_bool(node, "mask", TRUE); + if (rec->fullword) iconfig_node_set_bool(node, "fullword", TRUE); + if (rec->regexp) iconfig_node_set_bool(node, "regexp", TRUE); + if (rec->case_sensitive) iconfig_node_set_bool(node, "matchcase", TRUE); + if (rec->servertag) iconfig_node_set_str(node, "servertag", rec->servertag); if (rec->channels != NULL && *rec->channels != NULL) { node = iconfig_node_section(node, "channels", NODE_TYPE_LIST); @@ -121,8 +122,11 @@ static void hilight_init_rec(HILIGHT_REC *rec) { #ifdef HAVE_REGEX_H if (rec->regexp_compiled) regfree(&rec->preg); - rec->regexp_compiled = !rec->regexp ? FALSE : - regcomp(&rec->preg, rec->text, REG_EXTENDED|REG_ICASE) == 0; + if (!rec->regexp) + rec->regexp_compiled = FALSE; + else + rec->regexp_compiled = regcomp(&rec->preg, rec->text, + rec->case_sensitive ? REG_EXTENDED : (REG_EXTENDED|REG_ICASE)) == 0; #endif } @@ -174,7 +178,7 @@ static HILIGHT_REC *hilight_find(const char *text, char **channels) if (channels == NULL || rec->channels == NULL) continue; /* other doesn't have channels */ - if (strarray_length(channels) != strarray_length(rec->channels)) + if (g_strv_length(channels) != g_strv_length(rec->channels)) continue; /* different amount of channels */ /* check that channels match */ @@ -191,7 +195,7 @@ static HILIGHT_REC *hilight_find(const char *text, char **channels) } static int hilight_match_text(HILIGHT_REC *rec, const char *text, - int *match_beg, int *match_end) + int *match_beg, int *match_end) { char *match; @@ -200,9 +204,9 @@ static int hilight_match_text(HILIGHT_REC *rec, const char *text, regmatch_t rmatch[1]; if (rec->regexp_compiled && - regexec(&rec->preg, text, 1, rmatch, 0) == 0) { + regexec(&rec->preg, text, 1, rmatch, 0) == 0) { if (rmatch[0].rm_so > 0 && - match_beg != NULL && match_end != NULL) { + match_beg != NULL && match_end != NULL) { *match_beg = rmatch[0].rm_so; *match_end = rmatch[0].rm_eo; } @@ -210,9 +214,15 @@ static int hilight_match_text(HILIGHT_REC *rec, const char *text, } #endif } else { - match = rec->fullword ? - stristr_full(text, rec->text) : - stristr(text, rec->text); + if (rec->case_sensitive) { + match = rec->fullword ? + strstr_full(text, rec->text) : + strstr(text, rec->text); + } else { + match = rec->fullword ? + stristr_full(text, rec->text) : + stristr(text, rec->text); + } if (match != NULL) { if (match_beg != NULL && match_end != NULL) { *match_beg = (int) (match-text); @@ -222,7 +232,7 @@ static int hilight_match_text(HILIGHT_REC *rec, const char *text, } } - return FALSE; + return FALSE; } #define hilight_match_level(rec, level) \ @@ -267,14 +277,14 @@ HILIGHT_REC *hilight_match(SERVER_REC *server, const char *channel, HILIGHT_REC *rec = tmp->data; if (!rec->nickmask && hilight_match_level(rec, level) && - hilight_match_channel(rec, channel) && - (rec->servertag == NULL || - (server != NULL && g_ascii_strcasecmp(rec->servertag, server->tag) == 0)) && - hilight_match_text(rec, str, match_beg, match_end)) + hilight_match_channel(rec, channel) && + (rec->servertag == NULL || + (server != NULL && g_ascii_strcasecmp(rec->servertag, server->tag) == 0)) && + hilight_match_text(rec, str, match_beg, match_end)) return rec; } - return NULL; + return NULL; } static char *hilight_get_act_color(HILIGHT_REC *rec) @@ -308,7 +318,7 @@ void hilight_update_text_dest(TEXT_DEST_REC *dest, HILIGHT_REC *rec) g_free_and_null(dest->hilight_color); if (rec->act_color != NULL && g_strcmp0(rec->act_color, "%n") == 0) dest->level |= MSGLEVEL_NO_ACT; - else + else dest->hilight_color = hilight_get_act_color(rec); } @@ -362,29 +372,29 @@ static void sig_print_text(TEXT_DEST_REC *dest, const char *text, /* hilight whole line */ char *tmp = strip_codes(text); newstr = g_strconcat(color, tmp, NULL); - g_free(tmp); + g_free(tmp); } else { /* hilight part of the line */ - GString *tmp; - char *middle; + GString *tmp; + char *middle; int pos, color_pos, color_len; - tmp = g_string_new(NULL); + tmp = g_string_new(NULL); - /* start of the line */ + /* start of the line */ pos = strip_real_length(text, hilight_start, NULL, NULL); g_string_append(tmp, text); - g_string_truncate(tmp, pos); + g_string_truncate(tmp, pos); /* color */ - g_string_append(tmp, color); + g_string_append(tmp, color); /* middle of the line, stripped */ middle = strip_codes(text+pos); - pos = tmp->len; + pos = tmp->len; g_string_append(tmp, middle); - g_string_truncate(tmp, pos+hilight_len); - g_free(middle); + g_string_truncate(tmp, pos+hilight_len); + g_free(middle); /* end of the line */ pos = strip_real_length(text, hilight_end, @@ -398,8 +408,8 @@ static void sig_print_text(TEXT_DEST_REC *dest, const char *text, } g_string_append(tmp, text+pos); - newstr = tmp->str; - g_string_free(tmp, FALSE); + newstr = tmp->str; + g_string_free(tmp, FALSE); } signal_emit("print text", 3, dest, newstr, stripped); @@ -417,7 +427,7 @@ HILIGHT_REC *hilight_match_nick(SERVER_REC *server, const char *channel, HILIGHT_REC *rec; rec = hilight_match(server, channel, nick, address, - level, msg, NULL, NULL); + level, msg, NULL, NULL); return (rec == NULL || !rec->nick) ? NULL : rec; } @@ -464,6 +474,7 @@ static void read_hilight_config(void) rec->priority = config_node_get_int(node, "priority", 0); rec->nick = config_node_get_bool(node, "nick", TRUE); rec->word = config_node_get_bool(node, "word", TRUE); + rec->case_sensitive = config_node_get_bool(node, "matchcase", FALSE); rec->nickmask = config_node_get_bool(node, "mask", FALSE); rec->fullword = config_node_get_bool(node, "fullword", FALSE); @@ -475,7 +486,7 @@ static void read_hilight_config(void) if (node != NULL) rec->channels = config_node_get_list(node); } - reset_cache(); + reset_cache(); } static void hilight_print(int index, HILIGHT_REC *rec) @@ -495,6 +506,7 @@ static void hilight_print(int index, HILIGHT_REC *rec) if (rec->nickmask) g_string_append(options, "-mask "); if (rec->fullword) g_string_append(options, "-full "); + if (rec->case_sensitive) g_string_append(options, "-matchcase "); if (rec->regexp) { g_string_append(options, "-regexp "); #ifdef HAVE_REGEX_H @@ -519,10 +531,10 @@ static void hilight_print(int index, HILIGHT_REC *rec) if (levelstr != NULL) levelstr = g_strconcat(levelstr, " ", NULL); printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, - TXT_HILIGHT_LINE, index, rec->text, - chans != NULL ? chans : "", - levelstr != NULL ? levelstr : "", - options->str); + TXT_HILIGHT_LINE, index, rec->text, + chans != NULL ? chans : "", + levelstr != NULL ? levelstr : "", + options->str); g_free_not_null(chans); g_free_not_null(levelstr); g_string_free(options, TRUE); @@ -543,12 +555,12 @@ static void cmd_hilight_show(void) printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_HILIGHT_FOOTER); } -/* SYNTAX: HILIGHT [-nick | -word | -line] [-mask | -full | -regexp] +/* SYNTAX: HILIGHT [-nick | -word | -line] [-mask | -full | -matchcase | -regexp] [-color <color>] [-actcolor <color>] [-level <level>] [-network <network>] [-channels <channels>] <text> */ static void cmd_hilight(const char *data) { - GHashTable *optlist; + GHashTable *optlist; HILIGHT_REC *rec; char *colorarg, *actcolorarg, *levelarg, *priorityarg, *chanarg, *text, *servertag; char **channels; @@ -562,7 +574,7 @@ static void cmd_hilight(const char *data) } if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS | - PARAM_FLAG_GETREST, "hilight", &optlist, &text)) + PARAM_FLAG_GETREST, "hilight", &optlist, &text)) return; chanarg = g_hash_table_lookup(optlist, "channels"); @@ -582,7 +594,7 @@ static void cmd_hilight(const char *data) rec = g_new0(HILIGHT_REC, 1); /* default to nick/word hilighting */ - rec->nick = TRUE; + rec->nick = TRUE; rec->word = TRUE; rec->text = g_strdup(text); @@ -602,15 +614,16 @@ static void cmd_hilight(const char *data) if (g_hash_table_lookup(optlist, "word") != NULL) { rec->word = TRUE; - rec->nick = FALSE; + rec->nick = FALSE; } if (g_hash_table_lookup(optlist, "nick") != NULL) - rec->nick = TRUE; + rec->nick = TRUE; rec->nickmask = g_hash_table_lookup(optlist, "mask") != NULL; rec->fullword = g_hash_table_lookup(optlist, "full") != NULL; rec->regexp = g_hash_table_lookup(optlist, "regexp") != NULL; + rec->case_sensitive = g_hash_table_lookup(optlist, "matchcase") != NULL; if (colorarg != NULL) { g_free_and_null(rec->color); @@ -631,7 +644,7 @@ static void cmd_hilight(const char *data) hilight_create(rec); hilight_print(g_slist_index(hilights, rec)+1, rec); - cmd_params_free(free_arg); + cmd_params_free(free_arg); reset_cache(); } @@ -649,7 +662,7 @@ static void cmd_dehilight(const char *data) } else { /* with mask */ char *chans[2] = { "*", NULL }; - rec = hilight_find(data, chans); + rec = hilight_find(data, chans); } if (rec == NULL) @@ -657,20 +670,20 @@ static void cmd_dehilight(const char *data) else { printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_HILIGHT_REMOVED, rec->text); hilight_remove(rec); - reset_cache(); + reset_cache(); } } static void hilight_nick_cache(GHashTable *list, CHANNEL_REC *channel, - NICK_REC *nick) + NICK_REC *nick) { GSList *tmp; HILIGHT_REC *match; - char *nickmask; + char *nickmask; int len, best_match; if (nick->host == NULL) - return; /* don't check until host is known */ + return; /* don't check until host is known */ nickmask = g_strconcat(nick->nick, "!", nick->host, NULL); @@ -679,8 +692,8 @@ static void hilight_nick_cache(GHashTable *list, CHANNEL_REC *channel, HILIGHT_REC *rec = tmp->data; if (rec->nickmask && - hilight_match_channel(rec, channel->name) && - match_wildcards(rec->text, nickmask)) { + hilight_match_channel(rec, channel->name) && + match_wildcards(rec->text, nickmask)) { len = strlen(rec->text); if (best_match < len) { best_match = len; @@ -691,7 +704,7 @@ static void hilight_nick_cache(GHashTable *list, CHANNEL_REC *channel, g_free_not_null(nickmask); if (match != NULL) - g_hash_table_insert(list, nick, match); + g_hash_table_insert(list, nick, match); } static void read_settings(void) @@ -706,28 +719,28 @@ void hilight_text_init(void) settings_add_str("lookandfeel", "hilight_act_color", "%M"); settings_add_level("lookandfeel", "hilight_level", "PUBLIC DCCMSGS"); - read_settings(); + read_settings(); nickmatch = nickmatch_init(hilight_nick_cache); read_hilight_config(); signal_add_first("print text", (SIGNAL_FUNC) sig_print_text); - signal_add("setup reread", (SIGNAL_FUNC) read_hilight_config); - signal_add("setup changed", (SIGNAL_FUNC) read_settings); + signal_add("setup reread", (SIGNAL_FUNC) read_hilight_config); + signal_add("setup changed", (SIGNAL_FUNC) read_settings); command_bind("hilight", NULL, (SIGNAL_FUNC) cmd_hilight); command_bind("dehilight", NULL, (SIGNAL_FUNC) cmd_dehilight); - command_set_options("hilight", "-color -actcolor -level -priority -network -channels nick word line mask full regexp"); + command_set_options("hilight", "-color -actcolor -level -priority -network -channels nick word line mask full regexp matchcase"); } void hilight_text_deinit(void) { hilights_destroy_all(); - nickmatch_deinit(nickmatch); + nickmatch_deinit(nickmatch); signal_remove("print text", (SIGNAL_FUNC) sig_print_text); - signal_remove("setup reread", (SIGNAL_FUNC) read_hilight_config); - signal_remove("setup changed", (SIGNAL_FUNC) read_settings); + signal_remove("setup reread", (SIGNAL_FUNC) read_hilight_config); + signal_remove("setup changed", (SIGNAL_FUNC) read_settings); command_unbind("hilight", (SIGNAL_FUNC) cmd_hilight); command_unbind("dehilight", (SIGNAL_FUNC) cmd_dehilight); diff --git a/src/fe-common/core/hilight-text.h b/src/fe-common/core/hilight-text.h index 3c897def..ae05e1ca 100644 --- a/src/fe-common/core/hilight-text.h +++ b/src/fe-common/core/hilight-text.h @@ -23,6 +23,7 @@ struct _HILIGHT_REC { unsigned int nickmask:1; /* `text' is a nick mask */ unsigned int fullword:1; /* match `text' only for full words */ unsigned int regexp:1; /* `text' is a regular expression */ + unsigned int case_sensitive:1;/* `text' must match case */ #ifdef HAVE_REGEX_H unsigned int regexp_compiled:1; /* should always be TRUE, unless regexp is invalid */ regex_t preg; diff --git a/src/fe-common/core/module-formats.c b/src/fe-common/core/module-formats.c index e6d32b6d..5c07f14c 100644 --- a/src/fe-common/core/module-formats.c +++ b/src/fe-common/core/module-formats.c @@ -221,8 +221,10 @@ FORMAT_REC fecommon_core_formats[] = { { "invalid_level", "Invalid message level", 0 }, { "invalid_size", "Invalid size", 0 }, { "invalid_charset", "Invalid charset: $0", 1, { 0 } }, + { "invalid_choice", "Invalid choice, must be one of $0", 1, { 0 } }, { "eval_max_recurse", "/eval hit maximum recursion limit", 0 }, { "program_not_found", "Could not find file or file is not executable", 0 }, + { "no_server_defined", "No servers defined for this network, see /help server for how to add one", 0 }, /* ---- */ { NULL, "Themes", 0 }, diff --git a/src/fe-common/core/module-formats.h b/src/fe-common/core/module-formats.h index 3f06bb97..2b45ff6b 100644 --- a/src/fe-common/core/module-formats.h +++ b/src/fe-common/core/module-formats.h @@ -190,8 +190,10 @@ enum { TXT_INVALID_LEVEL, TXT_INVALID_SIZE, TXT_INVALID_CHARSET, + TXT_INVALID_CHOICE, TXT_EVAL_MAX_RECURSE, TXT_PROGRAM_NOT_FOUND, + TXT_NO_SERVER_DEFINED, TXT_FILL_11, diff --git a/src/fe-common/core/module.h b/src/fe-common/core/module.h index 51b61b3e..db712ec7 100644 --- a/src/fe-common/core/module.h +++ b/src/fe-common/core/module.h @@ -2,7 +2,7 @@ #define MODULE_NAME "fe-common/core" -typedef guint32 unichar; +#include "utf8.h" typedef struct { time_t time; char *nick; diff --git a/src/fe-common/core/themes.c b/src/fe-common/core/themes.c index 58e7b557..2b1459be 100644 --- a/src/fe-common/core/themes.c +++ b/src/fe-common/core/themes.c @@ -365,9 +365,9 @@ char *theme_format_expand_get(THEME_REC *theme, const char **format) GString *str; char *ret; theme_rm_col dummy, reset; + int braces = 1; /* we start with one brace opened */ dummy.m[0] = '\0'; strcpy(reset.m, "n"); - int braces = 1; /* we start with one brace opened */ str = g_string_new(NULL); while (**format != '\0' && braces != 0) { diff --git a/src/fe-common/core/utf8.c b/src/fe-common/core/utf8.c deleted file mode 100644 index 2d07ea8e..00000000 --- a/src/fe-common/core/utf8.c +++ /dev/null @@ -1,26 +0,0 @@ -/* utf8.c - Operations on UTF-8 strings. - * - * Copyright (C) 2002 Timo Sirainen - * - * Based on GLib code by - * - * Copyright (C) 1999 Tom Tromey - * Copyright (C) 2000 Red Hat, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include "module.h" - diff --git a/src/fe-common/core/utf8.h b/src/fe-common/core/utf8.h deleted file mode 100644 index 3c15dc7d..00000000 --- a/src/fe-common/core/utf8.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef __UTF8_H -#define __UTF8_H - -/* XXX I didn't check the encoding range of big5+. This is standard big5. */ -#define is_big5_los(lo) (0x40 <= (lo) && (lo) <= 0x7E) /* standard */ -#define is_big5_lox(lo) (0x80 <= (lo) && (lo) <= 0xFE) /* extended */ -#define is_big5_lo(lo) ((is_big5_los(lo) || is_big5_lox(lo))) -#define is_big5_hi(hi) (0x81 <= (hi) && (hi) <= 0xFE) -#define is_big5(hi,lo) (is_big5_hi(hi) && is_big5_lo(lo)) - -/* Returns width for character (0-2). */ -int mk_wcwidth(unichar c); - -#define unichar_isprint(c) (((c) & ~0x80) >= 32) -#define is_utf8_leading(c) (((c) & 0xc0) != 0x80) - -#endif diff --git a/src/fe-common/core/wcwidth.c b/src/fe-common/core/wcwidth.c deleted file mode 100644 index 80d20fa1..00000000 --- a/src/fe-common/core/wcwidth.c +++ /dev/null @@ -1,220 +0,0 @@ -/* - * This is an implementation of wcwidth() and wcswidth() (defined in - * IEEE Std 1002.1-2001) for Unicode. - * - * http://www.opengroup.org/onlinepubs/007904975/functions/wcwidth.html - * http://www.opengroup.org/onlinepubs/007904975/functions/wcswidth.html - * - * In fixed-width output devices, Latin characters all occupy a single - * "cell" position of equal width, whereas ideographic CJK characters - * occupy two such cells. Interoperability between terminal-line - * applications and (teletype-style) character terminals using the - * UTF-8 encoding requires agreement on which character should advance - * the cursor by how many cell positions. No established formal - * standards exist at present on which Unicode character shall occupy - * how many cell positions on character terminals. These routines are - * a first attempt of defining such behavior based on simple rules - * applied to data provided by the Unicode Consortium. - * - * For some graphical characters, the Unicode standard explicitly - * defines a character-cell width via the definition of the East Asian - * FullWidth (F), Wide (W), Half-width (H), and Narrow (Na) classes. - * In all these cases, there is no ambiguity about which width a - * terminal shall use. For characters in the East Asian Ambiguous (A) - * class, the width choice depends purely on a preference of backward - * compatibility with either historic CJK or Western practice. - * Choosing single-width for these characters is easy to justify as - * the appropriate long-term solution, as the CJK practice of - * displaying these characters as double-width comes from historic - * implementation simplicity (8-bit encoded characters were displayed - * single-width and 16-bit ones double-width, even for Greek, - * Cyrillic, etc.) and not any typographic considerations. - * - * Much less clear is the choice of width for the Not East Asian - * (Neutral) class. Existing practice does not dictate a width for any - * of these characters. It would nevertheless make sense - * typographically to allocate two character cells to characters such - * as for instance EM SPACE or VOLUME INTEGRAL, which cannot be - * represented adequately with a single-width glyph. The following - * routines at present merely assign a single-cell width to all - * neutral characters, in the interest of simplicity. This is not - * entirely satisfactory and should be reconsidered before - * establishing a formal standard in this area. At the moment, the - * decision which Not East Asian (Neutral) characters should be - * represented by double-width glyphs cannot yet be answered by - * applying a simple rule from the Unicode database content. Setting - * up a proper standard for the behavior of UTF-8 character terminals - * will require a careful analysis not only of each Unicode character, - * but also of each presentation form, something the author of these - * routines has avoided to do so far. - * - * http://www.unicode.org/unicode/reports/tr11/ - * - * Markus Kuhn -- 2007-05-25 (Unicode 5.0) - * - * Permission to use, copy, modify, and distribute this software - * for any purpose and without fee is hereby granted. The author - * disclaims all warranties with regard to this software. - * - * Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c - */ - -#include "module.h" - -struct interval { - int first; - int last; -}; - -/* auxiliary function for binary search in interval table */ -static int bisearch(unichar ucs, const struct interval *table, int max) { - int min = 0; - int mid; - - if (ucs < table[0].first || ucs > table[max].last) - return 0; - while (max >= min) { - mid = (min + max) / 2; - if (ucs > table[mid].last) - min = mid + 1; - else if (ucs < table[mid].first) - max = mid - 1; - else - return 1; - } - - return 0; -} - - -/* The following two functions define the column width of an ISO 10646 - * character as follows: - * - * - The null character (U+0000) has a column width of 0. - * - * - Other C0/C1 control characters and DEL will lead to a return - * value of -1. - * - * - Non-spacing and enclosing combining characters (general - * category code Mn or Me in the Unicode database) have a - * column width of 0. - * - * - SOFT HYPHEN (U+00AD) has a column width of 1. - * - * - Other format characters (general category code Cf in the Unicode - * database) and ZERO WIDTH SPACE (U+200B) have a column width of 0. - * - * - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF) - * have a column width of 0. - * - * - Spacing characters in the East Asian Wide (W) or East Asian - * Full-width (F) category as defined in Unicode Technical - * Report #11 have a column width of 2. - * - * - All remaining characters (including all printable - * ISO 8859-1 and WGL4 characters, Unicode control characters, - * etc.) have a column width of 1. - * - * This implementation assumes that wchar_t characters are encoded - * in ISO 10646. - */ - -int mk_wcwidth(unichar ucs) -{ - /* sorted list of non-overlapping intervals of non-spacing characters */ - /* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */ - static const struct interval combining[] = { - { 0x0300, 0x036F }, { 0x0483, 0x0486 }, { 0x0488, 0x0489 }, - { 0x0591, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 }, - { 0x05C4, 0x05C5 }, { 0x05C7, 0x05C7 }, { 0x0600, 0x0603 }, - { 0x0610, 0x0615 }, { 0x064B, 0x065E }, { 0x0670, 0x0670 }, - { 0x06D6, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED }, - { 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A }, - { 0x07A6, 0x07B0 }, { 0x07EB, 0x07F3 }, { 0x0901, 0x0902 }, - { 0x093C, 0x093C }, { 0x0941, 0x0948 }, { 0x094D, 0x094D }, - { 0x0951, 0x0954 }, { 0x0962, 0x0963 }, { 0x0981, 0x0981 }, - { 0x09BC, 0x09BC }, { 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD }, - { 0x09E2, 0x09E3 }, { 0x0A01, 0x0A02 }, { 0x0A3C, 0x0A3C }, - { 0x0A41, 0x0A42 }, { 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D }, - { 0x0A70, 0x0A71 }, { 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC }, - { 0x0AC1, 0x0AC5 }, { 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD }, - { 0x0AE2, 0x0AE3 }, { 0x0B01, 0x0B01 }, { 0x0B3C, 0x0B3C }, - { 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 }, { 0x0B4D, 0x0B4D }, - { 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 }, { 0x0BC0, 0x0BC0 }, - { 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 }, { 0x0C46, 0x0C48 }, - { 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 }, { 0x0CBC, 0x0CBC }, - { 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD }, - { 0x0CE2, 0x0CE3 }, { 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D }, - { 0x0DCA, 0x0DCA }, { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 }, - { 0x0E31, 0x0E31 }, { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E }, - { 0x0EB1, 0x0EB1 }, { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC }, - { 0x0EC8, 0x0ECD }, { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 }, - { 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E }, - { 0x0F80, 0x0F84 }, { 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 }, - { 0x0F99, 0x0FBC }, { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 }, - { 0x1032, 0x1032 }, { 0x1036, 0x1037 }, { 0x1039, 0x1039 }, - { 0x1058, 0x1059 }, { 0x1160, 0x11FF }, { 0x135F, 0x135F }, - { 0x1712, 0x1714 }, { 0x1732, 0x1734 }, { 0x1752, 0x1753 }, - { 0x1772, 0x1773 }, { 0x17B4, 0x17B5 }, { 0x17B7, 0x17BD }, - { 0x17C6, 0x17C6 }, { 0x17C9, 0x17D3 }, { 0x17DD, 0x17DD }, - { 0x180B, 0x180D }, { 0x18A9, 0x18A9 }, { 0x1920, 0x1922 }, - { 0x1927, 0x1928 }, { 0x1932, 0x1932 }, { 0x1939, 0x193B }, - { 0x1A17, 0x1A18 }, { 0x1B00, 0x1B03 }, { 0x1B34, 0x1B34 }, - { 0x1B36, 0x1B3A }, { 0x1B3C, 0x1B3C }, { 0x1B42, 0x1B42 }, - { 0x1B6B, 0x1B73 }, { 0x1DC0, 0x1DCA }, { 0x1DFE, 0x1DFF }, - { 0x200B, 0x200F }, { 0x202A, 0x202E }, { 0x2060, 0x2063 }, - { 0x206A, 0x206F }, { 0x20D0, 0x20EF }, { 0x302A, 0x302F }, - { 0x3099, 0x309A }, { 0xA806, 0xA806 }, { 0xA80B, 0xA80B }, - { 0xA825, 0xA826 }, { 0xFB1E, 0xFB1E }, { 0xFE00, 0xFE0F }, - { 0xFE20, 0xFE23 }, { 0xFEFF, 0xFEFF }, { 0xFFF9, 0xFFFB }, - { 0x10A01, 0x10A03 }, { 0x10A05, 0x10A06 }, { 0x10A0C, 0x10A0F }, - { 0x10A38, 0x10A3A }, { 0x10A3F, 0x10A3F }, { 0x1D167, 0x1D169 }, - { 0x1D173, 0x1D182 }, { 0x1D185, 0x1D18B }, { 0x1D1AA, 0x1D1AD }, - { 0x1D242, 0x1D244 }, { 0xE0001, 0xE0001 }, { 0xE0020, 0xE007F }, - { 0xE0100, 0xE01EF } - }; - - /* test for 8-bit control characters */ - if (ucs == 0) - return 0; - if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0)) - return -1; - - /* binary search in table of non-spacing characters */ - if (bisearch(ucs, combining, - sizeof(combining) / sizeof(struct interval) - 1)) - return 0; - - /* if we arrive here, ucs is not a combining or C0/C1 control character */ - - return 1 + - (ucs >= 0x1100 && - (ucs <= 0x115f || /* Hangul Jamo init. consonants */ - ucs == 0x2329 || ucs == 0x232a || - (ucs >= 0x2e80 && ucs <= 0xa4cf && - ucs != 0x303f) || /* CJK ... Yi */ - (ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */ - (ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */ - (ucs >= 0xfe10 && ucs <= 0xfe19) || /* Vertical forms */ - (ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */ - (ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */ - (ucs >= 0xffe0 && ucs <= 0xffe6) || - (ucs >= 0x20000 && ucs <= 0x2fffd) || - (ucs >= 0x30000 && ucs <= 0x3fffd))); -} - - -#if 0 -int mk_wcswidth(const unichar *pwcs, size_t n) -{ - int w, width = 0; - - for (;*pwcs && n-- > 0; pwcs++) - if ((w = mk_wcwidth(*pwcs)) < 0) - return -1; - else - width += w; - - return width; -} -#endif |