summaryrefslogtreecommitdiff
path: root/src/fe-common/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/fe-common/core')
-rw-r--r--src/fe-common/core/Makefile.am5
-rw-r--r--src/fe-common/core/chat-completion.c49
-rw-r--r--src/fe-common/core/completion.c77
-rw-r--r--src/fe-common/core/fe-channels.c118
-rw-r--r--src/fe-common/core/fe-common-core.c11
-rw-r--r--src/fe-common/core/fe-core-commands.c3
-rw-r--r--src/fe-common/core/fe-exec.c15
-rw-r--r--src/fe-common/core/fe-ignore.c8
-rw-r--r--src/fe-common/core/fe-log.c2
-rw-r--r--src/fe-common/core/fe-messages.c5
-rw-r--r--src/fe-common/core/fe-server.c24
-rw-r--r--src/fe-common/core/fe-settings.c27
-rw-r--r--src/fe-common/core/formats.c28
-rw-r--r--src/fe-common/core/hilight-text.c149
-rw-r--r--src/fe-common/core/hilight-text.h1
-rw-r--r--src/fe-common/core/module-formats.c2
-rw-r--r--src/fe-common/core/module-formats.h2
-rw-r--r--src/fe-common/core/module.h2
-rw-r--r--src/fe-common/core/themes.c2
-rw-r--r--src/fe-common/core/utf8.c26
-rw-r--r--src/fe-common/core/utf8.h17
-rw-r--r--src/fe-common/core/wcwidth.c220
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