diff --git a/TODO b/TODO index 3307b9b2..6654d7e0 100644 --- a/TODO +++ b/TODO @@ -46,7 +46,6 @@ 20:47 <@Juerd> cras: for some reason irssi doesn't know this happens in a query, and displays "< Juerd:> foo" in the status window - set TOS field for all connections (DCC especially) - - /PROXY CTCP ON doesn't work well with multiple servers 22:51 [IRCNet] [zhafte] irssi muuten taitaa bugaa jos pistää ACT oikeaan reunaan, vai onkohan se vain mun terminaali? 22:52 [IRCNet] [zhafte] menevät välillä päällekkäin diff --git a/configure.in b/configure.in index 122ff9d9..e6c8ecc9 100644 --- a/configure.in +++ b/configure.in @@ -7,7 +7,7 @@ if test -n "`grep '^#undef VERSION' config.h.in`"; then fi AM_CONFIG_HEADER(config.h) -AM_INIT_AUTOMAKE(irssi, 0.8.10-rc4) +AM_INIT_AUTOMAKE(irssi, 0.8.10-rc5) AM_MAINTAINER_MODE diff --git a/docs/help/in/network.in b/docs/help/in/network.in index dce4abf2..abeadb32 100644 --- a/docs/help/in/network.in +++ b/docs/help/in/network.in @@ -5,11 +5,12 @@ -msgs: Maximum number of nicks in one /MSG command -modes: Maximum number of mode changes in one /MODE command -whois: Maximum number of nicks in one /WHOIS command - -cmdspeed: Same as /SET cmd_queue_speed, see section 3.1 + -cmdspeed: Same as /SET cmd_queue_speed, see section 3.1 -cmdmax: Same as /SET cmd_max_at_once, see section 3.1 -nick, -user, -realname: Specify what nick/user/name to use -host: Specify what host name to use, if you have multiple - -autosendcmd: Command to send after connecting to a server + -usermode: Specify what usermode to use on this network + -autosendcmd: Command to send after connecting to a server With -autosendcmd argument you can automatically run any commands after connecting to network. This is useful for automatically diff --git a/docs/help/in/recode.in b/docs/help/in/recode.in index 4f9781df..2b452d82 100644 --- a/docs/help/in/recode.in +++ b/docs/help/in/recode.in @@ -12,3 +12,37 @@ RECODE REMOVE %|[] %|Remove an entry from the conversion database (if target is omitted, the current channel or query will be used) +To specify your local charset you have to set term_charset + +Example: + +/SET term_charset + +To see the recode settings: /SET recode + +You can change them with /SET + +Examples: + +/SET recode_fallback +to set the fallback charset for incoming events + +This charset will be used if a conversion with +the defined charset(/recode add) fails, and if no +charset for the target(query or channel) is defined at all. + +/SET recode_out_default_charset +to set the global outgoing charset + +When it's set to a charset it will be used instead +of the charset you have defined with /recode add + +/SET recode_transliterate ON +to enable the global transliteration. + +The transliteration is based on your locale settings, +if it doesn't work properly your locale settings may be wrong. +You can enable it per target by adding //TRANSLIT to the + +Hint: can be almost everything listed by 'iconv -l' + diff --git a/docs/special_vars.txt b/docs/special_vars.txt index 2008931f..f19b2bb2 100644 --- a/docs/special_vars.txt +++ b/docs/special_vars.txt @@ -80,7 +80,7 @@ $A .. $Z is important. $Z time of day (hh:mm, can be changed with /SET timestamp_format) $$ a literal '$' - $versiontim prints time of the irssi version in HHMM format + $versiontime prints time of the irssi version in HHMM format $sysname system name (eg. Linux) $sysrelease system release (eg. 2.2.18) $sysarch system architecture (eg. i686) diff --git a/src/core/commands.h b/src/core/commands.h index bdc8755d..b4f4ea0e 100644 --- a/src/core/commands.h +++ b/src/core/commands.h @@ -38,7 +38,8 @@ enum { CMDERR_CHAN_NOT_SYNCED, /* channel not fully synchronized yet */ CMDERR_ILLEGAL_PROTO, /* requires different chat protocol than the active server */ CMDERR_NOT_GOOD_IDEA, /* not good idea to do, -yes overrides this */ - CMDERR_INVALID_TIME /* invalid time specification */ + CMDERR_INVALID_TIME, /* invalid time specification */ + CMDERR_INVALID_CHARSET /* invalid charset specification */ }; /* Return the full command for `alias' */ diff --git a/src/core/recode.c b/src/core/recode.c index aa9f8315..8237e056 100644 --- a/src/core/recode.c +++ b/src/core/recode.c @@ -20,7 +20,10 @@ #include "module.h" #include "settings.h" +#include "servers.h" +#include "signals.h" #include "lib-config/iconfig.h" +#include "misc.h" #ifdef HAVE_GLIB2 static gboolean recode_get_charset(const char **charset) @@ -29,39 +32,65 @@ static gboolean recode_get_charset(const char **charset) if (**charset) /* we use the same test as in src/fe-text/term.c:123 */ return !g_strcasecmp(*charset, "utf-8"); - + return g_get_charset(charset); } #endif +gboolean is_valid_charset(const char *charset) +{ +#ifdef HAVE_GLIB2 + const char *from="UTF-8"; + const char *str="irssi"; + char *recoded; + gboolean valid; + + if (!charset || *charset == '\0') + return FALSE; + recoded = g_convert(str, strlen(str), charset, from, NULL, NULL, NULL); + valid = (recoded != NULL); + g_free(recoded); + return valid; +#else + if (!charset || *charset =='\0') + return FALSE; + return TRUE; +#endif +} + +static gboolean is_translit(const char *charset) +{ + char *pos; + pos = stristr(charset, "//translit"); + return (pos != NULL); +} + char *recode_in(const char *str, const char *target) { #ifdef HAVE_GLIB2 const char *from = NULL; const char *to = NULL; + char *translit_to = NULL; char *recoded = NULL; - gboolean term_is_utf8; - gboolean str_is_utf8; - gboolean translit; + gboolean term_is_utf8, str_is_utf8, translit; int len; - + if (!str) return g_strdup(str); - + len = strlen(str); str_is_utf8 = g_utf8_validate(str, len, NULL); - translit = settings_get_bool("recode_transliterate"); - - if (target != NULL) + + if (target != NULL && from == NULL) from = iconfig_get_str("conversions", target, NULL); term_is_utf8 = recode_get_charset(&to); - - if (translit) - to = g_strdup_printf("%s//TRANSLIT", to); - + + if (translit && !is_translit(to)) + to = translit_to = g_strconcat(to, "//TRANSLIT", NULL); + if (from) recoded = g_convert(str, len, to, from, NULL, NULL, NULL); @@ -69,10 +98,10 @@ char *recode_in(const char *str, const char *target) if (term_is_utf8) { if (!str_is_utf8) from = settings_get_str("recode_fallback"); - + } else if (str_is_utf8) from = "UTF-8"; - + if (from) recoded = g_convert(str, len, to, from, NULL, NULL, NULL); @@ -93,31 +122,34 @@ char *recode_out(const char *str, const char *target) gboolean translit; gboolean term_is_utf8; int len; - + if (!str) return g_strdup(str); - + len = strlen(str); - + translit = settings_get_bool("recode_transliterate"); + if (target) { const char *to = NULL; + char *translit_to = NULL; + + /* default outgoing charset if set */ + to = settings_get_str("recode_out_default_charset"); + if (to == NULL || *to == '\0') + to = iconfig_get_str("conversions", target, NULL); + if (to && *to != '\0') { + if (translit && !is_translit(to)) + to = translit_to = g_strconcat(to ,"//TRANSLIT", NULL); - to = iconfig_get_str("conversions", target, NULL); - if (!to) - /* default outgoing charset if no conversion is set */ - to = settings_get_str("recode_out_default_charset"); - if (to) { - if (translit) - to = g_strdup_printf("%s//TRANSLIT", to); - term_is_utf8 = recode_get_charset(&from); recoded = g_convert(str, len, to, from, NULL, NULL, NULL); } + g_free(translit_to); } if (!recoded) recoded = g_strdup(str); - + return recoded; #else return g_strdup(str); @@ -128,7 +160,7 @@ void recode_init(void) { settings_add_str("misc", "recode_fallback", "ISO8859-1"); settings_add_str("misc", "recode_out_default_charset", ""); - settings_add_bool("misc", "recode_transliterate", TRUE); + settings_add_bool("misc", "recode_transliterate", FALSE); } void recode_deinit(void) diff --git a/src/core/recode.h b/src/core/recode.h index 47a11f09..2a50da9e 100644 --- a/src/core/recode.h +++ b/src/core/recode.h @@ -3,6 +3,7 @@ char *recode_in (const char *str, const char *target); char *recode_out (const char *str, const char *target); +gboolean is_valid_charset(const char *charset); void recode_init (void); void recode_deinit (void); diff --git a/src/core/settings.c b/src/core/settings.c index ba37ddb1..ce230f8a 100644 --- a/src/core/settings.c +++ b/src/core/settings.c @@ -25,6 +25,7 @@ #include "misc.h" #include "lib-config/iconfig.h" +#include "recode.h" #include "settings.h" #include "default-config.h" @@ -393,8 +394,8 @@ static void sig_init_finished(void) if (config_changed) { /* some backwards compatibility changes were made to config file, reload it */ - g_warning("Some time and size related settings were " - "automatically changed to new format, please /SAVE"); + g_warning("Some settings were automatically " + "updated, please /SAVE"); signal_emit("setup changed", 0); } } @@ -439,15 +440,41 @@ void settings_clean_invalid(void) static int backwards_compatibility(const char *module, CONFIG_NODE *node, CONFIG_NODE *parent) { - const char *new_key; + const char *new_key, *new_module; + CONFIG_NODE *new_node; char *new_value; int old_value; + new_value = NULL; new_key = NULL; new_module = NULL; + + /* fe-text term_type -> fe-common/core term_charset - for 0.8.10-> */ + if (strcmp(module, "fe-text") == 0) { + if (strcasecmp(node->key, "term_type") == 0 || + /* kludge for cvs-version where term_charset was in fe-text */ + strcasecmp(node->key, "term_charset") == 0) { + new_module = "fe-common/core"; + new_key = "term_charset"; + new_value = !is_valid_charset(node->value) ? NULL : + g_strdup(node->value); + new_node = iconfig_node_traverse("settings", FALSE); + new_node = new_node == NULL ? NULL : + config_node_section(new_node, new_module, -1); + + config_node_set_str(mainconfig, new_node, + new_key, new_value); + /* remove old */ + config_node_set_str(mainconfig, parent, + node->key, NULL); + g_free(new_value); + config_changed = TRUE; + return new_key != NULL; + } + } + new_value = NULL, new_key = NULL; /* FIXME: remove later - for 0.8.6 -> */ if (node->value == NULL || !is_numeric(node->value, '\0')) return FALSE; - new_value = NULL; new_key = NULL; old_value = atoi(node->value); if (strcmp(module, "fe-text") == 0) { diff --git a/src/fe-common/core/Makefile.am b/src/fe-common/core/Makefile.am index 75ff7a9a..c0b53177 100644 --- a/src/fe-common/core/Makefile.am +++ b/src/fe-common/core/Makefile.am @@ -25,6 +25,7 @@ libfe_common_core_a_SOURCES = \ fe-queries.c \ fe-server.c \ fe-settings.c \ + utf8.c \ formats.c \ hilight-text.c \ keyboard.c \ @@ -51,6 +52,7 @@ pkginc_fe_common_core_HEADERS = \ fe-exec.h \ fe-messages.h \ fe-queries.h \ + utf8.h \ formats.h \ hilight-text.h \ keyboard.h \ diff --git a/src/fe-common/core/fe-common-core.c b/src/fe-common/core/fe-common-core.c index 147d5448..443204cb 100644 --- a/src/fe-common/core/fe-common-core.c +++ b/src/fe-common/core/fe-common-core.c @@ -25,10 +25,14 @@ #include "levels.h" #include "settings.h" #include "irssi-version.h" +#ifdef HAVE_NL_LANGINFO +# include +#endif #include "servers.h" #include "channels.h" #include "servers-setup.h" +#include "recode.h" #include "autorun.h" #include "fe-core-commands.h" @@ -170,7 +174,11 @@ void fe_common_core_init(void) settings_add_bool("lookandfeel", "use_status_window", TRUE); settings_add_bool("lookandfeel", "use_msgs_window", FALSE); - +#if defined (HAVE_NL_LANGINFO) && defined(CODESET) + settings_add_str("lookandfeel", "term_charset", nl_langinfo(CODESET)); +#else + settings_add_str("lookandfeel", "term_charset", "ISO8859-1"); +#endif themes_init(); theme_register(fecommon_core_formats); diff --git a/src/fe-common/core/fe-core-commands.c b/src/fe-common/core/fe-core-commands.c index cc1f587c..13ddc8ac 100644 --- a/src/fe-common/core/fe-core-commands.c +++ b/src/fe-common/core/fe-core-commands.c @@ -48,7 +48,8 @@ static int ret_texts[] = { TXT_CHAN_NOT_SYNCED, TXT_ILLEGAL_PROTO, TXT_NOT_GOOD_IDEA, - TXT_INVALID_TIME + TXT_INVALID_TIME, + TXT_INVALID_CHARSET }; int command_hide_output; diff --git a/src/fe-common/core/fe-messages.c b/src/fe-common/core/fe-messages.c index f0015f20..d5b011c5 100644 --- a/src/fe-common/core/fe-messages.c +++ b/src/fe-common/core/fe-messages.c @@ -31,6 +31,7 @@ #include "channels.h" #include "nicklist.h" #include "ignore.h" +#include "recode.h" #include "window-items.h" #include "fe-queries.h" @@ -330,7 +331,7 @@ static void sig_message_quit(SERVER_REC *server, const char *nick, WINDOW_REC *window; GString *chans; GSList *tmp, *windows; - char *print_channel; + char *print_channel, *recoded; int once, count; if (ignore_check(server, nick, address, NULL, reason, MSGLEVEL_QUITS)) @@ -363,10 +364,12 @@ static void sig_message_quit(SERVER_REC *server, const char *nick, window = window_item_window((WI_ITEM_REC *) rec); if (g_slist_find(windows, window) == NULL) { windows = g_slist_append(windows, window); + recoded = recode_in(reason, rec->visible_name); printformat(server, rec->visible_name, MSGLEVEL_QUITS, - TXT_QUIT, nick, address, reason, + TXT_QUIT, nick, address, recoded, rec->visible_name); + g_free(recoded); } } count++; @@ -378,17 +381,22 @@ static void sig_message_quit(SERVER_REC *server, const char *nick, display the quit there too */ QUERY_REC *query = query_find(server, nick); if (query != NULL) { + recoded = recode_in(reason, nick); printformat(server, nick, MSGLEVEL_QUITS, - TXT_QUIT, nick, address, reason, ""); + TXT_QUIT, nick, address, recoded, ""); + g_free(recoded); } } if (once || count == 0) { if (chans->len > 0) g_string_truncate(chans, chans->len-1); + /* at least recode_fallback will be used */ + recoded = recode_in(reason, NULL); printformat(server, print_channel, MSGLEVEL_QUITS, count <= 1 ? TXT_QUIT : TXT_QUIT_ONCE, - nick, address, reason, chans->str); + nick, address, recoded, chans->str); + g_free(recoded); } g_string_free(chans, TRUE); } diff --git a/src/fe-common/core/fe-recode.c b/src/fe-common/core/fe-recode.c index a693b5ec..a46e3547 100644 --- a/src/fe-common/core/fe-recode.c +++ b/src/fe-common/core/fe-recode.c @@ -27,26 +27,21 @@ #include "settings.h" #include "printtext.h" #include "formats.h" +#include "recode.h" + +#ifdef HAVE_NL_LANGINFO +# include +#endif + #define SLIST_FOREACH(var, head) \ for ((var) = (head); \ (var); \ (var) = g_slist_next((var))) #ifdef HAVE_GLIB2 -static gboolean is_valid_charset(const char *charset) -{ - const char *from="UTF-8"; - const char *str="irssi"; - char *recoded; - if (!charset) - return FALSE; - recoded = g_convert(str, strlen(str), charset, from, NULL, NULL, NULL); - if (recoded) { - g_free(recoded); - return TRUE; - } else - return FALSE; -} +const char *recode_fallback = NULL; +const char *recode_out_default = NULL; +const char *term_charset = NULL; static const char *fe_recode_get_target (WI_ITEM_REC *witem) { @@ -123,7 +118,7 @@ static void fe_recode_add_cmd (const char *data, SERVER_REC *server, WI_ITEM_REC iconfig_set_str("conversions", target, charset); printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_CONVERSION_ADDED, target, charset); } else - printformat(NULL, NULL, MSGLEVEL_CLIENTERROR, TXT_CONVERSION_NOT_SUPPORTED, charset); + signal_emit("error command", 2, GINT_TO_POINTER(CMDERR_INVALID_CHARSET), charset); end: cmd_params_free(free_arg); } @@ -156,23 +151,76 @@ static void fe_recode_remove_cmd (const char *data, SERVER_REC *server, WI_ITEM_ static void read_settings(void) { - const char *charset; + const char *old_term_charset = g_strdup (term_charset); + const char *old_recode_fallback = g_strdup (recode_fallback); + const char *old_recode_out_default = g_strdup (recode_out_default); - charset = settings_get_str("recode_fallback"); - if (!is_valid_charset(charset)){ - printformat(NULL, NULL, MSGLEVEL_CLIENTERROR, TXT_CONVERSION_NOT_SUPPORTED, charset); - settings_set_str("recode_fallback", "ISO8859-1"); - } - charset = settings_get_str("term_charset"); - if (charset && !is_valid_charset(charset)) { - printformat(NULL, NULL, MSGLEVEL_CLIENTERROR, TXT_CONVERSION_NOT_SUPPORTED, charset); - settings_set_str("term_charset", "ISO8859-1"); - } - charset = settings_get_str("recode_out_default_charset"); - if (charset && !is_valid_charset(charset)) { - printformat(NULL, NULL, MSGLEVEL_CLIENTERROR, TXT_CONVERSION_NOT_SUPPORTED, charset); - settings_set_str("recode_out_default_charset", ""); - } + recode_fallback = settings_get_str("recode_fallback"); + if (!is_valid_charset(recode_fallback)) { + signal_emit("error command", 2, GINT_TO_POINTER(CMDERR_INVALID_CHARSET), recode_fallback); + settings_set_str("recode_fallback", old_recode_fallback != NULL ? old_recode_fallback : "ISO8859-1"); + } + recode_fallback = g_strdup(settings_get_str("recode_fallback")); + + term_charset = settings_get_str("term_charset"); + if (!is_valid_charset(term_charset)) { +#if defined (HAVE_NL_LANGINFO) && defined(CODESET) + settings_set_str("term_charset", is_valid_charset(old_term_charset) ? old_term_charset : nl_langinfo(CODESET)); +#else + settings_set_str("term_charset", is_valid_charset(old_term_charset) ? old_term_charset : "ISO8859-1"); +#endif + /* FIXME: move the check of term_charset into fe-text/term.c + it breaks the proper term_input_type + setup and reemitting of the signal is kludgy */ + if (g_strcasecmp(term_charset, old_term_charset) != 0); + signal_emit("setup changed", 0); + } + term_charset = g_strdup(settings_get_str("term_charset")); + + recode_out_default = settings_get_str("recode_out_default_charset"); + if (recode_out_default != NULL && *recode_out_default != '\0') + if( !is_valid_charset(recode_out_default)) { + signal_emit("error command", 2, GINT_TO_POINTER(CMDERR_INVALID_CHARSET), recode_out_default); + settings_set_str("recode_out_default_charset", old_recode_out_default); + } + recode_out_default = g_strdup(settings_get_str("recode_out_default_charset")); +} + +static void message_own_public(const SERVER_REC *server, const char *msg, + const char *target) +{ + char *recoded; + recoded = recode_in(msg, target); + signal_continue(3, server, recoded, target); + g_free(recoded); +} + +static void message_own_private(const SERVER_REC *server, const char *msg, + const char *target, const char *orig_target) +{ + char *recoded; + recoded = recode_in(msg, target); + signal_continue(4, server, recoded, target, orig_target); + g_free(recoded); +} + +static void message_irc_own_action(const SERVER_REC *server, const char *msg, + const char *nick, const char *addr, + const char *target) +{ + char *recoded; + recoded = recode_in(msg, target); + signal_continue(5, server, recoded, nick, addr, target); + g_free(recoded); +} + +static void message_irc_own_notice(const SERVER_REC *server, const char *msg, + const char *channel) +{ + char *recoded; + recoded = recode_in(msg, channel); + signal_continue(3, server, recoded, channel); + g_free(recoded); } #endif @@ -184,6 +232,11 @@ void fe_recode_init (void) command_bind("recode add", NULL, (SIGNAL_FUNC) fe_recode_add_cmd); command_bind("recode remove", NULL, (SIGNAL_FUNC) fe_recode_remove_cmd); signal_add("setup changed", (SIGNAL_FUNC) read_settings); + signal_add("message own_public", (SIGNAL_FUNC) message_own_public); + signal_add("message own_private", (SIGNAL_FUNC) message_own_private); + signal_add("message irc own_action", (SIGNAL_FUNC) message_irc_own_action); + signal_add("message irc own_notice", (SIGNAL_FUNC) message_irc_own_notice); + read_settings(); #endif } @@ -195,5 +248,10 @@ void fe_recode_deinit (void) command_unbind("recode add", (SIGNAL_FUNC) fe_recode_add_cmd); command_unbind("recode remove", (SIGNAL_FUNC) fe_recode_remove_cmd); signal_remove("setup changed", (SIGNAL_FUNC) read_settings); + signal_remove("message own_public", (SIGNAL_FUNC) message_own_public); + signal_remove("message own_private", (SIGNAL_FUNC) message_own_private); + signal_remove("message irc own_action", (SIGNAL_FUNC) message_irc_own_action); + signal_remove("message irc own_notice", (SIGNAL_FUNC) message_irc_own_notice); #endif } + diff --git a/src/fe-common/core/formats.c b/src/fe-common/core/formats.c index 2470ba26..3fcb8066 100644 --- a/src/fe-common/core/formats.c +++ b/src/fe-common/core/formats.c @@ -32,6 +32,9 @@ #include "formats.h" #include "themes.h" #include "translation.h" +#ifdef HAVE_GLIB2 +#include "utf8.h" +#endif static const char *format_backs = "04261537"; static const char *format_fores = "kbgcrmyw"; @@ -66,13 +69,13 @@ static void format_expand_code(const char **format, GString *out, int *flags) int set; if (flags == NULL) { - /* flags are being ignored - skip the code */ + /* flags are being ignored - skip the code */ while (**format != ']') (*format)++; - return; + return; } - set = TRUE; + set = TRUE; (*format)++; while (**format != ']' && **format != '\0') { if (**format == '+') @@ -94,7 +97,7 @@ static void format_expand_code(const char **format, GString *out, int *flags) (*format)++; } g_string_append_c(out, ','); - (*format)--; + (*format)--; break; case 's': case 'S': @@ -104,12 +107,12 @@ static void format_expand_code(const char **format, GString *out, int *flags) break; case 't': *flags |= set ? PRINT_FLAG_SET_TIMESTAMP : - PRINT_FLAG_UNSET_TIMESTAMP; - break; + PRINT_FLAG_UNSET_TIMESTAMP; + break; case 'T': *flags |= set ? PRINT_FLAG_SET_SERVERTAG : - PRINT_FLAG_UNSET_SERVERTAG; - break; + PRINT_FLAG_UNSET_SERVERTAG; + break; } (*format)++; @@ -120,12 +123,12 @@ int format_expand_styles(GString *out, const char **format, int *flags) { char *p, fmt; - fmt = **format; + fmt = **format; switch (fmt) { case '{': case '}': case '%': - /* escaped char */ + /* escaped char */ g_string_append_c(out, fmt); break; case 'U': @@ -165,7 +168,7 @@ int format_expand_styles(GString *out, const char **format, int *flags) g_string_append_c(out, FORMAT_STYLE_DEFAULTS); break; case '>': - /* clear to end of line */ + /* clear to end of line */ g_string_append_c(out, 4); g_string_append_c(out, FORMAT_STYLE_CLRTOEOL); break; @@ -175,7 +178,7 @@ int format_expand_styles(GString *out, const char **format, int *flags) break; case '[': /* code */ - format_expand_code(format, out, flags); + format_expand_code(format, out, flags); break; default: /* check if it's a background color */ @@ -219,10 +222,10 @@ void format_read_arglist(va_list va, FORMAT_REC *format, { int num, len, bufpos; - g_return_if_fail(format->params < arglist_size); + g_return_if_fail(format->params < arglist_size); bufpos = 0; - arglist[format->params] = NULL; + arglist[format->params] = NULL; for (num = 0; num < format->params; num++) { switch (format->paramtypes[num]) { case FORMAT_STRING: @@ -255,7 +258,7 @@ void format_read_arglist(va_list va, FORMAT_REC *format, arglist[num] = buffer+bufpos; len = g_snprintf(buffer+bufpos, buffer_size-bufpos, "%ld", l); - bufpos += len+1; + bufpos += len+1; break; } case FORMAT_FLOAT: { @@ -279,14 +282,14 @@ void format_create_dest(TEXT_DEST_REC *dest, void *server, const char *target, int level, WINDOW_REC *window) { - format_create_dest_tag(dest, server, NULL, target, level, window); + format_create_dest_tag(dest, server, NULL, target, level, window); } void format_create_dest_tag(TEXT_DEST_REC *dest, void *server, const char *server_tag, const char *target, int level, WINDOW_REC *window) { - memset(dest, 0, sizeof(TEXT_DEST_REC)); + memset(dest, 0, sizeof(TEXT_DEST_REC)); dest->server = server; dest->server_tag = server != NULL ? SERVER(server)->tag : server_tag; @@ -345,7 +348,7 @@ int format_get_length(const char *str) str++; if (*str != '%' && format_expand_styles(tmp, &str, NULL)) { - str++; + str++; continue; } @@ -356,13 +359,13 @@ int format_get_length(const char *str) #ifdef HAVE_GLIB2 len += advance(&str, utf8); #else - len++; + len++; str++; #endif } g_string_free(tmp, TRUE); - return len; + return len; } /* Return how many characters in `str' must be skipped before `len' @@ -389,27 +392,27 @@ int format_real_length(const char *str, int len) str++; if (*str != '%' && format_expand_styles(tmp, &str, NULL)) { - str++; + str++; continue; } /* %% or unknown %code, written as-is */ if (*str != '%') { if (--len == 0) - break; + break; } } #ifdef HAVE_GLIB2 len -= advance(&str, utf8); #else - len--; + len--; str++; #endif } g_string_free(tmp, TRUE); - return (int) (str-start); + return (int) (str-start); } char *format_string_expand(const char *text, int *flags) @@ -417,7 +420,7 @@ char *format_string_expand(const char *text, int *flags) GString *out; char code, *ret; - g_return_val_if_fail(text != NULL, NULL); + g_return_val_if_fail(text != NULL, NULL); out = g_string_new(NULL); @@ -478,7 +481,7 @@ static char *format_get_text_args(TEXT_DEST_REC *dest, if (ret != NULL) { /* string shouldn't end with \003 or it could mess up the next one or two characters */ - int diff; + int diff; int len = strlen(ret); while (len > 0 && ret[len-1] == 3) len--; diff = strlen(ret)-len; @@ -548,7 +551,7 @@ char *format_get_text_theme_charargs(THEME_REC *theme, const char *module, if (module_theme == NULL) return NULL; - text = module_theme->expanded_formats[formatnum]; + text = module_theme->expanded_formats[formatnum]; return format_get_text_args(dest, text, args); } @@ -594,7 +597,7 @@ char *format_add_linestart(const char *text, const char *linestart) ret = str->str; g_string_free(str, FALSE); - return ret; + return ret; } char *format_add_lineend(const char *text, const char *linestart) @@ -619,7 +622,7 @@ char *format_add_lineend(const char *text, const char *linestart) ret = str->str; g_string_free(str, FALSE); - return ret; + return ret; } #define LINE_START_IRSSI_LEVEL \ @@ -635,16 +638,16 @@ char *format_get_level_tag(THEME_REC *theme, TEXT_DEST_REC *dest) { int format; - /* check for flags if we want to override defaults */ + /* check for flags if we want to override defaults */ if (dest->flags & PRINT_FLAG_UNSET_LINE_START) return NULL; if (dest->flags & PRINT_FLAG_SET_LINE_START) format = TXT_LINE_START; - else if (dest->flags & PRINT_FLAG_SET_LINE_START_IRSSI) + else if (dest->flags & PRINT_FLAG_SET_LINE_START_IRSSI) format = TXT_LINE_START_IRSSI; else { - /* use defaults */ + /* use defaults */ if (dest->level & LINE_START_IRSSI_LEVEL) format = TXT_LINE_START_IRSSI; else if ((dest->level & NOT_LINE_START_LEVEL) == 0) @@ -658,20 +661,20 @@ char *format_get_level_tag(THEME_REC *theme, TEXT_DEST_REC *dest) static char *get_timestamp(THEME_REC *theme, TEXT_DEST_REC *dest, time_t t) { - char *format, str[256]; + char *format, str[256]; struct tm *tm; int diff; if ((timestamp_level & dest->level) == 0) return NULL; - /* check for flags if we want to override defaults */ + /* check for flags if we want to override defaults */ if (dest->flags & PRINT_FLAG_UNSET_TIMESTAMP) return NULL; if ((dest->flags & PRINT_FLAG_SET_TIMESTAMP) == 0 && (dest->level & (MSGLEVEL_NEVER|MSGLEVEL_LASTLOG)) != 0) - return NULL; + return NULL; if (timestamp_timeout > 0) { @@ -685,7 +688,7 @@ static char *get_timestamp(THEME_REC *theme, TEXT_DEST_REC *dest, time_t t) format = format_get_text_theme(theme, MODULE_NAME, dest, TXT_TIMESTAMP); if (strftime(str, sizeof(str), format, tm) <= 0) - str[0] = '\0'; + str[0] = '\0'; g_free(format); return g_strdup(str); } @@ -695,9 +698,9 @@ static char *get_server_tag(THEME_REC *theme, TEXT_DEST_REC *dest) int count = 0; if (dest->server_tag == NULL || hide_server_tags) - return NULL; + return NULL; - /* check for flags if we want to override defaults */ + /* check for flags if we want to override defaults */ if (dest->flags & PRINT_FLAG_UNSET_SERVERTAG) return NULL; @@ -718,7 +721,7 @@ static char *get_server_tag(THEME_REC *theme, TEXT_DEST_REC *dest) } if (count < 2) - return NULL; + return NULL; } return format_get_text_theme(theme, MODULE_NAME, dest, @@ -842,7 +845,7 @@ static void get_mirc_color(const char **str, int *fg_ret, int *bg_ret) /* foreground color */ if (**str != ',') { fg = **str-'0'; - (*str)++; + (*str)++; if (i_isdigit(**str)) { fg = fg*10 + (**str-'0'); (*str)++; @@ -879,7 +882,7 @@ int strip_real_length(const char *str, int len, { const char *start = str; - if (last_color_pos != NULL) + if (last_color_pos != NULL) *last_color_pos = -1; if (last_color_len != NULL) *last_color_len = -1; @@ -890,25 +893,25 @@ int strip_real_length(const char *str, int len, if (last_color_pos != NULL) *last_color_pos = (int) (str-start); - str++; + str++; get_mirc_color(&str, NULL, NULL); - if (last_color_len != NULL) + if (last_color_len != NULL) *last_color_len = (int) (str-mircstart); } else if (*str == 4 && str[1] != '\0') { if (str[1] < FORMAT_STYLE_SPECIAL && str[2] != '\0') { if (last_color_pos != NULL) *last_color_pos = (int) (str-start); - if (last_color_len != NULL) - *last_color_len = 3; + if (last_color_len != NULL) + *last_color_len = 3; str++; } else if (str[1] == FORMAT_STYLE_DEFAULTS) { if (last_color_pos != NULL) *last_color_pos = (int) (str-start); - if (last_color_len != NULL) - *last_color_len = 2; + if (last_color_len != NULL) + *last_color_len = 2; } - str += 2; + str += 2; } else { if (!IS_COLOR_CODE(*str)) { if (len-- == 0) @@ -923,61 +926,61 @@ int strip_real_length(const char *str, int len, char *strip_codes(const char *input) { - const char *p; - char *str, *out; + const char *p; + char *str, *out; - out = str = g_strdup(input); - for (p = input; *p != '\0'; p++) { - if (*p == 3) { - p++; + out = str = g_strdup(input); + for (p = input; *p != '\0'; p++) { + if (*p == 3) { + p++; - /* mirc color */ - get_mirc_color(&p, NULL, NULL); - p--; - continue; - } + /* mirc color */ + get_mirc_color(&p, NULL, NULL); + p--; + continue; + } - if (*p == 4 && p[1] != '\0') { - if (p[1] >= FORMAT_STYLE_SPECIAL) { - p++; - continue; - } + if (*p == 4 && p[1] != '\0') { + if (p[1] >= FORMAT_STYLE_SPECIAL) { + p++; + continue; + } - /* irssi color */ - if (p[2] != '\0') { - p += 2; - continue; - } + /* irssi color */ + if (p[2] != '\0') { + p += 2; + continue; + } } if (*p == 27 && p[1] != '\0') { - p++; + p++; p = get_ansi_color(current_theme, p, NULL, NULL, NULL); p--; } else if (!IS_COLOR_CODE(*p)) - *out++ = *p; - } + *out++ = *p; + } - *out = '\0'; - return str; + *out = '\0'; + return str; } /* send a fully parsed text string for GUI to print */ void format_send_to_gui(TEXT_DEST_REC *dest, const char *text) { - THEME_REC *theme; + THEME_REC *theme; char *dup, *str, *ptr, type; int fgcolor, bgcolor; int flags; - theme = dest->window != NULL && dest->window->theme != NULL ? + theme = dest->window != NULL && dest->window->theme != NULL ? dest->window->theme : current_theme; dup = str = g_strdup(text); flags = 0; fgcolor = theme->default_color; bgcolor = -1; while (*str != '\0') { - type = '\0'; + type = '\0'; for (ptr = str; *ptr != '\0'; ptr++) { if (IS_COLOR_CODE(*ptr) || *ptr == '\n') { type = *ptr; @@ -991,14 +994,14 @@ void format_send_to_gui(TEXT_DEST_REC *dest, const char *text) if (type == 7) { /* bell */ if (settings_get_bool("bell_beeps")) - signal_emit("beep", 0); + signal_emit("beep", 0); } else if (type == 4 && *ptr == FORMAT_STYLE_CLRTOEOL) { - /* clear to end of line */ + /* clear to end of line */ flags |= GUI_PRINT_FLAG_CLRTOEOL; } if (*str != '\0' || (flags & GUI_PRINT_FLAG_CLRTOEOL)) { - /* send the text to gui handler */ + /* send the text to gui handler */ signal_emit_id(signal_gui_print_text, 6, dest->window, GINT_TO_POINTER(fgcolor), GINT_TO_POINTER(bgcolor), @@ -1055,7 +1058,7 @@ void format_send_to_gui(TEXT_DEST_REC *dest, const char *text) while (*ptr != ',' && *ptr != '\0') ptr++; if (*ptr != '\0') *ptr++ = '\0'; - ptr--; + ptr--; signal_emit_id(signal_gui_print_text, 6, dest->window, NULL, NULL, GINT_TO_POINTER(GUI_PRINT_FLAG_INDENT_FUNC), @@ -1063,12 +1066,12 @@ void format_send_to_gui(TEXT_DEST_REC *dest, const char *text) break; } case FORMAT_STYLE_DEFAULTS: - fgcolor = theme->default_color; + fgcolor = theme->default_color; bgcolor = -1; flags &= GUI_PRINT_FLAG_INDENT|GUI_PRINT_FLAG_MONOSPACE; break; case FORMAT_STYLE_CLRTOEOL: - break; + break; default: if (*ptr != FORMAT_COLOR_NOCHANGE) { fgcolor = (unsigned char) *ptr-'0'; @@ -1090,8 +1093,8 @@ void format_send_to_gui(TEXT_DEST_REC *dest, const char *text) flags &= ~GUI_PRINT_FLAG_BLINK; else { /* blink */ - bgcolor -= 8; - flags |= GUI_PRINT_FLAG_BLINK; + bgcolor -= 8; + flags |= GUI_PRINT_FLAG_BLINK; } } } diff --git a/src/fe-common/core/module-formats.c b/src/fe-common/core/module-formats.c index 2bd4c23d..6d13ed08 100644 --- a/src/fe-common/core/module-formats.c +++ b/src/fe-common/core/module-formats.c @@ -218,6 +218,7 @@ FORMAT_REC fecommon_core_formats[] = { { "invalid_time", "Invalid timestamp", 0 }, { "invalid_level", "Invalid message level", 0 }, { "invalid_size", "Invalid size", 0 }, + { "invalid_charset", "Invalid charset: $0", 1, { 0 } }, /* ---- */ { NULL, "Themes", 0 }, @@ -253,7 +254,6 @@ FORMAT_REC fecommon_core_formats[] = { { "conversion_added", "Added {hilight $0}/{hilight $1} to conversion database", 2, { FORMAT_STRING, FORMAT_STRING } }, { "conversion_removed", "Removed {hilight $0} from conversion database", 1, { FORMAT_STRING } }, { "conversion_not_found", "{hilight $0} not found in conversion database", 1, { FORMAT_STRING } }, - { "conversion_not_supported", "Conversion to the character set {hilight $0} is not supported",1, { FORMAT_STRING } }, { "recode_header", "%#Target Character set", 0 }, { "recode_line", "%#%|$[!30]0 $1", 2, { FORMAT_STRING, FORMAT_STRING } }, @@ -261,7 +261,7 @@ FORMAT_REC fecommon_core_formats[] = { { NULL, "Misc", 0 }, { "unknown_chat_protocol", "Unknown chat protocol: $0", 1, { 0 } }, - { "unknown_chatnet", "Unknown chat network: $0 (create it with /IRCNET ADD)", 1, { 0 } }, + { "unknown_chatnet", "Unknown chat network: $0 (create it with /NETWORK ADD)", 1, { 0 } }, { "not_toggle", "Value must be either ON, OFF or TOGGLE", 0 }, { "perl_error", "Perl error: $0", 1, { 0 } }, { "bind_header", "%#Key Action", 0 }, diff --git a/src/fe-common/core/module-formats.h b/src/fe-common/core/module-formats.h index 95465c33..ea9af5d2 100644 --- a/src/fe-common/core/module-formats.h +++ b/src/fe-common/core/module-formats.h @@ -187,6 +187,7 @@ enum { TXT_INVALID_TIME, TXT_INVALID_LEVEL, TXT_INVALID_SIZE, + TXT_INVALID_CHARSET, TXT_FILL_11, @@ -219,7 +220,6 @@ enum { TXT_CONVERSION_ADDED, TXT_CONVERSION_REMOVED, TXT_CONVERSION_NOT_FOUND, - TXT_CONVERSION_NOT_SUPPORTED, TXT_RECODE_HEADER, TXT_RECODE_LINE, diff --git a/src/fe-common/core/module.h b/src/fe-common/core/module.h index 203e3a30..51b61b3e 100644 --- a/src/fe-common/core/module.h +++ b/src/fe-common/core/module.h @@ -2,6 +2,7 @@ #define MODULE_NAME "fe-common/core" +typedef guint32 unichar; typedef struct { time_t time; char *nick; diff --git a/src/fe-common/core/printtext.c b/src/fe-common/core/printtext.c index e51da230..a3d34a22 100644 --- a/src/fe-common/core/printtext.c +++ b/src/fe-common/core/printtext.c @@ -23,7 +23,6 @@ #include "modules.h" #include "signals.h" #include "commands.h" -#include "recode.h" #include "settings.h" #include "levels.h" @@ -160,7 +159,7 @@ void printformat_module_gui(const char *module, int formatnum, ...) static void print_line(TEXT_DEST_REC *dest, const char *text) { THEME_REC *theme; - char *str, *recoded, *tmp, *stripped; + char *str, *tmp, *stripped; g_return_if_fail(dest != NULL); g_return_if_fail(text != NULL); @@ -171,15 +170,12 @@ static void print_line(TEXT_DEST_REC *dest, const char *text) format_add_lineend(text, tmp); g_free_not_null(tmp); - recoded = recode_in(str, dest->target); - /* send both the formatted + stripped (for logging etc.) */ - stripped = strip_codes(recoded); - signal_emit_id(signal_print_text, 3, dest, recoded, stripped); + stripped = strip_codes(str); + signal_emit_id(signal_print_text, 3, dest, str, stripped); g_free_and_null(dest->hilight_color); g_free(str); - g_free(recoded); g_free(stripped); } diff --git a/src/fe-common/core/utf8.c b/src/fe-common/core/utf8.c new file mode 100644 index 00000000..4049991d --- /dev/null +++ b/src/fe-common/core/utf8.c @@ -0,0 +1,251 @@ +/* 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. + * + * UTF-8 width tables based on locale data from GNU libc by + * + * Copyright (C) 1991-2002 Free Software Foundation, 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 Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "module.h" + +#define UTF8_COMPUTE(Char, Mask, Len) \ + if (Char < 128) \ + { \ + Len = 1; \ + Mask = 0x7f; \ + } \ + else if ((Char & 0xe0) == 0xc0) \ + { \ + Len = 2; \ + Mask = 0x1f; \ + } \ + else if ((Char & 0xf0) == 0xe0) \ + { \ + Len = 3; \ + Mask = 0x0f; \ + } \ + else if ((Char & 0xf8) == 0xf0) \ + { \ + Len = 4; \ + Mask = 0x07; \ + } \ + else if ((Char & 0xfc) == 0xf8) \ + { \ + Len = 5; \ + Mask = 0x03; \ + } \ + else if ((Char & 0xfe) == 0xfc) \ + { \ + Len = 6; \ + Mask = 0x01; \ + } \ + else \ + Len = -1; + +#define UTF8_GET(Result, Chars, Count, Mask, Len) \ + (Result) = (Chars)[0] & (Mask); \ + for ((Count) = 1; (Count) < (Len); ++(Count)) \ + { \ + if (((Chars)[(Count)] & 0xc0) != 0x80) \ + { \ + (Result) = -1; \ + break; \ + } \ + (Result) <<= 6; \ + (Result) |= ((Chars)[(Count)] & 0x3f); \ + } + +unichar get_utf8_char(const unsigned char **ptr, int len) +{ + int i, result, mask, chrlen; + + mask = 0; + UTF8_COMPUTE(**ptr, mask, chrlen); + if (chrlen == -1) + return (unichar) -2; + + if (chrlen > len) + return (unichar) -1; + + UTF8_GET(result, *ptr, i, mask, chrlen); + if (result == -1) + return (unichar) -2; + + *ptr += chrlen-1; + return result; +} + +int strlen_utf8(const char *str) +{ + const unsigned char *p = (const unsigned char *) str; + int len; + + len = 0; + while (*p != '\0' && get_utf8_char(&p, 6) > 0) { + len++; + p++; + } + return len; +} + +int utf16_char_to_utf8(unichar c, char *outbuf) +{ + int len, i, first; + + len = 0; + if (c < 0x80) { + first = 0; + len = 1; + } else if (c < 0x800) { + first = 0xc0; + len = 2; + } else if (c < 0x10000) { + first = 0xe0; + len = 3; + } else if (c < 0x200000) { + first = 0xf0; + len = 4; + } else if (c < 0x4000000) { + first = 0xf8; + len = 5; + } else { + first = 0xfc; + len = 6; + } + + if (outbuf) { + for (i = len - 1; i > 0; --i) { + outbuf[i] = (c & 0x3f) | 0x80; + c >>= 6; + } + outbuf[0] = c | first; + } + + return len; +} + +void utf8_to_utf16(const char *str, unichar *out) +{ + const unsigned char *p = (const unsigned char *) str; + int i, result, mask, len; + + while (*p != '\0') { + mask = 0; + UTF8_COMPUTE(*p, mask, len); + if (len == -1) + break; + + UTF8_GET(result, p, i, mask, len); + if (result == -1) + break; + + p += len; + *out++ = result; + } + + *out = '\0'; +} + +void utf16_to_utf8(const unichar *str, char *out) +{ + int len; + + while (*str != '\0') { + len = utf16_char_to_utf8(*str, out); + out += len; + + str++; + } + *out = '\0'; +} + +static const unichar wcc[] = { + 0x0, 0x300, 0x34F, 0x360, 0x363, 0x483, 0x487, 0x488, 0x48A, 0x591, + 0x5A2, 0x5A3, 0x5BA, 0x5BB, 0x5BE, 0x5BF, 0x5C0, 0x5C1, 0x5C3, 0x5C4, + 0x5C5, 0x64B, 0x656, 0x670, 0x671, 0x6D6, 0x6E5, 0x6E7, 0x6E9, 0x6EA, + 0x6EE, 0x70F, 0x710, 0x711, 0x712, 0x730, 0x74B, 0x7A6, 0x7B1, 0x901, + 0x903, 0x93C, 0x93D, 0x941, 0x949, 0x94D, 0x94E, 0x951, 0x955, 0x962, + 0x964, 0x981, 0x982, 0x9BC, 0x9BD, 0x9C1, 0x9C5, 0x9CD, 0x9CE, 0x9E2, + 0x9E4, 0xA02, 0xA03, 0xA3C, 0xA3D, 0xA41, 0xA43, 0xA47, 0xA49, 0xA4B, + 0xA4E, 0xA70, 0xA72, 0xA81, 0xA83, 0xABC, 0xABD, 0xAC1, 0xAC6, 0xAC7, + 0xAC9, 0xACD, 0xACE, 0xB01, 0xB02, 0xB3C, 0xB3D, 0xB3F, 0xB40, 0xB41, + 0xB44, 0xB4D, 0xB4E, 0xB56, 0xB57, 0xB82, 0xB83, 0xBC0, 0xBC1, 0xBCD, + 0xBCE, 0xC3E, 0xC41, 0xC46, 0xC49, 0xC4A, 0xC4E, 0xC55, 0xC57, 0xCBF, + 0xCC0, 0xCC6, 0xCC7, 0xCCC, 0xCCE, 0xD41, 0xD44, 0xD4D, 0xD4E, 0xDCA, + 0xDCB, 0xDD2, 0xDD5, 0xDD6, 0xDD7, 0xE31, 0xE32, 0xE34, 0xE3B, 0xE47, + 0xE4F, 0xEB1, 0xEB2, 0xEB4, 0xEBA, 0xEBB, 0xEBD, 0xEC8, 0xECE, 0xF18, + 0xF1A, 0xF35, 0xF36, 0xF37, 0xF38, 0xF39, 0xF3A, 0xF71, 0xF7F, 0xF80, + 0xF85, 0xF86, 0xF88, 0xF90, 0xF98, 0xF99, 0xFBD, 0xFC6, 0xFC7, 0x102D, + 0x1031, 0x1032, 0x1033, 0x1036, 0x1038, 0x1039, 0x103A, 0x1058, 0x105A, + 0x1100, 0x1160, 0x17B7, 0x17BE, 0x17C6, 0x17C7, 0x17C9, 0x17D4, 0x180B, + 0x180F, 0x18A9, 0x18AA, 0x200B, 0x2010, 0x202A, 0x202F, 0x206A, 0x2070, + 0x20D0, 0x20E4, 0x2E80, 0x3008, 0x300C, 0x3014, 0x3016, 0x3018, 0x301C, + 0x302A, 0x3030, 0x303F, 0x3041, 0x3095, 0x3099, 0x309B, 0xA4C7, 0xAC00, + 0xD7A4, 0xF8F0, 0xF900, 0xFA2E, 0xFB1E, 0xFB1F, 0xFE20, 0xFE24, 0xFE30, + 0xFE6C, 0xFEFF, 0xFF00, 0xFF01, 0xFF5F, 0xFFE0, 0xFFE7, 0xFFF9, 0xFFFC, +#if 1 + 0x1D167, 0x1D16A, 0x1D173, 0x1D183, 0x1D185, 0x1D18C, 0x1D1AA, 0x1D1AE, + 0x20000, 0x2A6D7, 0x2F800, 0x2FA1E, 0xE0001, 0xE0002, 0xE0020, 0xE0080 +#endif +}; + +static const int wccnum = sizeof(wcc) / sizeof(wcc[0]) - 1; + +static const char wws[] = { + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, + 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, + 1, 2, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 2, 1, 2, + 1, 2, 1, 2, 0, 2, 1, 2, 1, 0, 2, 1, 2, 1, 0, 2, 1, 0, 1, 0, 1, 2, 1, 0, + 1, 2, 1, 2, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 2, 1, 2, 1, 0, 1, 0, 1, -1 +}; + +int utf8_width(unichar c) +{ + int p, q, r; + unichar d; + + if (c < wcc[1]) + return 1; + + p = 0; + q = wccnum; + + while (p < q - 1) { + r = (p + q)/2; + d = wcc[r]; + if (d < c) + p = r; + else if (d > c) + q = r; + else + return wws[r]; + } + + return wws[p]; +} diff --git a/src/fe-common/core/utf8.h b/src/fe-common/core/utf8.h new file mode 100644 index 00000000..456c6bf8 --- /dev/null +++ b/src/fe-common/core/utf8.h @@ -0,0 +1,31 @@ +#ifndef __UTF8_H +#define __UTF8_H + +/* Returns -2 = invalid, -1 = need more data, otherwise unichar. */ +unichar get_utf8_char(const unsigned char **ptr, int len); + +/* Returns length of UTF8 string */ +int strlen_utf8(const char *str); + +/* UTF-8 -> unichar string. The NUL is copied as well. */ +void utf8_to_utf16(const char *str, unichar *out); + +/* unichar -> UTF-8 string. outbuf must be at least 6 chars long. + Returns outbuf string length. */ +int utf16_char_to_utf8(unichar c, char *outbuf); + +/* unichar -> UTF-8 string. The NUL is copied as well. + Make sure out is at least 6 x length of str. */ +void utf16_to_utf8(const unichar *str, char *out); + +/* 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 utf8_width(unichar c); + +#endif diff --git a/src/fe-common/irc/fe-events-numeric.c b/src/fe-common/irc/fe-events-numeric.c index 6dcf8eee..f67cd844 100644 --- a/src/fe-common/irc/fe-events-numeric.c +++ b/src/fe-common/irc/fe-events-numeric.c @@ -24,6 +24,7 @@ #include "misc.h" #include "settings.h" #include "levels.h" +#include "recode.h" #include "irc-servers.h" #include "irc-channels.h" @@ -228,15 +229,17 @@ static void event_nick_in_use(IRC_SERVER_REC *server, const char *data) static void event_topic_get(IRC_SERVER_REC *server, const char *data) { const char *channel; - char *params, *topic; + char *params, *topic, *recoded; g_return_if_fail(data != NULL); params = event_get_params(data, 3, NULL, &channel, &topic); + recoded = recode_in(topic, channel); channel = get_visible_target(server, channel); printformat(server, channel, MSGLEVEL_CRAP, - IRCTXT_TOPIC, channel, topic); + IRCTXT_TOPIC, channel, recoded); g_free(params); + g_free(recoded); } static void event_topic_info(IRC_SERVER_REC *server, const char *data) diff --git a/src/fe-common/irc/fe-events.c b/src/fe-common/irc/fe-events.c index 90be755e..6e157caa 100644 --- a/src/fe-common/irc/fe-events.c +++ b/src/fe-common/irc/fe-events.c @@ -30,6 +30,7 @@ #include "servers-reconnect.h" #include "queries.h" #include "ignore.h" +#include "recode.h" #include "irc-servers.h" #include "irc-channels.h" @@ -44,57 +45,63 @@ static void event_privmsg(IRC_SERVER_REC *server, const char *data, const char *nick, const char *addr) { - char *params, *target, *msg; + char *params, *target, *msg, *recoded; g_return_if_fail(data != NULL); params = event_get_params(data, 2 | PARAM_FLAG_GETREST, &target, &msg); if (nick == NULL) nick = server->real_address; if (addr == NULL) addr = ""; - + recoded = recode_in(msg, target); if (*target == '@' && ischannel(target[1])) { /* Hybrid 6 feature, send msg to all ops in channel */ signal_emit("message irc op_public", 5, - server, msg, nick, addr, + server, recoded, nick, addr, get_visible_target(server, target+1)); } else { signal_emit(ischannel(*target) ? "message public" : "message private", 5, - server, msg, nick, addr, + server, recoded, nick, addr, get_visible_target(server, target)); } g_free(params); + g_free(recoded); } static void ctcp_action(IRC_SERVER_REC *server, const char *data, const char *nick, const char *addr, const char *target) { - g_return_if_fail(data != NULL); + char *recoded; + g_return_if_fail(data != NULL); + recoded = recode_in(data, target); signal_emit("message irc action", 5, - server, data, nick, addr, + server, recoded, nick, addr, get_visible_target(server, target)); + g_free(recoded); } static void event_notice(IRC_SERVER_REC *server, const char *data, const char *nick, const char *addr) { - char *params, *target, *msg; + char *params, *target, *msg, *recoded; g_return_if_fail(data != NULL); params = event_get_params(data, 2 | PARAM_FLAG_GETREST, &target, &msg); + recoded = recode_in(msg, target); if (nick == NULL) { nick = server->real_address == NULL ? server->connrec->address : server->real_address; } - signal_emit("message irc notice", 5, server, msg, nick, addr, + signal_emit("message irc notice", 5, server, recoded, nick, addr, get_visible_target(server, target)); g_free(params); + g_free(recoded); } static void event_join(IRC_SERVER_REC *server, const char *data, @@ -116,15 +123,17 @@ static void event_join(IRC_SERVER_REC *server, const char *data, static void event_part(IRC_SERVER_REC *server, const char *data, const char *nick, const char *addr) { - char *params, *channel, *reason; + char *params, *channel, *reason, *recoded; g_return_if_fail(data != NULL); params = event_get_params(data, 2 | PARAM_FLAG_GETREST, &channel, &reason); + recoded = recode_in(reason, channel); signal_emit("message part", 5, server, - get_visible_target(server, channel), nick, addr, reason); + get_visible_target(server, channel), nick, addr, recoded); g_free(params); + g_free(recoded); } static void event_quit(IRC_SERVER_REC *server, const char *data, @@ -139,16 +148,18 @@ static void event_quit(IRC_SERVER_REC *server, const char *data, static void event_kick(IRC_SERVER_REC *server, const char *data, const char *kicker, const char *addr) { - char *params, *channel, *nick, *reason; + char *params, *channel, *nick, *reason, *recoded; g_return_if_fail(data != NULL); params = event_get_params(data, 3 | PARAM_FLAG_GETREST, &channel, &nick, &reason); + recoded = recode_in(reason, channel); signal_emit("message kick", 6, server, get_visible_target(server, channel), - nick, kicker, addr, reason); + nick, kicker, addr, recoded); g_free(params); + g_free(recoded); } static void event_kill(IRC_SERVER_REC *server, const char *data, @@ -244,15 +255,17 @@ static void event_invite(IRC_SERVER_REC *server, const char *data, static void event_topic(IRC_SERVER_REC *server, const char *data, const char *nick, const char *addr) { - char *params, *channel, *topic; + char *params, *channel, *topic, *recoded; g_return_if_fail(data != NULL); params = event_get_params(data, 2 | PARAM_FLAG_GETREST, &channel, &topic); + recoded = recode_in(topic, channel); signal_emit("message topic", 5, server, - get_visible_target(server, channel), topic, nick, addr); + get_visible_target(server, channel), recoded, nick, addr); g_free(params); + g_free(recoded); } static void event_error(IRC_SERVER_REC *server, const char *data) diff --git a/src/fe-text/Makefile.am b/src/fe-text/Makefile.am index 68bf7169..39d7a3a3 100644 --- a/src/fe-text/Makefile.am +++ b/src/fe-text/Makefile.am @@ -64,7 +64,6 @@ irssi_SOURCES = \ textbuffer-commands.c \ textbuffer-reformat.c \ textbuffer-view.c \ - utf8.c \ irssi.c \ module-formats.c @@ -81,7 +80,6 @@ noinst_HEADERS = \ textbuffer.h \ textbuffer-view.h \ textbuffer-reformat.h \ - utf8.h \ module.h \ module-formats.h diff --git a/src/fe-text/statusbar.c b/src/fe-text/statusbar.c index 0de19e00..5eba9557 100644 --- a/src/fe-text/statusbar.c +++ b/src/fe-text/statusbar.c @@ -21,7 +21,6 @@ #include "module.h" #include "signals.h" #include "expandos.h" -#include "recode.h" #include "special-vars.h" #include "themes.h" @@ -687,8 +686,6 @@ void statusbar_item_default_handler(SBAR_ITEM_REC *item, int get_size_only, SERVER_REC *server; WI_ITEM_REC *wiitem; char *tmpstr, *tmpstr2; - const char *target; - char *recoded; int len; if (str == NULL) @@ -727,11 +724,7 @@ void statusbar_item_default_handler(SBAR_ITEM_REC *item, int get_size_only, tmpstr2 = reverse_controls(tmpstr); g_free(tmpstr); - target = wiitem ? window_item_get_target(wiitem) : NULL; - recoded = recode_in(tmpstr2, target); - g_free(tmpstr2); - - tmpstr = recoded; + tmpstr = tmpstr2; if (get_size_only) { item->min_size = item->max_size = format_get_length(tmpstr); } else { diff --git a/src/fe-text/term.c b/src/fe-text/term.c index 5e62ce5d..59c3fe4d 100644 --- a/src/fe-text/term.c +++ b/src/fe-text/term.c @@ -152,7 +152,6 @@ void term_common_init(void) settings_add_bool("lookandfeel", "term_force_colors", FALSE); settings_add_bool("lookandfeel", "term_auto_detach", FALSE); settings_add_bool("lookandfeel", "mirc_blink_fix", FALSE); - settings_add_str("lookandfeel", "term_charset", "ISO8859-1"); force_colors = FALSE; term_use_colors = term_has_colors() && settings_get_bool("colors");