Created
March 20, 2011 19:31
-
-
Save pyropeter/878585 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #0 0x00007fc9b86cf655 in raise () from /lib/libc.so.6 | |
| #1 0x00007fc9b86d0ad6 in abort () from /lib/libc.so.6 | |
| #2 0x00007fc9b96f5131 in g_assertion_message () from /usr/lib/libglib-2.0.so.0 | |
| #3 0x00007fc9b96f56d0 in g_assertion_message_expr () | |
| from /usr/lib/libglib-2.0.so.0 | |
| #4 0x000000000048f22c in signal_unref_full (rec=0x10ce060, remove=1) | |
| at signals.c:64 | |
| #5 0x000000000048f4c5 in signal_emit_real (rec=0x10ce060, | |
| params=<value optimized out>, va=<value optimized out>, | |
| first_hook=<value optimized out>) at signals.c:287 | |
| #6 0x000000000048f91c in signal_emit (signal=<value optimized out>, params=4) | |
| at signals.c:304 | |
| #7 0x000000000045b16d in irc_server_event (server=0x11b54f0, | |
| line=0x11bb400 "PRIVMSG #pyropeter :foo", nick=0x11bb3d1 "PyroPeter", | |
| address=0x11bb3db "~pyropeter@unixboard/users/pyropeter") at irc.c:304 | |
| #8 0x000000000048f3f3 in signal_emit_real (rec=0x10d2250, | |
| params=<value optimized out>, va=<value optimized out>, | |
| first_hook=<value optimized out>) at signals.c:258 | |
| #9 0x000000000048fa07 in signal_emit_id (signal_id=<value optimized out>, | |
| params=4) at signals.c:322 | |
| #10 0x000000000048f3f3 in signal_emit_real (rec=0x10dd0d0, | |
| params=<value optimized out>, va=<value optimized out>, | |
| first_hook=<value optimized out>) at signals.c:258 | |
| #11 0x000000000048fa07 in signal_emit_id (signal_id=<value optimized out>, | |
| params=2) at signals.c:322 | |
| #12 0x000000000045b037 in irc_parse_incoming (server=0x11b54f0) at irc.c:379 | |
| #13 0x000000000048212f in irssi_io_invoke (source=<value optimized out>, | |
| condition=<value optimized out>, data=<value optimized out>) at misc.c:54 | |
| #14 0x00007fc9b96cfbf3 in g_main_context_dispatch () | |
| from /usr/lib/libglib-2.0.so.0 | |
| #15 0x00007fc9b96d03d0 in ?? () from /usr/lib/libglib-2.0.so.0 | |
| #16 0x00007fc9b96d066d in g_main_context_iteration () | |
| from /usr/lib/libglib-2.0.so.0 | |
| #17 0x000000000042c69c in main (argc=<value optimized out>, | |
| argv=0x7fff7e3d7e68) at irssi.c:356 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| .... | |
| sig_print_text() 8/<g gPyroPeterg8/>g efoo | |
| msglevel nohilight | |
| nohilight | |
| nickmatch | |
| msglevel hilight | |
| line | |
| sig_print_text() >/< PyroPeter> foo | |
| msglevel nohilight | |
| nohilight | |
| nickmatch | |
| II: 298, 2 | |
| signal_unref_full: gui print text, 2 | |
| II: 298, 2 | |
| signal_unref_full: gui print text, 2 | |
| II: 294, 3 | |
| signal_unref_full: gui print text finished, 3 | |
| II: 296, 6 | |
| signal_unref_full: print text, 6 | |
| return sig_print_text | |
| II: 296, 5 | |
| signal_unref_full: print text, 5 | |
| II: 25, 5 | |
| signal_unref_full: message public, 5 | |
| II: 8658432, 0 | |
| ** | |
| ERROR:signals.c:64:signal_unref_full: assertion failed: (rec->refcount > 0) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| sig_print_text() 8/<g gPyroPeterg8/>g efoo | |
| msglevel nohilight | |
| II: 298, 2 | |
| signal_unref_full: gui print text, 2 | |
| II: 298, 2 | |
| signal_unref_full: gui print text, 2 | |
| II: 298, 2 | |
| signal_unref_full: gui print text, 2 | |
| II: 298, 2 | |
| signal_unref_full: gui print text, 2 | |
| II: 298, 2 | |
| signal_unref_full: gui print text, 2 | |
| II: 298, 2 | |
| signal_unref_full: gui print text, 2 | |
| II: 298, 2 | |
| signal_unref_full: gui print text, 2 | |
| II: 294, 3 | |
| signal_unref_full: gui print text finished, 3 | |
| II: 296, 5 | |
| signal_unref_full: print text, 5 | |
| II: 25, 5 | |
| signal_unref_full: message public, 5 | |
| II: 38581648, 0 | |
| ** | |
| ERROR:signals.c:64:signal_unref_full: assertion failed: (rec->refcount > 0) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| fe-messages.c : irssi | |
| Copyright (C) 2000 Timo Sirainen | |
| This program is free software; you can redistribute it and/or modify | |
| it under the terms of the GNU General Public License as published by | |
| the Free Software Foundation; either version 2 of the License, or | |
| (at your option) any later version. | |
| This program 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 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" | |
| #include "module-formats.h" | |
| #include "signals.h" | |
| #include "commands.h" | |
| #include "levels.h" | |
| #include "misc.h" | |
| #include "special-vars.h" | |
| #include "settings.h" | |
| #include "servers.h" | |
| #include "channels.h" | |
| #include "nicklist.h" | |
| #include "ignore.h" | |
| #include "window-items.h" | |
| #include "fe-queries.h" | |
| #include "hilight-text.h" | |
| #include "printtext.h" | |
| #define ishighalnum(c) ((unsigned char) (c) >= 128 || i_isalnum(c)) | |
| #define isnickchar(a) \ | |
| (i_isalnum(a) || (a) == '`' || (a) == '-' || (a) == '_' || \ | |
| (a) == '[' || (a) == ']' || (a) == '{' || (a) == '}' || \ | |
| (a) == '|' || (a) == '\\' || (a) == '^') | |
| GHashTable *printnicks; | |
| /* convert _underlined_ and *bold* words (and phrases) to use real | |
| underlining or bolding */ | |
| char *expand_emphasis(WI_ITEM_REC *item, const char *text) | |
| { | |
| GString *str; | |
| char *ret; | |
| int pos; | |
| g_return_val_if_fail(text != NULL, NULL); | |
| str = g_string_new(text); | |
| for (pos = 0; pos < str->len; pos++) { | |
| char type, *bgn, *end; | |
| bgn = str->str + pos; | |
| if (*bgn == '*') | |
| type = 2; /* bold */ | |
| else if (*bgn == '_') | |
| type = 31; /* underlined */ | |
| else | |
| continue; | |
| /* check that the beginning marker starts a word, and | |
| that the matching end marker ends a word */ | |
| if ((pos > 0 && bgn[-1] != ' ') || !ishighalnum(bgn[1])) | |
| continue; | |
| if ((end = strchr(bgn+1, *bgn)) == NULL) | |
| continue; | |
| if (!ishighalnum(end[-1]) || ishighalnum(end[1]) || | |
| end[1] == type || end[1] == '*' || end[1] == '_') | |
| continue; | |
| if (IS_CHANNEL(item)) { | |
| /* check that this isn't a _nick_, we don't want to | |
| use emphasis on them. */ | |
| int found; | |
| char c; | |
| char *end2; | |
| /* check if _foo_ is a nick */ | |
| c = end[1]; | |
| end[1] = '\0'; | |
| found = nicklist_find(CHANNEL(item), bgn) != NULL; | |
| end[1] = c; | |
| if (found) continue; | |
| /* check if the whole 'word' (e.g. "_foo_^") is a nick | |
| in "_foo_^ ", end will be the second _, end2 the ^ */ | |
| end2 = end; | |
| while (isnickchar(end2[1])) | |
| end2++; | |
| c = end2[1]; | |
| end2[1] = '\0'; | |
| found = nicklist_find(CHANNEL(item), bgn) != NULL; | |
| end2[1] = c; | |
| if (found) continue; | |
| } | |
| /* allow only *word* emphasis, not *multiple words* */ | |
| if (!settings_get_bool("emphasis_multiword")) { | |
| char *c; | |
| for (c = bgn+1; c != end; c++) { | |
| if (!ishighalnum(*c)) | |
| break; | |
| } | |
| if (c != end) continue; | |
| } | |
| if (settings_get_bool("emphasis_replace")) { | |
| *bgn = *end = type; | |
| pos += (end-bgn); | |
| } else { | |
| g_string_insert_c(str, pos, type); | |
| pos += (end - bgn) + 2; | |
| g_string_insert_c(str, pos++, type); | |
| } | |
| } | |
| ret = str->str; | |
| g_string_free(str, FALSE); | |
| return ret; | |
| } | |
| static char *channel_get_nickmode_rec(NICK_REC *nickrec) | |
| { | |
| char *emptystr; | |
| char *nickmode; | |
| if (!settings_get_bool("show_nickmode")) | |
| return g_strdup(""); | |
| emptystr = settings_get_bool("show_nickmode_empty") ? " " : ""; | |
| if (nickrec == NULL || nickrec->prefixes[0] == '\0') | |
| nickmode = g_strdup(emptystr); | |
| else { | |
| nickmode = g_malloc(2); | |
| nickmode[0] = nickrec->prefixes[0]; | |
| nickmode[1] = '\0'; | |
| } | |
| return nickmode; | |
| } | |
| char *channel_get_nickmode(CHANNEL_REC *channel, const char *nick) | |
| { | |
| g_return_val_if_fail(nick != NULL, NULL); | |
| return channel_get_nickmode_rec(channel == NULL ? NULL : | |
| nicklist_find(channel, nick)); | |
| } | |
| static void sig_message_public(SERVER_REC *server, const char *msg, | |
| const char *nick, const char *address, | |
| const char *target, NICK_REC *nickrec) | |
| { | |
| CHANNEL_REC *chanrec; | |
| const char *printnick; | |
| int for_me, print_channel, level; | |
| char *nickmode, *color, *freemsg = NULL; | |
| HILIGHT_REC *hilight; | |
| level = MSGLEVEL_PUBLIC; | |
| /* NOTE: this may return NULL if some channel is just closed with | |
| /WINDOW CLOSE and server still sends the few last messages */ | |
| chanrec = channel_find(server, target); | |
| if (nickrec == NULL && chanrec != NULL) | |
| nickrec = nicklist_find(chanrec, nick); | |
| print_channel = chanrec == NULL || | |
| !window_item_is_active((WI_ITEM_REC *) chanrec); | |
| if (!print_channel && settings_get_bool("print_active_channel") && | |
| window_item_window((WI_ITEM_REC *) chanrec)->items->next != NULL) | |
| print_channel = TRUE; | |
| if (settings_get_bool("emphasis")) | |
| msg = freemsg = expand_emphasis((WI_ITEM_REC *) chanrec, msg); | |
| /* get nick mode & nick what to print the msg with | |
| (in case there's multiple identical nicks) */ | |
| nickmode = channel_get_nickmode_rec(nickrec); | |
| printnick = nickrec == NULL ? nick : | |
| g_hash_table_lookup(printnicks, nickrec); | |
| if (printnick == NULL) | |
| printnick = nick; | |
| int formatnum; | |
| TEXT_DEST_REC dest; | |
| format_create_dest(&dest, server, target, level, NULL); | |
| hilight = hilight_match_nick_or_mask(server, target, | |
| nick, address, MSGLEVEL_PUBLIC, msg); | |
| if (hilight != NULL) { | |
| // -nick or -mask | |
| hilight_update_text_dest(&dest, hilight); | |
| if (hilight->nick && !hilight->invert) { | |
| // hilight needs to be handled specially | |
| formatnum = print_channel ? TXT_PUBMSG_HILIGHT_CHANNEL : | |
| TXT_PUBMSG_HILIGHT; | |
| } else { | |
| dest.level ^= MSGLEVEL_HILIGHT; | |
| // hilight is handled by hilight-text.c, sig_print_text | |
| formatnum = print_channel ? TXT_PUBMSG_CHANNEL : | |
| TXT_PUBMSG; | |
| } | |
| } else { | |
| // check if message starts with own nick | |
| for_me = !settings_get_bool("hilight_nick_matches") ? FALSE : | |
| nick_match_msg(chanrec, msg, server->nick); | |
| if (for_me) | |
| dest.level |= MSGLEVEL_HILIGHT; | |
| if (for_me) | |
| formatnum = print_channel ? TXT_PUBMSG_ME_CHANNEL : | |
| TXT_PUBMSG_ME; | |
| else | |
| formatnum = print_channel ? TXT_PUBMSG_CHANNEL : | |
| TXT_PUBMSG; | |
| } | |
| // check if format needs an additional 'color' parameter | |
| if (formatnum == TXT_PUBMSG_HILIGHT_CHANNEL | |
| || formatnum == TXT_PUBMSG_HILIGHT) { | |
| color = hilight_get_color(hilight); | |
| printformat_dest(&dest, formatnum, color, printnick, | |
| msg, nickmode); | |
| } else { | |
| printformat_dest(&dest, formatnum, printnick, | |
| msg, nickmode); | |
| } | |
| g_free_not_null(nickmode); | |
| g_free_not_null(freemsg); | |
| g_free_not_null(color); | |
| } | |
| static void sig_message_private(SERVER_REC *server, const char *msg, | |
| const char *nick, const char *address) | |
| { | |
| QUERY_REC *query; | |
| char *freemsg = NULL; | |
| query = query_find(server, nick); | |
| if (settings_get_bool("emphasis")) | |
| msg = freemsg = expand_emphasis((WI_ITEM_REC *) query, msg); | |
| printformat(server, nick, MSGLEVEL_MSGS, | |
| query == NULL ? TXT_MSG_PRIVATE : | |
| TXT_MSG_PRIVATE_QUERY, nick, address, msg); | |
| g_free_not_null(freemsg); | |
| } | |
| static void sig_message_own_public(SERVER_REC *server, const char *msg, | |
| const char *target) | |
| { | |
| WINDOW_REC *window; | |
| CHANNEL_REC *channel; | |
| char *nickmode; | |
| char *freemsg = NULL; | |
| int print_channel; | |
| channel = channel_find(server, target); | |
| if (channel != NULL) | |
| target = channel->visible_name; | |
| nickmode = channel_get_nickmode(channel, server->nick); | |
| window = channel == NULL ? NULL : | |
| window_item_window((WI_ITEM_REC *) channel); | |
| print_channel = window == NULL || | |
| window->active != (WI_ITEM_REC *) channel; | |
| if (!print_channel && settings_get_bool("print_active_channel") && | |
| window != NULL && g_slist_length(window->items) > 1) | |
| print_channel = TRUE; | |
| if (settings_get_bool("emphasis")) | |
| msg = freemsg = expand_emphasis((WI_ITEM_REC *) channel, msg); | |
| if (!print_channel) { | |
| printformat(server, target, MSGLEVEL_PUBLIC | MSGLEVEL_NOHILIGHT | MSGLEVEL_NO_ACT, | |
| TXT_OWN_MSG, server->nick, msg, nickmode); | |
| } else { | |
| printformat(server, target, MSGLEVEL_PUBLIC | MSGLEVEL_NOHILIGHT | MSGLEVEL_NO_ACT, | |
| TXT_OWN_MSG_CHANNEL, server->nick, target, msg, nickmode); | |
| } | |
| g_free_not_null(nickmode); | |
| g_free_not_null(freemsg); | |
| } | |
| static void sig_message_own_private(SERVER_REC *server, const char *msg, | |
| const char *target, const char *origtarget) | |
| { | |
| QUERY_REC *query; | |
| char *freemsg = NULL; | |
| g_return_if_fail(server != NULL); | |
| g_return_if_fail(msg != NULL); | |
| if (target == NULL) { | |
| /* this should only happen if some special target failed and | |
| we should display some error message. currently the special | |
| targets are only ',' and '.'. */ | |
| g_return_if_fail(strcmp(origtarget, ",") == 0 || | |
| strcmp(origtarget, ".") == 0); | |
| printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, | |
| *origtarget == ',' ? TXT_NO_MSGS_GOT : | |
| TXT_NO_MSGS_SENT); | |
| signal_stop(); | |
| return; | |
| } | |
| query = privmsg_get_query(server, target, TRUE, MSGLEVEL_MSGS); | |
| if (settings_get_bool("emphasis")) | |
| msg = freemsg = expand_emphasis((WI_ITEM_REC *) query, msg); | |
| printformat(server, target, | |
| MSGLEVEL_MSGS | MSGLEVEL_NOHILIGHT | MSGLEVEL_NO_ACT, | |
| query == NULL ? TXT_OWN_MSG_PRIVATE : | |
| TXT_OWN_MSG_PRIVATE_QUERY, target, msg, server->nick); | |
| g_free_not_null(freemsg); | |
| } | |
| static void sig_message_join(SERVER_REC *server, const char *channel, | |
| const char *nick, const char *address) | |
| { | |
| printformat(server, channel, MSGLEVEL_JOINS, | |
| TXT_JOIN, nick, address, channel); | |
| } | |
| static void sig_message_part(SERVER_REC *server, const char *channel, | |
| const char *nick, const char *address, | |
| const char *reason) | |
| { | |
| printformat(server, channel, MSGLEVEL_PARTS, | |
| TXT_PART, nick, address, channel, reason); | |
| } | |
| static void sig_message_quit(SERVER_REC *server, const char *nick, | |
| const char *address, const char *reason) | |
| { | |
| WINDOW_REC *window; | |
| GString *chans; | |
| GSList *tmp, *windows; | |
| char *print_channel; | |
| int once, count; | |
| if (ignore_check(server, nick, address, NULL, reason, MSGLEVEL_QUITS)) | |
| return; | |
| print_channel = NULL; | |
| once = settings_get_bool("show_quit_once"); | |
| count = 0; windows = NULL; | |
| chans = g_string_new(NULL); | |
| for (tmp = server->channels; tmp != NULL; tmp = tmp->next) { | |
| CHANNEL_REC *rec = tmp->data; | |
| if (!nicklist_find(rec, nick)) | |
| continue; | |
| if (ignore_check(server, nick, address, rec->visible_name, | |
| reason, MSGLEVEL_QUITS)) { | |
| count++; | |
| continue; | |
| } | |
| if (print_channel == NULL || | |
| active_win->active == (WI_ITEM_REC *) rec) | |
| print_channel = rec->visible_name; | |
| if (once) | |
| g_string_append_printf(chans, "%s,", rec->visible_name); | |
| else { | |
| window = window_item_window((WI_ITEM_REC *) rec); | |
| if (g_slist_find(windows, window) == NULL) { | |
| windows = g_slist_append(windows, window); | |
| printformat(server, rec->visible_name, | |
| MSGLEVEL_QUITS, | |
| TXT_QUIT, nick, address, reason, | |
| rec->visible_name); | |
| } | |
| } | |
| count++; | |
| } | |
| g_slist_free(windows); | |
| if (!once) { | |
| /* check if you had query with the nick and | |
| display the quit there too */ | |
| QUERY_REC *query = query_find(server, nick); | |
| if (query != NULL) { | |
| printformat(server, nick, MSGLEVEL_QUITS, | |
| TXT_QUIT, nick, address, reason, ""); | |
| } | |
| } | |
| if (once || count == 0) { | |
| if (chans->len > 0) | |
| g_string_truncate(chans, chans->len-1); | |
| printformat(server, print_channel, MSGLEVEL_QUITS, | |
| count <= 1 ? TXT_QUIT : TXT_QUIT_ONCE, | |
| nick, address, reason, chans->str); | |
| } | |
| g_string_free(chans, TRUE); | |
| } | |
| static void sig_message_kick(SERVER_REC *server, const char *channel, | |
| const char *nick, const char *kicker, | |
| const char *address, const char *reason) | |
| { | |
| printformat(server, channel, MSGLEVEL_KICKS, | |
| TXT_KICK, nick, channel, kicker, reason, address); | |
| } | |
| static void print_nick_change_channel(SERVER_REC *server, const char *channel, | |
| const char *newnick, const char *oldnick, | |
| const char *address, | |
| int ownnick) | |
| { | |
| int level; | |
| if (ignore_check(server, oldnick, address, | |
| channel, newnick, MSGLEVEL_NICKS)) | |
| return; | |
| level = MSGLEVEL_NICKS; | |
| if (ownnick) level |= MSGLEVEL_NO_ACT; | |
| printformat(server, channel, level, | |
| ownnick ? TXT_YOUR_NICK_CHANGED : TXT_NICK_CHANGED, | |
| oldnick, newnick, channel, address); | |
| } | |
| static void print_nick_change(SERVER_REC *server, const char *newnick, | |
| const char *oldnick, const char *address, | |
| int ownnick) | |
| { | |
| GSList *tmp, *windows; | |
| int msgprint; | |
| msgprint = FALSE; | |
| /* Print to each channel where the nick is. | |
| Don't print more than once to the same window. */ | |
| windows = NULL; | |
| for (tmp = server->channels; tmp != NULL; tmp = tmp->next) { | |
| CHANNEL_REC *channel = tmp->data; | |
| WINDOW_REC *window = | |
| window_item_window((WI_ITEM_REC *) channel); | |
| if (nicklist_find(channel, newnick) == NULL || | |
| g_slist_find(windows, window) != NULL) | |
| continue; | |
| windows = g_slist_append(windows, window); | |
| print_nick_change_channel(server, channel->visible_name, | |
| newnick, oldnick, address, ownnick); | |
| msgprint = TRUE; | |
| } | |
| g_slist_free(windows); | |
| if (!msgprint && ownnick) { | |
| printformat(server, NULL, MSGLEVEL_NICKS, | |
| TXT_YOUR_NICK_CHANGED, oldnick, newnick, "", | |
| address); | |
| } | |
| } | |
| static void sig_message_nick(SERVER_REC *server, const char *newnick, | |
| const char *oldnick, const char *address) | |
| { | |
| print_nick_change(server, newnick, oldnick, address, FALSE); | |
| } | |
| static void sig_message_own_nick(SERVER_REC *server, const char *newnick, | |
| const char *oldnick, const char *address) | |
| { | |
| if (!settings_get_bool("show_own_nickchange_once")) | |
| print_nick_change(server, newnick, oldnick, address, TRUE); | |
| else { | |
| printformat(server, NULL, MSGLEVEL_NICKS, | |
| TXT_YOUR_NICK_CHANGED, oldnick, newnick, "", | |
| address); | |
| } | |
| } | |
| static void sig_message_invite(SERVER_REC *server, const char *channel, | |
| const char *nick, const char *address) | |
| { | |
| char *str; | |
| str = show_lowascii(channel); | |
| printformat(server, NULL, MSGLEVEL_INVITES, | |
| TXT_INVITE, nick, str, address); | |
| g_free(str); | |
| } | |
| static void sig_message_topic(SERVER_REC *server, const char *channel, | |
| const char *topic, | |
| const char *nick, const char *address) | |
| { | |
| printformat(server, channel, MSGLEVEL_TOPICS, | |
| *topic != '\0' ? TXT_NEW_TOPIC : TXT_TOPIC_UNSET, | |
| nick, channel, topic, address); | |
| } | |
| static int printnick_exists(NICK_REC *first, NICK_REC *ignore, | |
| const char *nick) | |
| { | |
| char *printnick; | |
| while (first != NULL) { | |
| if (first != ignore) { | |
| printnick = g_hash_table_lookup(printnicks, first); | |
| if (printnick != NULL && strcmp(printnick, nick) == 0) | |
| return TRUE; | |
| } | |
| first = first->next; | |
| } | |
| return FALSE; | |
| } | |
| static NICK_REC *printnick_find_original(NICK_REC *nick) | |
| { | |
| while (nick != NULL) { | |
| if (g_hash_table_lookup(printnicks, nick) == NULL) | |
| return nick; | |
| nick = nick->next; | |
| } | |
| return NULL; | |
| } | |
| static void sig_nicklist_new(CHANNEL_REC *channel, NICK_REC *nick) | |
| { | |
| NICK_REC *firstnick; | |
| GString *newnick; | |
| char *nickhost, *p; | |
| int n; | |
| if (nick->host == NULL) | |
| return; | |
| firstnick = g_hash_table_lookup(channel->nicks, nick->nick); | |
| if (firstnick->next == NULL) | |
| return; | |
| if (nick == channel->ownnick) { | |
| /* own nick is being added, might be a nick change and | |
| someone else having the original nick already in use.. */ | |
| nick = printnick_find_original(firstnick->next); | |
| if (nick == NULL) | |
| return; /* nope, we have it */ | |
| } | |
| /* identical nick already exists, have to change it somehow.. */ | |
| p = strchr(nick->host, '@'); | |
| if (p == NULL) p = nick->host; else p++; | |
| nickhost = g_strdup_printf("%s@%s", nick->nick, p); | |
| p = strchr(nickhost+strlen(nick->nick), '.'); | |
| if (p != NULL) *p = '\0'; | |
| if (!printnick_exists(firstnick, nick, nickhost)) { | |
| /* use nick@host */ | |
| g_hash_table_insert(printnicks, nick, nickhost); | |
| return; | |
| } | |
| newnick = g_string_new(NULL); | |
| n = 2; | |
| do { | |
| g_string_printf(newnick, "%s%d", nickhost, n); | |
| n++; | |
| } while (printnick_exists(firstnick, nick, newnick->str)); | |
| g_hash_table_insert(printnicks, nick, newnick->str); | |
| g_string_free(newnick, FALSE); | |
| g_free(nickhost); | |
| } | |
| static void sig_nicklist_remove(CHANNEL_REC *channel, NICK_REC *nick) | |
| { | |
| char *nickname; | |
| nickname = g_hash_table_lookup(printnicks, nick); | |
| if (nickname != NULL) { | |
| g_free(nickname); | |
| g_hash_table_remove(printnicks, nick); | |
| } | |
| } | |
| static void sig_nicklist_changed(CHANNEL_REC *channel, NICK_REC *nick) | |
| { | |
| sig_nicklist_remove(channel, nick); | |
| sig_nicklist_new(channel, nick); | |
| } | |
| static void sig_channel_joined(CHANNEL_REC *channel) | |
| { | |
| NICK_REC *nick; | |
| char *nickname; | |
| /* channel->ownnick is set at this point - check if our own nick | |
| has been changed, if it was set it back to the original nick and | |
| change the previous original to something else */ | |
| nickname = g_hash_table_lookup(printnicks, channel->ownnick); | |
| if (nickname == NULL) | |
| return; | |
| g_free(nickname); | |
| g_hash_table_remove(printnicks, channel->ownnick); | |
| /* our own nick is guaranteed to be the first in list */ | |
| nick = channel->ownnick->next; | |
| while (nick != NULL) { | |
| if (g_hash_table_lookup(printnicks, nick) == NULL) { | |
| sig_nicklist_new(channel, nick); | |
| break; | |
| } | |
| nick = nick->next; | |
| } | |
| } | |
| static void g_hash_free_value(void *key, void *value) | |
| { | |
| g_free(value); | |
| } | |
| void fe_messages_init(void) | |
| { | |
| printnicks = g_hash_table_new((GHashFunc) g_direct_hash, | |
| (GCompareFunc) g_direct_equal); | |
| settings_add_bool("lookandfeel", "hilight_nick_matches", TRUE); | |
| settings_add_bool("lookandfeel", "emphasis", TRUE); | |
| settings_add_bool("lookandfeel", "emphasis_replace", FALSE); | |
| settings_add_bool("lookandfeel", "emphasis_multiword", FALSE); | |
| settings_add_bool("lookandfeel", "show_nickmode", TRUE); | |
| settings_add_bool("lookandfeel", "show_nickmode_empty", TRUE); | |
| settings_add_bool("lookandfeel", "print_active_channel", FALSE); | |
| settings_add_bool("lookandfeel", "show_quit_once", FALSE); | |
| settings_add_bool("lookandfeel", "show_own_nickchange_once", FALSE); | |
| signal_add_last("message public", (SIGNAL_FUNC) sig_message_public); | |
| signal_add_last("message private", (SIGNAL_FUNC) sig_message_private); | |
| signal_add_last("message own_public", (SIGNAL_FUNC) sig_message_own_public); | |
| signal_add_last("message own_private", (SIGNAL_FUNC) sig_message_own_private); | |
| signal_add_last("message join", (SIGNAL_FUNC) sig_message_join); | |
| signal_add_last("message part", (SIGNAL_FUNC) sig_message_part); | |
| signal_add_last("message quit", (SIGNAL_FUNC) sig_message_quit); | |
| signal_add_last("message kick", (SIGNAL_FUNC) sig_message_kick); | |
| signal_add_last("message nick", (SIGNAL_FUNC) sig_message_nick); | |
| signal_add_last("message own_nick", (SIGNAL_FUNC) sig_message_own_nick); | |
| signal_add_last("message invite", (SIGNAL_FUNC) sig_message_invite); | |
| signal_add_last("message topic", (SIGNAL_FUNC) sig_message_topic); | |
| signal_add("nicklist new", (SIGNAL_FUNC) sig_nicklist_new); | |
| signal_add("nicklist remove", (SIGNAL_FUNC) sig_nicklist_remove); | |
| signal_add("nicklist changed", (SIGNAL_FUNC) sig_nicklist_changed); | |
| signal_add("nicklist host changed", (SIGNAL_FUNC) sig_nicklist_new); | |
| signal_add("channel joined", (SIGNAL_FUNC) sig_channel_joined); | |
| } | |
| void fe_messages_deinit(void) | |
| { | |
| g_hash_table_foreach(printnicks, (GHFunc) g_hash_free_value, NULL); | |
| g_hash_table_destroy(printnicks); | |
| signal_remove("message public", (SIGNAL_FUNC) sig_message_public); | |
| signal_remove("message private", (SIGNAL_FUNC) sig_message_private); | |
| signal_remove("message own_public", (SIGNAL_FUNC) sig_message_own_public); | |
| signal_remove("message own_private", (SIGNAL_FUNC) sig_message_own_private); | |
| signal_remove("message join", (SIGNAL_FUNC) sig_message_join); | |
| signal_remove("message part", (SIGNAL_FUNC) sig_message_part); | |
| signal_remove("message quit", (SIGNAL_FUNC) sig_message_quit); | |
| signal_remove("message kick", (SIGNAL_FUNC) sig_message_kick); | |
| signal_remove("message nick", (SIGNAL_FUNC) sig_message_nick); | |
| signal_remove("message own_nick", (SIGNAL_FUNC) sig_message_own_nick); | |
| signal_remove("message invite", (SIGNAL_FUNC) sig_message_invite); | |
| signal_remove("message topic", (SIGNAL_FUNC) sig_message_topic); | |
| signal_remove("nicklist new", (SIGNAL_FUNC) sig_nicklist_new); | |
| signal_remove("nicklist remove", (SIGNAL_FUNC) sig_nicklist_remove); | |
| signal_remove("nicklist changed", (SIGNAL_FUNC) sig_nicklist_changed); | |
| signal_remove("nicklist host changed", (SIGNAL_FUNC) sig_nicklist_new); | |
| signal_remove("channel joined", (SIGNAL_FUNC) sig_channel_joined); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| hilight-text.c : irssi | |
| Copyright (C) 1999-2000 Timo Sirainen | |
| This program is free software; you can redistribute it and/or modify | |
| it under the terms of the GNU General Public License as published by | |
| the Free Software Foundation; either version 2 of the License, or | |
| (at your option) any later version. | |
| This program 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 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" | |
| #include "module-formats.h" | |
| #include "signals.h" | |
| #include "commands.h" | |
| #include "levels.h" | |
| #include "misc.h" | |
| #include "lib-config/iconfig.h" | |
| #include "settings.h" | |
| #include "servers.h" | |
| #include "channels.h" | |
| #include "nicklist.h" | |
| #include "hilight-text.h" | |
| #include "nickmatch-cache.h" | |
| #include "printtext.h" | |
| #include "formats.h" | |
| // peter likes printf | |
| #include <stdio.h> | |
| #define PYRO(...) \ | |
| ({ fprintf(stderr, __VA_ARGS__); \ | |
| fflush(stderr); }) | |
| static NICKMATCH_REC *nickmatch; | |
| static int never_hilight_level, default_hilight_level; | |
| GSList *hilights; | |
| static void reset_level_cache(void) | |
| { | |
| GSList *tmp; | |
| never_hilight_level = MSGLEVEL_ALL & ~default_hilight_level; | |
| for (tmp = hilights; tmp != NULL; tmp = tmp->next) { | |
| HILIGHT_REC *rec = tmp->data; | |
| if (never_hilight_level & rec->level) | |
| never_hilight_level &= ~rec->level; | |
| } | |
| } | |
| static void reset_cache(void) | |
| { | |
| reset_level_cache(); | |
| nickmatch_rebuild(nickmatch); | |
| } | |
| static void hilight_add_config(HILIGHT_REC *rec) | |
| { | |
| CONFIG_NODE *node; | |
| g_return_if_fail(rec != NULL); | |
| node = iconfig_node_traverse("(hilights", TRUE); | |
| node = config_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->invert) iconfig_node_set_bool(node, "invert", TRUE); | |
| if (rec->channels != NULL && *rec->channels != NULL) { | |
| node = config_node_section(node, "channels", NODE_TYPE_LIST); | |
| iconfig_node_add_list(node, rec->channels); | |
| } | |
| } | |
| static void hilight_remove_config(HILIGHT_REC *rec) | |
| { | |
| CONFIG_NODE *node; | |
| g_return_if_fail(rec != NULL); | |
| node = iconfig_node_traverse("hilights", FALSE); | |
| if (node != NULL) iconfig_node_list_remove(node, g_slist_index(hilights, rec)); | |
| } | |
| static void hilight_destroy(HILIGHT_REC *rec) | |
| { | |
| g_return_if_fail(rec != NULL); | |
| #ifdef HAVE_REGEX_H | |
| if (rec->regexp_compiled) regfree(&rec->preg); | |
| #endif | |
| if (rec->channels != NULL) g_strfreev(rec->channels); | |
| g_free_not_null(rec->color); | |
| g_free_not_null(rec->act_color); | |
| g_free(rec->text); | |
| g_free(rec); | |
| } | |
| static void hilights_destroy_all(void) | |
| { | |
| g_slist_foreach(hilights, (GFunc) hilight_destroy, NULL); | |
| g_slist_free(hilights); | |
| hilights = NULL; | |
| } | |
| 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; | |
| #endif | |
| } | |
| void hilight_create(HILIGHT_REC *rec) | |
| { | |
| if (g_slist_find(hilights, rec) != NULL) { | |
| hilight_remove_config(rec); | |
| hilights = g_slist_remove(hilights, rec); | |
| } | |
| hilights = g_slist_append(hilights, rec); | |
| hilight_add_config(rec); | |
| hilight_init_rec(rec); | |
| signal_emit("hilight created", 1, rec); | |
| } | |
| void hilight_remove(HILIGHT_REC *rec) | |
| { | |
| g_return_if_fail(rec != NULL); | |
| hilight_remove_config(rec); | |
| hilights = g_slist_remove(hilights, rec); | |
| signal_emit("hilight destroyed", 1, rec); | |
| hilight_destroy(rec); | |
| } | |
| static HILIGHT_REC *hilight_find(const char *text, char **channels) | |
| { | |
| GSList *tmp; | |
| char **chan; | |
| g_return_val_if_fail(text != NULL, NULL); | |
| for (tmp = hilights; tmp != NULL; tmp = tmp->next) { | |
| HILIGHT_REC *rec = tmp->data; | |
| if (g_strcasecmp(rec->text, text) != 0) | |
| continue; | |
| if ((channels == NULL && rec->channels == NULL)) | |
| return rec; /* no channels - ok */ | |
| if (channels != NULL && strcmp(*channels, "*") == 0) | |
| return rec; /* ignore channels */ | |
| if (channels == NULL || rec->channels == NULL) | |
| continue; /* other doesn't have channels */ | |
| if (strarray_length(channels) != strarray_length(rec->channels)) | |
| continue; /* different amount of channels */ | |
| /* check that channels match */ | |
| for (chan = channels; *chan != NULL; chan++) { | |
| if (strarray_find(rec->channels, *chan) == -1) | |
| break; | |
| } | |
| if (*chan == NULL) | |
| return rec; /* channels ok */ | |
| } | |
| return NULL; | |
| } | |
| static int hilight_match_text(HILIGHT_REC *rec, const char *text, | |
| int *match_beg, int *match_end) | |
| { | |
| char *match; | |
| if (rec->regexp) { | |
| #ifdef HAVE_REGEX_H | |
| regmatch_t rmatch[1]; | |
| if (rec->regexp_compiled && | |
| regexec(&rec->preg, text, 1, rmatch, 0) == 0) { | |
| if (rmatch[0].rm_so > 0 && | |
| match_beg != NULL && match_end != NULL) { | |
| *match_beg = rmatch[0].rm_so; | |
| *match_end = rmatch[0].rm_eo; | |
| } | |
| return TRUE; | |
| } | |
| #endif | |
| } 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); | |
| *match_end = *match_beg + strlen(rec->text); | |
| } | |
| return TRUE; | |
| } | |
| } | |
| return FALSE; | |
| } | |
| #define hilight_match_level(rec, level) \ | |
| (level & (((rec)->level != 0 ? rec->level : default_hilight_level))) | |
| #define hilight_match_channel(rec, channel) \ | |
| ((rec)->channels == NULL || ((channel) != NULL && \ | |
| strarray_find((rec)->channels, (channel)) != -1)) | |
| HILIGHT_REC *hilight_match(SERVER_REC *server, const char *channel, | |
| const char *nick, const char *address, | |
| int level, const char *str, | |
| int *match_beg, int *match_end) | |
| { | |
| GSList *tmp; | |
| CHANNEL_REC *chanrec; | |
| NICK_REC *nickrec; | |
| g_return_val_if_fail(str != NULL, NULL); | |
| if ((never_hilight_level & level) == level) | |
| return NULL; | |
| if (nick != NULL) { | |
| /* check nick mask hilights */ | |
| chanrec = channel_find(server, channel); | |
| nickrec = chanrec == NULL ? NULL : | |
| nicklist_find(chanrec, nick); | |
| if (nickrec != NULL) { | |
| HILIGHT_REC *rec; | |
| if (nickrec->host == NULL) | |
| nicklist_set_host(chanrec, nickrec, address); | |
| rec = nickmatch_find(nickmatch, nickrec); | |
| if (rec != NULL && hilight_match_level(rec, level)) | |
| return rec; | |
| } | |
| } | |
| for (tmp = hilights; tmp != NULL; tmp = tmp->next) { | |
| HILIGHT_REC *rec = tmp->data; | |
| if (!rec->nickmask && hilight_match_level(rec, level) && | |
| hilight_match_channel(rec, channel) && | |
| hilight_match_text(rec, str, match_beg, match_end)) | |
| return rec; | |
| } | |
| return NULL; | |
| } | |
| static char *hilight_get_act_color(HILIGHT_REC *rec) | |
| { | |
| g_return_val_if_fail(rec != NULL, NULL); | |
| return g_strdup(rec->act_color != NULL ? rec->act_color : | |
| rec->color != NULL ? rec->color : | |
| settings_get_str("hilight_act_color")); | |
| } | |
| char *hilight_get_color(HILIGHT_REC *rec) | |
| { | |
| const char *color; | |
| g_return_val_if_fail(rec != NULL, NULL); | |
| color = rec->color != NULL ? rec->color : | |
| settings_get_str("hilight_color"); | |
| return format_string_expand(color, NULL); | |
| } | |
| void hilight_update_text_dest(TEXT_DEST_REC *dest, HILIGHT_REC *rec) | |
| { | |
| dest->level |= MSGLEVEL_HILIGHT; | |
| dest->hilight = rec; | |
| if (rec->priority > 0) | |
| dest->hilight_priority = rec->priority; | |
| g_free_and_null(dest->hilight_color); | |
| if (rec->act_color != NULL && strcmp(rec->act_color, "%n") == 0) | |
| dest->level |= MSGLEVEL_NO_ACT; | |
| else | |
| dest->hilight_color = hilight_get_act_color(rec); | |
| } | |
| static void hilight_print(int index, HILIGHT_REC *rec); | |
| static void sig_print_text(TEXT_DEST_REC *dest, const char *text, | |
| const char *stripped) | |
| { | |
| HILIGHT_REC *hilight; | |
| char *color, *newstr; | |
| int old_level, hilight_start, hilight_end, hilight_len; | |
| int nick_match; | |
| PYRO("sig_print_text() %s\n", text); | |
| if (dest->level & MSGLEVEL_NOHILIGHT) | |
| return; | |
| PYRO("msglevel nohilight\n"); | |
| hilight_start = hilight_end = 0; | |
| hilight = (dest->hilight != NULL) ? dest->hilight : hilight_match( | |
| dest->server, dest->target, | |
| NULL, NULL, dest->level, stripped, | |
| &hilight_start, | |
| &hilight_end); | |
| if (hilight == NULL) | |
| return; | |
| PYRO("nohilight\n"); | |
| nick_match = hilight->nick && (dest->level & (MSGLEVEL_PUBLIC|MSGLEVEL_ACTIONS)) == MSGLEVEL_PUBLIC; | |
| old_level = dest->level; | |
| if (!nick_match || (dest->level & MSGLEVEL_HILIGHT)) { | |
| /* update the level / hilight info */ | |
| hilight_update_text_dest(dest, hilight); | |
| } | |
| if (nick_match) | |
| return; /* fe-messages.c should have taken care of this */ | |
| PYRO("nickmatch\n"); | |
| if (old_level & MSGLEVEL_HILIGHT) { | |
| /* nick is highlighted, just set priority */ | |
| return; | |
| } | |
| PYRO("msglevel hilight\n"); | |
| color = hilight_get_color(hilight); | |
| hilight_len = hilight_end-hilight_start; | |
| if (!hilight->word) { | |
| /* hilight whole line */ | |
| char *tmp = strip_codes(text); | |
| newstr = g_strconcat(color, tmp, NULL); | |
| g_free(tmp); | |
| PYRO("line\n"); | |
| } else { | |
| /* hilight part of the line */ | |
| GString *tmp; | |
| char *middle; | |
| int pos, color_pos, color_len; | |
| tmp = g_string_new(NULL); | |
| /* start of the line */ | |
| pos = strip_real_length(text, hilight_start, NULL, NULL); | |
| g_string_append(tmp, text); | |
| g_string_truncate(tmp, pos); | |
| /* color */ | |
| g_string_append(tmp, color); | |
| /* middle of the line, stripped */ | |
| middle = strip_codes(text+pos); | |
| pos = tmp->len; | |
| g_string_append(tmp, middle); | |
| g_string_truncate(tmp, pos+hilight_len); | |
| g_free(middle); | |
| /* end of the line */ | |
| pos = strip_real_length(text, hilight_end, | |
| &color_pos, &color_len); | |
| if (color_pos > 0) | |
| g_string_append_len(tmp, text+color_pos, color_len); | |
| else { | |
| /* no colors in line, change back to default */ | |
| g_string_append_c(tmp, 4); | |
| g_string_append_c(tmp, FORMAT_STYLE_DEFAULTS); | |
| } | |
| g_string_append(tmp, text+pos); | |
| newstr = tmp->str; | |
| g_string_free(tmp, FALSE); | |
| PYRO("else\n"); | |
| } | |
| signal_emit("print text", 3, dest, newstr, stripped); | |
| g_free(color); | |
| g_free(newstr); | |
| signal_stop(); | |
| PYRO("return sig_print_text\n"); | |
| } | |
| HILIGHT_REC *hilight_match_nick_or_mask(SERVER_REC *server, const char *channel, | |
| const char *nick, const char *address, | |
| int level, const char *msg) | |
| { | |
| HILIGHT_REC *rec; | |
| rec = hilight_match(server, channel, nick, address, | |
| level, msg, NULL, NULL); | |
| return (rec != NULL && (rec->nick || rec->nickmask)) ? rec : NULL; | |
| } | |
| static void read_hilight_config(void) | |
| { | |
| CONFIG_NODE *node; | |
| HILIGHT_REC *rec; | |
| GSList *tmp; | |
| char *text, *color; | |
| hilights_destroy_all(); | |
| node = iconfig_node_traverse("hilights", FALSE); | |
| if (node == NULL) { | |
| reset_cache(); | |
| return; | |
| } | |
| tmp = config_node_first(node->value); | |
| for (; tmp != NULL; tmp = config_node_next(tmp)) { | |
| node = tmp->data; | |
| if (node->type != NODE_TYPE_BLOCK) | |
| continue; | |
| text = config_node_get_str(node, "text", NULL); | |
| if (text == NULL || *text == '\0') | |
| continue; | |
| rec = g_new0(HILIGHT_REC, 1); | |
| hilights = g_slist_append(hilights, rec); | |
| rec->text = g_strdup(text); | |
| color = config_node_get_str(node, "color", NULL); | |
| rec->color = color == NULL || *color == '\0' ? NULL : | |
| g_strdup(color); | |
| color = config_node_get_str(node, "act_color", NULL); | |
| rec->act_color = color == NULL || *color == '\0' ? NULL : | |
| g_strdup(color); | |
| rec->level = config_node_get_int(node, "level", 0); | |
| 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->nickmask = config_node_get_bool(node, "mask", FALSE); | |
| rec->fullword = config_node_get_bool(node, "fullword", FALSE); | |
| rec->regexp = config_node_get_bool(node, "regexp", FALSE); | |
| rec->invert = config_node_get_bool(node, "invert", FALSE); | |
| hilight_init_rec(rec); | |
| node = config_node_section(node, "channels", -1); | |
| if (node != NULL) rec->channels = config_node_get_list(node); | |
| } | |
| reset_cache(); | |
| } | |
| static void hilight_print(int index, HILIGHT_REC *rec) | |
| { | |
| char *chans, *levelstr; | |
| GString *options; | |
| options = g_string_new(NULL); | |
| if (!rec->nick || !rec->word) { | |
| if (rec->nick) g_string_append(options, "-nick "); | |
| if (rec->word) g_string_append(options, "-word "); | |
| } | |
| if (rec->nickmask) g_string_append(options, "-mask "); | |
| if (rec->fullword) g_string_append(options, "-full "); | |
| if (rec->regexp) { | |
| g_string_append(options, "-regexp "); | |
| #ifdef HAVE_REGEX_H | |
| if (!rec->regexp_compiled) | |
| g_string_append(options, "[INVALID!] "); | |
| #endif | |
| } | |
| if (rec->invert) g_string_append(options, "-invert "); | |
| if (rec->priority != 0) | |
| g_string_append_printf(options, "-priority %d ", rec->priority); | |
| if (rec->color != NULL) | |
| g_string_append_printf(options, "-color %s ", rec->color); | |
| if (rec->act_color != NULL) | |
| g_string_append_printf(options, "-actcolor %s ", rec->act_color); | |
| chans = rec->channels == NULL ? NULL : | |
| g_strjoinv(",", rec->channels); | |
| levelstr = rec->level == 0 ? NULL : | |
| bits2level(rec->level); | |
| 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); | |
| g_free_not_null(chans); | |
| g_free_not_null(levelstr); | |
| g_string_free(options, TRUE); | |
| } | |
| static void cmd_hilight_show(void) | |
| { | |
| GSList *tmp; | |
| int index; | |
| printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_HILIGHT_HEADER); | |
| index = 1; | |
| for (tmp = hilights; tmp != NULL; tmp = tmp->next, index++) { | |
| HILIGHT_REC *rec = tmp->data; | |
| hilight_print(index, rec); | |
| } | |
| printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, TXT_HILIGHT_FOOTER); | |
| } | |
| /* SYNTAX: HILIGHT [-nick | -word | -line] [-mask | -full | -regexp] [-invert] | |
| [-color <color>] [-actcolor <color>] [-level <level>] | |
| [-channels <channels>] <text> */ | |
| static void cmd_hilight(const char *data) | |
| { | |
| GHashTable *optlist; | |
| HILIGHT_REC *rec; | |
| char *colorarg, *actcolorarg, *levelarg, *priorityarg, *chanarg, *text; | |
| char **channels; | |
| void *free_arg; | |
| g_return_if_fail(data != NULL); | |
| if (*data == '\0') { | |
| cmd_hilight_show(); | |
| return; | |
| } | |
| if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS | | |
| PARAM_FLAG_GETREST, "hilight", &optlist, &text)) | |
| return; | |
| chanarg = g_hash_table_lookup(optlist, "channels"); | |
| levelarg = g_hash_table_lookup(optlist, "level"); | |
| priorityarg = g_hash_table_lookup(optlist, "priority"); | |
| colorarg = g_hash_table_lookup(optlist, "color"); | |
| actcolorarg = g_hash_table_lookup(optlist, "actcolor"); | |
| if (*text == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); | |
| channels = (chanarg == NULL || *chanarg == '\0') ? NULL : | |
| g_strsplit(chanarg, ",", -1); | |
| rec = hilight_find(text, channels); | |
| if (rec == NULL) { | |
| rec = g_new0(HILIGHT_REC, 1); | |
| /* default to nick/word hilighting */ | |
| rec->nick = TRUE; | |
| rec->word = TRUE; | |
| rec->text = g_strdup(text); | |
| rec->channels = channels; | |
| } else { | |
| g_strfreev(channels); | |
| } | |
| rec->level = (levelarg == NULL || *levelarg == '\0') ? 0 : | |
| level2bits(replace_chars(levelarg, ',', ' '), NULL); | |
| rec->priority = priorityarg == NULL ? 0 : atoi(priorityarg); | |
| if (g_hash_table_lookup(optlist, "line") != NULL) { | |
| rec->word = FALSE; | |
| rec->nick = FALSE; | |
| } | |
| if (g_hash_table_lookup(optlist, "word") != NULL) { | |
| rec->word = TRUE; | |
| rec->nick = FALSE; | |
| } | |
| if (g_hash_table_lookup(optlist, "nick") != NULL) | |
| 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->invert = g_hash_table_lookup(optlist, "invert") != NULL; | |
| if (colorarg != NULL) { | |
| g_free_and_null(rec->color); | |
| if (*colorarg != '\0') | |
| rec->color = g_strdup(colorarg); | |
| } | |
| if (actcolorarg != NULL) { | |
| g_free_and_null(rec->act_color); | |
| if (*actcolorarg != '\0') | |
| rec->act_color = g_strdup(actcolorarg); | |
| } | |
| hilight_create(rec); | |
| hilight_print(g_slist_index(hilights, rec)+1, rec); | |
| cmd_params_free(free_arg); | |
| reset_cache(); | |
| } | |
| /* SYNTAX: DEHILIGHT <id>|<mask> */ | |
| static void cmd_dehilight(const char *data) | |
| { | |
| HILIGHT_REC *rec; | |
| GSList *tmp; | |
| if (is_numeric(data, ' ')) { | |
| /* with index number */ | |
| tmp = g_slist_nth(hilights, atoi(data)-1); | |
| rec = tmp == NULL ? NULL : tmp->data; | |
| } else { | |
| /* with mask */ | |
| char *chans[2] = { "*", NULL }; | |
| rec = hilight_find(data, chans); | |
| } | |
| if (rec == NULL) | |
| printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_HILIGHT_NOT_FOUND, data); | |
| else { | |
| printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, TXT_HILIGHT_REMOVED, rec->text); | |
| hilight_remove(rec); | |
| reset_cache(); | |
| } | |
| } | |
| static void hilight_nick_cache(GHashTable *list, CHANNEL_REC *channel, | |
| NICK_REC *nick) | |
| { | |
| GSList *tmp; | |
| HILIGHT_REC *match; | |
| char *nickmask; | |
| int len, best_match; | |
| if (nick->host == NULL) | |
| return; /* don't check until host is known */ | |
| nickmask = g_strconcat(nick->nick, "!", nick->host, NULL); | |
| best_match = 0; match = NULL; | |
| for (tmp = hilights; tmp != NULL; tmp = tmp->next) { | |
| HILIGHT_REC *rec = tmp->data; | |
| if (rec->nickmask && | |
| hilight_match_channel(rec, channel->name) && | |
| match_wildcards(rec->text, nickmask)) { | |
| len = strlen(rec->text); | |
| if (best_match < len) { | |
| best_match = len; | |
| match = rec; | |
| } | |
| } | |
| } | |
| g_free_not_null(nickmask); | |
| if (match != NULL) | |
| g_hash_table_insert(list, nick, match); | |
| } | |
| static void read_settings(void) | |
| { | |
| default_hilight_level = settings_get_level("hilight_level"); | |
| reset_level_cache(); | |
| } | |
| void hilight_text_init(void) | |
| { | |
| settings_add_str("lookandfeel", "hilight_color", "%Y"); | |
| settings_add_str("lookandfeel", "hilight_act_color", "%M"); | |
| settings_add_level("lookandfeel", "hilight_level", "PUBLIC DCCMSGS"); | |
| 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); | |
| command_bind("hilight", NULL, (SIGNAL_FUNC) cmd_hilight); | |
| command_bind("dehilight", NULL, (SIGNAL_FUNC) cmd_dehilight); | |
| command_set_options("hilight", "-color -actcolor -level -priority -channels nick word line mask full regexp invert"); | |
| } | |
| void hilight_text_deinit(void) | |
| { | |
| hilights_destroy_all(); | |
| 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); | |
| command_unbind("hilight", (SIGNAL_FUNC) cmd_hilight); | |
| command_unbind("dehilight", (SIGNAL_FUNC) cmd_dehilight); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* | |
| signals.c : irssi | |
| Copyright (C) 1999-2002 Timo Sirainen | |
| This program is free software; you can redistribute it and/or modify | |
| it under the terms of the GNU General Public License as published by | |
| the Free Software Foundation; either version 2 of the License, or | |
| (at your option) any later version. | |
| This program 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 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. | |
| */ | |
| // peter likes printf | |
| #include <stdio.h> | |
| #define PYRO(...) \ | |
| ({ fprintf(stderr, __VA_ARGS__); \ | |
| fflush(stderr); }) | |
| //#define PYRO(...) ({}) | |
| #include "module.h" | |
| #include "signals.h" | |
| #include "modules.h" | |
| typedef struct _SignalHook { | |
| struct _SignalHook *next; | |
| int priority; | |
| const char *module; | |
| SIGNAL_FUNC func; | |
| void *user_data; | |
| } SignalHook; | |
| typedef struct { | |
| int id; /* signal id */ | |
| int refcount; | |
| int emitting; /* signal is being emitted */ | |
| int stop_emit; /* this signal was stopped */ | |
| int continue_emit; /* this signal emit was continued elsewhere */ | |
| int remove_count; /* hooks were removed from signal */ | |
| SignalHook *hooks; | |
| } Signal; | |
| void *signal_user_data; | |
| static GHashTable *signals; | |
| static Signal *current_emitted_signal; | |
| static SignalHook *current_emitted_hook; | |
| #define signal_ref(signal) ++(signal)->refcount | |
| #define signal_unref(signal) (signal_unref_full(signal, TRUE)) | |
| static int signal_unref_full(Signal *rec, int remove) | |
| { | |
| g_assert(rec->refcount > 0); | |
| PYRO("signal_unref_full: %s, %i\n", signal_get_id_str(rec->id), rec->refcount); | |
| if (--rec->refcount != 0) | |
| return TRUE; | |
| /* remove whole signal from memory */ | |
| if (rec->hooks != NULL) { | |
| g_error("signal_unref(%s) : BUG - hook list wasn't empty", | |
| signal_get_id_str(rec->id)); | |
| } | |
| if (remove) | |
| g_hash_table_remove(signals, GINT_TO_POINTER(rec->id)); | |
| g_free(rec); | |
| return FALSE; | |
| } | |
| static void signal_hash_ref(void *key, Signal *rec) | |
| { | |
| PYRO("signal_hash_ref: %s, %i\n", signal_get_id_str(rec->id), rec->refcount); | |
| signal_ref(rec); | |
| } | |
| static int signal_hash_unref(void *key, Signal *rec) | |
| { | |
| return !signal_unref_full(rec, FALSE); | |
| } | |
| void signal_add_full(const char *module, int priority, | |
| const char *signal, SIGNAL_FUNC func, void *user_data) | |
| { | |
| signal_add_full_id(module, priority, signal_get_uniq_id(signal), | |
| func, user_data); | |
| } | |
| /* bind a signal */ | |
| void signal_add_full_id(const char *module, int priority, | |
| int signal_id, SIGNAL_FUNC func, void *user_data) | |
| { | |
| Signal *signal; | |
| SignalHook *hook, **tmp; | |
| g_return_if_fail(signal_id >= 0); | |
| g_return_if_fail(func != NULL); | |
| signal = g_hash_table_lookup(signals, GINT_TO_POINTER(signal_id)); | |
| if (signal == NULL) { | |
| /* new signal */ | |
| signal = g_new0(Signal, 1); | |
| signal->id = signal_id; | |
| g_hash_table_insert(signals, GINT_TO_POINTER(signal_id), signal); | |
| } | |
| hook = g_new0(SignalHook, 1); | |
| hook->priority = priority; | |
| hook->module = module; | |
| hook->func = func; | |
| hook->user_data = user_data; | |
| /* insert signal to proper position in list */ | |
| for (tmp = &signal->hooks; ; tmp = &(*tmp)->next) { | |
| if (*tmp == NULL) { | |
| /* last in list */ | |
| *tmp = hook; | |
| break; | |
| } else if (priority <= (*tmp)->priority) { | |
| /* insert before others with same priority */ | |
| hook->next = *tmp; | |
| *tmp = hook; | |
| break; | |
| } | |
| } | |
| PYRO("signal_add_full_id: %s, %i\n", signal_get_id_str(signal->id), signal->refcount); | |
| signal_ref(signal); | |
| } | |
| static void signal_remove_hook(Signal *rec, SignalHook **hook_pos) | |
| { | |
| SignalHook *hook; | |
| hook = *hook_pos; | |
| *hook_pos = hook->next; | |
| g_free(hook); | |
| signal_unref(rec); | |
| } | |
| /* Remove function from signal's emit list */ | |
| static int signal_remove_func(Signal *rec, SIGNAL_FUNC func, void *user_data) | |
| { | |
| SignalHook **hook; | |
| for (hook = &rec->hooks; *hook != NULL; hook = &(*hook)->next) { | |
| if ((*hook)->func == func && (*hook)->user_data == user_data) { | |
| if (rec->emitting) { | |
| /* mark it removed after emitting is done */ | |
| (*hook)->func = NULL; | |
| rec->remove_count++; | |
| } else { | |
| /* remove the function from emit list */ | |
| signal_remove_hook(rec, hook); | |
| } | |
| return TRUE; | |
| } | |
| } | |
| return FALSE; | |
| } | |
| void signal_remove_id(int signal_id, SIGNAL_FUNC func, void *user_data) | |
| { | |
| Signal *rec; | |
| g_return_if_fail(signal_id >= 0); | |
| g_return_if_fail(func != NULL); | |
| rec = g_hash_table_lookup(signals, GINT_TO_POINTER(signal_id)); | |
| if (rec != NULL) | |
| signal_remove_func(rec, func, user_data); | |
| } | |
| /* unbind signal */ | |
| void signal_remove_full(const char *signal, SIGNAL_FUNC func, void *user_data) | |
| { | |
| g_return_if_fail(signal != NULL); | |
| signal_remove_id(signal_get_uniq_id(signal), func, user_data); | |
| } | |
| static void signal_hooks_clean(Signal *rec) | |
| { | |
| SignalHook **hook, **next; | |
| int count; | |
| count = rec->remove_count; | |
| rec->remove_count = 0; | |
| for (hook = &rec->hooks; *hook != NULL; hook = next) { | |
| next = &(*hook)->next; | |
| if ((*hook)->func == NULL) { | |
| next = hook; | |
| signal_remove_hook(rec, hook); | |
| if (--count == 0) | |
| break; | |
| } | |
| } | |
| } | |
| static int signal_emit_real(Signal *rec, int params, va_list va, | |
| SignalHook *first_hook) | |
| { | |
| const void *arglist[SIGNAL_MAX_ARGUMENTS]; | |
| Signal *prev_emitted_signal; | |
| SignalHook *hook, *prev_emitted_hook; | |
| int i, stopped, stop_emit_count, continue_emit_count; | |
| for (i = 0; i < SIGNAL_MAX_ARGUMENTS; i++) | |
| arglist[i] = i >= params ? NULL : va_arg(va, const void *); | |
| /* signal_stop_by_name("signal"); signal_emit("signal", ...); | |
| fails if we compare rec->stop_emit against 0. */ | |
| stop_emit_count = rec->stop_emit; | |
| continue_emit_count = rec->continue_emit; | |
| // this stops the crash | |
| //PYRO("signal_emit_real: %s, %i\n", signal_get_id_str(rec->id), rec->refcount); | |
| signal_ref(rec); | |
| //PYRO("signal_emit_real: %s, %i\n", signal_get_id_str(rec->id), rec->refcount); | |
| stopped = FALSE; | |
| rec->emitting++; | |
| prev_emitted_signal = current_emitted_signal; | |
| prev_emitted_hook = current_emitted_hook; | |
| current_emitted_signal = rec; | |
| for (hook = first_hook; hook != NULL; hook = hook->next) { | |
| if (hook->func == NULL) | |
| continue; /* removed */ | |
| current_emitted_hook = hook; | |
| #if SIGNAL_MAX_ARGUMENTS != 6 | |
| # error SIGNAL_MAX_ARGUMENTS changed - update code | |
| #endif | |
| signal_user_data = hook->user_data; | |
| hook->func(arglist[0], arglist[1], arglist[2], arglist[3], | |
| arglist[4], arglist[5]); | |
| if (rec->continue_emit != continue_emit_count) | |
| rec->continue_emit--; | |
| if (rec->stop_emit != stop_emit_count) { | |
| stopped = TRUE; | |
| rec->stop_emit--; | |
| break; | |
| } | |
| } | |
| current_emitted_signal = prev_emitted_signal; | |
| current_emitted_hook = prev_emitted_hook; | |
| rec->emitting--; | |
| signal_user_data = NULL; | |
| if (!rec->emitting) { | |
| g_assert(rec->stop_emit == 0); | |
| g_assert(rec->continue_emit == 0); | |
| if (rec->remove_count > 0) | |
| signal_hooks_clean(rec); | |
| } | |
| PYRO("II: %i, %i\n", rec->id, rec->refcount); | |
| signal_unref(rec); | |
| return stopped; | |
| } | |
| int signal_emit(const char *signal, int params, ...) | |
| { | |
| Signal *rec; | |
| va_list va; | |
| int signal_id; | |
| g_return_val_if_fail(params >= 0 && params <= SIGNAL_MAX_ARGUMENTS, FALSE); | |
| signal_id = signal_get_uniq_id(signal); | |
| rec = g_hash_table_lookup(signals, GINT_TO_POINTER(signal_id)); | |
| if (rec != NULL) { | |
| va_start(va, params); | |
| signal_emit_real(rec, params, va, rec->hooks); | |
| va_end(va); | |
| } | |
| return rec != NULL; | |
| } | |
| int signal_emit_id(int signal_id, int params, ...) | |
| { | |
| Signal *rec; | |
| va_list va; | |
| g_return_val_if_fail(signal_id >= 0, FALSE); | |
| g_return_val_if_fail(params >= 0 && params <= SIGNAL_MAX_ARGUMENTS, FALSE); | |
| rec = g_hash_table_lookup(signals, GINT_TO_POINTER(signal_id)); | |
| if (rec != NULL) { | |
| va_start(va, params); | |
| signal_emit_real(rec, params, va, rec->hooks); | |
| va_end(va); | |
| } | |
| return rec != NULL; | |
| } | |
| void signal_continue(int params, ...) | |
| { | |
| Signal *rec; | |
| va_list va; | |
| rec = current_emitted_signal; | |
| if (rec == NULL || rec->emitting <= rec->continue_emit) | |
| g_warning("signal_continue() : no signals are being emitted currently"); | |
| else { | |
| va_start(va, params); | |
| /* stop the signal */ | |
| if (rec->emitting > rec->stop_emit) | |
| rec->stop_emit++; | |
| /* re-emit */ | |
| rec->continue_emit++; | |
| signal_emit_real(rec, params, va, current_emitted_hook->next); | |
| va_end(va); | |
| } | |
| } | |
| /* stop the current ongoing signal emission */ | |
| void signal_stop(void) | |
| { | |
| Signal *rec; | |
| rec = current_emitted_signal; | |
| if (rec == NULL) | |
| g_warning("signal_stop() : no signals are being emitted currently"); | |
| else if (rec->emitting > rec->stop_emit) | |
| rec->stop_emit++; | |
| } | |
| /* stop ongoing signal emission by signal name */ | |
| void signal_stop_by_name(const char *signal) | |
| { | |
| Signal *rec; | |
| int signal_id; | |
| signal_id = signal_get_uniq_id(signal); | |
| rec = g_hash_table_lookup(signals, GINT_TO_POINTER(signal_id)); | |
| if (rec == NULL) | |
| g_warning("signal_stop_by_name() : unknown signal \"%s\"", signal); | |
| else if (rec->emitting > rec->stop_emit) | |
| rec->stop_emit++; | |
| } | |
| /* return the name of the signal that is currently being emitted */ | |
| const char *signal_get_emitted(void) | |
| { | |
| return signal_get_id_str(signal_get_emitted_id()); | |
| } | |
| /* return the ID of the signal that is currently being emitted */ | |
| int signal_get_emitted_id(void) | |
| { | |
| Signal *rec; | |
| rec = current_emitted_signal; | |
| g_return_val_if_fail(rec != NULL, -1); | |
| return rec->id; | |
| } | |
| /* return TRUE if specified signal was stopped */ | |
| int signal_is_stopped(int signal_id) | |
| { | |
| Signal *rec; | |
| rec = g_hash_table_lookup(signals, GINT_TO_POINTER(signal_id)); | |
| g_return_val_if_fail(rec != NULL, FALSE); | |
| return rec->emitting <= rec->stop_emit; | |
| } | |
| static void signal_remove_module(void *signal, Signal *rec, | |
| const char *module) | |
| { | |
| SignalHook **hook, **next; | |
| for (hook = &rec->hooks; *hook != NULL; hook = next) { | |
| next = &(*hook)->next; | |
| if (strcasecmp((*hook)->module, module) == 0) { | |
| next = hook; | |
| signal_remove_hook(rec, hook); | |
| } | |
| } | |
| } | |
| /* remove all signals that belong to `module' */ | |
| void signals_remove_module(const char *module) | |
| { | |
| g_return_if_fail(module != NULL); | |
| g_hash_table_foreach(signals, (GHFunc) signal_hash_ref, NULL); | |
| g_hash_table_foreach(signals, (GHFunc) signal_remove_module, | |
| (void *) module); | |
| g_hash_table_foreach_remove(signals, (GHRFunc) signal_hash_unref, NULL); | |
| } | |
| void signals_init(void) | |
| { | |
| signals = g_hash_table_new(NULL, NULL); | |
| } | |
| static void signal_free(void *key, Signal *rec) | |
| { | |
| /* refcount-1 because we just referenced it ourself */ | |
| g_warning("signal_free(%s) : signal still has %d references:", | |
| signal_get_id_str(rec->id), rec->refcount-1); | |
| while (rec->hooks != NULL) { | |
| g_warning(" - module '%s' function %p", | |
| rec->hooks->module, rec->hooks->func); | |
| signal_remove_hook(rec, &rec->hooks); | |
| } | |
| } | |
| void signals_deinit(void) | |
| { | |
| g_hash_table_foreach(signals, (GHFunc) signal_hash_ref, NULL); | |
| g_hash_table_foreach(signals, (GHFunc) signal_free, NULL); | |
| g_hash_table_foreach_remove(signals, (GHRFunc) signal_hash_unref, NULL); | |
| g_hash_table_destroy(signals); | |
| module_uniq_destroy("signals"); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| diff --git a/docs/help/in/hilight.in b/docs/help/in/hilight.in | |
| index fce51eb..c3ebe78 100644 | |
| --- a/docs/help/in/hilight.in | |
| +++ b/docs/help/in/hilight.in | |
| @@ -3,6 +3,7 @@ | |
| -mask: Match only for nick, <text> is a nick mask | |
| -regexp: <text> is a regular expression | |
| + -invert: Suppress any hilights on a matching message | |
| -full: <text> must match to full words | |
| -nick: Hilight only the nick, not the whole line (default) | |
| -word: Hilight only the word (default with non-public messages) | |
| @@ -26,6 +27,10 @@ Hilight all messages from "mynick": | |
| Hilight lines that were written by nicks from *.fi with bold green | |
| /HILIGHT -color %%G -mask *!*@*.fi | |
| +Hilight lines containing "mynick", except those from "root": | |
| + /HILIGHT mynick | |
| + /HILIGHT -invert -mask root!*@* | |
| + | |
| For regular expressions, see `man 7 regex`. | |
| See also: DEHILIGHT, SET HILIGHT | |
| diff --git a/src/core/signals.c b/src/core/signals.c | |
| index 1f425ba..d213444 100644 | |
| --- a/src/core/signals.c | |
| +++ b/src/core/signals.c | |
| @@ -18,6 +18,13 @@ | |
| 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
| */ | |
| +// peter likes printf | |
| +#include <stdio.h> | |
| +#define PYRO(...) \ | |
| + ({ fprintf(stderr, __VA_ARGS__); \ | |
| + fflush(stderr); }) | |
| +//#define PYRO(...) ({}) | |
| + | |
| #include "module.h" | |
| #include "signals.h" | |
| #include "modules.h" | |
| @@ -56,6 +63,8 @@ static int signal_unref_full(Signal *rec, int remove) | |
| { | |
| g_assert(rec->refcount > 0); | |
| +PYRO("signal_unref_full: %s, %i\n", signal_get_id_str(rec->id), rec->refcount); | |
| + | |
| if (--rec->refcount != 0) | |
| return TRUE; | |
| @@ -74,6 +83,8 @@ static int signal_unref_full(Signal *rec, int remove) | |
| static void signal_hash_ref(void *key, Signal *rec) | |
| { | |
| + | |
| +PYRO("signal_hash_ref: %s, %i\n", signal_get_id_str(rec->id), rec->refcount); | |
| signal_ref(rec); | |
| } | |
| @@ -127,6 +138,8 @@ void signal_add_full_id(const char *module, int priority, | |
| } | |
| } | |
| +PYRO("signal_add_full_id: %s, %i\n", signal_get_id_str(signal->id), signal->refcount); | |
| + | |
| signal_ref(signal); | |
| } | |
| @@ -221,7 +234,10 @@ static int signal_emit_real(Signal *rec, int params, va_list va, | |
| stop_emit_count = rec->stop_emit; | |
| continue_emit_count = rec->continue_emit; | |
| +// this stops the crash | |
| +//PYRO("signal_emit_real: %s, %i\n", signal_get_id_str(rec->id), rec->refcount); | |
| signal_ref(rec); | |
| +//PYRO("signal_emit_real: %s, %i\n", signal_get_id_str(rec->id), rec->refcount); | |
| stopped = FALSE; | |
| rec->emitting++; | |
| @@ -266,6 +282,8 @@ static int signal_emit_real(Signal *rec, int params, va_list va, | |
| signal_hooks_clean(rec); | |
| } | |
| + | |
| +PYRO("II: %i, %i\n", rec->id, rec->refcount); | |
| signal_unref(rec); | |
| return stopped; | |
| } | |
| diff --git a/src/fe-common/core/fe-messages.c b/src/fe-common/core/fe-messages.c | |
| index 846272f..50d4212 100644 | |
| --- a/src/fe-common/core/fe-messages.c | |
| +++ b/src/fe-common/core/fe-messages.c | |
| @@ -167,6 +167,8 @@ 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; | |
| + | |
| + level = MSGLEVEL_PUBLIC; | |
| /* NOTE: this may return NULL if some channel is just closed with | |
| /WINDOW CLOSE and server still sends the few last messages */ | |
| @@ -174,22 +176,12 @@ static void sig_message_public(SERVER_REC *server, const char *msg, | |
| if (nickrec == NULL && chanrec != NULL) | |
| nickrec = nicklist_find(chanrec, nick); | |
| - for_me = !settings_get_bool("hilight_nick_matches") ? FALSE : | |
| - nick_match_msg(chanrec, msg, server->nick); | |
| - hilight = for_me ? NULL : | |
| - hilight_match_nick(server, target, nick, address, MSGLEVEL_PUBLIC, msg); | |
| - color = (hilight == NULL) ? NULL : hilight_get_color(hilight); | |
| - | |
| print_channel = chanrec == NULL || | |
| !window_item_is_active((WI_ITEM_REC *) chanrec); | |
| if (!print_channel && settings_get_bool("print_active_channel") && | |
| window_item_window((WI_ITEM_REC *) chanrec)->items->next != NULL) | |
| print_channel = TRUE; | |
| - level = MSGLEVEL_PUBLIC; | |
| - if (for_me) | |
| - level |= MSGLEVEL_HILIGHT; | |
| - | |
| if (settings_get_bool("emphasis")) | |
| msg = freemsg = expand_emphasis((WI_ITEM_REC *) chanrec, msg); | |
| @@ -201,29 +193,52 @@ static void sig_message_public(SERVER_REC *server, const char *msg, | |
| if (printnick == NULL) | |
| printnick = nick; | |
| - if (color != NULL) { | |
| - /* highlighted nick */ | |
| - TEXT_DEST_REC dest; | |
| - format_create_dest(&dest, server, target, level, NULL); | |
| - hilight_update_text_dest(&dest,hilight); | |
| - if (!print_channel) /* message to active channel in window */ | |
| - printformat_dest(&dest, TXT_PUBMSG_HILIGHT, color, | |
| - printnick, msg, nickmode); | |
| - else /* message to not existing/active channel */ | |
| - printformat_dest(&dest, TXT_PUBMSG_HILIGHT_CHANNEL, | |
| - color, printnick, target, msg, | |
| - nickmode); | |
| + | |
| + | |
| + int formatnum; | |
| + TEXT_DEST_REC dest; | |
| + format_create_dest(&dest, server, target, level, NULL); | |
| + hilight = hilight_match_nick_or_mask(server, target, | |
| + nick, address, MSGLEVEL_PUBLIC, msg); | |
| + | |
| + if (hilight != NULL) { | |
| + // -nick or -mask | |
| + hilight_update_text_dest(&dest, hilight); | |
| + if (hilight->nick && !hilight->invert) { | |
| + // hilight needs to be handled specially | |
| + formatnum = print_channel ? TXT_PUBMSG_HILIGHT_CHANNEL : | |
| + TXT_PUBMSG_HILIGHT; | |
| + } else { | |
| + dest.level ^= MSGLEVEL_HILIGHT; | |
| + // hilight is handled by hilight-text.c, sig_print_text | |
| + formatnum = print_channel ? TXT_PUBMSG_CHANNEL : | |
| + TXT_PUBMSG; | |
| + } | |
| } else { | |
| - if (!print_channel) | |
| - printformat(server, target, level, | |
| - for_me ? TXT_PUBMSG_ME : TXT_PUBMSG, | |
| - printnick, msg, nickmode); | |
| + // check if message starts with own nick | |
| + for_me = !settings_get_bool("hilight_nick_matches") ? FALSE : | |
| + nick_match_msg(chanrec, msg, server->nick); | |
| + if (for_me) | |
| + dest.level |= MSGLEVEL_HILIGHT; | |
| + | |
| + if (for_me) | |
| + formatnum = print_channel ? TXT_PUBMSG_ME_CHANNEL : | |
| + TXT_PUBMSG_ME; | |
| else | |
| - printformat(server, target, level, | |
| - for_me ? TXT_PUBMSG_ME_CHANNEL : | |
| - TXT_PUBMSG_CHANNEL, | |
| - printnick, target, msg, nickmode); | |
| - } | |
| + formatnum = print_channel ? TXT_PUBMSG_CHANNEL : | |
| + TXT_PUBMSG; | |
| + } | |
| + | |
| + // check if format needs an additional 'color' parameter | |
| + if (formatnum == TXT_PUBMSG_HILIGHT_CHANNEL | |
| + || formatnum == TXT_PUBMSG_HILIGHT) { | |
| + color = hilight_get_color(hilight); | |
| + printformat_dest(&dest, formatnum, color, printnick, | |
| + msg, nickmode); | |
| + } else { | |
| + printformat_dest(&dest, formatnum, printnick, | |
| + msg, nickmode); | |
| + } | |
| g_free_not_null(nickmode); | |
| g_free_not_null(freemsg); | |
| diff --git a/src/fe-common/core/formats.h b/src/fe-common/core/formats.h | |
| index 6c55a06..042c211 100644 | |
| --- a/src/fe-common/core/formats.h | |
| +++ b/src/fe-common/core/formats.h | |
| @@ -3,6 +3,7 @@ | |
| #include "themes.h" | |
| #include "fe-windows.h" | |
| +#include "hilight-rec.h" | |
| #define GUI_PRINT_FLAG_BOLD 0x0001 | |
| #define GUI_PRINT_FLAG_REVERSE 0x0002 | |
| @@ -52,6 +53,7 @@ typedef struct _TEXT_DEST_REC { | |
| int hilight_priority; | |
| char *hilight_color; | |
| int flags; | |
| + HILIGHT_REC *hilight; | |
| } TEXT_DEST_REC; | |
| #define window_get_theme(window) \ | |
| diff --git a/src/fe-common/core/hilight-text.c b/src/fe-common/core/hilight-text.c | |
| index f501db9..67694e4 100644 | |
| --- a/src/fe-common/core/hilight-text.c | |
| +++ b/src/fe-common/core/hilight-text.c | |
| @@ -36,6 +36,12 @@ | |
| #include "printtext.h" | |
| #include "formats.h" | |
| +// peter likes printf | |
| +#include <stdio.h> | |
| +#define PYRO(...) \ | |
| + ({ fprintf(stderr, __VA_ARGS__); \ | |
| + fflush(stderr); }) | |
| + | |
| static NICKMATCH_REC *nickmatch; | |
| static int never_hilight_level, default_hilight_level; | |
| GSList *hilights; | |
| @@ -78,6 +84,7 @@ static void hilight_add_config(HILIGHT_REC *rec) | |
| 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->invert) iconfig_node_set_bool(node, "invert", TRUE); | |
| if (rec->channels != NULL && *rec->channels != NULL) { | |
| node = config_node_section(node, "channels", NODE_TYPE_LIST); | |
| @@ -299,6 +306,8 @@ void hilight_update_text_dest(TEXT_DEST_REC *dest, HILIGHT_REC *rec) | |
| { | |
| dest->level |= MSGLEVEL_HILIGHT; | |
| + dest->hilight = rec; | |
| + | |
| if (rec->priority > 0) | |
| dest->hilight_priority = rec->priority; | |
| @@ -319,17 +328,24 @@ static void sig_print_text(TEXT_DEST_REC *dest, const char *text, | |
| int old_level, hilight_start, hilight_end, hilight_len; | |
| int nick_match; | |
| + PYRO("sig_print_text() %s\n", text); | |
| + | |
| if (dest->level & MSGLEVEL_NOHILIGHT) | |
| return; | |
| + PYRO("msglevel nohilight\n"); | |
| + | |
| hilight_start = hilight_end = 0; | |
| - hilight = hilight_match(dest->server, dest->target, | |
| + hilight = (dest->hilight != NULL) ? dest->hilight : hilight_match( | |
| + dest->server, dest->target, | |
| NULL, NULL, dest->level, stripped, | |
| &hilight_start, | |
| &hilight_end); | |
| if (hilight == NULL) | |
| return; | |
| + PYRO("nohilight\n"); | |
| + | |
| nick_match = hilight->nick && (dest->level & (MSGLEVEL_PUBLIC|MSGLEVEL_ACTIONS)) == MSGLEVEL_PUBLIC; | |
| old_level = dest->level; | |
| @@ -341,11 +357,15 @@ static void sig_print_text(TEXT_DEST_REC *dest, const char *text, | |
| if (nick_match) | |
| return; /* fe-messages.c should have taken care of this */ | |
| + PYRO("nickmatch\n"); | |
| + | |
| if (old_level & MSGLEVEL_HILIGHT) { | |
| /* nick is highlighted, just set priority */ | |
| return; | |
| } | |
| + PYRO("msglevel hilight\n"); | |
| + | |
| color = hilight_get_color(hilight); | |
| hilight_len = hilight_end-hilight_start; | |
| @@ -354,6 +374,8 @@ static void sig_print_text(TEXT_DEST_REC *dest, const char *text, | |
| char *tmp = strip_codes(text); | |
| newstr = g_strconcat(color, tmp, NULL); | |
| g_free(tmp); | |
| + | |
| + PYRO("line\n"); | |
| } else { | |
| /* hilight part of the line */ | |
| GString *tmp; | |
| @@ -391,6 +413,8 @@ static void sig_print_text(TEXT_DEST_REC *dest, const char *text, | |
| newstr = tmp->str; | |
| g_string_free(tmp, FALSE); | |
| + | |
| + PYRO("else\n"); | |
| } | |
| signal_emit("print text", 3, dest, newstr, stripped); | |
| @@ -399,9 +423,11 @@ static void sig_print_text(TEXT_DEST_REC *dest, const char *text, | |
| g_free(newstr); | |
| signal_stop(); | |
| + | |
| + PYRO("return sig_print_text\n"); | |
| } | |
| -HILIGHT_REC *hilight_match_nick(SERVER_REC *server, const char *channel, | |
| +HILIGHT_REC *hilight_match_nick_or_mask(SERVER_REC *server, const char *channel, | |
| const char *nick, const char *address, | |
| int level, const char *msg) | |
| { | |
| @@ -409,7 +435,7 @@ HILIGHT_REC *hilight_match_nick(SERVER_REC *server, const char *channel, | |
| rec = hilight_match(server, channel, nick, address, | |
| level, msg, NULL, NULL); | |
| - return (rec == NULL || !rec->nick) ? NULL : rec; | |
| + return (rec != NULL && (rec->nick || rec->nickmask)) ? rec : NULL; | |
| } | |
| static void read_hilight_config(void) | |
| @@ -459,6 +485,7 @@ static void read_hilight_config(void) | |
| rec->nickmask = config_node_get_bool(node, "mask", FALSE); | |
| rec->fullword = config_node_get_bool(node, "fullword", FALSE); | |
| rec->regexp = config_node_get_bool(node, "regexp", FALSE); | |
| + rec->invert = config_node_get_bool(node, "invert", FALSE); | |
| hilight_init_rec(rec); | |
| @@ -489,6 +516,7 @@ static void hilight_print(int index, HILIGHT_REC *rec) | |
| g_string_append(options, "[INVALID!] "); | |
| #endif | |
| } | |
| + if (rec->invert) g_string_append(options, "-invert "); | |
| if (rec->priority != 0) | |
| g_string_append_printf(options, "-priority %d ", rec->priority); | |
| @@ -528,7 +556,7 @@ 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 | -regexp] [-invert] | |
| [-color <color>] [-actcolor <color>] [-level <level>] | |
| [-channels <channels>] <text> */ | |
| static void cmd_hilight(const char *data) | |
| @@ -595,6 +623,7 @@ static void cmd_hilight(const char *data) | |
| 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->invert = g_hash_table_lookup(optlist, "invert") != NULL; | |
| if (colorarg != NULL) { | |
| g_free_and_null(rec->color); | |
| @@ -696,7 +725,7 @@ void hilight_text_init(void) | |
| command_bind("hilight", NULL, (SIGNAL_FUNC) cmd_hilight); | |
| command_bind("dehilight", NULL, (SIGNAL_FUNC) cmd_dehilight); | |
| - command_set_options("hilight", "-color -actcolor -level -priority -channels nick word line mask full regexp"); | |
| + command_set_options("hilight", "-color -actcolor -level -priority -channels nick word line mask full regexp invert"); | |
| } | |
| void hilight_text_deinit(void) | |
| diff --git a/src/fe-common/core/hilight-text.h b/src/fe-common/core/hilight-text.h | |
| index 74c5878..3741eef 100644 | |
| --- a/src/fe-common/core/hilight-text.h | |
| +++ b/src/fe-common/core/hilight-text.h | |
| @@ -1,35 +1,8 @@ | |
| #ifndef __HILIGHT_TEXT_H | |
| #define __HILIGHT_TEXT_H | |
| -#ifdef HAVE_REGEX_H | |
| -# include <regex.h> | |
| -#endif | |
| - | |
| #include "formats.h" | |
| - | |
| -typedef struct _HILIGHT_REC HILIGHT_REC; | |
| - | |
| -struct _HILIGHT_REC { | |
| - char *text; | |
| - | |
| - char **channels; /* if non-NULL, check the text only from these channels */ | |
| - int level; /* match only messages with this level, 0=default */ | |
| - char *color; /* if starts with number, \003 is automatically | |
| - inserted before it. */ | |
| - char *act_color; /* color for window activity */ | |
| - int priority; | |
| - | |
| - unsigned int nick:1; /* hilight only nick if possible */ | |
| - unsigned int word:1; /* hilight only word, not full line */ | |
| - | |
| - 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 */ | |
| -#ifdef HAVE_REGEX_H | |
| - unsigned int regexp_compiled:1; /* should always be TRUE, unless regexp is invalid */ | |
| - regex_t preg; | |
| -#endif | |
| -}; | |
| +#include "hilight-rec.h" | |
| extern GSList *hilights; | |
| @@ -38,7 +11,7 @@ HILIGHT_REC *hilight_match(SERVER_REC *server, const char *channel, | |
| int level, const char *str, | |
| int *match_beg, int *match_end); | |
| -HILIGHT_REC *hilight_match_nick(SERVER_REC *server, const char *channel, | |
| +HILIGHT_REC *hilight_match_nick_or_mask(SERVER_REC *server, const char *channel, | |
| const char *nick, const char *address, | |
| int level, const char *msg); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment