From d3dc9a1307adc40425bf162f1f867a39e535f501 Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Thu, 4 May 2000 10:32:42 +0000 Subject: .. lots of changes .. git-svn-id: http://svn.irssi.org/repos/irssi/trunk@197 dbcabf3a-b0e7-0310-adc4-f8d773084564 --- src/common-setup.h | 3 - src/core/levels.c | 1 - src/core/levels.h | 19 +- src/core/server.c | 10 +- src/core/settings.c | 21 +- src/fe-common/core/Makefile.am | 2 +- src/fe-common/core/autorun.c | 2 +- src/fe-common/core/command-history.c | 4 +- src/fe-common/core/fe-common-core.c | 51 +- src/fe-common/core/fe-core-commands.c | 77 ++- src/fe-common/core/fe-log.c | 37 +- src/fe-common/core/fe-server.c | 10 + src/fe-common/core/fe-settings.c | 13 +- src/fe-common/core/hilight-text.c | 2 +- src/fe-common/core/module-formats.c | 8 +- src/fe-common/core/module-formats.h | 6 + src/fe-common/core/nick-hilight.c | 115 ----- src/fe-common/core/printtext.c | 34 +- src/fe-common/core/printtext.h | 3 + src/fe-common/core/window-activity.c | 117 +++++ src/fe-common/core/windows.c | 395 +++++++++++++-- src/fe-common/core/windows.h | 5 + src/fe-common/irc/Makefile.am | 4 +- src/fe-common/irc/dcc/module-formats.h | 2 +- src/fe-common/irc/fe-channels.c | 141 ++++++ src/fe-common/irc/fe-common-irc.c | 20 +- src/fe-common/irc/fe-events-numeric.c | 2 +- src/fe-common/irc/fe-events.c | 51 +- src/fe-common/irc/fe-ignore.c | 4 +- src/fe-common/irc/fe-irc-commands.c | 119 +---- src/fe-common/irc/fe-irc-server.c | 215 ++++++++ src/fe-common/irc/fe-netsplit.c | 69 +++ src/fe-common/irc/fe-query.c | 62 +++ src/fe-common/irc/irc-nick-hilight.c | 89 ---- src/fe-common/irc/irc-window-activity.c | 89 ++++ src/fe-common/irc/module-formats.c | 19 +- src/fe-common/irc/module-formats.h | 19 +- src/fe-none/.cvsignore | 1 + src/fe-text/Makefile.am | 11 +- src/fe-text/gui-entry.c | 30 +- src/fe-text/gui-entry.h | 4 + src/fe-text/gui-mainwindows.c | 66 --- src/fe-text/gui-mainwindows.h | 21 - src/fe-text/gui-printtext.c | 12 +- src/fe-text/gui-readline.c | 516 ++++++++++--------- src/fe-text/gui-statusbar-items.c | 693 -------------------------- src/fe-text/gui-statusbar-items.h | 7 - src/fe-text/gui-statusbar.h | 21 - src/fe-text/gui-textwidget.c | 15 +- src/fe-text/gui-windows.c | 312 ++++++------ src/fe-text/gui-windows.h | 120 +++-- src/fe-text/irssi.c | 149 +++--- src/fe-text/mainwindows.c | 606 +++++++++++++++++++++++ src/fe-text/mainwindows.h | 29 ++ src/fe-text/module-formats.c | 3 + src/fe-text/module-formats.h | 9 +- src/fe-text/screen.c | 246 +++++----- src/fe-text/statusbar-items.c | 843 ++++++++++++++++++++++++++++++++ src/fe-text/statusbar.c | 266 ++++++++++ src/fe-text/statusbar.h | 45 ++ src/irc/core/bans.c | 17 +- src/irc/core/channel-events.c | 34 +- src/irc/core/channels-query.c | 4 +- src/irc/core/channels-setup.c | 85 ++-- src/irc/core/channels-setup.h | 3 +- src/irc/core/channels.c | 19 +- src/irc/core/channels.h | 1 + src/irc/core/ctcp.c | 2 +- src/irc/core/ignore.c | 5 +- src/irc/core/irc-commands.c | 59 ++- src/irc/core/irc-log.c | 4 +- src/irc/core/irc-server.c | 6 +- src/irc/core/irc-server.h | 1 + src/irc/core/irc.c | 1 + src/irc/core/ircnet-setup.c | 1 + src/irc/core/massjoin.c | 17 +- src/irc/core/modes.c | 89 +++- src/irc/core/netsplit.c | 80 ++- src/irc/core/netsplit.h | 12 +- src/irc/core/nicklist.c | 21 +- src/irc/core/nicklist.h | 2 + src/irc/core/server-reconnect.c | 26 +- src/irc/core/server-setup.c | 129 ++++- src/irc/core/server-setup.h | 9 +- src/irc/dcc/Makefile.am | 4 +- src/irc/dcc/dcc-chat.c | 2 +- src/irc/dcc/dcc-chat.h | 7 - src/irc/dcc/dcc-files.c | 2 +- src/irc/dcc/dcc-files.h | 7 - src/irc/dcc/dcc.c | 26 +- src/irc/flood/autoignore.c | 4 +- src/irc/flood/flood.c | 122 +++-- src/irc/notifylist/notify-commands.c | 2 +- src/irc/notifylist/notify-whois.c | 2 +- src/perl/irssi-perl.c | 53 +- src/perl/xs/Irssi-core.xs | 13 +- src/perl/xs/Irssi-netsplit.xs | 23 +- src/perl/xs/Irssi-server.xs | 2 +- src/perl/xs/module.h | 1 + src/perl/xs/typemap | 1 + 100 files changed, 4532 insertions(+), 2231 deletions(-) delete mode 100644 src/fe-common/core/nick-hilight.c create mode 100644 src/fe-common/core/window-activity.c create mode 100644 src/fe-common/irc/fe-irc-server.c create mode 100644 src/fe-common/irc/fe-netsplit.c delete mode 100644 src/fe-common/irc/irc-nick-hilight.c create mode 100644 src/fe-common/irc/irc-window-activity.c delete mode 100644 src/fe-text/gui-mainwindows.c delete mode 100644 src/fe-text/gui-mainwindows.h delete mode 100644 src/fe-text/gui-statusbar-items.c delete mode 100644 src/fe-text/gui-statusbar-items.h delete mode 100644 src/fe-text/gui-statusbar.h create mode 100644 src/fe-text/mainwindows.c create mode 100644 src/fe-text/mainwindows.h create mode 100644 src/fe-text/statusbar-items.c create mode 100644 src/fe-text/statusbar.c create mode 100644 src/fe-text/statusbar.h delete mode 100644 src/irc/dcc/dcc-chat.h delete mode 100644 src/irc/dcc/dcc-files.h (limited to 'src') diff --git a/src/common-setup.h b/src/common-setup.h index a658e836..9bdd6eeb 100644 --- a/src/common-setup.h +++ b/src/common-setup.h @@ -16,9 +16,6 @@ /* How often to check for gone status of nick */ #define MAX_GONE_REFRESH_TIME 300 -/* Maximum time to wait for more JOINs before sending massjoin signal */ -#define MAX_MASSJOIN_WAIT 5000 - /* How long to keep netsplits in memory (seconds) */ #define NETSPLIT_MAX_REMEMBER (60*30) diff --git a/src/core/levels.c b/src/core/levels.c index 7e55d738..9682dcdd 100644 --- a/src/core/levels.c +++ b/src/core/levels.c @@ -36,7 +36,6 @@ static char *levels[] = "KICKS", "MODES", "TOPICS", - "WALLS", "WALLOPS", "INVITES", "NICKS", diff --git a/src/core/levels.h b/src/core/levels.h index f3a54507..ccaf6daa 100644 --- a/src/core/levels.h +++ b/src/core/levels.h @@ -20,17 +20,16 @@ #define MSGLEVEL_KICKS 0x0000400 #define MSGLEVEL_MODES 0x0000800 #define MSGLEVEL_TOPICS 0x0001000 -#define MSGLEVEL_WALLS 0x0002000 -#define MSGLEVEL_WALLOPS 0x0004000 -#define MSGLEVEL_INVITES 0x0008000 -#define MSGLEVEL_NICKS 0x0010000 -#define MSGLEVEL_DCC 0x0020000 -#define MSGLEVEL_CLIENTNOTICE 0x0040000 -#define MSGLEVEL_CLIENTCRAP 0x0080000 -#define MSGLEVEL_CLIENTERROR 0x0100000 -#define MSGLEVEL_HILIGHT 0x0200000 +#define MSGLEVEL_WALLOPS 0x0002000 +#define MSGLEVEL_INVITES 0x0004000 +#define MSGLEVEL_NICKS 0x0008000 +#define MSGLEVEL_DCC 0x0010000 +#define MSGLEVEL_CLIENTNOTICE 0x0020000 +#define MSGLEVEL_CLIENTCRAP 0x0040000 +#define MSGLEVEL_CLIENTERROR 0x0080000 +#define MSGLEVEL_HILIGHT 0x0100000 -#define MSGLEVEL_ALL 0x03fffff +#define MSGLEVEL_ALL 0x01fffff #define MSGLEVEL_NOHILIGHT 0x1000000 /* Don't try to hilight words in this message */ #define MSGLEVEL_NO_ACT 0x2000000 /* Don't trigger channel activity */ diff --git a/src/core/server.c b/src/core/server.c index dcfefc5a..a600e74a 100644 --- a/src/core/server.c +++ b/src/core/server.c @@ -60,7 +60,9 @@ static char *server_create_address_tag(const char *address) const char *start, *end; /* try to generate a reasonable server tag */ - if (g_strncasecmp(address, "irc", 3) == 0 || + if (strchr(address, '.') == NULL) { + start = end = NULL; + } else if (g_strncasecmp(address, "irc", 3) == 0 || g_strncasecmp(address, "chat", 4) == 0) { /* irc-2.cs.hut.fi -> hut, chat.bt.net -> bt */ end = strrchr(address, '.'); @@ -224,14 +226,14 @@ SERVER_REC *server_find_tag(const char *tag) for (tmp = servers; tmp != NULL; tmp = tmp->next) { SERVER_REC *server = tmp->data; - if (strcmp(server->tag, tag) == 0) + if (g_strcasecmp(server->tag, tag) == 0) return server; } for (tmp = lookup_servers; tmp != NULL; tmp = tmp->next) { SERVER_REC *server = tmp->data; - if (strcmp(server->tag, tag) == 0) + if (g_strcasecmp(server->tag, tag) == 0) return server; } @@ -249,7 +251,7 @@ SERVER_REC *server_find_ircnet(const char *ircnet) SERVER_REC *server = tmp->data; if (server->connrec->ircnet != NULL && - strcmp(server->connrec->ircnet, ircnet) == 0) return server; + g_strcasecmp(server->connrec->ircnet, ircnet) == 0) return server; } return NULL; diff --git a/src/core/settings.c b/src/core/settings.c index 5db3c790..a7e27a63 100644 --- a/src/core/settings.c +++ b/src/core/settings.c @@ -258,7 +258,11 @@ static void init_configfile(void) if (stat(str, &statbuf) != 0) { /* ~/.irssi not found, create it. */ if (mkdir(str, 0700) != 0) - g_error("Couldn't create %s/.irssi directory", g_get_home_dir()); + g_error(_("Couldn't create %s/.irssi directory"), g_get_home_dir()); + } else { + if (!S_ISDIR(statbuf.st_mode)) { + g_error(_("%s/.irssi is not a directory.\nYou should remove it with command: rm ~/.irssi"), g_get_home_dir()); + } } g_free(str); @@ -266,7 +270,7 @@ static void init_configfile(void) /* any errors? */ if (config_last_error(mainconfig) != NULL) { - last_error_msg = g_strdup_printf("Ignored errors in configuration file:\n%s", + last_error_msg = g_strdup_printf(_("Ignored errors in configuration file:\n%s"), config_last_error(mainconfig)); signal_add("irssi init finished", (SIGNAL_FUNC) sig_print_config_error); } @@ -291,7 +295,7 @@ static void cmd_rehash(const char *data) if (config_last_error(tempconfig) != NULL) { /* error */ - str = g_strdup_printf("Errors in configuration file:\n%s", + str = g_strdup_printf(_("Errors in configuration file:\n%s"), config_last_error(tempconfig)); signal_emit("gui dialog", 2, "error", str); g_free(str); @@ -308,7 +312,16 @@ static void cmd_rehash(const char *data) static void cmd_save(const char *data) { - config_write(mainconfig, *data == '\0' ? NULL : data, 0660); + char *str; + + if (config_write(mainconfig, *data == '\0' ? NULL : data, 0660) == 0) + return; + + /* error */ + str = g_strdup_printf(_("Couldn't save configuration file: %s"), + config_last_error(mainconfig)); + signal_emit("gui dialog", 2, "error", str); + g_free(str); } void settings_init(void) diff --git a/src/fe-common/core/Makefile.am b/src/fe-common/core/Makefile.am index 025a9dda..c8931435 100644 --- a/src/fe-common/core/Makefile.am +++ b/src/fe-common/core/Makefile.am @@ -17,7 +17,7 @@ libfe_common_core_la_SOURCES = \ hilight-text.c \ keyboard.c \ module-formats.c \ - nick-hilight.c \ + window-activity.c \ printtext.c \ themes.c \ translation.c \ diff --git a/src/fe-common/core/autorun.c b/src/fe-common/core/autorun.c index f1e5d88d..506e45ff 100644 --- a/src/fe-common/core/autorun.c +++ b/src/fe-common/core/autorun.c @@ -44,7 +44,7 @@ static void sig_autorun(void) recvlen = read(f, tmpbuf, sizeof(tmpbuf)); ret = line_split(tmpbuf, recvlen, &str, &buffer); - eval_special_string(str, "", active_win->active_server, active_win->active); + if (ret > 0) eval_special_string(str, "", active_win->active_server, active_win->active); } while (ret > 0); line_split_free(buffer); diff --git a/src/fe-common/core/command-history.c b/src/fe-common/core/command-history.c index 01ae46d7..fa7a1375 100644 --- a/src/fe-common/core/command-history.c +++ b/src/fe-common/core/command-history.c @@ -151,7 +151,7 @@ static char *special_history_func(const char *text, void *item, int *free_ret) static void read_settings(void) { - window_history = settings_get_bool("toggle_window_history"); + window_history = settings_get_bool("window_history"); } void command_history_init(void) @@ -159,7 +159,7 @@ void command_history_init(void) settings_add_int("history", "max_textwidget_lines", 1000); settings_add_int("history", "block_remove_lines", 20); settings_add_int("history", "max_command_history", 100); - settings_add_bool("history", "toggle_window_history", FALSE); + settings_add_bool("history", "window_history", FALSE); special_history_func_set(special_history_func); diff --git a/src/fe-common/core/fe-common-core.c b/src/fe-common/core/fe-common-core.c index d111584d..a348583d 100644 --- a/src/fe-common/core/fe-common-core.c +++ b/src/fe-common/core/fe-common-core.c @@ -47,37 +47,34 @@ void fe_server_deinit(void); void fe_settings_init(void); void fe_settings_deinit(void); -void nick_hilight_init(void); -void nick_hilight_deinit(void); +void window_activity_init(void); +void window_activity_deinit(void); void fe_core_commands_init(void); void fe_core_commands_deinit(void); void fe_common_core_init(void) { - settings_add_bool("lookandfeel", "toggle_show_menubar", TRUE); - settings_add_bool("lookandfeel", "toggle_show_toolbar", FALSE); - settings_add_bool("lookandfeel", "toggle_show_statusbar", TRUE); - settings_add_bool("lookandfeel", "toggle_show_nicklist", TRUE); - settings_add_bool("lookandfeel", "toggle_show_timestamps", FALSE); - settings_add_bool("lookandfeel", "toggle_show_msgs_timestamps", FALSE); - settings_add_bool("lookandfeel", "toggle_hide_text_style", FALSE); - settings_add_bool("lookandfeel", "toggle_bell_beeps", FALSE); - settings_add_bool("lookandfeel", "toggle_actlist_moves", FALSE); - settings_add_bool("lookandfeel", "toggle_show_nickmode", TRUE); - settings_add_bool("lookandfeel", "toggle_show_topicbar", TRUE); - - settings_add_bool("lookandfeel", "toggle_use_status_window", FALSE); - settings_add_bool("lookandfeel", "toggle_use_msgs_window", TRUE); - settings_add_bool("lookandfeel", "toggle_autoraise_msgs_window", FALSE); - settings_add_bool("lookandfeel", "toggle_autocreate_query", TRUE); - settings_add_bool("lookandfeel", "toggle_notifylist_popups", FALSE); - settings_add_bool("lookandfeel", "toggle_use_tabbed_windows", TRUE); - settings_add_int("lookandfeel", "tab_orientation", 3); + /*settings_add_bool("lookandfeel", "show_menubar", TRUE); + settings_add_bool("lookandfeel", "show_toolbar", FALSE); + settings_add_bool("lookandfeel", "show_statusbar", TRUE); + settings_add_bool("lookandfeel", "show_nicklist", TRUE);*/ + settings_add_bool("lookandfeel", "timestamps", TRUE); + settings_add_bool("lookandfeel", "msgs_timestamps", FALSE); + settings_add_bool("lookandfeel", "hide_text_style", FALSE); + settings_add_bool("lookandfeel", "bell_beeps", FALSE); + settings_add_bool("lookandfeel", "show_nickmode", TRUE); + + settings_add_bool("lookandfeel", "use_status_window", FALSE); + settings_add_bool("lookandfeel", "use_msgs_window", TRUE); + /*settings_add_bool("lookandfeel", "autoraise_msgs_window", FALSE);*/ + settings_add_bool("lookandfeel", "autocreate_query", TRUE); + /*settings_add_bool("lookandfeel", "use_tabbed_windows", TRUE); + settings_add_int("lookandfeel", "tab_orientation", 3);*/ settings_add_str("lookandfeel", "current_theme", "default"); autorun_init(); - nick_hilight_init(); + window_activity_init(); hilight_text_init(); command_history_init(); keyboard_init(); @@ -95,7 +92,7 @@ void fe_common_core_init(void) void fe_common_core_deinit(void) { autorun_deinit(); - nick_hilight_deinit(); + window_activity_deinit(); hilight_text_deinit(); command_history_deinit(); keyboard_deinit(); @@ -116,13 +113,15 @@ void fe_common_core_finish_init(void) signal(SIGPIPE, SIG_IGN); - if (settings_get_bool("toggle_use_status_window")) { + if (settings_get_bool("use_status_window")) { window = window_create(NULL, TRUE); window_set_name(window, "(status)"); - window_set_level(window, MSGLEVEL_ALL ^ (settings_get_bool("toggle_use_msgs_window") ? (MSGLEVEL_MSGS|MSGLEVEL_ACTIONS) : 0)); + window_set_level(window, MSGLEVEL_ALL ^ + (settings_get_bool("use_msgs_window") ? + (MSGLEVEL_MSGS|MSGLEVEL_ACTIONS) : 0)); } - if (settings_get_bool("toggle_use_msgs_window")) { + if (settings_get_bool("use_msgs_window")) { window = window_create(NULL, TRUE); window_set_name(window, "(msgs)"); window_set_level(window, MSGLEVEL_MSGS|MSGLEVEL_ACTIONS); diff --git a/src/fe-common/core/fe-core-commands.c b/src/fe-common/core/fe-core-commands.c index b036385d..41320eed 100644 --- a/src/fe-common/core/fe-core-commands.c +++ b/src/fe-common/core/fe-core-commands.c @@ -23,35 +23,35 @@ #include "signals.h" #include "commands.h" #include "levels.h" +#include "misc.h" #include "line-split.h" #include "irssi-version.h" #include "windows.h" -static gchar *ret_texts[] = -{ - "Invalid parameter", - "Not enough parameters given", - "Not connected to IRC server yet", - "Not joined to any channels yet", - "Error: getsockname() failed", - "Error: listen() failed", - "Multiple matches found, be more specific", - "Nick not found", - "Not joined to such channel", - "Server not found", - "Channel not fully synchronized yet, try again after a while", - "Doing this is not a good idea. Add -YES if you really mean it", +static const char *ret_texts[] = { + "Invalid parameter", + "Not enough parameters given", + "Not connected to IRC server yet", + "Not joined to any channels yet", + "Error: getsockname() failed", + "Error: listen() failed", + "Multiple matches found, be more specific", + "Nick not found", + "Not joined to such channel", + "Server not found", + "Channel not fully synchronized yet, try again after a while", + "Doing this is not a good idea. Add -YES if you really mean it", }; -static gint commands_compare(COMMAND_REC *rec, COMMAND_REC *rec2) +static int commands_compare(COMMAND_REC *rec, COMMAND_REC *rec2) { - if (rec->category == NULL && rec2->category != NULL) - return -1; - if (rec2->category == NULL && rec->category != NULL) - return 1; + if (rec->category == NULL && rec2->category != NULL) + return -1; + if (rec2->category == NULL && rec->category != NULL) + return 1; - return strcmp(rec->cmd, rec2->cmd); + return strcmp(rec->cmd, rec2->cmd); } static void help_category(GSList *cmdlist, gint items, gint max) @@ -118,7 +118,7 @@ static int show_help(COMMAND_REC *cmd) recvlen = read(f, tmpbuf, sizeof(tmpbuf)); ret = line_split(tmpbuf, recvlen, &str, &buffer); - printtext(NULL, NULL, MSGLEVEL_NEVER, str); + if (ret > 0) printtext(NULL, NULL, MSGLEVEL_NEVER, str); } while (ret > 0); line_split_free(buffer); @@ -227,6 +227,37 @@ static void cmd_version(char *data) printtext(NULL, NULL, MSGLEVEL_CLIENTNOTICE, "Client: "PACKAGE" " IRSSI_VERSION); } +static void cmd_cat(const char *data) +{ + char tmpbuf[1024], *str, *fname; + LINEBUF_REC *buffer = NULL; + int f, ret, recvlen; + + fname = convert_home(data); + f = open(fname, O_RDONLY); + g_free(fname); + if (f == -1) { + /* file not found */ + printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "%s", g_strerror(errno)); + return; + } + + do { + recvlen = read(f, tmpbuf, sizeof(tmpbuf)); + + ret = line_split(tmpbuf, recvlen, &str, &buffer); + if (ret > 0) printtext(NULL, NULL, MSGLEVEL_CLIENTCRAP, "%s", str); + } while (ret > 0); + line_split_free(buffer); + + close(f); +} + +static void cmd_beep(void) +{ + printbeep(); +} + static void cmd_unknown(const char *data, void *server, WI_ITEM_REC *item) { char *cmd; @@ -248,6 +279,8 @@ void fe_core_commands_init(void) command_bind("help", NULL, (SIGNAL_FUNC) cmd_help); command_bind("echo", NULL, (SIGNAL_FUNC) cmd_echo); command_bind("version", NULL, (SIGNAL_FUNC) cmd_version); + command_bind("cat", NULL, (SIGNAL_FUNC) cmd_cat); + command_bind("beep", NULL, (SIGNAL_FUNC) cmd_beep); signal_add("unknown command", (SIGNAL_FUNC) cmd_unknown); signal_add("default command", (SIGNAL_FUNC) cmd_unknown); @@ -259,6 +292,8 @@ void fe_core_commands_deinit(void) command_unbind("help", (SIGNAL_FUNC) cmd_help); command_unbind("echo", (SIGNAL_FUNC) cmd_echo); command_unbind("version", (SIGNAL_FUNC) cmd_version); + command_unbind("cat", (SIGNAL_FUNC) cmd_cat); + command_unbind("beep", (SIGNAL_FUNC) cmd_beep); signal_remove("unknown command", (SIGNAL_FUNC) cmd_unknown); signal_remove("default command", (SIGNAL_FUNC) cmd_unknown); diff --git a/src/fe-common/core/fe-log.c b/src/fe-common/core/fe-log.c index 636c461b..11fe5b2f 100644 --- a/src/fe-common/core/fe-log.c +++ b/src/fe-common/core/fe-log.c @@ -43,16 +43,16 @@ static const char *autolog_path; static void cmd_log_open(const char *data) { - /* /LOG OPEN [-noopen] [-autoopen] [-channels ] [-window] + /* /LOG OPEN [-noopen] [-autoopen] [-targets ] [-window] [-rotate hour|day|week|month] [] */ - char *params, *args, *itemarg, *rotatearg, *fname, *levels; + char *params, *args, *targetarg, *rotatearg, *fname, *levels; char window[MAX_INT_STRLEN]; LOG_REC *log; int opened, level, rotate; - args = "channels rotate"; + args = "targets rotate"; params = cmd_get_params(data, 5 | PARAM_FLAG_MULTIARGS | PARAM_FLAG_GETREST, - &args, &itemarg, &rotatearg, &fname, &levels); + &args, &targetarg, &rotatearg, &fname, &levels); if (*fname == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); rotate = LOG_ROTATE_NEVER; @@ -67,10 +67,10 @@ static void cmd_log_open(const char *data) if (stristr(args, "-window")) { /* log by window ref# */ ltoa(window, active_win->refnum); - itemarg = window; + targetarg = window; } - log = log_create_rec(fname, level, itemarg); + log = log_create_rec(fname, level, targetarg); if (log != NULL && log->handle == -1 && stristr(args, "-noopen") == NULL) { /* start logging */ opened = log_start_logging(log); @@ -193,7 +193,7 @@ static void cmd_window_log(const char *data) open_log = log == NULL; close_log = log != NULL; } else { - printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_NOT_TOGGLE); + printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_NOT_TOGGLE); g_free(params); return; } @@ -230,17 +230,34 @@ static void cmd_window_logfile(const char *data) log = log_find_item(window); if (log != NULL) { - printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_WINDOWLOG_FILE_LOGGING); + printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_WINDOWLOG_FILE_LOGGING); return; } log = log_create_rec(data, MSGLEVEL_ALL, window); if (log == NULL) - printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_WINDOWLOG_FILE, data); + printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_WINDOWLOG_FILE, data); else log_update(log); } +/* window's refnum changed - update the logs to log the new window refnum */ +static void sig_window_refnum_changed(WINDOW_REC *window, gpointer old_refnum) +{ + char winnum[MAX_INT_STRLEN]; + LOG_REC *log; + + ltoa(winnum, GPOINTER_TO_INT(old_refnum)); + log = log_find_item(winnum); + + if (log != NULL) { + ltoa(winnum, window->refnum); + + g_strfreev(log->items); + log->items = g_strsplit(winnum, " ", -1); + } +} + static void autologs_close_all(void) { GSList *tmp, *next; @@ -379,6 +396,7 @@ void fe_log_init(void) command_bind("window logfile", NULL, (SIGNAL_FUNC) cmd_window_logfile); signal_add_first("print text stripped", (SIGNAL_FUNC) sig_printtext_stripped); signal_add("window item remove", (SIGNAL_FUNC) sig_window_item_remove); + signal_add("window refnum changed", (SIGNAL_FUNC) sig_window_refnum_changed); signal_add("log locked", (SIGNAL_FUNC) sig_log_locked); signal_add("setup changed", (SIGNAL_FUNC) read_settings); } @@ -397,6 +415,7 @@ void fe_log_deinit(void) command_unbind("window logfile", (SIGNAL_FUNC) cmd_window_logfile); signal_remove("print text stripped", (SIGNAL_FUNC) sig_printtext_stripped); signal_remove("window item remove", (SIGNAL_FUNC) sig_window_item_remove); + signal_remove("window refnum changed", (SIGNAL_FUNC) sig_window_refnum_changed); signal_remove("log locked", (SIGNAL_FUNC) sig_log_locked); signal_remove("setup changed", (SIGNAL_FUNC) read_settings); } diff --git a/src/fe-common/core/fe-server.c b/src/fe-common/core/fe-server.c index 960b94f9..fff3d1fc 100644 --- a/src/fe-common/core/fe-server.c +++ b/src/fe-common/core/fe-server.c @@ -77,6 +77,14 @@ static void sig_server_disconnected(SERVER_REC *server) IRCTXT_CONNECTION_LOST, server->connrec->address); } +static void sig_server_quit(SERVER_REC *server, const char *msg) +{ + g_return_if_fail(server != NULL); + + printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, + IRCTXT_SERVER_QUIT, server->connrec->address, msg); +} + void fe_server_init(void) { signal_add("server looking", (SIGNAL_FUNC) sig_server_looking); @@ -84,6 +92,7 @@ void fe_server_init(void) signal_add("server connected", (SIGNAL_FUNC) sig_server_connected); signal_add("server connect failed", (SIGNAL_FUNC) sig_connect_failed); signal_add("server disconnected", (SIGNAL_FUNC) sig_server_disconnected); + signal_add("server quit", (SIGNAL_FUNC) sig_server_quit); } void fe_server_deinit(void) @@ -93,4 +102,5 @@ void fe_server_deinit(void) signal_remove("server connected", (SIGNAL_FUNC) sig_server_connected); signal_remove("server connect failed", (SIGNAL_FUNC) sig_connect_failed); signal_remove("server disconnected", (SIGNAL_FUNC) sig_server_disconnected); + signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit); } diff --git a/src/fe-common/core/fe-settings.c b/src/fe-common/core/fe-settings.c index 5e4b6df6..f05faad0 100644 --- a/src/fe-common/core/fe-settings.c +++ b/src/fe-common/core/fe-settings.c @@ -23,6 +23,7 @@ #include "signals.h" #include "commands.h" #include "server.h" +#include "misc.h" #include "lib-config/iconfig.h" #include "settings.h" @@ -66,19 +67,17 @@ static void cmd_set(char *data) { GSList *sets, *tmp; char *params, *key, *value, *last_section; - int keylen, found; + int found; params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &key, &value); - keylen = strlen(key); last_section = ""; found = 0; - sets = settings_get_sorted(); for (tmp = sets; tmp != NULL; tmp = tmp->next) { SETTINGS_REC *rec = tmp->data; if ((*value != '\0' && g_strcasecmp(rec->key, key) != 0) || - (*value == '\0' && keylen != 0 && g_strncasecmp(rec->key, key, keylen) != 0)) + (*value == '\0' && *key != '\0' && stristr(rec->key, key) == NULL)) continue; if (strcmp(last_section, rec->section) != 0) { @@ -140,7 +139,7 @@ static void show_aliases(const char *alias) GSList *tmp; int aliaslen; - printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_ALIASLIST_HEADER); + printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_ALIASLIST_HEADER); node = iconfig_node_traverse("aliases", FALSE); tmp = node == NULL ? NULL : node->value; @@ -155,11 +154,11 @@ static void show_aliases(const char *alias) if (aliaslen != 0 && g_strncasecmp(node->key, alias, aliaslen) != 0) continue; - printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_ALIASLIST_LINE, + printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_ALIASLIST_LINE, node->key, node->value); } - printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_ALIASLIST_FOOTER); + printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_ALIASLIST_FOOTER); } static void alias_remove(const char *alias) diff --git a/src/fe-common/core/hilight-text.c b/src/fe-common/core/hilight-text.c index a96f7395..61156e01 100644 --- a/src/fe-common/core/hilight-text.c +++ b/src/fe-common/core/hilight-text.c @@ -314,7 +314,7 @@ static void cmd_dehilight(const char *data) if (is_numeric(data, ' ')) { /* with index number */ - tmp = g_slist_nth(hilights, atol(data)-1); + tmp = g_slist_nth(hilights, atoi(data)-1); rec = tmp == NULL ? NULL : tmp->data; } else { /* with mask */ diff --git a/src/fe-common/core/module-formats.c b/src/fe-common/core/module-formats.c index e8287a98..358f467c 100644 --- a/src/fe-common/core/module-formats.c +++ b/src/fe-common/core/module-formats.c @@ -31,8 +31,13 @@ FORMAT_REC fecommon_core_formats[] = { "line_start", "%B-%W!%B-%n ", 0 }, { "line_start_irssi", "%B-%W!%B- %WIrssi:%n ", 0 }, { "timestamp", "[$[-2.0]3:$[-2.0]4] ", 6, { 1, 1, 1, 1, 1, 1 } }, - { "daychange", "Day changed to $[-2.0]1-$[-2.0]0 $2", 3, { 1, 1, 1 } }, + { "daychange", "Day changed to ${[-2.0]1}-$[-2.0]0 $2", 3, { 1, 1, 1 } }, { "talking_with", "You are now talking with %_$0%_", 1, { 0 } }, + { "refnum_too_low", "Window number must be greater than 1", 0 }, + { "refnum_not_found", "No such window: $0", 1, { 0 } }, + { "windowlist_header", "Ref Name Active item Server Level", 0 }, + { "windowlist_line", "$[3]0 %|$[20]1 $[15]2 $[15]3 $4", 5, { 1, 0, 0, 0, 0 } }, + { "windowlist_footer", "", 0 }, /* ---- */ { NULL, "Server", 0 }, @@ -42,6 +47,7 @@ FORMAT_REC fecommon_core_formats[] = { "connection_established", "Connection to %_$0%_ established", 1, { 0 } }, { "cant_connect", "Unable to connect server %_$0%_ port %_$1%_ %K[%n$2%K]", 3, { 0, 1, 0 } }, { "connection_lost", "Connection lost to %_$0%_", 1, { 0 } }, + { "server_quit", "Disconnecting from server $0: %K[%n$1%K]", 2, { 0, 0 } }, { "server_changed", "Changed to %_$2%_ server %_$1%_", 3, { 0, 0, 0 } }, { "unknown_server_tag", "Unknown server tag %_$0%_", 1, { 0 } }, diff --git a/src/fe-common/core/module-formats.h b/src/fe-common/core/module-formats.h index 6730f413..db94140e 100644 --- a/src/fe-common/core/module-formats.h +++ b/src/fe-common/core/module-formats.h @@ -10,6 +10,11 @@ enum { IRCTXT_TIMESTAMP, IRCTXT_DAYCHANGE, IRCTXT_TALKING_WITH, + IRCTXT_REFNUM_TOO_LOW, + IRCTXT_REFNUM_NOT_FOUND, + IRCTXT_WINDOWLIST_HEADER, + IRCTXT_WINDOWLIST_LINE, + IRCTXT_WINDOWLIST_FOOTER, IRCTXT_FILL_2, @@ -18,6 +23,7 @@ enum { IRCTXT_CONNECTION_ESTABLISHED, IRCTXT_CANT_CONNECT, IRCTXT_CONNECTION_LOST, + IRCTXT_SERVER_QUIT, IRCTXT_SERVER_CHANGED, IRCTXT_UNKNOWN_SERVER_TAG, diff --git a/src/fe-common/core/nick-hilight.c b/src/fe-common/core/nick-hilight.c deleted file mode 100644 index 8244ff50..00000000 --- a/src/fe-common/core/nick-hilight.c +++ /dev/null @@ -1,115 +0,0 @@ -/* - nick-hilight.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include "module.h" -#include "signals.h" -#include "levels.h" -#include "server.h" - -#include "windows.h" -#include "window-items.h" - -static void sig_hilight_text(SERVER_REC *server, const char *channel, gpointer levelptr, const char *msg) -{ - WINDOW_REC *window; - int level, oldlevel; - - level = GPOINTER_TO_INT(levelptr); - window = window_find_closest(server, channel, level); - if (window == active_win || (level & (MSGLEVEL_NEVER|MSGLEVEL_NO_ACT|MSGLEVEL_MSGS))) - return; - - oldlevel = window->new_data; - if (window->new_data < NEWDATA_TEXT) { - window->new_data = NEWDATA_TEXT; - signal_emit("window hilight", 1, window); - } - - signal_emit("window activity", 2, window, GINT_TO_POINTER(oldlevel)); -} - -static void sig_dehilight(WINDOW_REC *window, WI_ITEM_REC *item) -{ - g_return_if_fail(window != NULL); - - if (item != NULL && item->new_data != 0) { - item->new_data = 0; - signal_emit("window item hilight", 1, item); - } -} - -static void sig_dehilight_window(WINDOW_REC *window) -{ - int oldlevel; - - g_return_if_fail(window != NULL); - - if (window->new_data == 0) - return; - - if (window->new_data != 0) { - oldlevel = window->new_data; - window->new_data = 0; - signal_emit("window hilight", 2, window, GINT_TO_POINTER(oldlevel)); - } - signal_emit("window activity", 2, window, GINT_TO_POINTER(oldlevel)); - - g_slist_foreach(window->items, (GFunc) sig_dehilight, NULL); -} - -static void sig_hilight_window_item(WI_ITEM_REC *item) -{ - WINDOW_REC *window; - GSList *tmp; - int level, oldlevel; - - window = window_item_window(item); level = 0; - for (tmp = window->items; tmp != NULL; tmp = tmp->next) { - item = tmp->data; - - if (item->new_data > level) - level = item->new_data; - } - - oldlevel = window->new_data; - if (window->new_data < level || level == 0) { - window->new_data = level; - signal_emit("window hilight", 2, window, GINT_TO_POINTER(oldlevel)); - } - signal_emit("window activity", 2, window, GINT_TO_POINTER(oldlevel)); -} - -void nick_hilight_init(void) -{ - signal_add("print text", (SIGNAL_FUNC) sig_hilight_text); - signal_add("window item changed", (SIGNAL_FUNC) sig_dehilight); - signal_add("window changed", (SIGNAL_FUNC) sig_dehilight_window); - signal_add("window dehilight", (SIGNAL_FUNC) sig_dehilight_window); - signal_add("window item hilight", (SIGNAL_FUNC) sig_hilight_window_item); -} - -void nick_hilight_deinit(void) -{ - signal_remove("print text", (SIGNAL_FUNC) sig_hilight_text); - signal_remove("window item changed", (SIGNAL_FUNC) sig_dehilight); - signal_remove("window changed", (SIGNAL_FUNC) sig_dehilight_window); - signal_remove("window dehilight", (SIGNAL_FUNC) sig_dehilight_window); - signal_remove("window item hilight", (SIGNAL_FUNC) sig_hilight_window_item); -} diff --git a/src/fe-common/core/printtext.c b/src/fe-common/core/printtext.c index a80177b6..7152e910 100644 --- a/src/fe-common/core/printtext.c +++ b/src/fe-common/core/printtext.c @@ -1,7 +1,7 @@ /* printtext.c : irssi - Copyright (C) 1999 Timo Sirainen + 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 @@ -33,7 +33,7 @@ #include "themes.h" #include "windows.h" -static gboolean toggle_show_timestamps, toggle_show_msgs_timestamps, toggle_hide_text_style; +static gboolean timestamps, msgs_timestamps, hide_text_style; static gint printtag; static gchar ansitab[8] = { 0, 4, 2, 6, 1, 5, 3, 7 }; @@ -108,7 +108,7 @@ static char *convert_ansi(char *str, int *fgcolor, int *bgcolor, int *flags) if (*str == 'm') { - if (!toggle_hide_text_style) + if (!hide_text_style) { *fgcolor = fg; *bgcolor = bg == -1 ? -1 : bg; @@ -410,7 +410,7 @@ static void add_timestamp(WINDOW_REC *window, GString *out, void *server, const struct tm *tm; GString *tmp; - if (!(level != MSGLEVEL_NEVER && (toggle_show_timestamps || (toggle_show_msgs_timestamps && (level & MSGLEVEL_MSGS) != 0)))) + if (!(level != MSGLEVEL_NEVER && (timestamps || (msgs_timestamps && (level & MSGLEVEL_MSGS) != 0)))) return; t = time(NULL); @@ -574,6 +574,7 @@ static void sig_print_text(void *server, const char *target, gpointer level, con flags = 0; fgcolor = -1; bgcolor = -1; type = '\0'; + window->last_line = time(NULL); newline(window); out = g_string_new(text); @@ -612,7 +613,7 @@ static void sig_print_text(void *server, const char *target, gpointer level, con if (type == 7) { /* bell */ - if (settings_get_bool("toggle_bell_beeps")) + if (settings_get_bool("bell_beeps")) flags |= PRINTFLAG_BEEP; } if (*str != '\0' || flags & PRINTFLAG_BEEP) @@ -628,12 +629,12 @@ static void sig_print_text(void *server, const char *target, gpointer level, con { case 2: /* bold */ - if (!toggle_hide_text_style) + if (!hide_text_style) flags ^= PRINTFLAG_BOLD; break; case 6: /* blink */ - if (!toggle_hide_text_style) + if (!hide_text_style) flags ^= PRINTFLAG_BLINK; break; case 15: @@ -643,12 +644,12 @@ static void sig_print_text(void *server, const char *target, gpointer level, con break; case 22: /* reverse */ - if (!toggle_hide_text_style) + if (!hide_text_style) flags ^= PRINTFLAG_REVERSE; break; case 31: /* underline */ - if (!toggle_hide_text_style) + if (!hide_text_style) flags ^= PRINTFLAG_UNDERLINE; case 27: /* ansi color code */ @@ -711,7 +712,7 @@ static void sig_print_text(void *server, const char *target, gpointer level, con } /* MIRC color */ - if (toggle_hide_text_style) + if (hide_text_style) { /* don't show them. */ if (isdigit((gint) *ptr)) @@ -776,7 +777,7 @@ static int sig_check_daychange(void) time_t t; struct tm *tm; - if (!toggle_show_timestamps) + if (!timestamps) { /* display day change notice only when using timestamps */ return TRUE; @@ -800,6 +801,9 @@ static int sig_check_daychange(void) { WINDOW_REC *win = tmp->data; + if (win->active == NULL) + continue; /* FIXME: how to print in these windows? */ + printformat(win->active->server, win->active->name, MSGLEVEL_NEVER, IRCTXT_DAYCHANGE, tm->tm_mday, tm->tm_mon+1, 1900+tm->tm_year); } @@ -833,9 +837,9 @@ static void sig_gui_dialog(const char *type, const char *text) static void read_settings(void) { - toggle_show_timestamps = settings_get_bool("toggle_show_timestamps"); - toggle_show_msgs_timestamps = settings_get_bool("toggle_show_msgs_timestamps"); - toggle_hide_text_style = settings_get_bool("toggle_hide_text_style"); + timestamps = settings_get_bool("timestamps"); + msgs_timestamps = settings_get_bool("msgs_timestamps"); + hide_text_style = settings_get_bool("hide_text_style"); } void printtext_init(void) @@ -852,7 +856,6 @@ void printtext_init(void) signal_add("print text", (SIGNAL_FUNC) sig_print_text); signal_add("gui dialog", (SIGNAL_FUNC) sig_gui_dialog); signal_add("setup changed", (SIGNAL_FUNC) read_settings); - command_bind("beep", NULL, (SIGNAL_FUNC) printbeep); } void printtext_deinit(void) @@ -861,5 +864,4 @@ void printtext_deinit(void) signal_remove("print text", (SIGNAL_FUNC) sig_print_text); signal_remove("gui dialog", (SIGNAL_FUNC) sig_gui_dialog); signal_remove("setup changed", (SIGNAL_FUNC) read_settings); - command_unbind("beep", (SIGNAL_FUNC) printbeep); } diff --git a/src/fe-common/core/printtext.h b/src/fe-common/core/printtext.h index 6c32522e..18f3246e 100644 --- a/src/fe-common/core/printtext.h +++ b/src/fe-common/core/printtext.h @@ -56,6 +56,9 @@ void printtext(void *server, const char *channel, int level, const char *str, .. void printtext_multiline(void *server, const char *channel, int level, const char *format, const char *text); void printbeep(void); +/* strip all color (etc.) codes from `input'. returns newly allocated string. */ +char *strip_codes(const char *input); + void printtext_init(void); void printtext_deinit(void); diff --git a/src/fe-common/core/window-activity.c b/src/fe-common/core/window-activity.c new file mode 100644 index 00000000..ba3adb13 --- /dev/null +++ b/src/fe-common/core/window-activity.c @@ -0,0 +1,117 @@ +/* + window-activity.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "module.h" +#include "signals.h" +#include "levels.h" +#include "server.h" + +#include "windows.h" +#include "window-items.h" + +static void sig_hilight_text(SERVER_REC *server, const char *channel, gpointer levelptr, const char *msg) +{ + WINDOW_REC *window; + int level, oldlevel; + + level = GPOINTER_TO_INT(levelptr); + window = window_find_closest(server, channel, level); + if (window == active_win || (level & (MSGLEVEL_NEVER|MSGLEVEL_NO_ACT|MSGLEVEL_MSGS))) + return; + + oldlevel = window->new_data; + if (window->new_data < NEWDATA_TEXT) { + window->new_data = NEWDATA_TEXT; + signal_emit("window hilight", 1, window); + } + + signal_emit("window activity", 2, window, GINT_TO_POINTER(oldlevel)); +} + +static void sig_dehilight(WINDOW_REC *window, WI_ITEM_REC *item) +{ + g_return_if_fail(window != NULL); + + if (item != NULL && item->new_data != 0) { + item->new_data = 0; + signal_emit("window item hilight", 1, item); + } +} + +static void sig_dehilight_window(WINDOW_REC *window) +{ + GSList *tmp; + int oldlevel; + + g_return_if_fail(window != NULL); + + if (window->new_data == 0) + return; + + if (window->new_data != 0) { + oldlevel = window->new_data; + window->new_data = 0; + signal_emit("window hilight", 2, window, GINT_TO_POINTER(oldlevel)); + } + signal_emit("window activity", 2, window, GINT_TO_POINTER(oldlevel)); + + for (tmp = window->items; tmp != NULL; tmp = tmp->next) + sig_dehilight(window, tmp->data); +} + +static void sig_hilight_window_item(WI_ITEM_REC *item) +{ + WINDOW_REC *window; + GSList *tmp; + int level, oldlevel; + + window = window_item_window(item); level = 0; + for (tmp = window->items; tmp != NULL; tmp = tmp->next) { + item = tmp->data; + + if (item->new_data > level) + level = item->new_data; + } + + oldlevel = window->new_data; + if (window->new_data < level || level == 0) { + window->new_data = level; + signal_emit("window hilight", 2, window, GINT_TO_POINTER(oldlevel)); + } + signal_emit("window activity", 2, window, GINT_TO_POINTER(oldlevel)); +} + +void window_activity_init(void) +{ + signal_add("print text", (SIGNAL_FUNC) sig_hilight_text); + signal_add("window item changed", (SIGNAL_FUNC) sig_dehilight); + signal_add("window changed", (SIGNAL_FUNC) sig_dehilight_window); + signal_add("window dehilight", (SIGNAL_FUNC) sig_dehilight_window); + signal_add("window item hilight", (SIGNAL_FUNC) sig_hilight_window_item); +} + +void window_activity_deinit(void) +{ + signal_remove("print text", (SIGNAL_FUNC) sig_hilight_text); + signal_remove("window item changed", (SIGNAL_FUNC) sig_dehilight); + signal_remove("window changed", (SIGNAL_FUNC) sig_dehilight_window); + signal_remove("window dehilight", (SIGNAL_FUNC) sig_dehilight_window); + signal_remove("window item hilight", (SIGNAL_FUNC) sig_hilight_window_item); +} diff --git a/src/fe-common/core/windows.c b/src/fe-common/core/windows.c index 3a88833b..6587a4e8 100644 --- a/src/fe-common/core/windows.c +++ b/src/fe-common/core/windows.c @@ -24,6 +24,7 @@ #include "signals.h" #include "commands.h" #include "server.h" +#include "misc.h" #include "settings.h" #include "levels.h" @@ -32,7 +33,8 @@ #include "windows.h" #include "window-items.h" -GSList *windows; +GSList *windows; /* first in the list is the active window, + next is the last active, etc. */ WINDOW_REC *active_win; static int window_get_new_refnum(void) @@ -65,7 +67,7 @@ WINDOW_REC *window_create(WI_ITEM_REC *item, int automatic) rec = g_new0(WINDOW_REC, 1); rec->refnum = window_get_new_refnum(); - windows = g_slist_append(windows, rec); + windows = g_slist_prepend(windows, rec); signal_emit("window created", 2, rec, GINT_TO_POINTER(automatic)); if (item != NULL) window_add_item(rec, item, automatic); @@ -77,8 +79,26 @@ WINDOW_REC *window_create(WI_ITEM_REC *item, int automatic) return rec; } +/* removed_refnum was removed from the windows list, pack the windows so + there won't be any holes. If there is any holes after removed_refnum, + leave the windows behind it alone. */ +static void windows_pack(int removed_refnum) +{ + WINDOW_REC *window; + int refnum; + + for (refnum = removed_refnum+1;; refnum++) { + window = window_find_refnum(refnum); + if (window == NULL) break; + + window_set_refnum(window, refnum-1); + } +} + void window_destroy(WINDOW_REC *window) { + int refnum; + g_return_if_fail(window != NULL); if (window->destroying) return; @@ -93,29 +113,25 @@ void window_destroy(WINDOW_REC *window) g_slist_foreach(window->waiting_channels, (GFunc) g_free, NULL); g_slist_free(window->waiting_channels); + refnum = window->refnum; g_free_not_null(window->name); g_free(window); -} -void window_set_active_num(int number) -{ - GSList *win; - - win = g_slist_nth(windows, number); - if (win == NULL) return; + if (active_win == window && windows != NULL) + window_set_active(windows->data); - active_win = win->data; - signal_emit("window changed", 1, active_win); + windows_pack(refnum); } void window_set_active(WINDOW_REC *window) { - int number; - - number = g_slist_index(windows, window); - if (number == -1) return; + if (window == active_win) + return; active_win = window; + windows = g_slist_remove(windows, active_win); + windows = g_slist_prepend(windows, active_win); + signal_emit("window changed", 1, active_win); } @@ -125,6 +141,30 @@ void window_change_server(WINDOW_REC *window, void *server) signal_emit("window server changed", 2, window, server); } +void window_set_refnum(WINDOW_REC *window, int refnum) +{ + GSList *tmp; + int old_refnum; + + g_return_if_fail(window != NULL); + g_return_if_fail(refnum >= 1); + if (window->refnum == refnum) return; + + for (tmp = windows; tmp != NULL; tmp = tmp->next) { + WINDOW_REC *rec = tmp->data; + + if (rec->refnum == refnum) { + rec->refnum = window->refnum; + signal_emit("window refnum changed", 2, rec, GINT_TO_POINTER(refnum)); + break; + } + } + + old_refnum = window->refnum; + window->refnum = refnum; + signal_emit("window refnum changed", 2, window, GINT_TO_POINTER(old_refnum)); +} + void window_set_name(WINDOW_REC *window, const char *name) { g_free_not_null(window->name); @@ -182,6 +222,68 @@ WINDOW_REC *window_find_closest(void *server, const char *name, int level) return active_win; } +WINDOW_REC *window_find_refnum(int refnum) +{ + GSList *tmp; + + for (tmp = windows; tmp != NULL; tmp = tmp->next) { + WINDOW_REC *rec = tmp->data; + + if (rec->refnum == refnum) + return rec; + } + + return NULL; +} + +static int windows_refnum_last(void) +{ + GSList *tmp; + int max; + + max = -1; + for (tmp = windows; tmp != NULL; tmp = tmp->next) { + WINDOW_REC *rec = tmp->data; + + if (rec->refnum > max) + max = rec->refnum; + } + + return max; +} + +static int window_refnum_prev(int refnum) +{ + GSList *tmp; + int max; + + max = -1; + for (tmp = windows; tmp != NULL; tmp = tmp->next) { + WINDOW_REC *rec = tmp->data; + + if (rec->refnum < refnum && (max == -1 || rec->refnum > max)) + max = rec->refnum; + } + + return max; +} + +static int window_refnum_next(int refnum) +{ + GSList *tmp; + int min; + + min = -1; + for (tmp = windows; tmp != NULL; tmp = tmp->next) { + WINDOW_REC *rec = tmp->data; + + if (rec->refnum > refnum && (min == -1 || rec->refnum < min)) + min = rec->refnum; + } + + return min; +} + static void cmd_window(const char *data, void *server, WI_ITEM_REC *item) { command_runsub("window", data, server, item); @@ -194,7 +296,7 @@ static void cmd_window_new(const char *data, void *server, WI_ITEM_REC *item) g_return_if_fail(data != NULL); - type = (g_strcasecmp(data, "hide") == 0 || g_strcasecmp(data, "tab") == 0) ? 1 : + type = (g_strncasecmp(data, "hid", 3) == 0 || g_strcasecmp(data, "tab") == 0) ? 1 : (g_strcasecmp(data, "split") == 0 ? 2 : 0); signal_emit("gui window create override", 1, GINT_TO_POINTER(type)); @@ -210,13 +312,15 @@ static void cmd_window_close(const char *data) } /* return the first window number with the highest activity */ -static int window_highest_activity(WINDOW_REC *window) +static WINDOW_REC *window_highest_activity(WINDOW_REC *window) { - WINDOW_REC *rec; + WINDOW_REC *rec, *max_win; GSList *tmp; - int max_num, max_act, through; + int max_act, through; + + g_return_val_if_fail(window != NULL, NULL); - max_num = 0; max_act = 0; through = FALSE; + max_win = NULL; max_act = 0; through = FALSE; tmp = g_slist_find(windows, window); for (;; tmp = tmp->next) { @@ -232,20 +336,41 @@ static int window_highest_activity(WINDOW_REC *window) if (rec->new_data && max_act < rec->new_data) { max_act = rec->new_data; - max_num = g_slist_index(windows, rec)+1; + max_win = rec; } } - return max_num; + return max_win; } -/* channel name - first try channel from same server */ -static int window_find_name(WINDOW_REC *window, const char *name) +WINDOW_REC *window_find_name(const char *name) { + GSList *tmp; + + g_return_val_if_fail(name != NULL, NULL); + + for (tmp = windows; tmp != NULL; tmp = tmp->next) { + WINDOW_REC *rec = tmp->data; + + if (rec->name != NULL && g_strcasecmp(rec->name, name) == 0) + return rec; + } + + return NULL; +} + +WINDOW_REC *window_find_item(WINDOW_REC *window, const char *name) +{ + WINDOW_REC *rec; WI_ITEM_REC *item; - int num; - item = window_item_find(window->active_server, name); + g_return_val_if_fail(name != NULL, NULL); + + rec = window_find_name(name); + if (rec != NULL) return rec; + + item = window == NULL ? NULL : + window_item_find(window->active_server, name); if (item == NULL && window->active_server != NULL) { /* not found from the active server - any server? */ item = window_item_find(NULL, name); @@ -257,7 +382,8 @@ static int window_find_name(WINDOW_REC *window, const char *name) /* still nothing? maybe user just left the # in front of channel, try again with it.. */ chan = g_strdup_printf("#%s", name); - item = window_item_find(window->active_server, chan); + item = window == NULL ? NULL : + window_item_find(window->active_server, chan); if (item == NULL) item = window_item_find(NULL, chan); g_free(chan); } @@ -265,48 +391,63 @@ static int window_find_name(WINDOW_REC *window, const char *name) if (item == NULL) return 0; - /* get the window number */ - window = MODULE_DATA(item); - if (window == NULL) return 0; + return MODULE_DATA(item); +} - num = g_slist_index(windows, window); - return num < 0 ? 0 : num+1; +static void cmd_window_refnum(const char *data) +{ + WINDOW_REC *window; + + if (!is_numeric(data, 0)) { + printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_REFNUM_NOT_FOUND, data); + return; + } + + window = window_find_refnum(atoi(data)); + if (window == NULL) + printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_REFNUM_NOT_FOUND, data); + else + window_set_active(window); } static void cmd_window_goto(const char *data) { - int num; + WINDOW_REC *window; g_return_if_fail(data != NULL); - num = 0; + if (is_numeric(data, 0)) { + cmd_window_refnum(data); + return; + } + if (g_strcasecmp(data, "active") == 0) - num = window_highest_activity(active_win); - else if (isdigit(*data)) - num = atol(data); + window = window_highest_activity(active_win); else - num = window_find_name(active_win, data); + window = window_find_item(active_win, data); - if (num > 0) - window_set_active_num(num-1); + if (window != NULL) + window_set_active(window); } -static void cmd_window_next(const char *data) +static void cmd_window_next(void) { int num; - num = g_slist_index(windows, active_win)+1; - if (num >= g_slist_length(windows)) num = 0; - window_set_active_num(num); + num = window_refnum_next(active_win->refnum); + if (num < 1) num = windows_refnum_last(); + + window_set_active(window_find_refnum(num)); } -static void cmd_window_prev(const char *data) +static void cmd_window_prev(void) { int num; - num = g_slist_index(windows, active_win)-1; - if (num < 0) num = g_slist_length(windows)-1; - window_set_active_num(num); + num = window_refnum_prev(active_win->refnum); + if (num < 1) num = window_refnum_next(0); + + window_set_active(window_find_refnum(num)); } static void cmd_window_level(const char *data) @@ -392,11 +533,155 @@ static void cmd_window_item_next(const char *data, void *server, WI_ITEM_REC *it window_item_set_active(window, next); } +static void cmd_window_number(const char *data) +{ + int num; + + num = atoi(data); + if (num < 1) + printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_REFNUM_TOO_LOW); + else + window_set_refnum(active_win, num); +} + static void cmd_window_name(const char *data) { window_set_name(active_win, data); } +/* we're moving the first window to last - move the first contiguous block + of refnums to left. Like if there's windows 1..5 and 7..10, move 1 to + 11, 2..5 to 1..4 and leave 7..10 alone */ +static void windows_move_left(WINDOW_REC *move_window) +{ + WINDOW_REC *window; + int refnum; + + window_set_refnum(move_window, windows_refnum_last()+1); + for (refnum = 2;; refnum++) { + window = window_find_refnum(refnum); + if (window == NULL) break; + + window_set_refnum(window, refnum-1); + } +} + +/* we're moving the last window to first - make some space so we can use the + refnum 1 */ +static void windows_move_right(WINDOW_REC *move_window) +{ + WINDOW_REC *window; + int refnum; + + /* find the first unused refnum, like if there's windows + 1..5 and 7..10, we only need to move 1..5 to 2..6 */ + refnum = 1; + while (window_find_refnum(refnum) != NULL) refnum++; + + refnum--; + while (refnum > 0) { + window = window_find_refnum(refnum); + g_return_if_fail(window != NULL); + window_set_refnum(window, window == move_window ? 1 : refnum+1); + + refnum--; + } +} + +static void cmd_window_move_left(void) +{ + int refnum; + + refnum = window_refnum_prev(active_win->refnum); + if (refnum != -1) { + window_set_refnum(active_win, active_win->refnum-1); + return; + } + + windows_move_left(active_win); +} + +static void cmd_window_move_right(void) +{ + int refnum; + + refnum = window_refnum_next(active_win->refnum); + if (refnum != -1) { + window_set_refnum(active_win, active_win->refnum+1); + return; + } + + windows_move_right(active_win); +} + +static void cmd_window_move(const char *data, SERVER_REC *server, WI_ITEM_REC *item) +{ + int new_refnum, refnum; + + if (!is_numeric(data, 0)) { + command_runsub("window move", data, server, item); + return; + } + + new_refnum = atoi(data); + if (new_refnum > active_win->refnum) { + for (;;) { + refnum = window_refnum_next(active_win->refnum); + if (refnum == -1 || refnum > new_refnum) + break; + + window_set_refnum(active_win, refnum); + } + } else { + for (;;) { + refnum = window_refnum_prev(active_win->refnum); + if (refnum == -1 || refnum < new_refnum) + break; + + window_set_refnum(active_win, refnum); + } + } +} + +static int windows_compare(WINDOW_REC *w1, WINDOW_REC *w2) +{ + return w1->refnum < w2->refnum ? -1 : 1; +} + +GSList *windows_get_sorted(void) +{ + GSList *tmp, *list; + + list = NULL; + for (tmp = windows; tmp != NULL; tmp = tmp->next) { + list = g_slist_insert_sorted(list, tmp->data, (GCompareFunc) windows_compare); + } + + return list; +} + +static void cmd_window_list(void) +{ + GSList *tmp, *sorted; + char *levelstr; + + sorted = windows_get_sorted(); + printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_WINDOWLIST_HEADER); + for (tmp = sorted; tmp != NULL; tmp = tmp->next) { + WINDOW_REC *rec = tmp->data; + + levelstr = bits2level(rec->level); + printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_WINDOWLIST_LINE, + rec->refnum, rec->name == NULL ? "" : rec->name, + rec->active == NULL ? "" : rec->active->name, + rec->active_server == NULL ? "" : ((SERVER_REC *) rec->active_server)->tag, + levelstr); + g_free(levelstr); + } + g_slist_free(sorted); + printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_WINDOWLIST_FOOTER); +} + static void sig_server_looking(void *server) { GSList *tmp; @@ -434,14 +719,21 @@ void windows_init(void) command_bind("window", NULL, (SIGNAL_FUNC) cmd_window); command_bind("window new", NULL, (SIGNAL_FUNC) cmd_window_new); command_bind("window close", NULL, (SIGNAL_FUNC) cmd_window_close); + command_bind("window kill", NULL, (SIGNAL_FUNC) cmd_window_close); command_bind("window server", NULL, (SIGNAL_FUNC) cmd_window_server); + command_bind("window refnum", NULL, (SIGNAL_FUNC) cmd_window_refnum); command_bind("window goto", NULL, (SIGNAL_FUNC) cmd_window_goto); command_bind("window prev", NULL, (SIGNAL_FUNC) cmd_window_prev); command_bind("window next", NULL, (SIGNAL_FUNC) cmd_window_next); command_bind("window level", NULL, (SIGNAL_FUNC) cmd_window_level); command_bind("window item prev", NULL, (SIGNAL_FUNC) cmd_window_item_prev); command_bind("window item next", NULL, (SIGNAL_FUNC) cmd_window_item_next); + command_bind("window number", NULL, (SIGNAL_FUNC) cmd_window_number); command_bind("window name", NULL, (SIGNAL_FUNC) cmd_window_name); + command_bind("window move", NULL, (SIGNAL_FUNC) cmd_window_move); + command_bind("window move left", NULL, (SIGNAL_FUNC) cmd_window_move_left); + command_bind("window move right", NULL, (SIGNAL_FUNC) cmd_window_move_right); + command_bind("window list", NULL, (SIGNAL_FUNC) cmd_window_list); signal_add("server looking", (SIGNAL_FUNC) sig_server_looking); signal_add("server disconnected", (SIGNAL_FUNC) sig_server_disconnected); signal_add("server connect failed", (SIGNAL_FUNC) sig_server_disconnected); @@ -452,14 +744,21 @@ void windows_deinit(void) command_unbind("window", (SIGNAL_FUNC) cmd_window); command_unbind("window new", (SIGNAL_FUNC) cmd_window_new); command_unbind("window close", (SIGNAL_FUNC) cmd_window_close); + command_unbind("window kill", (SIGNAL_FUNC) cmd_window_close); command_unbind("window server", (SIGNAL_FUNC) cmd_window_server); + command_unbind("window refnum", (SIGNAL_FUNC) cmd_window_refnum); command_unbind("window goto", (SIGNAL_FUNC) cmd_window_goto); command_unbind("window prev", (SIGNAL_FUNC) cmd_window_prev); command_unbind("window next", (SIGNAL_FUNC) cmd_window_next); command_unbind("window level", (SIGNAL_FUNC) cmd_window_level); command_unbind("window item prev", (SIGNAL_FUNC) cmd_window_item_prev); command_unbind("window item next", (SIGNAL_FUNC) cmd_window_item_next); + command_unbind("window number", (SIGNAL_FUNC) cmd_window_number); command_unbind("window name", (SIGNAL_FUNC) cmd_window_name); + command_unbind("window move", (SIGNAL_FUNC) cmd_window_move); + command_unbind("window move left", (SIGNAL_FUNC) cmd_window_move_left); + command_unbind("window move right", (SIGNAL_FUNC) cmd_window_move_right); + command_unbind("window list", (SIGNAL_FUNC) cmd_window_list); signal_remove("server looking", (SIGNAL_FUNC) sig_server_looking); signal_remove("server disconnected", (SIGNAL_FUNC) sig_server_disconnected); signal_remove("server connect failed", (SIGNAL_FUNC) sig_server_disconnected); diff --git a/src/fe-common/core/windows.h b/src/fe-common/core/windows.h index f279e888..a3b06d86 100644 --- a/src/fe-common/core/windows.h +++ b/src/fe-common/core/windows.h @@ -41,6 +41,7 @@ typedef struct { int level; int new_data; time_t last_timestamp; /* When was last timestamp printed */ + time_t last_line; /* When was last line printed */ gpointer gui_data; } WINDOW_REC; @@ -55,11 +56,15 @@ void window_set_active_num(int number); void window_set_active(WINDOW_REC *window); void window_change_server(WINDOW_REC *window, void *server); +void window_set_refnum(WINDOW_REC *window, int refnum); void window_set_name(WINDOW_REC *window, const char *name); void window_set_level(WINDOW_REC *window, int level); WINDOW_REC *window_find_level(void *server, int level); WINDOW_REC *window_find_closest(void *server, const char *name, int level); +WINDOW_REC *window_find_refnum(int refnum); +WINDOW_REC *window_find_name(const char *name); +WINDOW_REC *window_find_item(WINDOW_REC *window, const char *name); void windows_init(void); void windows_deinit(void); diff --git a/src/fe-common/irc/Makefile.am b/src/fe-common/irc/Makefile.am index 440f14bd..d4ca3f70 100644 --- a/src/fe-common/irc/Makefile.am +++ b/src/fe-common/irc/Makefile.am @@ -15,13 +15,15 @@ libfe_common_irc_la_SOURCES = \ completion.c \ fe-channels.c \ fe-irc-commands.c \ + fe-irc-server.c \ fe-ctcp.c \ fe-events.c \ fe-events-numeric.c \ fe-ignore.c \ + fe-netsplit.c \ fe-query.c \ fe-common-irc.c \ - irc-nick-hilight.c \ + irc-window-activity.c \ irc-hilight-text.c \ module-formats.c diff --git a/src/fe-common/irc/dcc/module-formats.h b/src/fe-common/irc/dcc/module-formats.h index 40d6f090..bc58035e 100644 --- a/src/fe-common/irc/dcc/module-formats.h +++ b/src/fe-common/irc/dcc/module-formats.h @@ -6,9 +6,9 @@ enum { IRCTXT_FILL_1, IRCTXT_OWN_DCC, - IRCTXT_DCC_MSG, IRCTXT_OWN_DCC_ME, IRCTXT_OWN_DCC_CTCP, + IRCTXT_DCC_MSG, IRCTXT_ACTION_DCC, IRCTXT_DCC_CTCP, IRCTXT_DCC_CHAT, diff --git a/src/fe-common/irc/fe-channels.c b/src/fe-common/irc/fe-channels.c index c95e6411..6403412a 100644 --- a/src/fe-common/irc/fe-channels.c +++ b/src/fe-common/irc/fe-channels.c @@ -24,9 +24,12 @@ #include "signals.h" #include "commands.h" #include "levels.h" +#include "misc.h" #include "irc.h" #include "channels.h" +#include "channels-setup.h" +#include "nicklist.h" #include "windows.h" #include "window-items.h" @@ -100,6 +103,134 @@ static void cmd_wjoin(const char *data, void *server, WI_ITEM_REC *item) signal_remove("channel created", (SIGNAL_FUNC) signal_channel_created_curwin); } +static void cmd_channel_list_joined(void) +{ + CHANNEL_REC *channel; + GString *nicks; + GSList *nicklist, *tmp, *ntmp; + char *mode; + + if (channels == NULL) { + printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_NOT_IN_CHANNELS); + return; + } + + /* print active channel */ + channel = irc_item_channel(active_win->active); + if (channel != NULL) + printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_CURRENT_CHANNEL, channel->name); + + /* print list of all channels, their modes, server tags and nicks */ + printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_CHANLIST_HEADER); + for (tmp = channels; tmp != NULL; tmp = tmp->next) { + channel = tmp->data; + + nicklist = nicklist_getnicks(channel); + mode = channel_get_mode(channel); + nicks = g_string_new(NULL); + for (ntmp = nicklist; ntmp != NULL; ntmp = ntmp->next) { + NICK_REC *rec = ntmp->data; + + g_string_sprintfa(nicks, "%s ", rec->nick); + } + + g_string_truncate(nicks, nicks->len-1); + printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_CHANLIST_LINE, + channel->name, mode, channel->server->tag, nicks->str); + + g_free(mode); + g_slist_free(nicklist); + g_string_free(nicks, TRUE); + } +} + +static void cmd_channel_list(void) +{ + GString *str; + GSList *tmp; + + str = g_string_new(NULL); + printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_CHANSETUP_HEADER); + for (tmp = setupchannels; tmp != NULL; tmp = tmp->next) { + SETUP_CHANNEL_REC *rec = tmp->data; + + g_string_truncate(str, 0); + if (rec->autojoin) + g_string_append(str, "autojoin "); + if (rec->botmasks != NULL && *rec->botmasks != '\0') + g_string_sprintfa(str, "bots: %s ", rec->botmasks); + if (rec->autosendcmd != NULL && *rec->autosendcmd != '\0') + g_string_sprintfa(str, "botcmd: %s ", rec->autosendcmd); + + g_string_truncate(str, str->len-1); + printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_CHANSETUP_LINE, + rec->name, rec->ircnet == NULL ? "" : rec->ircnet, + rec->password == NULL ? "" : rec->password, str->str); + } + g_string_free(str, TRUE); + printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_CHANSETUP_FOOTER); +} + +static void cmd_channel(const char *data, IRC_SERVER_REC *server, WI_ITEM_REC *item) +{ + if (ischannel(*data)) { + signal_emit("command join", 2, data, server); + return; + } + + command_runsub("channel", data, server, item); +} + +static void cmd_channel_add(const char *data) +{ + char *params, *args, *botarg, *botcmdarg, *ircnet, *channel, *password; + SETUP_CHANNEL_REC *rec; + + args = "bots botcmd"; + params = cmd_get_params(data, 6 | PARAM_FLAG_MULTIARGS, &args, + &botarg, &botcmdarg, &channel, &ircnet, &password); + + if (*ircnet == '\0' || *channel == '\0') + cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); + rec = channels_setup_find(channel, ircnet); + if (rec == NULL) { + rec = g_new0(SETUP_CHANNEL_REC, 1); + rec->name = g_strdup(channel); + rec->ircnet = g_strdup(ircnet); + } else { + g_free_not_null(rec->botmasks); + g_free_not_null(rec->autosendcmd); + g_free_not_null(rec->password); + } + rec->autojoin = stristr(args, "-auto") != NULL; + rec->botmasks = *botarg == '\0' ? NULL : g_strdup(botarg); + rec->autosendcmd = *botcmdarg == '\0' ? NULL : g_strdup(botcmdarg); + rec->password = *password == '\0' ? NULL : g_strdup(password); + channels_setup_create(rec); + printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_CHANSETUP_ADDED, channel, ircnet); + + g_free(params); +} + +static void cmd_channel_remove(const char *data) +{ + char *params, *ircnet, *channel; + SETUP_CHANNEL_REC *rec; + + params = cmd_get_params(data, 2, &channel, &ircnet); + if (*ircnet == '\0' || *channel == '\0') + cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); + + rec = channels_setup_find(channel, ircnet); + if (rec == NULL) + printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_CHANSETUP_NOT_FOUND, channel, ircnet); + else { + printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_CHANSETUP_REMOVED, channel, ircnet); + channels_setup_destroy(rec); + } + g_free(params); +} + void fe_channels_init(void) { signal_add("channel created", (SIGNAL_FUNC) signal_channel_created); @@ -109,6 +240,11 @@ void fe_channels_init(void) signal_add_last("server disconnected", (SIGNAL_FUNC) sig_disconnected); command_bind("wjoin", NULL, (SIGNAL_FUNC) cmd_wjoin); + command_bind("channel ", NULL, (SIGNAL_FUNC) cmd_channel_list_joined); + command_bind("channel", NULL, (SIGNAL_FUNC) cmd_channel); + command_bind("channel add", NULL, (SIGNAL_FUNC) cmd_channel_add); + command_bind("channel remove", NULL, (SIGNAL_FUNC) cmd_channel_remove); + command_bind("channel list", NULL, (SIGNAL_FUNC) cmd_channel_list); } void fe_channels_deinit(void) @@ -120,4 +256,9 @@ void fe_channels_deinit(void) signal_remove("server disconnected", (SIGNAL_FUNC) sig_disconnected); command_unbind("wjoin", (SIGNAL_FUNC) cmd_wjoin); + command_unbind("channel", (SIGNAL_FUNC) cmd_channel); + command_unbind("channel ", (SIGNAL_FUNC) cmd_channel_list_joined); + command_unbind("channel add", (SIGNAL_FUNC) cmd_channel_add); + command_unbind("channel remove", (SIGNAL_FUNC) cmd_channel_remove); + command_unbind("channel list", (SIGNAL_FUNC) cmd_channel_list); } diff --git a/src/fe-common/irc/fe-common-irc.c b/src/fe-common/irc/fe-common-irc.c index b8166f5e..bde1d9fe 100644 --- a/src/fe-common/irc/fe-common-irc.c +++ b/src/fe-common/irc/fe-common-irc.c @@ -35,6 +35,9 @@ void fe_channels_deinit(void); void fe_irc_commands_init(void); void fe_irc_commands_deinit(void); +void fe_irc_server_init(void); +void fe_irc_server_deinit(void); + void fe_ctcp_init(void); void fe_ctcp_deinit(void); @@ -53,8 +56,8 @@ void fe_ignore_deinit(void); void fe_query_init(void); void fe_query_deinit(void); -void irc_nick_hilight_init(void); -void irc_nick_hilight_deinit(void); +void irc_window_activity_init(void); +void irc_window_activity_deinit(void); void fe_notifylist_init(void); void fe_notifylist_deinit(void); @@ -62,6 +65,9 @@ void fe_notifylist_deinit(void); void fe_flood_init(void); void fe_flood_deinit(void); +void fe_netsplit_init(void); +void fe_netsplit_deinit(void); + static char *autocon_server; static char *autocon_password; static int autocon_port; @@ -96,6 +102,7 @@ void fe_common_irc_init(void) fe_channels_init(); fe_irc_commands_init(); + fe_irc_server_init(); fe_ctcp_init(); fe_dcc_init(); fe_events_init(); @@ -103,15 +110,17 @@ void fe_common_irc_init(void) fe_ignore_init(); fe_notifylist_init(); fe_flood_init(); + fe_netsplit_init(); fe_query_init(); completion_init(); - irc_nick_hilight_init(); + irc_window_activity_init(); } void fe_common_irc_deinit(void) { fe_channels_deinit(); fe_irc_commands_deinit(); + fe_irc_server_deinit(); fe_ctcp_deinit(); fe_dcc_deinit(); fe_events_deinit(); @@ -119,9 +128,10 @@ void fe_common_irc_deinit(void) fe_ignore_deinit(); fe_notifylist_deinit(); fe_flood_deinit(); + fe_netsplit_deinit(); fe_query_deinit(); completion_deinit(); - irc_nick_hilight_deinit(); + irc_window_activity_deinit(); } void fe_common_irc_finish_init(void) @@ -162,7 +172,7 @@ void fe_common_irc_finish_init(void) if (*rec->ircnet != '\0') ircnets = g_slist_append(ircnets, rec->ircnet); - str = g_strdup_printf("%s %d", rec->server, rec->port); + str = g_strdup_printf("%s %d", rec->address, rec->port); signal_emit("command connect", 1, str); g_free(str); } diff --git a/src/fe-common/irc/fe-events-numeric.c b/src/fe-common/irc/fe-events-numeric.c index 44169fe8..5b692e58 100644 --- a/src/fe-common/irc/fe-events-numeric.c +++ b/src/fe-common/irc/fe-events-numeric.c @@ -607,7 +607,7 @@ static void event_motd(gchar *data, SERVER_REC *server, gchar *nick, gchar *addr /* numeric event. */ gchar *params, *args, *ptr; - if (settings_get_bool("toggle_skip_motd")) + if (settings_get_bool("skip_motd")) return; params = event_get_params(data, 2 | PARAM_FLAG_GETREST, NULL, &args); diff --git a/src/fe-common/irc/fe-events.c b/src/fe-common/irc/fe-events.c index c846211a..f6a2557c 100644 --- a/src/fe-common/irc/fe-events.c +++ b/src/fe-common/irc/fe-events.c @@ -32,6 +32,7 @@ #include "query.h" #include "nicklist.h" #include "ignore.h" +#include "netsplit.h" #include "irc-hilight-text.h" #include "windows.h" @@ -83,7 +84,7 @@ static void event_privmsg(gchar *data, IRC_SERVER_REC *server, gchar *nick, gcha color = irc_hilight_find_nick(target, nick, addr); nickrec = chanrec == NULL ? NULL : nicklist_find(chanrec, nick); - nickmode = !settings_get_bool("toggle_show_nickmode") || nickrec == NULL ? "" : + nickmode = !settings_get_bool("show_nickmode") || nickrec == NULL ? "" : nickrec->op ? "@" : nickrec->voice ? "+" : " "; window = chanrec == NULL ? NULL : window_item_window((WI_ITEM_REC *) chanrec); @@ -125,7 +126,7 @@ static void event_privmsg(gchar *data, IRC_SERVER_REC *server, gchar *nick, gcha else { /* private message */ - if (settings_get_bool("toggle_autocreate_query") && query_find(server, nick) == NULL) + if (settings_get_bool("autocreate_query") && query_find(server, nick) == NULL) item = (WI_ITEM_REC *) query_create(server, nick, TRUE); else item = (WI_ITEM_REC *) query_find(server, nick); @@ -183,7 +184,7 @@ static void ctcp_action_msg(gchar *data, IRC_SERVER_REC *server, gchar *nick, gc else { /* private action */ - if (settings_get_bool("toggle_autocreate_query") && query_find(server, nick) == NULL) + if (settings_get_bool("autocreate_query") && query_find(server, nick) == NULL) item = (WI_ITEM_REC *) query_create(server, nick, TRUE); else item = (WI_ITEM_REC *) channel_find(server, nick); @@ -280,6 +281,9 @@ static void event_quit(const char *data, IRC_SERVER_REC *server, const char *nic if (ignore_check(server, nick, addr, NULL, data, MSGLEVEL_QUITS)) return; + if (settings_get_bool("hide_netsplit_quits") && quitmsg_is_split(data)) + return; + print_channel = NULL; once = settings_get_bool("show_quit_once"); chans = !once ? NULL : g_string_new(NULL); @@ -558,46 +562,46 @@ static void event_ban_type_changed(gchar *bantype) static void sig_server_lag_disconnected(IRC_SERVER_REC *server) { - g_return_if_fail(server != NULL); + g_return_if_fail(server != NULL); - printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, - IRCTXT_LAG_DISCONNECTED, server->connrec->address, time(NULL)-server->lag_sent); + printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, + IRCTXT_LAG_DISCONNECTED, server->connrec->address, time(NULL)-server->lag_sent); } static void sig_server_reconnect_removed(RECONNECT_REC *reconnect) { - g_return_if_fail(reconnect != NULL); + g_return_if_fail(reconnect != NULL); - printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, - IRCTXT_RECONNECT_REMOVED, reconnect->conn->address, reconnect->conn->port, - reconnect->conn->ircnet == NULL ? "" : reconnect->conn->ircnet); + printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, + IRCTXT_RECONNECT_REMOVED, reconnect->conn->address, reconnect->conn->port, + reconnect->conn->ircnet == NULL ? "" : reconnect->conn->ircnet); } static void sig_server_reconnect_not_found(gchar *tag) { - g_return_if_fail(tag != NULL); + g_return_if_fail(tag != NULL); - printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, - IRCTXT_RECONNECT_NOT_FOUND, tag); + printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, + IRCTXT_RECONNECT_NOT_FOUND, tag); } static void event_received(gchar *data, IRC_SERVER_REC *server, gchar *nick, gchar *addr) { - g_return_if_fail(data != NULL); + char *params, *cmd, *args, *ptr; - if (!isdigit((gint) *data)) - printtext(server, NULL, MSGLEVEL_CRAP, "%s", data); - else - { - /* numeric event. */ - gchar *params, *cmd, *args, *ptr; + g_return_if_fail(data != NULL); - params = event_get_params(data, 3 | PARAM_FLAG_GETREST, &cmd, NULL, &args); - ptr = strstr(args, " :"); + if (!isdigit((gint) *data)) { + printtext(server, NULL, MSGLEVEL_CRAP, "%s", data); + return; + } + + /* numeric event. */ + params = event_get_params(data, 3 | PARAM_FLAG_GETREST, &cmd, NULL, &args); + ptr = strstr(args, " :"); if (ptr != NULL) *(ptr+1) = ' '; printtext(server, NULL, MSGLEVEL_CRAP, "%s", args); g_free(params); - } } static void sig_empty(void) @@ -612,6 +616,7 @@ static void read_settings(void) void fe_events_init(void) { + settings_add_bool("misc", "hide_netsplit_quits", TRUE); beep_msg_level = 0; read_settings(); diff --git a/src/fe-common/irc/fe-ignore.c b/src/fe-common/irc/fe-ignore.c index 35da7c84..db91826e 100644 --- a/src/fe-common/irc/fe-ignore.c +++ b/src/fe-common/irc/fe-ignore.c @@ -191,7 +191,7 @@ static void cmd_ignore(const char *data) else { key = ignore_get_key(rec); levels = ignore_get_levels(rec->level, rec->except_level); - printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_IGNORED, key, levels); + printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_IGNORED, key, levels); g_free(key); g_free(levels); } @@ -212,7 +212,7 @@ static void cmd_unignore(const char *data) if (is_numeric(data, ' ')) { /* with index number */ - tmp = g_slist_nth(ignores, atol(data)-1); + tmp = g_slist_nth(ignores, atoi(data)-1); rec = tmp == NULL ? NULL : tmp->data; } else { /* with mask */ diff --git a/src/fe-common/irc/fe-irc-commands.c b/src/fe-common/irc/fe-irc-commands.c index bc6097cf..dc844346 100644 --- a/src/fe-common/irc/fe-irc-commands.c +++ b/src/fe-common/irc/fe-irc-commands.c @@ -28,7 +28,6 @@ #include "levels.h" #include "irc.h" #include "server.h" -#include "server-reconnect.h" #include "mode-lists.h" #include "nicklist.h" #include "channels.h" @@ -37,66 +36,6 @@ #include "windows.h" #include "window-items.h" -static void cmd_server(const char *data) -{ - if (*data == '+' && data[1] != '\0') - window_create(NULL, FALSE); -} - -static void print_servers(void) -{ - GSList *tmp; - - for (tmp = servers; tmp != NULL; tmp = tmp->next) { - IRC_SERVER_REC *rec = tmp->data; - - printformat(NULL, NULL, MSGLEVEL_CRAP, IRCTXT_SERVER_LIST, - rec->tag, rec->connrec->address, rec->connrec->port, - rec->connrec->ircnet == NULL ? "" : rec->connrec->ircnet, rec->connrec->nick); - } -} - -static void print_lookup_servers(void) -{ - GSList *tmp; - for (tmp = lookup_servers; tmp != NULL; tmp = tmp->next) { - IRC_SERVER_REC *rec = tmp->data; - - printformat(NULL, NULL, MSGLEVEL_CRAP, IRCTXT_SERVER_LOOKUP_LIST, - rec->tag, rec->connrec->address, rec->connrec->port, - rec->connrec->ircnet == NULL ? "" : rec->connrec->ircnet, rec->connrec->nick); - } -} - -static void print_reconnects(void) -{ - GSList *tmp; - char *tag, *next_connect; - int left; - - for (tmp = reconnects; tmp != NULL; tmp = tmp->next) { - RECONNECT_REC *rec = tmp->data; - IRC_SERVER_CONNECT_REC *conn = rec->conn; - - tag = g_strdup_printf("RECON-%d", rec->tag); - left = rec->next_connect-time(NULL); - next_connect = g_strdup_printf("%02d:%02d", left/60, left%60); - printformat(NULL, NULL, MSGLEVEL_CRAP, IRCTXT_SERVER_RECONNECT_LIST, - tag, conn->address, conn->port, - conn->ircnet == NULL ? "" : conn->ircnet, - conn->nick, next_connect); - g_free(next_connect); - g_free(tag); - } -} - -static void cmd_servers(void) -{ - print_servers(); - print_lookup_servers(); - print_reconnects(); -} - static void cmd_unquery(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item) { QUERY_REC *query; @@ -196,7 +135,7 @@ static void cmd_msg(gchar *data, IRC_SERVER_REC *server, WI_ITEM_REC *item) { /* msg to channel */ nickrec = channel == NULL ? NULL : nicklist_find(channel, server->nick); - nickmode = !settings_get_bool("toggle_show_nickmode") || nickrec == NULL ? "" : + nickmode = !settings_get_bool("show_nickmode") || nickrec == NULL ? "" : nickrec->op ? "@" : nickrec->voice ? "+" : " "; window = channel == NULL ? NULL : window_item_window((WI_ITEM_REC *) channel); @@ -329,8 +268,8 @@ static void cmd_ban(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item) GSList *tmp; g_return_if_fail(data != NULL); - if (*data == '\0') - return; /* setting ban - don't handle here */ + if (*data != '\0') + return; /* setting ban - don't handle here */ if (server == NULL || !server->connected) cmd_return_error(CMDERR_NOT_CONNECTED); @@ -415,52 +354,6 @@ static void cmd_join(const char *data, IRC_SERVER_REC *server) } } -static void cmd_channel(const char *data, IRC_SERVER_REC *server) -{ - CHANNEL_REC *channel; - GString *nicks; - GSList *nicklist, *tmp, *ntmp; - char *mode; - - if (*data != '\0') { - cmd_join(data, server); - return; - } - - if (channels == NULL) { - printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_NOT_IN_CHANNELS); - return; - } - - /* print active channel */ - channel = irc_item_channel(active_win->active); - if (channel != NULL) - printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_CURRENT_CHANNEL, channel->name); - - /* print list of all channels, their modes, server tags and nicks */ - printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_CHANLIST_HEADER); - for (tmp = channels; tmp != NULL; tmp = tmp->next) { - channel = tmp->data; - - nicklist = nicklist_getnicks(channel); - mode = channel_get_mode(channel); - nicks = g_string_new(NULL); - for (ntmp = nicklist; ntmp != NULL; ntmp = ntmp->next) { - NICK_REC *rec = ntmp->data; - - g_string_sprintfa(nicks, "%s ", rec->nick); - } - - g_string_truncate(nicks, nicks->len-1); - printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_CHANLIST_LINE, - channel->name, mode, channel->server->tag, nicks->str); - - g_free(mode); - g_slist_free(nicklist); - g_string_free(nicks, TRUE); - } -} - static void cmd_nick(const char *data, IRC_SERVER_REC *server) { g_return_if_fail(data != NULL); @@ -506,8 +399,6 @@ static void cmd_ts(const char *data) void fe_irc_commands_init(void) { - command_bind("server", NULL, (SIGNAL_FUNC) cmd_server); - command_bind("servers", NULL, (SIGNAL_FUNC) cmd_servers); command_bind("query", NULL, (SIGNAL_FUNC) cmd_query); command_bind("unquery", NULL, (SIGNAL_FUNC) cmd_unquery); command_bind("msg", NULL, (SIGNAL_FUNC) cmd_msg); @@ -519,7 +410,6 @@ void fe_irc_commands_init(void) command_bind("ban", NULL, (SIGNAL_FUNC) cmd_ban); command_bind("invitelist", NULL, (SIGNAL_FUNC) cmd_invitelist); command_bind("join", NULL, (SIGNAL_FUNC) cmd_join); - command_bind("channel", NULL, (SIGNAL_FUNC) cmd_channel); command_bind("nick", NULL, (SIGNAL_FUNC) cmd_nick); command_bind("ver", NULL, (SIGNAL_FUNC) cmd_ver); command_bind("ts", NULL, (SIGNAL_FUNC) cmd_ts); @@ -527,8 +417,6 @@ void fe_irc_commands_init(void) void fe_irc_commands_deinit(void) { - command_unbind("server", (SIGNAL_FUNC) cmd_server); - command_unbind("servers", (SIGNAL_FUNC) cmd_servers); command_unbind("query", (SIGNAL_FUNC) cmd_query); command_unbind("unquery", (SIGNAL_FUNC) cmd_unquery); command_unbind("msg", (SIGNAL_FUNC) cmd_msg); @@ -540,7 +428,6 @@ void fe_irc_commands_deinit(void) command_unbind("ban", (SIGNAL_FUNC) cmd_ban); command_unbind("invitelist", (SIGNAL_FUNC) cmd_invitelist); command_unbind("join", (SIGNAL_FUNC) cmd_join); - command_unbind("channel", (SIGNAL_FUNC) cmd_channel); command_unbind("nick", (SIGNAL_FUNC) cmd_nick); command_unbind("ver", (SIGNAL_FUNC) cmd_ver); command_unbind("ts", (SIGNAL_FUNC) cmd_ts); diff --git a/src/fe-common/irc/fe-irc-server.c b/src/fe-common/irc/fe-irc-server.c new file mode 100644 index 00000000..30e09886 --- /dev/null +++ b/src/fe-common/irc/fe-irc-server.c @@ -0,0 +1,215 @@ +/* + fe-irc-server.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "module.h" +#include "module-formats.h" +#include "signals.h" +#include "commands.h" +#include "misc.h" + +#include "levels.h" +#include "irc-server.h" +#include "server-reconnect.h" +#include "server-setup.h" + +#include "windows.h" + +static void print_servers(void) +{ + GSList *tmp; + + for (tmp = servers; tmp != NULL; tmp = tmp->next) { + IRC_SERVER_REC *rec = tmp->data; + + printformat(NULL, NULL, MSGLEVEL_CRAP, IRCTXT_SERVER_LIST, + rec->tag, rec->connrec->address, rec->connrec->port, + rec->connrec->ircnet == NULL ? "" : rec->connrec->ircnet, rec->connrec->nick); + } +} + +static void print_lookup_servers(void) +{ + GSList *tmp; + for (tmp = lookup_servers; tmp != NULL; tmp = tmp->next) { + IRC_SERVER_REC *rec = tmp->data; + + printformat(NULL, NULL, MSGLEVEL_CRAP, IRCTXT_SERVER_LOOKUP_LIST, + rec->tag, rec->connrec->address, rec->connrec->port, + rec->connrec->ircnet == NULL ? "" : rec->connrec->ircnet, rec->connrec->nick); + } +} + +static void print_reconnects(void) +{ + GSList *tmp; + char *tag, *next_connect; + int left; + + for (tmp = reconnects; tmp != NULL; tmp = tmp->next) { + RECONNECT_REC *rec = tmp->data; + IRC_SERVER_CONNECT_REC *conn = rec->conn; + + tag = g_strdup_printf("RECON-%d", rec->tag); + left = rec->next_connect-time(NULL); + next_connect = g_strdup_printf("%02d:%02d", left/60, left%60); + printformat(NULL, NULL, MSGLEVEL_CRAP, IRCTXT_SERVER_RECONNECT_LIST, + tag, conn->address, conn->port, + conn->ircnet == NULL ? "" : conn->ircnet, + conn->nick, next_connect); + g_free(next_connect); + g_free(tag); + } +} + +static void server_add(const char *data) +{ + SETUP_SERVER_REC *rec; + char *params, *args, *ircnet, *host, *cmdspeed, *cmdmax; + char *addr, *portstr, *password, *nick; + int port; + + args = "ircnet host cmdspeed cmdmax"; + params = cmd_get_params(data, 9 | PARAM_FLAG_MULTIARGS, + &args, &ircnet, &host, &cmdspeed, &cmdmax, + &addr, &portstr, &password, &nick); + if (*addr == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); + port = *portstr == '\0' ? 6667 : atoi(portstr); + + rec = server_setup_find(addr, port); + if (rec == NULL) { + rec = g_new0(SETUP_SERVER_REC, 1); + rec->address = g_strdup(addr); + rec->port = port; + } else { + g_free_and_null(rec->ircnet); + g_free_and_null(rec->password); + g_free_and_null(rec->own_host); + } + + rec->autoconnect = stristr(args, "-auto") != NULL; + if (*ircnet != '\0') rec->ircnet = g_strdup(ircnet); + if (*password != '\0') rec->password = g_strdup(password); + if (*host != '\0') rec->own_host = g_strdup(host); + rec->cmd_queue_speed = atoi(cmdspeed); + rec->max_cmds_at_once = atoi(cmdmax); + + server_setup_add(rec); + printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_SETUPSERVER_ADDED, addr, port); + + g_free(params); +} + +static void server_remove(const char *data) +{ + SETUP_SERVER_REC *rec; + char *params, *args, *addr, *portstr; + int port; + + params = cmd_get_params(data, 3 | PARAM_FLAG_OPTARGS, &args, &addr, &portstr); + if (*addr == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); + port = *portstr == '\0' ? 6667 : atoi(portstr); + + rec = server_setup_find(addr, port); + if (rec == NULL) + printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_SETUPSERVER_NOT_FOUND, addr, port); + else { + server_setup_remove(rec); + printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_SETUPSERVER_REMOVED, addr, port); + } + + g_free(params); +} + +static void server_list(const char *data) +{ + GString *str; + GSList *tmp; + + str = g_string_new(NULL); + printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_SETUPSERVER_HEADER); + for (tmp = setupservers; tmp != NULL; tmp = tmp->next) { + SETUP_SERVER_REC *rec = tmp->data; + + g_string_truncate(str, 0); + if (rec->password != NULL) + g_string_append(str, "(pass) "); + if (rec->autoconnect) + g_string_append(str, "autoconnect "); + if (rec->max_cmds_at_once > 0) + g_string_sprintfa(str, "cmdmax: %d ", rec->max_cmds_at_once); + if (rec->cmd_queue_speed > 0) + g_string_sprintfa(str, "cmdspeed: %d ", rec->cmd_queue_speed); + if (rec->own_host != NULL) + g_string_sprintfa(str, "host: %s ", rec->own_host); + printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_SETUPSERVER_LINE, + rec->address, rec->port, + rec->ircnet == NULL ? "" : rec->ircnet, + str->str); + } + printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_SETUPSERVER_FOOTER); + g_string_free(str, TRUE); +} + +static void cmd_server(const char *data) +{ + char *params, *args, *ircnetarg, *hostarg, *addr; + + if (*data == '\0') { + print_servers(); + print_lookup_servers(); + print_reconnects(); + + signal_stop(); + return; + } + + args = "ircnet host"; + params = cmd_get_params(data, 4 | PARAM_FLAG_MULTIARGS, + &args, &ircnetarg, &hostarg, &addr); + + if (stristr(args, "-list") != NULL) { + server_list(data); + signal_stop(); + } else if (stristr(args, "-add") != NULL) { + if (*addr == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); + server_add(data); + signal_stop(); + } else if (stristr(args, "-remove") != NULL) { + if (*addr == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); + server_remove(data); + signal_stop(); + } else { + if (*addr == '\0' || strcmp(addr, "+") == 0) + cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); + if (*addr == '+') window_create(NULL, FALSE); + } + + g_free(params); +} + +void fe_irc_server_init(void) +{ + command_bind("server", NULL, (SIGNAL_FUNC) cmd_server); +} + +void fe_irc_server_deinit(void) +{ + command_unbind("server", (SIGNAL_FUNC) cmd_server); +} diff --git a/src/fe-common/irc/fe-netsplit.c b/src/fe-common/irc/fe-netsplit.c new file mode 100644 index 00000000..b13ae437 --- /dev/null +++ b/src/fe-common/irc/fe-netsplit.c @@ -0,0 +1,69 @@ +/* + fe-netsplit.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "module.h" +#include "module-formats.h" +#include "signals.h" +#include "commands.h" + +#include "levels.h" +#include "netsplit.h" + +static void sig_netsplit_servers(NETSPLIT_SERVER_REC *rec) +{ + printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_NETSPLIT, rec->server, rec->destserver); +} + +static void split_print(const char *nick, NETSPLIT_REC *rec) +{ + NETSPLIT_CHAN_REC *chan; + + chan = rec->channels->data; + printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_NETSPLITS_LINE, + rec->nick, chan == NULL ? "" : chan->name, + rec->server->server, rec->server->destserver); +} + +static void cmd_netsplit(const char *data, IRC_SERVER_REC *server) +{ + if (server == NULL || !server->connected) + cmd_return_error(CMDERR_NOT_CONNECTED); + + if (server->split_servers == NULL) { + printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_NO_NETSPLITS); + return; + } + + printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_NETSPLITS_HEADER); + g_hash_table_foreach(server->splits, (GHFunc) split_print, NULL); + printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_NETSPLITS_FOOTER); +} + +void fe_netsplit_init(void) +{ + signal_add("netsplit new server", (SIGNAL_FUNC) sig_netsplit_servers); + command_bind("netsplit", NULL, (SIGNAL_FUNC) cmd_netsplit); +} + +void fe_netsplit_deinit(void) +{ + signal_remove("netsplit new server", (SIGNAL_FUNC) sig_netsplit_servers); + command_unbind("netsplit", (SIGNAL_FUNC) cmd_netsplit); +} diff --git a/src/fe-common/irc/fe-query.c b/src/fe-common/irc/fe-query.c index be46ea0b..5444a031 100644 --- a/src/fe-common/irc/fe-query.c +++ b/src/fe-common/irc/fe-query.c @@ -23,6 +23,7 @@ #include "modules.h" #include "signals.h" #include "commands.h" +#include "settings.h" #include "irc.h" #include "levels.h" @@ -31,6 +32,8 @@ #include "windows.h" #include "window-items.h" +static int queryclose_tag, query_auto_close; + static void signal_query_created(QUERY_REC *query, gpointer automatic) { window_item_create((WI_ITEM_REC *) query, GPOINTER_TO_INT(automatic)); @@ -110,12 +113,67 @@ static void cmd_wquery(const char *data, void *server, WI_ITEM_REC *item) signal_remove("query created", (SIGNAL_FUNC) signal_query_created_curwin); } +static void sig_window_changed(WINDOW_REC *window) +{ + GSList *tmp; + + if (query_auto_close <= 0) + return; + + for (tmp = window->items; tmp != NULL; tmp = tmp->next) { + if (irc_item_query(tmp->data)) + break; + } + if (tmp == NULL) return; /* no queries in window */ + + /* reset the window's last_line timestamp so that query doesn't get + closed immediately after switched to the window. */ + window->last_line = time(NULL); +} + +static int sig_query_autoclose(void) +{ + WINDOW_REC *window; + GSList *tmp, *next; + time_t now; + + now = time(NULL); + for (tmp = queries; tmp != NULL; tmp = next) { + QUERY_REC *rec = tmp->data; + + next = tmp->next; + window = window_item_window((WI_ITEM_REC *) rec); + if (window != active_win && rec->new_data == 0 && + now-window->last_line > query_auto_close) + query_destroy(rec); + } + return 1; +} + +static void read_settings(void) +{ + query_auto_close = settings_get_int("query_auto_close"); + if (query_auto_close > 0 && queryclose_tag == -1) + queryclose_tag = g_timeout_add(5000, (GSourceFunc) sig_query_autoclose, NULL); + else if (query_auto_close <= 0 && queryclose_tag != -1) { + g_source_remove(queryclose_tag); + queryclose_tag = -1; + } +} + void fe_query_init(void) { + settings_add_int("lookandfeel", "query_auto_close", 0); + + queryclose_tag = -1; + read_settings(); + signal_add("query created", (SIGNAL_FUNC) signal_query_created); signal_add("query destroyed", (SIGNAL_FUNC) signal_query_destroyed); signal_add("window item remove", (SIGNAL_FUNC) signal_window_item_removed); signal_add("server connected", (SIGNAL_FUNC) sig_server_connected); + signal_add("window changed", (SIGNAL_FUNC) sig_window_changed); + signal_add("setup changed", (SIGNAL_FUNC) read_settings); command_bind("wquery", NULL, (SIGNAL_FUNC) cmd_wquery); command_bind("window server", NULL, (SIGNAL_FUNC) cmd_window_server); @@ -123,10 +181,14 @@ void fe_query_init(void) void fe_query_deinit(void) { + if (queryclose_tag != -1) g_source_remove(queryclose_tag); + signal_remove("query created", (SIGNAL_FUNC) signal_query_created); signal_remove("query destroyed", (SIGNAL_FUNC) signal_query_destroyed); signal_remove("window item remove", (SIGNAL_FUNC) signal_window_item_removed); signal_remove("server connected", (SIGNAL_FUNC) sig_server_connected); + signal_remove("window changed", (SIGNAL_FUNC) sig_window_changed); + signal_remove("setup changed", (SIGNAL_FUNC) read_settings); command_unbind("wquery", (SIGNAL_FUNC) cmd_wquery); command_unbind("window server", (SIGNAL_FUNC) cmd_window_server); diff --git a/src/fe-common/irc/irc-nick-hilight.c b/src/fe-common/irc/irc-nick-hilight.c deleted file mode 100644 index 0d790822..00000000 --- a/src/fe-common/irc/irc-nick-hilight.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - irc-nick-hilight.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include "module.h" -#include "signals.h" -#include "levels.h" - -#include "irc.h" -#include "ignore.h" -#include "irc-server.h" - -#include "completion.h" -#include "windows.h" -#include "window-items.h" - -static void event_privmsg(const char *data, IRC_SERVER_REC *server, const char *nick, const char *addr) -{ - WINDOW_REC *window; - WI_ITEM_REC *item; - char *params, *target, *msg; - int level; - - g_return_if_fail(data != NULL); - - params = event_get_params(data, 2 | PARAM_FLAG_GETREST, &target, &msg); - - if (*msg == 1) { - /* don't hilight CTCPs */ - g_free(params); - return; - } - - /* get window and window item */ - level = ischannel(*target) ? MSGLEVEL_PUBLIC : MSGLEVEL_MSGS; - item = window_item_find(server, ischannel(*target) ? target : nick); - window = item == NULL ? - window_find_closest(server, target, GPOINTER_TO_INT(level)) : - window_item_window(item); - - /* check that msg wasn't send to current window and - that it didn't get ignored */ - if (window != active_win && !ignore_check(server, nick, addr, target, msg, level)) { - /* hilight */ - level = !ischannel(*target) || - completion_msgtoyou((SERVER_REC *) server, msg) ? - NEWDATA_MSG_FORYOU : NEWDATA_MSG; - if (item != NULL && item->new_data < level) { - item->new_data = level; - signal_emit("window item hilight", 1, item); - } else { - int oldlevel = window->new_data; - - if (window->new_data < level) { - window->new_data = level; - signal_emit("window hilight", 2, window, GINT_TO_POINTER(oldlevel)); - } - signal_emit("window activity", 2, window, GINT_TO_POINTER(oldlevel)); - } - } - - g_free(params); -} - -void irc_nick_hilight_init(void) -{ - signal_add_last("event privmsg", (SIGNAL_FUNC) event_privmsg); -} - -void irc_nick_hilight_deinit(void) -{ - signal_remove("event privmsg", (SIGNAL_FUNC) event_privmsg); -} diff --git a/src/fe-common/irc/irc-window-activity.c b/src/fe-common/irc/irc-window-activity.c new file mode 100644 index 00000000..5a9aa86f --- /dev/null +++ b/src/fe-common/irc/irc-window-activity.c @@ -0,0 +1,89 @@ +/* + irc-window-activity.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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "module.h" +#include "signals.h" +#include "levels.h" + +#include "irc.h" +#include "ignore.h" +#include "irc-server.h" + +#include "completion.h" +#include "windows.h" +#include "window-items.h" + +static void event_privmsg(const char *data, IRC_SERVER_REC *server, const char *nick, const char *addr) +{ + WINDOW_REC *window; + WI_ITEM_REC *item; + char *params, *target, *msg; + int level; + + g_return_if_fail(data != NULL); + + params = event_get_params(data, 2 | PARAM_FLAG_GETREST, &target, &msg); + + if (*msg == 1) { + /* don't hilight CTCPs */ + g_free(params); + return; + } + + /* get window and window item */ + level = ischannel(*target) ? MSGLEVEL_PUBLIC : MSGLEVEL_MSGS; + item = window_item_find(server, ischannel(*target) ? target : nick); + window = item == NULL ? + window_find_closest(server, target, GPOINTER_TO_INT(level)) : + window_item_window(item); + + /* check that msg wasn't send to current window and + that it didn't get ignored */ + if (window != active_win && !ignore_check(server, nick, addr, target, msg, level)) { + /* hilight */ + level = !ischannel(*target) || + completion_msgtoyou((SERVER_REC *) server, msg) ? + NEWDATA_MSG_FORYOU : NEWDATA_MSG; + if (item != NULL && item->new_data < level) { + item->new_data = level; + signal_emit("window item hilight", 1, item); + } else { + int oldlevel = window->new_data; + + if (window->new_data < level) { + window->new_data = level; + signal_emit("window hilight", 2, window, GINT_TO_POINTER(oldlevel)); + } + signal_emit("window activity", 2, window, GINT_TO_POINTER(oldlevel)); + } + } + + g_free(params); +} + +void irc_window_activity_init(void) +{ + signal_add_last("event privmsg", (SIGNAL_FUNC) event_privmsg); +} + +void irc_window_activity_deinit(void) +{ + signal_remove("event privmsg", (SIGNAL_FUNC) event_privmsg); +} diff --git a/src/fe-common/irc/module-formats.c b/src/fe-common/irc/module-formats.c index 4b46959c..b1040d40 100644 --- a/src/fe-common/irc/module-formats.c +++ b/src/fe-common/irc/module-formats.c @@ -36,6 +36,17 @@ FORMAT_REC fecommon_irc_formats[] = { "server_reconnect_removed", "Removed reconnection to server %_$0%_ port %_$1%_", 3, { 0, 1, 0 } }, { "server_reconnect_not_found", "Reconnection tag %_$0%_ not found", 1, { 0 } }, { "query_server_changed", "Query with %_$2%_ changed to server %_$1%_", 3, { 0, 0, 0 } }, + { "setupserver_added", "Server $0 saved", 2, { 0, 0 } }, + { "setupserver_removed", "Server $0 removed", 2, { 0, 0 } }, + { "setupserver_not_found", "Server $0 not found", 2, { 0, 0 } }, + { "setupserver_header", "Server Port IRC Net Settings", 0 }, + { "setupserver_line", "%|$[!20]0 $[5]1 $[10]2 $3", 4, { 0, 1, 0, 0 } }, + { "setupserver_footer", "", 0 }, + { "netsplit", "%RNetsplit%n detected between servers %_$0%_ and %_$1%_%:Use /NETSPLIT to see who left", 2, { 0, 0 } }, + { "no_netsplits", "There are no net splits", 0 }, + { "netsplits_header", "Nick Channel Server Splitted server", 0 }, + { "netsplits_line", "$[9]0 $[10]1 $[20]2 $3", 4, { 0, 0, 0, 0 } }, + { "netsplits_footer", "", 0 }, /* ---- */ { NULL, "Channels", 0 }, @@ -73,11 +84,17 @@ FORMAT_REC fecommon_irc_formats[] = { "ebanlist_long", "%_$0%_: ban exception %c$1 %K[%nby %_$2%_, $3 secs ago%K]", 4, { 0, 0, 0, 1 } }, { "invitelist", "%_$0%_: invite %c$1", 2, { 0, 0 } }, { "no_such_channel", "$0: No such channel", 1, { 0 } }, + { "channel_synced", "Join to %_$0%_ was synced in %_$1%_ secs", 2, { 0, 2 } }, { "not_in_channels", "You are not on any channels", 0 }, { "current_channel", "Current channel $0", 1, { 0 } }, { "chanlist_header", "You are on the following channels:", 0 }, { "chanlist_line", "$[-10]0 %|+$1 ($2): $3", 4, { 0, 0, 0, 0 } }, - { "channel_synced", "Join to %_$0%_ was synced in %_$1%_ secs", 2, { 0, 2 } }, + { "chansetup_not_found", "Channel $0 not found", 2, { 0, 0 } }, + { "chansetup_added", "Channel $0 saved", 2, { 0, 0 } }, + { "chansetup_removed", "Channel $0 removed", 2, { 0, 0 } }, + { "chansetup_header", "Channel IRC net Password Settings", 0 }, + { "chansetup_line", "$[15]0 %|$[10]1 $[10]2 $3", 4, { 0, 0, 0, 0 } }, + { "chansetup_footer", "", 0 }, /* ---- */ { NULL, "Nick", 0 }, diff --git a/src/fe-common/irc/module-formats.h b/src/fe-common/irc/module-formats.h index 325d3f4a..c7dc5bf8 100644 --- a/src/fe-common/irc/module-formats.h +++ b/src/fe-common/irc/module-formats.h @@ -13,6 +13,17 @@ enum { IRCTXT_RECONNECT_REMOVED, IRCTXT_RECONNECT_NOT_FOUND, IRCTXT_QUERY_SERVER_CHANGED, + IRCTXT_SETUPSERVER_ADDED, + IRCTXT_SETUPSERVER_REMOVED, + IRCTXT_SETUPSERVER_NOT_FOUND, + IRCTXT_SETUPSERVER_HEADER, + IRCTXT_SETUPSERVER_LINE, + IRCTXT_SETUPSERVER_FOOTER, + IRCTXT_NETSPLIT, + IRCTXT_NO_NETSPLITS, + IRCTXT_NETSPLITS_HEADER, + IRCTXT_NETSPLITS_LINE, + IRCTXT_NETSPLITS_FOOTER, IRCTXT_FILL_2, @@ -49,11 +60,17 @@ enum { IRCTXT_EBANLIST_LONG, IRCTXT_INVITELIST, IRCTXT_NO_SUCH_CHANNEL, + IRCTXT_CHANNEL_SYNCED, IRCTXT_NOT_IN_CHANNELS, IRCTXT_CURRENT_CHANNEL, IRCTXT_CHANLIST_HEADER, IRCTXT_CHANLIST_LINE, - IRCTXT_CHANNEL_SYNCED, + IRCTXT_CHANSETUP_NOT_FOUND, + IRCTXT_CHANSETUP_ADDED, + IRCTXT_CHANSETUP_REMOVED, + IRCTXT_CHANSETUP_HEADER, + IRCTXT_CHANSETUP_LINE, + IRCTXT_CHANSETUP_FOOTER, IRCTXT_FILL_4, diff --git a/src/fe-none/.cvsignore b/src/fe-none/.cvsignore index 8553e9e9..59b736b5 100644 --- a/src/fe-none/.cvsignore +++ b/src/fe-none/.cvsignore @@ -6,3 +6,4 @@ Makefile Makefile.in so_locations +irssi-bot diff --git a/src/fe-text/Makefile.am b/src/fe-text/Makefile.am index c651cf0e..0120a4d9 100644 --- a/src/fe-text/Makefile.am +++ b/src/fe-text/Makefile.am @@ -20,12 +20,12 @@ irssi_text_LDADD = \ irssi_text_SOURCES = \ gui-entry.c \ - gui-mainwindows.c \ + mainwindows.c \ gui-printtext.c \ gui-readline.c \ gui-special-vars.c \ - gui-statusbar.c \ - gui-statusbar-items.c \ + statusbar.c \ + statusbar-items.c \ gui-textwidget.c \ gui-windows.c \ irssi.c \ @@ -34,12 +34,11 @@ irssi_text_SOURCES = \ noinst_HEADERS = \ gui-entry.h \ - gui-mainwindows.h \ + mainwindows.h \ gui-printtext.h \ gui-readline.h \ gui-special-vars.h \ - gui-statusbar.h \ - gui-statusbar-items.h \ + statusbar.h \ gui-textwidget.h \ gui-windows.h \ module-formats.h \ diff --git a/src/fe-text/gui-entry.c b/src/fe-text/gui-entry.c index d4505195..5f96d30f 100644 --- a/src/fe-text/gui-entry.c +++ b/src/fe-text/gui-entry.c @@ -23,7 +23,7 @@ #include "screen.h" static GString *entry; -static int promptlen, pos, scrstart, scrpos; +static int promptlen, permanent_prompt, pos, scrstart, scrpos; static char *prompt; static void entry_screenpos(void) @@ -71,14 +71,11 @@ static void entry_update(void) void gui_entry_set_prompt(const char *str) { if (str != NULL) { - if (prompt != NULL) g_free(prompt); - prompt = g_strdup(str); + if (permanent_prompt) return; + g_free_not_null(prompt); + prompt = g_strdup(str); promptlen = strlen(prompt); - if (promptlen > 20) { - promptlen = 20; - prompt[20] = '\0'; - } } set_color(0); @@ -88,6 +85,23 @@ void gui_entry_set_prompt(const char *str) entry_update(); } +void gui_entry_set_perm_prompt(const char *str) +{ + g_return_if_fail(str != NULL); + + g_free_not_null(prompt); + prompt = g_strdup(str); + promptlen = strlen(prompt); + + permanent_prompt = TRUE; + gui_entry_set_prompt(NULL); +} + +void gui_entry_remove_perm_prompt(void) +{ + permanent_prompt = FALSE; +} + void gui_entry_set_text(const char *str) { g_return_if_fail(str != NULL); @@ -166,8 +180,10 @@ void gui_entry_redraw(void) void gui_entry_init(void) { entry = g_string_new(NULL); + pos = scrpos = 0; prompt = NULL; promptlen = 0; + permanent_prompt = FALSE; } void gui_entry_deinit(void) diff --git a/src/fe-text/gui-entry.h b/src/fe-text/gui-entry.h index 443d2509..4fbf5c16 100644 --- a/src/fe-text/gui-entry.h +++ b/src/fe-text/gui-entry.h @@ -3,6 +3,10 @@ void gui_entry_set_prompt(const char *str); +/* permanent prompt can't be overwritten with gui_entry_set_prompt() */ +void gui_entry_set_perm_prompt(const char *str); +void gui_entry_remove_perm_prompt(void); + void gui_entry_set_text(const char *str); char *gui_entry_get_text(void); diff --git a/src/fe-text/gui-mainwindows.c b/src/fe-text/gui-mainwindows.c deleted file mode 100644 index d5d66c1d..00000000 --- a/src/fe-text/gui-mainwindows.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - gui-mainwindows.c : irssi - - Copyright (C) 1999 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include "module.h" -#include "signals.h" - -#include "windows.h" -#include "gui-mainwindows.h" - -GList *mainwindows; - -MAIN_WINDOW_REC *gui_mainwindow_create(void) -{ - MAIN_WINDOW_REC *window; - - window = g_new0(MAIN_WINDOW_REC, 1); - mainwindows = g_list_append(mainwindows, window); - - return window; -} - -void gui_mainwindow_destroy(MAIN_WINDOW_REC *window) -{ - g_return_if_fail(window != NULL); - if (window->destroying) return; - - mainwindows = g_list_remove(mainwindows, window); - - window->destroying = TRUE; - while (window->children != NULL) - window_destroy(window->children->data); - window->destroying = FALSE; - - g_free(window); - - if (mainwindows == NULL) - signal_emit("gui exit", 0); -} - -void gui_mainwindows_init(void) -{ - mainwindows = NULL; -} - -void gui_mainwindows_deinit(void) -{ - while (mainwindows != NULL) - gui_mainwindow_destroy(mainwindows->data); -} diff --git a/src/fe-text/gui-mainwindows.h b/src/fe-text/gui-mainwindows.h deleted file mode 100644 index b91f35a9..00000000 --- a/src/fe-text/gui-mainwindows.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef __GUI_MAINWINDOWS_H -#define __GUI_MAINWINDOWS_H - -#include "windows.h" - -typedef struct { - WINDOW_REC *active; - GList *children; - - int destroying; -} MAIN_WINDOW_REC; - -extern GList *mainwindows; - -void gui_mainwindows_init(void); -void gui_mainwindows_deinit(void); - -MAIN_WINDOW_REC *gui_mainwindow_create(void); -void gui_mainwindow_destroy(MAIN_WINDOW_REC *window); - -#endif diff --git a/src/fe-text/gui-printtext.c b/src/fe-text/gui-printtext.c index 1ef4aa32..59e00d52 100644 --- a/src/fe-text/gui-printtext.c +++ b/src/fe-text/gui-printtext.c @@ -28,7 +28,6 @@ #include "themes.h" #include "screen.h" -#include "gui-mainwindows.h" #include "gui-windows.h" #define TEXT_CHUNK_USABLE_SIZE (LINE_TEXT_CHUNK_SIZE-2-sizeof(char*)) @@ -46,6 +45,9 @@ static LINE_REC *create_line(GUI_WINDOW_REC *gui, gint level) gui->cur_line->level = (gint32) GPOINTER_TO_INT(level); gui->cur_line->time = time(NULL); + /* temporarily mark the end of line. */ + memcpy(gui->cur_text->buffer+gui->cur_text->pos, "\0\x80", 2); + gui->last_color = -1; gui->last_flags = 0; @@ -67,6 +69,8 @@ static TEXT_CHUNK_REC *create_text_chunk(GUI_WINDOW_REC *gui) g_return_val_if_fail(gui != NULL, NULL); rec = g_new(TEXT_CHUNK_REC, 1); + rec->overflow[0] = 0; + rec->overflow[1] = (char) LINE_CMD_OVERFLOW; rec->pos = 0; rec->lines = 0; @@ -268,7 +272,7 @@ static void gui_printtext(WINDOW_REC *window, gpointer fgcolor, gpointer bgcolor if (visible) { /* draw the line to screen. */ - lines = gui_window_line_draw(gui, line, first_text_line+gui->ypos, gui->last_subline, -1); + lines = gui_window_line_draw(gui, line, gui->parent->first_line+gui->ypos, gui->last_subline, -1); } else { @@ -289,7 +293,7 @@ static void cmd_clear(gchar *data) if (is_window_visible(active_win)) { - for (n = first_text_line; n < last_text_line; n++) + for (n = gui->parent->first_line; n <= gui->parent->last_line; n++) { move(n, 0); clrtoeol(); @@ -300,7 +304,7 @@ static void cmd_clear(gchar *data) gui->ypos = -1; gui->bottom_startline = gui->startline = g_list_last(gui->lines); gui->bottom_subline = gui->subline = gui->last_subline+1; - gui->empty_linecount = last_text_line-first_text_line; + gui->empty_linecount = gui->parent->last_line-gui->parent->first_line+1; gui->bottom = TRUE; } diff --git a/src/fe-text/gui-readline.c b/src/fe-text/gui-readline.c index 39608119..0171dc8d 100644 --- a/src/fe-text/gui-readline.c +++ b/src/fe-text/gui-readline.c @@ -31,25 +31,71 @@ #include "screen.h" #include "gui-entry.h" -#include "gui-mainwindows.h" #include "gui-windows.h" #include -static gint readtag, sigint_count = 0; +typedef void (*ENTRY_REDIRECT_KEY_FUNC) (int key, void *data, SERVER_REC *server, WI_ITEM_REC *item); +typedef void (*ENTRY_REDIRECT_ENTRY_FUNC) (const char *line, void *data, SERVER_REC *server, WI_ITEM_REC *item); + +typedef struct { + SIGNAL_FUNC func; + int key; + void *data; +} ENTRY_REDIRECT_REC; + +static ENTRY_REDIRECT_REC *redir; + +static int readtag, sigint_count = 0; static time_t idle_time; +static void handle_key_redirect(int key) +{ + ENTRY_REDIRECT_KEY_FUNC func; + void *data; + + func = (ENTRY_REDIRECT_KEY_FUNC) redir->func; + data = redir->data; + g_free_and_null(redir); + + if (func != NULL) + func(key, data, active_win->active_server, active_win->active); + + gui_entry_remove_perm_prompt(); + window_update_prompt(active_win); +} + +static void handle_entry_redirect(const char *line) +{ + ENTRY_REDIRECT_ENTRY_FUNC func; + void *data; + + func = (ENTRY_REDIRECT_ENTRY_FUNC) redir->func; + data = redir->data; + g_free_and_null(redir); + + if (func != NULL) + func(line, data, active_win->active_server, active_win->active); + + gui_entry_remove_perm_prompt(); + window_update_prompt(active_win); +} + static void window_prev_page(void) { - gui_window_scroll(active_win, -(last_text_line-first_text_line)/2); + GUI_WINDOW_REC *gui = WINDOW_GUI(active_win); + + gui_window_scroll(active_win, -(gui->parent->last_line-gui->parent->first_line)/2); } static void window_next_page(void) { - gui_window_scroll(active_win, (last_text_line-first_text_line)/2); + GUI_WINDOW_REC *gui = WINDOW_GUI(active_win); + + gui_window_scroll(active_win, (gui->parent->last_line-gui->parent->first_line)/2); } -static char *get_key_name(int key) +static const char *get_key_name(int key) { static char str[MAX_INT_STRLEN]; @@ -76,157 +122,163 @@ static char *get_key_name(int key) } } -void handle_key(gint key) +void handle_key(int key) { - const char *text; - char *str; - int c; - - /* Quit if we get 5 CTRL-C's in a row. */ - if (key != 3) - sigint_count = 0; - else if (++sigint_count >= 5) - raise(SIGTERM); - - idle_time = time(NULL); - switch (key) - { - case 27: - c = getch(); - if (c == toupper(c) && c != tolower(c)) - str = g_strdup_printf("ALT-SHIFT-%c", c); - else { - if (c < 256) - str = g_strdup_printf("ALT-%c", toupper(c)); - else - str = g_strdup_printf("ALT-%s", get_key_name(c)); - } - key_pressed(str, NULL); - g_free(str); - break; + const char *text; + char *str; + int c; + + /* Quit if we get 5 CTRL-C's in a row. */ + if (key != 3) + sigint_count = 0; + else if (++sigint_count >= 5) + raise(SIGTERM); + + idle_time = time(NULL); + + if (redir != NULL && redir->key) { + handle_key_redirect(key); + return; + } + + switch (key) + { + case 27: + c = getch(); + if (c == toupper(c) && c != tolower(c)) + str = g_strdup_printf("ALT-SHIFT-%c", c); + else { + if (c < 256) + str = g_strdup_printf("ALT-%c", toupper(c)); + else + str = g_strdup_printf("ALT-%s", get_key_name(c)); + } + key_pressed(str, NULL); + g_free(str); + break; case KEY_HOME: - /* home */ - gui_entry_set_pos(0); - gui_entry_move_pos(0); - break; - case KEY_END: - /* end */ - gui_entry_set_pos(strlen(gui_entry_get_text())); - gui_entry_move_pos(0); - break; - case KEY_PPAGE: - /* page up */ - window_prev_page(); - break; - case KEY_NPAGE: - /* page down */ - window_next_page(); - break; - - case KEY_UP: - /* up */ - text = command_history_prev(active_win, gui_entry_get_text()); - gui_entry_set_text(text); - break; - case KEY_DOWN: - /* down */ - text = command_history_next(active_win, gui_entry_get_text()); - gui_entry_set_text(text); - break; - case KEY_RIGHT: - /* right */ - gui_entry_move_pos(1); - break; - case KEY_LEFT: - /* left */ - gui_entry_move_pos(-1); - break; + /* home */ + gui_entry_set_pos(0); + gui_entry_move_pos(0); + break; + case KEY_END: + /* end */ + gui_entry_set_pos(strlen(gui_entry_get_text())); + gui_entry_move_pos(0); + break; + case KEY_PPAGE: + /* page up */ + window_prev_page(); + break; + case KEY_NPAGE: + /* page down */ + window_next_page(); + break; + + case KEY_UP: + /* up */ + text = command_history_prev(active_win, gui_entry_get_text()); + gui_entry_set_text(text); + break; + case KEY_DOWN: + /* down */ + text = command_history_next(active_win, gui_entry_get_text()); + gui_entry_set_text(text); + break; + case KEY_RIGHT: + /* right */ + gui_entry_move_pos(1); + break; + case KEY_LEFT: + /* left */ + gui_entry_move_pos(-1); + break; case 21: - /* Ctrl-U, clear line */ - gui_entry_set_text(""); - break; + /* Ctrl-U, clear line */ + gui_entry_set_text(""); + break; case 9: - key_pressed("Tab", NULL); - break; + key_pressed("Tab", NULL); + break; case 8: case 127: - case KEY_BACKSPACE: - gui_entry_erase(1); - break; - - case KEY_DC: - if (gui_entry_get_pos() < strlen(gui_entry_get_text())) - { - gui_entry_move_pos(1); - gui_entry_erase(1); - } - break; + case KEY_BACKSPACE: + gui_entry_erase(1); + break; + + case KEY_DC: + if (gui_entry_get_pos() < strlen(gui_entry_get_text())) { + gui_entry_move_pos(1); + gui_entry_erase(1); + } + break; case 0: - /* Ctrl-space - ignore */ - break; - case 1: - /* C-A, home */ - gui_entry_set_pos(0); - gui_entry_move_pos(0); - break; - case 5: - /* C-E, end */ - gui_entry_set_pos(strlen(gui_entry_get_text())); - gui_entry_move_pos(0); - break; - - case '\n': + /* Ctrl-space - ignore */ + break; + case 1: + /* C-A, home */ + gui_entry_set_pos(0); + gui_entry_move_pos(0); + break; + case 5: + /* C-E, end */ + gui_entry_set_pos(strlen(gui_entry_get_text())); + gui_entry_move_pos(0); + break; + + case '\n': case 13: - key_pressed("Return", NULL); + key_pressed("Return", NULL); - str = gui_entry_get_text(); - if (*str == '\0') break; + str = gui_entry_get_text(); + if (*str == '\0') break; - translate_output(str); - signal_emit("send command", 3, str, active_win->active_server, active_win->active); + translate_output(str); - command_history_add(active_win, gui_entry_get_text(), FALSE); - gui_entry_set_text(""); - command_history_clear_pos(active_win); - break; + if (redir == NULL) + signal_emit("send command", 3, str, active_win->active_server, active_win->active); + else + handle_entry_redirect(str); - default: - if (key > 0 && key < 32) - { - str = g_strdup_printf("CTRL-%c", key == 31 ? '-' : key+'A'-1); - key_pressed(str, NULL); - g_free(str); + command_history_add(active_win, gui_entry_get_text(), FALSE); + gui_entry_set_text(""); + command_history_clear_pos(active_win); break; - } - - if (key < 256) - { - gchar str[2]; - str[0] = toupper(key); str[1] = '\0'; - key_pressed(str, NULL); - gui_entry_insert_char((gchar) key); - } - break; - } + default: + if (key > 0 && key < 32) { + str = g_strdup_printf("CTRL-%c", key == 31 ? '-' : key+'A'-1); + key_pressed(str, NULL); + g_free(str); + break; + } + + if (key < 256) { + char str[2]; + + str[0] = toupper(key); str[1] = '\0'; + key_pressed(str, NULL); + gui_entry_insert_char((char) key); + } + break; + } } void readline(void) { - gint key; + int key; - for (;;) - { - key = getch(); - if (key == ERR) break; + for (;;) { + key = getch(); + if (key == ERR) break; - handle_key(key); - } + handle_key(key); + } } time_t get_idle_time(void) @@ -236,147 +288,169 @@ time_t get_idle_time(void) static void sig_prev_page(void) { - window_prev_page(); + window_prev_page(); } static void sig_next_page(void) { - window_next_page(); + window_next_page(); } -static void sig_change_window(gchar *data) +static void sig_change_window(const char *data) { - signal_emit("command window goto", 3, data, active_win->active_server, active_win->active); + signal_emit("command window goto", 3, data, active_win->active_server, active_win->active); } static void sig_completion(void) { - gchar *line; - gint pos; - - pos = gui_entry_get_pos(); - - line = completion_line(active_win, gui_entry_get_text(), &pos); - if (line != NULL) - { - gui_entry_set_text(line); - gui_entry_set_pos(pos); - g_free(line); - } + char *line; + int pos; + + pos = gui_entry_get_pos(); + + line = completion_line(active_win, gui_entry_get_text(), &pos); + if (line != NULL) { + gui_entry_set_text(line); + gui_entry_set_pos(pos); + g_free(line); + } } static void sig_replace(void) { - gchar *line; - gint pos; - - pos = gui_entry_get_pos(); - - line = auto_completion(gui_entry_get_text(), &pos); - if (line != NULL) - { - gui_entry_set_text(line); - gui_entry_set_pos(pos); - g_free(line); - } + char *line; + int pos; + + pos = gui_entry_get_pos(); + + line = auto_completion(gui_entry_get_text(), &pos); + if (line != NULL) { + gui_entry_set_text(line); + gui_entry_set_pos(pos); + g_free(line); + } } static void sig_prev_window(void) { - signal_emit("command window prev", 3, "", active_win->active_server, active_win->active); + signal_emit("command window prev", 3, "", active_win->active_server, active_win->active); } static void sig_next_window(void) { - signal_emit("command window next", 3, "", active_win->active_server, active_win->active); + signal_emit("command window next", 3, "", active_win->active_server, active_win->active); +} + +static void sig_up_window(void) +{ + signal_emit("command window up", 3, "", active_win->active_server, active_win->active); +} + +static void sig_down_window(void) +{ + signal_emit("command window down", 3, "", active_win->active_server, active_win->active); } static void sig_window_goto_active(void) { - signal_emit("command window goto", 3, "active", active_win->active_server, active_win->active); + signal_emit("command window goto", 3, "active", active_win->active_server, active_win->active); } -static void sig_prev_channel(void) +static void sig_prev_window_item(void) { - signal_emit("command channel prev", 3, "", active_win->active_server, active_win->active); + signal_emit("command window item prev", 3, "", active_win->active_server, active_win->active); } -static void sig_next_channel(void) +static void sig_next_window_item(void) { - signal_emit("command channel next", 3, "", active_win->active_server, active_win->active); + signal_emit("command window item next", 3, "", active_win->active_server, active_win->active); } -static void sig_addchar(gchar *data) +static void sig_addchar(const char *data) { - gui_entry_insert_char(*data); + gui_entry_insert_char(*data); } -static void signal_window_auto_changed(WINDOW_REC *window) +static void sig_window_auto_changed(WINDOW_REC *window) { command_history_next(active_win, gui_entry_get_text()); gui_entry_set_text(""); } +static void sig_gui_entry_redirect(SIGNAL_FUNC func, const char *entry, gpointer key, void *data) +{ + redir = g_new0(ENTRY_REDIRECT_REC, 1); + redir->func = func; + redir->key = key != NULL; + redir->data = data; + + gui_entry_set_perm_prompt(entry); +} + void gui_readline_init(void) { - static gchar changekeys[] = "1234567890QWERTYUIO"; - gchar *key, *data; - gint n; - - idle_time = time(NULL); - readtag = g_input_add(0, G_INPUT_READ, (GInputFunction) readline, NULL); - - key_bind("completion", NULL, "Nick completion", "Tab", (SIGNAL_FUNC) sig_completion); - key_bind("check replaces", NULL, "Check word replaces", " ", (SIGNAL_FUNC) sig_replace); - key_bind("check replaces", NULL, NULL, "Return", (SIGNAL_FUNC) sig_replace); - key_bind("window prev", NULL, "Previous window", "CTRL-P", (SIGNAL_FUNC) sig_prev_window); - key_bind("window prev", NULL, NULL, "ALT-Left", (SIGNAL_FUNC) sig_prev_window); - key_bind("window next", NULL, "Next window", "CTRL-N", (SIGNAL_FUNC) sig_next_window); - key_bind("window next", NULL, NULL, "ALT-Right", (SIGNAL_FUNC) sig_next_window); - key_bind("window active", NULL, "Go to next window with the highest activity", "ALT-A", (SIGNAL_FUNC) sig_window_goto_active); - key_bind("channel next", NULL, "Next channel", "CTRL-X", (SIGNAL_FUNC) sig_next_channel); - key_bind("channel prev", NULL, "Next channel", NULL, (SIGNAL_FUNC) sig_prev_channel); - - key_bind("redraw", NULL, "Redraw window", "CTRL-L", (SIGNAL_FUNC) irssi_redraw); - key_bind("prev page", NULL, "Previous page", "ALT-P", (SIGNAL_FUNC) sig_prev_page); - key_bind("next page", NULL, "Next page", "ALT-N", (SIGNAL_FUNC) sig_next_page); - - key_bind("special char", "\x02", "Insert special character", "CTRL-B", (SIGNAL_FUNC) sig_addchar); - key_bind("special char", "\x1f", NULL, "CTRL--", (SIGNAL_FUNC) sig_addchar); - key_bind("special char", "\x03", NULL, "CTRL-C", (SIGNAL_FUNC) sig_addchar); - key_bind("special char", "\x16", NULL, "CTRL-V", (SIGNAL_FUNC) sig_addchar); - key_bind("special char", "\x07", NULL, "CTRL-G", (SIGNAL_FUNC) sig_addchar); - key_bind("special char", "\x0f", NULL, "CTRL-O", (SIGNAL_FUNC) sig_addchar); - - for (n = 0; changekeys[n] != '\0'; n++) - { - key = g_strdup_printf("ALT-%c", changekeys[n]); - data = g_strdup_printf("%d", n+1); - key_bind("change window", data, "Change window", key, (SIGNAL_FUNC) sig_change_window); - g_free(data); g_free(key); - } - - signal_add("window changed automatic", (SIGNAL_FUNC) signal_window_auto_changed); + static char changekeys[] = "1234567890QWERTYUIO"; + char *key, data[MAX_INT_STRLEN]; + int n; + + redir = NULL; + idle_time = time(NULL); + readtag = g_input_add(0, G_INPUT_READ, (GInputFunction) readline, NULL); + + key_bind("completion", NULL, "Nick completion", "Tab", (SIGNAL_FUNC) sig_completion); + key_bind("check replaces", NULL, "Check word replaces", " ", (SIGNAL_FUNC) sig_replace); + key_bind("check replaces", NULL, NULL, "Return", (SIGNAL_FUNC) sig_replace); + key_bind("window prev", NULL, "Previous window", "CTRL-P", (SIGNAL_FUNC) sig_prev_window); + key_bind("window prev", NULL, NULL, "ALT-Left", (SIGNAL_FUNC) sig_prev_window); + key_bind("window next", NULL, "Next window", "CTRL-N", (SIGNAL_FUNC) sig_next_window); + key_bind("window next", NULL, NULL, "ALT-Right", (SIGNAL_FUNC) sig_next_window); + key_bind("window up", NULL, "Upper window", "ALT-Up", (SIGNAL_FUNC) sig_up_window); + key_bind("window down", NULL, "Lower window", "ALT-Down", (SIGNAL_FUNC) sig_down_window); + key_bind("window active", NULL, "Go to next window with the highest activity", "ALT-A", (SIGNAL_FUNC) sig_window_goto_active); + key_bind("window item next", NULL, "Next channel", "CTRL-X", (SIGNAL_FUNC) sig_next_window_item); + key_bind("window item prev", NULL, "Next channel", NULL, (SIGNAL_FUNC) sig_prev_window_item); + + key_bind("redraw", NULL, "Redraw window", "CTRL-L", (SIGNAL_FUNC) irssi_redraw); + key_bind("prev page", NULL, "Previous page", "ALT-P", (SIGNAL_FUNC) sig_prev_page); + key_bind("next page", NULL, "Next page", "ALT-N", (SIGNAL_FUNC) sig_next_page); + + key_bind("special char", "\x02", "Insert special character", "CTRL-B", (SIGNAL_FUNC) sig_addchar); + key_bind("special char", "\x1f", NULL, "CTRL--", (SIGNAL_FUNC) sig_addchar); + key_bind("special char", "\x03", NULL, "CTRL-C", (SIGNAL_FUNC) sig_addchar); + key_bind("special char", "\x16", NULL, "CTRL-V", (SIGNAL_FUNC) sig_addchar); + key_bind("special char", "\x07", NULL, "CTRL-G", (SIGNAL_FUNC) sig_addchar); + key_bind("special char", "\x0f", NULL, "CTRL-O", (SIGNAL_FUNC) sig_addchar); + + for (n = 0; changekeys[n] != '\0'; n++) { + key = g_strdup_printf("ALT-%c", changekeys[n]); + ltoa(data, n+1); + key_bind("change window", data, "Change window", key, (SIGNAL_FUNC) sig_change_window); + g_free(key); + } + + signal_add("window changed automatic", (SIGNAL_FUNC) sig_window_auto_changed); + signal_add("gui entry redirect", (SIGNAL_FUNC) sig_gui_entry_redirect); } void gui_readline_deinit(void) { - g_source_remove(readtag); + g_source_remove(readtag); - key_unbind("completion", (SIGNAL_FUNC) sig_completion); - key_unbind("check replaces", (SIGNAL_FUNC) sig_replace); - key_unbind("window prev", (SIGNAL_FUNC) sig_prev_window); - key_unbind("window next", (SIGNAL_FUNC) sig_next_window); - key_unbind("window active", (SIGNAL_FUNC) sig_window_goto_active); - key_unbind("channel next", (SIGNAL_FUNC) sig_next_channel); - key_unbind("channel prev", (SIGNAL_FUNC) sig_prev_channel); + key_unbind("completion", (SIGNAL_FUNC) sig_completion); + key_unbind("check replaces", (SIGNAL_FUNC) sig_replace); + key_unbind("window prev", (SIGNAL_FUNC) sig_prev_window); + key_unbind("window next", (SIGNAL_FUNC) sig_next_window); + key_unbind("window active", (SIGNAL_FUNC) sig_window_goto_active); + key_unbind("window item next", (SIGNAL_FUNC) sig_next_window_item); + key_unbind("window item prev", (SIGNAL_FUNC) sig_prev_window_item); - key_unbind("redraw", (SIGNAL_FUNC) irssi_redraw); - key_unbind("prev page", (SIGNAL_FUNC) sig_prev_page); - key_unbind("next page", (SIGNAL_FUNC) sig_next_page); + key_unbind("redraw", (SIGNAL_FUNC) irssi_redraw); + key_unbind("prev page", (SIGNAL_FUNC) sig_prev_page); + key_unbind("next page", (SIGNAL_FUNC) sig_next_page); - key_unbind("special char", (SIGNAL_FUNC) sig_addchar); - key_unbind("change window", (SIGNAL_FUNC) sig_change_window); + key_unbind("special char", (SIGNAL_FUNC) sig_addchar); + key_unbind("change window", (SIGNAL_FUNC) sig_change_window); - signal_remove("window changed automatic", (SIGNAL_FUNC) signal_window_auto_changed); + signal_remove("window changed automatic", (SIGNAL_FUNC) sig_window_auto_changed); + signal_remove("gui entry redirect", (SIGNAL_FUNC) sig_gui_entry_redirect); } diff --git a/src/fe-text/gui-statusbar-items.c b/src/fe-text/gui-statusbar-items.c deleted file mode 100644 index 1cb3740e..00000000 --- a/src/fe-text/gui-statusbar-items.c +++ /dev/null @@ -1,693 +0,0 @@ -/* - gui-statusbar-items.c : irssi - - Copyright (C) 1999 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include "module.h" -#include "signals.h" -#include "server.h" -#include "misc.h" -#include "settings.h" - -#include "irc.h" -#include "channels.h" -#include "query.h" -#include "irc-server.h" -#include "nicklist.h" - -#include "windows.h" - -#include "screen.h" -#include "gui-statusbar.h" -#include "gui-mainwindows.h" -#include "gui-windows.h" - -/* how often to redraw lagging time */ -#define LAG_REFRESH_TIME 10 -/* If we haven't been able to check lag for this long, "(??)" is added after - the lag */ -#define MAX_LAG_UNKNOWN_TIME 30 - -/* clock */ -static int clock_tag, clock_timetag; -static time_t clock_last; - -/* nick */ -static int nick_tag; - -/* channel */ -static int channel_tag; - -/* activity */ -static int activity_tag; -static GList *activity_list; - -/* more */ -static int more_tag; - -/* lag */ -static int lag_tag, lag_timetag, lag_min_show; -static time_t lag_last_draw; - -/* topic */ -static int topic_tag; - -/* redraw clock */ -static void statusbar_clock(int xpos, int ypos, int size) -{ - struct tm *tm; - gchar str[5]; - - clock_last = time(NULL); - tm = localtime(&clock_last); - - sprintf(str, "%02d:%02d", tm->tm_hour, tm->tm_min); - - move(ypos, xpos); - set_color((1 << 4)+3); addch('['); - set_color((1 << 4)+15); addstr(str); - set_color((1 << 4)+3); addch(']'); - - screen_refresh(); -} - -/* check if we need to redraw clock.. */ -static int statusbar_clock_timeout(void) -{ - struct tm *tm; - time_t t; - int min; - - tm = localtime(&clock_last); - min = tm->tm_min; - - t = time(NULL); - tm = localtime(&t); - - if (tm->tm_min != min) - { - /* minute changed, redraw! */ - gui_statusbar_redraw(clock_tag); - } - return 1; -} - -/* redraw nick */ -static void statusbar_nick(int xpos, int ypos, int size) -{ - CHANNEL_REC *channel; - IRC_SERVER_REC *server; - NICK_REC *nickrec; - int size_needed; - int umode_size; - gchar nick[10]; - - server = (IRC_SERVER_REC *) (active_win == NULL ? NULL : active_win->active_server); - - umode_size = server == NULL || server->usermode == NULL ? 0 : strlen(server->usermode)+3; - - /* nick */ - if (server == NULL || server->nick == NULL) - { - nick[0] = '\0'; - nickrec = NULL; - } - else - { - strncpy(nick, server->nick, 9); - nick[9] = '\0'; - - channel = irc_item_channel(active_win->active); - nickrec = channel == NULL ? NULL : nicklist_find(channel, server->nick); - } - - size_needed = 2 + strlen(nick) + umode_size + - (server != NULL && server->usermode_away ? 7 : 0) + - (nickrec != NULL && (nickrec->op || nickrec->voice) ? 1 : 0); /* @ + */ - - if (size != size_needed) - { - /* we need more (or less..) space! */ - gui_statusbar_resize(nick_tag, size_needed); - return; - } - - /* size ok, draw the nick */ - move(ypos, xpos); - - set_color((1 << 4)+3); addch('['); - if (nickrec != NULL && (nickrec->op || nickrec->voice)) - { - set_color((1 << 4)+15); addch(nickrec->op ? '@' : '+'); - } - set_color((1 << 4)+7); addstr(nick); - if (umode_size) - { - set_color((1 << 4)+15); addch('('); - set_color((1 << 4)+3); addch('+'); - set_color((1 << 4)+7); addstr(server->usermode); - set_color((1 << 4)+15); addch(')'); - if (server->usermode_away) - { - set_color((1 << 4)+7); addstr(" ("); - set_color((1 << 4)+10); addstr("zZzZ"); - set_color((1 << 4)+7); addch(')'); - } - } - set_color((1 << 4)+3); addch(']'); - screen_refresh(); -} - -static void sig_statusbar_nick_redraw(void) -{ - gui_statusbar_redraw(nick_tag); -} - -/* redraw channel */ -static void statusbar_channel(int xpos, int ypos, int size) -{ - WI_ITEM_REC *item; - CHANNEL_REC *channel; - SERVER_REC *server; - gchar channame[21], window[MAX_INT_STRLEN], *mode; - int size_needed; - int mode_size; - - server = active_win == NULL ? NULL : active_win->active_server; - - ltoa(window, active_win == NULL ? 0 : - g_slist_index(windows, active_win)+1); - - item = active_win != NULL && irc_item_check(active_win->active) ? - active_win->active : NULL; - if (item == NULL) - { - /* display server tag */ - channame[0] = '\0'; - mode = NULL; - mode_size = 0; - - size_needed = 3 + strlen(window) + (server == NULL ? 0 : strlen(server->tag)); - } - else - { - /* display channel + mode */ - strncpy(channame, item->name, 20); channame[20] = '\0'; - - channel = irc_item_channel(item); - if (channel == NULL) { - mode_size = 0; - mode = NULL; - } else { - mode = channel_get_mode(channel); - mode_size = strlen(mode); - if (mode_size > 0) mode_size += 3; /* (+) */ - } - - size_needed = 3 + strlen(window) + strlen(channame) + mode_size; - } - - if (size != size_needed) - { - /* we need more (or less..) space! */ - gui_statusbar_resize(channel_tag, size_needed); - if (mode != NULL) g_free(mode); - return; - } - - move(ypos, xpos); - set_color((1 << 4)+3); addch('['); - - /* window number */ - set_color((1 << 4)+7); addstr(window); - set_color((1 << 4)+3); addch(':'); - - if (channame[0] == '\0' && server != NULL) - { - /* server tag */ - set_color((1 << 4)+7); addstr(server->tag); - } - else if (channame[0] != '\0') - { - /* channel + mode */ - set_color((1 << 4)+7); addstr(channame); - if (mode_size) - { - set_color((1 << 4)+15); addch('('); - set_color((1 << 4)+3); addch('+'); - set_color((1 << 4)+7); addstr(mode); - set_color((1 << 4)+15); addch(')'); - } - } - set_color((1 << 4)+3); addch(']'); - screen_refresh(); - - if (mode != NULL) g_free(mode); -} - -static void sig_statusbar_channel_redraw(void) -{ - gui_statusbar_redraw(channel_tag); -} - -static void draw_activity(gchar *title, gboolean act, gboolean det) -{ - WINDOW_REC *window; - GList *tmp; - gchar str[(sizeof(int) * CHAR_BIT + 2) / 3 + 1]; - gboolean first, is_det; - - set_color((1 << 4)+7); addstr(title); - - first = TRUE; - for (tmp = activity_list; tmp != NULL; tmp = tmp->next) - { - window = tmp->data; - - is_det = window->new_data == NEWDATA_MSG_FORYOU; - if (is_det && !det) continue; - if (!is_det && !act) continue; - - if (first) - first = FALSE; - else - { - set_color((1 << 4)+3); - addch(','); - } - - sprintf(str, "%d", g_slist_index(windows, window)+1); - switch (window->new_data) - { - case NEWDATA_TEXT: - set_color((1 << 4)+3); - break; - case NEWDATA_MSG: - set_color((1 << 4)+15); - break; - case NEWDATA_MSG_FORYOU: - set_color((1 << 4)+13); - break; - } - addstr(str); - } -} - -/* redraw activity */ -static void statusbar_activity(int xpos, int ypos, int size) -{ - WINDOW_REC *window; - GList *tmp; - gchar str[MAX_INT_STRLEN]; - int size_needed; - gboolean act, det; - - size_needed = 0; act = det = FALSE; - for (tmp = activity_list; tmp != NULL; tmp = tmp->next) - { - window = tmp->data; - - size_needed += 1+g_snprintf(str, sizeof(str), "%d", g_slist_index(windows, window)+1); - - if (!use_colors && window->new_data == NEWDATA_MSG_FORYOU) - det = TRUE; - else - act = TRUE; - } - - if (act) size_needed += 6; /* [Act: ], -1 */ - if (det) size_needed += 6; /* [Det: ], -1 */ - if (act && det) size_needed--; - - if (size != size_needed) - { - /* we need more (or less..) space! */ - gui_statusbar_resize(activity_tag, size_needed); - return; - } - - if (size == 0) - return; - - move(ypos, xpos); - set_color((1 << 4)+3); addch('['); - if (act) draw_activity("Act: ", TRUE, !det); - if (act && det) addch(' '); - if (det) draw_activity("Det: ", FALSE, TRUE); - set_color((1 << 4)+3); addch(']'); - - screen_refresh(); -} - -static void sig_statusbar_activity_hilight(WINDOW_REC *window, gpointer oldlevel) -{ - int pos, inspos; - GList *tmp; - - g_return_if_fail(window != NULL); - - if (settings_get_bool("toggle_actlist_moves")) - { - /* Move the window to the first in the activity list */ - if (g_list_find(activity_list, window) != NULL) - activity_list = g_list_remove(activity_list, window); - if (window->new_data != 0) - activity_list = g_list_prepend(activity_list, window); - gui_statusbar_redraw(activity_tag); - return; - } - - if (g_list_find(activity_list, window) != NULL) - { - /* already in activity list */ - if (window->new_data == 0) - { - /* remove from activity list */ - activity_list = g_list_remove(activity_list, window); - gui_statusbar_redraw(activity_tag); - } - else if (window->new_data != GPOINTER_TO_INT(oldlevel)) - { - /* different level as last time, just redraw it. */ - gui_statusbar_redraw(activity_tag); - } - return; - } - - if (window->new_data == 0) - return; - - /* add window to activity list .. */ - pos = g_slist_index(windows, window); - - inspos = 0; - for (tmp = activity_list; tmp != NULL; tmp = tmp->next, inspos++) - { - if (pos < g_slist_index(windows, tmp->data)) - { - activity_list = g_list_insert(activity_list, window, inspos); - break; - } - } - if (tmp == NULL) - activity_list = g_list_append(activity_list, window); - - gui_statusbar_redraw(activity_tag); -} - -static void sig_statusbar_activity_window_destroyed(WINDOW_REC *window) -{ - g_return_if_fail(window != NULL); - - if (g_list_find(activity_list, window) != NULL) - { - activity_list = g_list_remove(activity_list, window); - gui_statusbar_redraw(activity_tag); - } -} - -/* redraw -- more -- */ -static void statusbar_more(int xpos, int ypos, int size) -{ - if (size != 10) return; - - move(ypos, xpos); - set_color((1 << 4)+15); addstr("-- more --"); - screen_refresh(); -} - -static void sig_statusbar_more_check_remove(WINDOW_REC *window) -{ - g_return_if_fail(window != NULL); - - if (!is_window_visible(window)) - return; - - if (more_tag != -1 && WINDOW_GUI(window)->bottom) - { - gui_statusbar_remove(more_tag); - more_tag = -1; - } -} - -static void sig_statusbar_more_check(WINDOW_REC *window) -{ - g_return_if_fail(window != NULL); - - if (WINDOW_GUI(window)->parent->active != window) - return; - - if (!WINDOW_GUI(window)->bottom) - { - if (more_tag == -1) - more_tag = gui_statusbar_allocate(10, FALSE, FALSE, 0, statusbar_more); - } - else if (more_tag != -1) - { - gui_statusbar_remove(more_tag); - more_tag = -1; - } -} - -static void statusbar_lag(int xpos, int ypos, int size) -{ - IRC_SERVER_REC *server; - GString *str; - int size_needed, lag_unknown; - time_t now; - - now = time(NULL); - str = g_string_new(NULL); - - server = (IRC_SERVER_REC *) (active_win == NULL ? NULL : active_win->active_server); - if (server == NULL || server->lag_last_check == 0) - size_needed = 0; - else if (server->lag_sent == 0 || now-server->lag_sent < 5) { - lag_unknown = now-server->lag_last_check > MAX_LAG_UNKNOWN_TIME; - - if (server->lag < lag_min_show && !lag_unknown) - size_needed = 0; /* small lag, don't display */ - else { - g_string_sprintf(str, "%d.%02d", server->lag/1000, (server->lag % 1000)/10); - if (lag_unknown) - g_string_append(str, " (??)"); - size_needed = str->len+7; - } - } else { - /* big lag, still waiting .. */ - g_string_sprintf(str, "%ld (??)", now-server->lag_sent); - size_needed = str->len+7; - } - - if (size != size_needed) - { - /* we need more (or less..) space! */ - gui_statusbar_resize(lag_tag, size_needed); - g_string_free(str, TRUE); - return; - } - - if (size != 0) - { - lag_last_draw = now; - move(ypos, xpos); - set_color((1 << 4)+3); addch('['); - set_color((1 << 4)+7); addstr("Lag: "); - - set_color((1 << 4)+15); addstr(str->str); - set_color((1 << 4)+3); addch(']'); - - screen_refresh(); - } - g_string_free(str, TRUE); -} - -static void sig_statusbar_lag_redraw(void) -{ - gui_statusbar_redraw(lag_tag); -} - -static int statusbar_lag_timeout(void) -{ - /* refresh statusbar every 10 seconds */ - if (time(NULL)-lag_last_draw < LAG_REFRESH_TIME) - return 1; - - gui_statusbar_redraw(lag_tag); - return 1; -} - -static void statusbar_topic(int xpos, int ypos, int size) -{ - CHANNEL_REC *channel; - QUERY_REC *query; - char *str, *topic; - - if (size != COLS-2) { - /* get all space for topic */ - gui_statusbar_resize(topic_tag, COLS-2); - return; - } - - move(ypos, xpos); - set_bg((1<<4)+7); clrtoeol(); set_bg(0); - - if (active_win == NULL) - return; - - topic = NULL; - channel = irc_item_channel(active_win->active); - query = irc_item_query(active_win->active); - if (channel != NULL && channel->topic != NULL) topic = channel->topic; - if (query != NULL && query->address != NULL) topic = query->address; - if (topic == NULL) return; - - str = g_strdup_printf("%.*s", size, topic); - set_color((1<<4)+15); addstr(str); - g_free(str); - - screen_refresh(); -} - -static void sig_statusbar_topic_redraw(void) -{ - gui_statusbar_redraw(topic_tag); -} - -static void read_settings(void) -{ - int ypos; - - if (topic_tag == -1 && settings_get_bool("toggle_show_topicbar")) { - ypos = gui_statusbar_create(TRUE); - topic_tag = gui_statusbar_allocate(0, FALSE, TRUE, ypos, statusbar_topic); - signal_add("window changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw); - signal_add("window item changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw); - signal_add("channel topic changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw); - signal_add("query address changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw); - } else if (topic_tag != -1 && !settings_get_bool("toggle_show_topicbar")) { - gui_statusbar_delete(TRUE, 0); - topic_tag = -1; - signal_remove("window changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw); - signal_remove("window item changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw); - signal_remove("channel topic changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw); - signal_remove("query address changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw); - } - - lag_min_show = settings_get_int("lag_min_show")*10; -} - -void gui_statusbar_items_init(void) -{ - settings_add_int("misc", "lag_min_show", 100); - - /* clock */ - clock_tag = gui_statusbar_allocate(7, FALSE, FALSE, 0, statusbar_clock); - clock_timetag = g_timeout_add(1000, (GSourceFunc) statusbar_clock_timeout, NULL); - - /* nick */ - nick_tag = gui_statusbar_allocate(2, FALSE, FALSE, 0, statusbar_nick); - signal_add("server connected", (SIGNAL_FUNC) sig_statusbar_nick_redraw); - signal_add("channel wholist", (SIGNAL_FUNC) sig_statusbar_nick_redraw); - signal_add("window changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw); - signal_add("window item changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw); - signal_add("nick mode changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw); - signal_add("user mode changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw); - signal_add("server nick changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw); - signal_add("window server changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw); - signal_add("away mode changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw); - - /* channel */ - channel_tag = gui_statusbar_allocate(2, FALSE, FALSE, 0, statusbar_channel); - signal_add("window changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw); - signal_add("window item changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw); - signal_add("channel mode changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw); - signal_add("window server changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw); - - /* activity */ - activity_list = NULL; - activity_tag = gui_statusbar_allocate(0, FALSE, FALSE, 0, statusbar_activity); - signal_add("window activity", (SIGNAL_FUNC) sig_statusbar_activity_hilight); - signal_add("window destroyed", (SIGNAL_FUNC) sig_statusbar_activity_window_destroyed); - - /* more */ - more_tag = -1; - signal_add("gui page scrolled", (SIGNAL_FUNC) sig_statusbar_more_check_remove); - signal_add("window item changed", (SIGNAL_FUNC) sig_statusbar_more_check); - signal_add("gui print text", (SIGNAL_FUNC) sig_statusbar_more_check); - - /* lag */ - lag_tag = gui_statusbar_allocate(0, FALSE, FALSE, 0, statusbar_lag); - lag_timetag = g_timeout_add(1000*LAG_REFRESH_TIME, (GSourceFunc) statusbar_lag_timeout, NULL); - signal_add("server lag", (SIGNAL_FUNC) sig_statusbar_lag_redraw); - signal_add("window server changed", (SIGNAL_FUNC) sig_statusbar_lag_redraw); - - /* topic bar */ - topic_tag = -1; - signal_add("setup changed", (SIGNAL_FUNC) read_settings); - - read_settings(); -} - -void gui_statusbar_items_deinit(void) -{ - /* clock */ - gui_statusbar_remove(clock_tag); - - /* nick */ - gui_statusbar_remove(nick_tag); - g_source_remove(clock_timetag); - signal_remove("server connected", (SIGNAL_FUNC) sig_statusbar_nick_redraw); - signal_remove("channel wholist", (SIGNAL_FUNC) sig_statusbar_nick_redraw); - signal_remove("window changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw); - signal_remove("window item changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw); - signal_remove("nick mode changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw); - signal_remove("user mode changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw); - signal_remove("server nick changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw); - signal_remove("window server changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw); - signal_remove("away mode changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw); - - /* channel */ - gui_statusbar_remove(channel_tag); - signal_remove("window changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw); - signal_remove("window item changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw); - signal_remove("channel mode changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw); - signal_remove("window server changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw); - - /* activity */ - gui_statusbar_remove(activity_tag); - signal_remove("window activity", (SIGNAL_FUNC) sig_statusbar_activity_hilight); - signal_remove("window destroyed", (SIGNAL_FUNC) sig_statusbar_activity_window_destroyed); - g_list_free(activity_list); - - /* more */ - if (more_tag != -1) gui_statusbar_remove(more_tag); - signal_remove("gui page scrolled", (SIGNAL_FUNC) sig_statusbar_more_check_remove); - signal_remove("window item changed", (SIGNAL_FUNC) sig_statusbar_more_check); - signal_remove("gui print text", (SIGNAL_FUNC) sig_statusbar_more_check); - - /* lag */ - gui_statusbar_remove(lag_tag); - g_source_remove(lag_timetag); - signal_remove("server lag", (SIGNAL_FUNC) sig_statusbar_lag_redraw); - signal_remove("window server changed", (SIGNAL_FUNC) sig_statusbar_lag_redraw); - - /* topic */ - if (topic_tag != -1) gui_statusbar_delete(TRUE, 0); - signal_remove("setup changed", (SIGNAL_FUNC) read_settings); -} diff --git a/src/fe-text/gui-statusbar-items.h b/src/fe-text/gui-statusbar-items.h deleted file mode 100644 index f71415f0..00000000 --- a/src/fe-text/gui-statusbar-items.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef __GUI_STATUSBAR_ITEMS_H -#define __GUI_STATUSBAR_ITEMS_H - -void gui_statusbar_items_init(void); -void gui_statusbar_items_deinit(void); - -#endif diff --git a/src/fe-text/gui-statusbar.h b/src/fe-text/gui-statusbar.h deleted file mode 100644 index bdaba584..00000000 --- a/src/fe-text/gui-statusbar.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef __GUI_STATUSBAR_H -#define __GUI_STATUSBAR_H - -typedef void (*STATUSBAR_FUNC) (gint xpos, gint ypos, gint size); - -/* create new statusbar, return position */ -gint gui_statusbar_create(gboolean up); -void gui_statusbar_delete(gboolean up, gint ypos); - -/* allocate area in statusbar, returns tag or -1 if failed */ -gint gui_statusbar_allocate(gint size, gboolean right_justify, gboolean up, gint ypos, STATUSBAR_FUNC func); -void gui_statusbar_resize(gint tag, gint size); -void gui_statusbar_remove(gint tag); - -/* redraw item, -1 = all */ -void gui_statusbar_redraw(gint tag); - -void gui_statusbar_init(void); -void gui_statusbar_deinit(void); - -#endif diff --git a/src/fe-text/gui-textwidget.c b/src/fe-text/gui-textwidget.c index c4d6d2f4..a380322b 100644 --- a/src/fe-text/gui-textwidget.c +++ b/src/fe-text/gui-textwidget.c @@ -29,7 +29,6 @@ #include "windows.h" #include "screen.h" -#include "gui-mainwindows.h" #include "gui-windows.h" static gchar *gui_window_line2text(LINE_REC *line) @@ -178,7 +177,7 @@ static void cmd_lastlog(const char *data) countstr = text; text = ""; } - count = atol(countstr); + count = atoi(countstr); if (count == 0) count = -1; level = lastlog_parse_args(args, &flags); @@ -188,7 +187,7 @@ static void cmd_lastlog(const char *data) printformat(NULL, NULL, MSGLEVEL_LASTLOG, IRCTXT_LASTLOG_START); list = gui_window_find_text(active_win, text, startline, flags & LASTLOG_FLAG_REGEXP, flags & LASTLOG_FLAG_WORD); - tmp = lastlog_find_startline(list, count, atol(start), level); + tmp = lastlog_find_startline(list, count, atoi(start), level); for (; tmp != NULL && (count < 0 || count > 0); tmp = tmp->next, count--) { LINE_REC *rec = tmp->data; @@ -197,13 +196,13 @@ static void cmd_lastlog(const char *data) continue; text = gui_window_line2text(rec); - if (settings_get_bool("toggle_show_timestamps")) - printtext(NULL, NULL, MSGLEVEL_LASTLOG, text); + if (settings_get_bool("timestamps")) + printtext(NULL, NULL, MSGLEVEL_LASTLOG, "%s", text); else { tm = localtime(&rec->time); str = g_strdup_printf("[%02d:%02d] %s", tm->tm_hour, tm->tm_min, text); - printtext(NULL, NULL, MSGLEVEL_LASTLOG, str); + printtext(NULL, NULL, MSGLEVEL_LASTLOG, "%s", str); g_free(str); } g_free(text); @@ -249,7 +248,7 @@ static void scrollback_goto_pos(WINDOW_REC *window, GList *pos) gui->bottom = TRUE; gui->startline = gui->bottom_startline; gui->subline = gui->bottom_subline; - gui->ypos = last_text_line-first_text_line-1; + gui->ypos = gui->parent->last_line-gui->parent->first_line-1; } if (is_window_visible(window)) @@ -362,7 +361,7 @@ static void cmd_scrollback_end(gchar *data) gui->bottom = TRUE; gui->startline = gui->bottom_startline; gui->subline = gui->bottom_subline; - gui->ypos = last_text_line-first_text_line-1; + gui->ypos = gui->parent->last_line-gui->parent->first_line-1; if (is_window_visible(active_win)) gui_window_redraw(active_win); diff --git a/src/fe-text/gui-windows.c b/src/fe-text/gui-windows.c index bdcfa916..df1ba8ec 100644 --- a/src/fe-text/gui-windows.c +++ b/src/fe-text/gui-windows.c @@ -30,14 +30,13 @@ #include "screen.h" #include "gui-entry.h" -#include "gui-mainwindows.h" #include "gui-windows.h" #include #define DEFAULT_INDENT_POS 10 -int first_text_line = 0, last_text_line = 0; +static int window_create_override; static GUI_WINDOW_REC *gui_window_init(WINDOW_REC *window, MAIN_WINDOW_REC *parent) { @@ -49,7 +48,7 @@ static GUI_WINDOW_REC *gui_window_init(WINDOW_REC *window, MAIN_WINDOW_REC *pare gui->bottom = TRUE; gui->line_chunk = g_mem_chunk_new("line chunk", sizeof(LINE_REC), sizeof(LINE_REC)*100, G_ALLOC_AND_FREE); - gui->empty_linecount = last_text_line-first_text_line-1; + gui->empty_linecount = parent->last_line-parent->first_line; return gui; } @@ -65,19 +64,31 @@ static void gui_window_deinit(GUI_WINDOW_REC *gui) g_free(gui); } +static void sig_window_create_override(gpointer tab) +{ + window_create_override = GPOINTER_TO_INT(tab); +} + static void gui_window_created(WINDOW_REC *window) { - MAIN_WINDOW_REC *parent; + MAIN_WINDOW_REC *parent; - g_return_if_fail(window != NULL); + g_return_if_fail(window != NULL); - parent = (active_win == NULL || WINDOW_GUI(active_win) == NULL) ? - gui_mainwindow_create() : WINDOW_GUI(active_win)->parent; - if (parent->children == NULL) parent->active = window; - parent->children = g_list_append(parent->children, window); + parent = window_create_override != 0 && + active_win != NULL && WINDOW_GUI(active_win) != NULL ? + WINDOW_GUI(active_win)->parent : mainwindow_create(); + if (parent == NULL) { + /* not enough space for new window, but we really can't + abort creation of the window anymore, so create hidden + window instead. */ + parent = WINDOW_GUI(active_win)->parent; + } + window_create_override = -1; - window->gui_data = gui_window_init(window, parent); - signal_emit("gui window created", 1, window); + if (parent->active == NULL) parent->active = window; + window->gui_data = gui_window_init(window, parent); + signal_emit("gui window created", 1, window); } static void gui_window_destroyed(WINDOW_REC *window) @@ -89,39 +100,35 @@ static void gui_window_destroyed(WINDOW_REC *window) gui = WINDOW_GUI(window); parent = gui->parent; - parent->children = g_list_remove(parent->children, window); signal_emit("gui window destroyed", 1, window); gui_window_deinit(gui); window->gui_data = NULL; - if (parent->children == NULL) - gui_mainwindow_destroy(parent); - - if (windows != NULL && active_win == window && !quitting) - window_set_active(windows->data); + if (mainwindows->next != NULL && parent->active == window) + mainwindow_destroy(parent); } void gui_window_clear(WINDOW_REC *window) { - MAIN_WINDOW_REC *parent; + MAIN_WINDOW_REC *parent; - g_return_if_fail(window != NULL); + g_return_if_fail(window != NULL); - parent = WINDOW_GUI(window)->parent; - gui_window_deinit(WINDOW_GUI(window)); - window->gui_data = gui_window_init(window, parent); + parent = WINDOW_GUI(window)->parent; + gui_window_deinit(WINDOW_GUI(window)); + window->gui_data = gui_window_init(window, parent); - window->lines = 0; + window->lines = 0; - if (is_window_visible(window)) - gui_window_redraw(window); + if (is_window_visible(window)) + gui_window_redraw(window); } -gint gui_window_update_bottom(GUI_WINDOW_REC *gui, gint lines) +int gui_window_update_bottom(GUI_WINDOW_REC *gui, int lines) { - gint linecount, last_linecount; + int linecount, last_linecount; if (gui->bottom_startline == NULL) return -1; @@ -173,7 +180,7 @@ void gui_window_newline(GUI_WINDOW_REC *gui, gboolean visible) g_return_if_fail(gui != NULL); gui->xpos = 0; - last_line = gui->ypos >= last_text_line-first_text_line-1; + last_line = gui->ypos >= gui->parent->last_line-gui->parent->first_line; if (gui->empty_linecount > 0) { @@ -211,8 +218,8 @@ void gui_window_newline(GUI_WINDOW_REC *gui, gboolean visible) if (visible) { - scroll_up(first_text_line, last_text_line-1); - move(last_text_line-1, 0); clrtoeol(); + scroll_up(gui->parent->first_line, gui->parent->last_line); + move(gui->parent->last_line, 0); clrtoeol(); } } } @@ -240,6 +247,8 @@ gint gui_window_get_linecount(GUI_WINDOW_REC *gui, LINE_REC *line) ptr++; switch ((guchar) *ptr) { + case LINE_CMD_OVERFLOW: + g_error("buffer overflow!"); case LINE_CMD_EOL: return lines; case LINE_CMD_CONTINUE: @@ -306,6 +315,8 @@ gint gui_window_line_draw(GUI_WINDOW_REC *gui, LINE_REC *line, gint ypos, gint s } else switch ((guchar) *ptr) { + case LINE_CMD_OVERFLOW: + g_error("buffer overflow!"); case LINE_CMD_EOL: return lines; case LINE_CMD_CONTINUE: @@ -365,7 +376,7 @@ gint gui_window_line_draw(GUI_WINDOW_REC *gui, LINE_REC *line, gint ypos, gint s else { gui_window_newline(gui, TRUE); - ypos = first_text_line+gui->ypos; + ypos = gui->parent->first_line+gui->ypos; } lines++; } @@ -409,7 +420,7 @@ void gui_window_redraw(WINDOW_REC *window) gui = WINDOW_GUI(window); - for (ypos = first_text_line; ypos < last_text_line; ypos++) + for (ypos = gui->parent->first_line; ypos <= gui->parent->last_line; ypos++) { set_color(0); move(ypos, 0); @@ -417,12 +428,12 @@ void gui_window_redraw(WINDOW_REC *window) } skip = gui->subline; - ypos = first_text_line; + ypos = gui->parent->first_line; for (line = gui->startline; line != NULL; line = line->next) { LINE_REC *rec = line->data; - max = last_text_line - ypos-1; + max = gui->parent->last_line - ypos; if (max < 0) break; lines = gui_window_line_draw(gui, rec, ypos, skip, max); @@ -460,7 +471,7 @@ static void gui_window_scroll_up(GUI_WINDOW_REC *gui, gint lines) gui->ypos -= -count; } - gui->bottom = (gui->ypos >= -1 && gui->ypos <= last_text_line-first_text_line-1); + gui->bottom = (gui->ypos >= -1 && gui->ypos <= gui->parent->last_line-gui->parent->first_line); } static void gui_window_scroll_down(GUI_WINDOW_REC *gui, gint lines) @@ -507,28 +518,28 @@ static void gui_window_scroll_down(GUI_WINDOW_REC *gui, gint lines) gui->startline = gui->startline->next; } - gui->bottom = (gui->ypos >= -1 && gui->ypos <= last_text_line-first_text_line-1); + gui->bottom = (gui->ypos >= -1 && gui->ypos <= gui->parent->last_line-gui->parent->first_line); } -void gui_window_scroll(WINDOW_REC *window, gint lines) +void gui_window_scroll(WINDOW_REC *window, int lines) { - GUI_WINDOW_REC *gui; + GUI_WINDOW_REC *gui; - g_return_if_fail(window != NULL); + g_return_if_fail(window != NULL); - gui = WINDOW_GUI(window); + gui = WINDOW_GUI(window); - if (lines < 0) - gui_window_scroll_up(gui, -lines); - else - gui_window_scroll_down(gui, lines); + if (lines < 0) + gui_window_scroll_up(gui, -lines); + else + gui_window_scroll_down(gui, lines); - if (is_window_visible(window)) - gui_window_redraw(window); - signal_emit("gui page scrolled", 1, window); + if (is_window_visible(window)) + gui_window_redraw(window); + signal_emit("gui page scrolled", 1, window); } -static void window_update_prompt(WINDOW_REC *window) +void window_update_prompt(WINDOW_REC *window) { WI_ITEM_REC *item; char *text, *str; @@ -551,11 +562,34 @@ static void window_update_prompt(WINDOW_REC *window) if (*str != '\0') g_free(str); } +void gui_window_reparent(WINDOW_REC *window, MAIN_WINDOW_REC *parent) +{ + MAIN_WINDOW_REC *oldparent; + int ychange; + + oldparent = WINDOW_GUI(window)->parent; + ychange = (parent->last_line - parent->first_line) - + (oldparent->last_line - oldparent->first_line); + + WINDOW_GUI(window)->parent = parent; + if (ychange != 0) gui_window_resize(window, ychange, FALSE); +} + static void signal_window_changed(WINDOW_REC *window) { g_return_if_fail(window != NULL); - WINDOW_GUI(window)->parent->active = window; + if (is_window_visible(window)) { + /* already visible, great! */ + active_mainwin = WINDOW_GUI(window)->parent; + } else { + /* move it to active main window */ + if (active_mainwin == NULL) + active_mainwin = WINDOW_GUI(window)->parent; + else + gui_window_reparent(window, active_mainwin); + active_mainwin->active = window; + } screen_refresh_freeze(); window_update_prompt(window); @@ -565,15 +599,6 @@ static void signal_window_changed(WINDOW_REC *window) static void signal_window_item_update(WINDOW_REC *window) { - CHANNEL_REC *channel; - - channel = irc_item_channel(window->active); - if (channel != NULL) { - /* redraw channel widgets */ - signal_emit("channel topic changed", 1, channel); - signal_emit("channel mode changed", 1, channel); - } - window_update_prompt(window); } @@ -625,6 +650,8 @@ GList *gui_window_find_text(WINDOW_REC *window, gchar *text, GList *startline, i } else if ((guchar) *ptr == LINE_CMD_EOL) break; + else if ((guchar) *ptr == LINE_CMD_OVERFLOW) + g_error("buffer overflow!"); } } str[n] = '\0'; @@ -645,138 +672,89 @@ GList *gui_window_find_text(WINDOW_REC *window, gchar *text, GList *startline, i static void gui_window_horiz_resize(WINDOW_REC *window) { - GUI_WINDOW_REC *gui; - gint linecount; + GUI_WINDOW_REC *gui; + int linecount; - gui = WINDOW_GUI(window); - if (gui->lines == NULL) return; + gui = WINDOW_GUI(window); + if (gui->lines == NULL) return; - linecount = gui_window_get_linecount(gui, g_list_last(gui->lines)->data); - gui->last_subline = linecount-1; + linecount = gui_window_get_linecount(gui, g_list_last(gui->lines)->data); + gui->last_subline = linecount-1; - /* fake a /CLEAR and scroll window up one page */ - gui->ypos = -1; - gui->bottom = TRUE; - gui->empty_linecount = last_text_line-first_text_line-1; + /* fake a /CLEAR and scroll window up one page */ + gui->ypos = -1; + gui->bottom = TRUE; + gui->empty_linecount = gui->parent->last_line-gui->parent->first_line; - gui->bottom_startline = gui->startline = g_list_last(gui->lines); - gui->bottom_subline = gui->subline = gui->last_subline+1; - gui_window_scroll(window, -gui->empty_linecount-1); + gui->bottom_startline = gui->startline = g_list_last(gui->lines); + gui->bottom_subline = gui->subline = gui->last_subline+1; + gui_window_scroll(window, -gui->empty_linecount-1); - gui->bottom_startline = gui->startline; - gui->bottom_subline = gui->subline; + gui->bottom_startline = gui->startline; + gui->bottom_subline = gui->subline; - /* remove the empty lines from the end */ - if (gui->bottom && gui->startline == gui->lines) - gui->empty_linecount = (last_text_line-first_text_line-1); - else - gui->empty_linecount = 0; + /* remove the empty lines from the end */ + if (gui->bottom && gui->startline == gui->lines) + gui->empty_linecount = (gui->parent->last_line-gui->parent->first_line); + else + gui->empty_linecount = 0; } -void gui_windows_resize(gint ychange, gboolean xchange) +void gui_window_resize(WINDOW_REC *window, int ychange, int xchange) { - GUI_WINDOW_REC *gui; - WINDOW_REC *window; - GSList *tmp; - - screen_refresh_freeze(); - for (tmp = windows; tmp != NULL; tmp = tmp->next) - { - window = tmp->data; + GUI_WINDOW_REC *gui; gui = WINDOW_GUI(window); - if (xchange) - { - /* window width changed, we'll need to recalculate a few things.. */ - gui_window_horiz_resize(window); - continue; + if (xchange) { + /* window width changed, we'll need to recalculate a few things.. */ + gui_window_horiz_resize(window); + return; } - if (ychange < 0 && gui->empty_linecount > 0) - { - /* empty space at the bottom of the screen - just eat it. */ - gui->empty_linecount += ychange; - if (gui->empty_linecount < 0) - gui->empty_linecount = 0; - } - else if (gui->bottom && gui->startline == gui->lines && ychange > 0) - { - /* less than screenful of text, add empty space */ - gui->empty_linecount += ychange; - } - else - { - gui_window_update_bottom(WINDOW_GUI(window), -ychange); - gui_window_scroll(window, -ychange); + if (ychange < 0 && gui->empty_linecount > 0) { + /* empty space at the bottom of the screen - just eat it. */ + gui->empty_linecount += ychange; + if (gui->empty_linecount >= 0) + ychange = 0; + else { + ychange -= gui->empty_linecount; + gui->empty_linecount = 0; + } } - } - - irssi_redraw(); - screen_refresh_thaw(); -} - -static void cmd_window_move(gchar *data) -{ - GSList *w1, *w2; - WINDOW_REC *window; - g_return_if_fail(data != NULL); - - window = active_win; - w1 = g_slist_find(windows, window); - if (g_strcasecmp(data, "LEFT") == 0 || g_strncasecmp(data, "PREV", 4) == 0) - { - w2 = g_slist_nth(windows, g_slist_index(windows, window)-1); - if (w2 == NULL) - { - window = w1->data; - windows = g_slist_remove(windows, window); - windows = g_slist_append(windows, window); - w2 = g_slist_last(windows); - } - } - else if (g_strcasecmp(data, "RIGHT") == 0 || g_strcasecmp(data, "NEXT") == 0) - { - w2 = w1->next; - if (w2 == NULL) - { - window = w1->data; - windows = g_slist_remove(windows, window); - windows = g_slist_prepend(windows, window); + if (gui->bottom && gui->startline == gui->lines && ychange > 0) { + /* less than screenful of text, add empty space */ + gui->empty_linecount += ychange; + } else { + gui_window_update_bottom(WINDOW_GUI(window), -ychange); + gui_window_scroll(window, -ychange); } - } - else - return; - - if (w2 != NULL) - { - window = w1->data; - w1->data = w2->data; - w2->data = window; - } - - window_set_active(window); } void gui_windows_init(void) { - signal_add("window created", (SIGNAL_FUNC) gui_window_created); - signal_add("window destroyed", (SIGNAL_FUNC) gui_window_destroyed); - signal_add("window changed", (SIGNAL_FUNC) signal_window_changed); - signal_add("window item changed", (SIGNAL_FUNC) signal_window_item_update); - signal_add("window name changed", (SIGNAL_FUNC) signal_window_item_update); - signal_add("window item remove", (SIGNAL_FUNC) signal_window_item_update); - command_bind("window move", NULL, (SIGNAL_FUNC) cmd_window_move); + window_create_override = -1; + + signal_add("gui window create override", (SIGNAL_FUNC) sig_window_create_override); + signal_add("window created", (SIGNAL_FUNC) gui_window_created); + signal_add("window destroyed", (SIGNAL_FUNC) gui_window_destroyed); + signal_add_first("window changed", (SIGNAL_FUNC) signal_window_changed); + signal_add("window item changed", (SIGNAL_FUNC) signal_window_item_update); + signal_add("window name changed", (SIGNAL_FUNC) signal_window_item_update); + signal_add("window item remove", (SIGNAL_FUNC) signal_window_item_update); } void gui_windows_deinit(void) { - signal_remove("window created", (SIGNAL_FUNC) gui_window_created); - signal_remove("window destroyed", (SIGNAL_FUNC) gui_window_destroyed); - signal_remove("window changed", (SIGNAL_FUNC) signal_window_changed); - signal_remove("window item changed", (SIGNAL_FUNC) signal_window_item_update); - signal_remove("window name changed", (SIGNAL_FUNC) signal_window_item_update); - signal_remove("window item remove", (SIGNAL_FUNC) signal_window_item_update); - command_unbind("window move", (SIGNAL_FUNC) cmd_window_move); + while (windows != NULL) + window_destroy(windows->data); + + signal_remove("gui window create override", (SIGNAL_FUNC) sig_window_create_override); + signal_remove("window created", (SIGNAL_FUNC) gui_window_created); + signal_remove("window destroyed", (SIGNAL_FUNC) gui_window_destroyed); + signal_remove("window changed", (SIGNAL_FUNC) signal_window_changed); + signal_remove("window item changed", (SIGNAL_FUNC) signal_window_item_update); + signal_remove("window name changed", (SIGNAL_FUNC) signal_window_item_update); + signal_remove("window item remove", (SIGNAL_FUNC) signal_window_item_update); } diff --git a/src/fe-text/gui-windows.h b/src/fe-text/gui-windows.h index 14a3a982..28dde1e9 100644 --- a/src/fe-text/gui-windows.h +++ b/src/fe-text/gui-windows.h @@ -2,7 +2,7 @@ #define __GUI_WINDOWS_H #include "server.h" -#include "gui-mainwindows.h" +#include "mainwindows.h" #define WINDOW_GUI(a) ((GUI_WINDOW_REC *) ((a)->gui_data)) @@ -12,63 +12,57 @@ #define LINE_TEXT_CHUNK_SIZE 2048 /* 7 first bits of LINE_REC's info byte. */ -enum -{ - LINE_CMD_EOL=0x80, /* line ends here. */ - LINE_CMD_CONTINUE, /* line continues in next block */ - LINE_CMD_COLOR8, /* change to dark grey, normally 8 = bold black */ - LINE_CMD_UNDERLINE, /* enable/disable underlining */ - LINE_CMD_BEEP, /* beep */ - LINE_CMD_INDENT /* if line is split, indent it at this position */ +enum { + LINE_CMD_EOL=0x80, /* line ends here. */ + LINE_CMD_CONTINUE, /* line continues in next block */ + LINE_CMD_OVERFLOW, /* buffer overflow! */ + LINE_CMD_COLOR8, /* change to dark grey, normally 8 = bold black */ + LINE_CMD_UNDERLINE, /* enable/disable underlining */ + LINE_CMD_BEEP, /* beep */ + LINE_CMD_INDENT /* if line is split, indent it at this position */ }; -typedef struct -{ - gchar *text; /* text in the line. \0 means that the next char will be a - color or command. <= 127 = color or if 8.bit is set, the - first 7 bits are the command. See LINE_CMD_xxxx. */ - - gint32 level; - time_t time; -} -LINE_REC; - -typedef struct -{ - gchar buffer[LINE_TEXT_CHUNK_SIZE]; - gint pos; - gint lines; -} -TEXT_CHUNK_REC; - -typedef struct -{ - MAIN_WINDOW_REC *parent; - - GMemChunk *line_chunk; - GSList *text_chunks; - GList *lines; - - LINE_REC *cur_line; - TEXT_CHUNK_REC *cur_text; - - gint xpos, ypos; /* cursor position in screen */ - GList *startline; /* line at the top of the screen */ - gint subline; /* number of "real lines" to skip from `startline' */ - - GList *bottom_startline; /* marks the bottom of the text buffer */ - gint bottom_subline; - gint empty_linecount; /* how many empty lines are in screen. - a screenful when started or used /CLEAR */ - gboolean bottom; /* window is at the bottom of the text buffer */ - - /* for gui-printtext.c */ - gint last_subline; - gint last_color, last_flags; -} -GUI_WINDOW_REC; - -extern gint first_text_line, last_text_line; +typedef struct { + /* text in the line. \0 means that the next char will be a + color or command. <= 127 = color or if 8.bit is set, the + first 7 bits are the command. See LINE_CMD_xxxx. */ + char *text; + + int level; + time_t time; +} LINE_REC; + +typedef struct { + char buffer[LINE_TEXT_CHUNK_SIZE]; + char overflow[2]; + int pos; + int lines; +} TEXT_CHUNK_REC; + +typedef struct { + MAIN_WINDOW_REC *parent; + + GMemChunk *line_chunk; + GSList *text_chunks; + GList *lines; + + LINE_REC *cur_line; + TEXT_CHUNK_REC *cur_text; + + int xpos, ypos; /* cursor position in screen */ + GList *startline; /* line at the top of the screen */ + int subline; /* number of "real lines" to skip from `startline' */ + + GList *bottom_startline; /* marks the bottom of the text buffer */ + int bottom_subline; + int empty_linecount; /* how many empty lines are in screen. + a screenful when started or used /CLEAR */ + int bottom; /* window is at the bottom of the text buffer */ + + /* for gui-printtext.c */ + int last_subline; + int last_color, last_flags; +} GUI_WINDOW_REC; void gui_windows_init(void); void gui_windows_deinit(void); @@ -76,18 +70,20 @@ void gui_windows_deinit(void); WINDOW_REC *gui_window_create(MAIN_WINDOW_REC *parent); void gui_window_set_server(WINDOW_REC *window, SERVER_REC *server); -GList *gui_window_find_text(WINDOW_REC *window, gchar *text, GList *startline, int regexp, int fullword); +GList *gui_window_find_text(WINDOW_REC *window, char *text, GList *startline, int regexp, int fullword); /* get number of real lines that line record takes */ -gint gui_window_get_linecount(GUI_WINDOW_REC *gui, LINE_REC *line); -gint gui_window_line_draw(GUI_WINDOW_REC *gui, LINE_REC *line, gint ypos, gint skip, gint max); +int gui_window_get_linecount(GUI_WINDOW_REC *gui, LINE_REC *line); +int gui_window_line_draw(GUI_WINDOW_REC *gui, LINE_REC *line, int ypos, int skip, int max); void gui_window_clear(WINDOW_REC *window); void gui_window_redraw(WINDOW_REC *window); -void gui_windows_resize(gint ychange, gboolean xchange); +void gui_window_resize(WINDOW_REC *window, int ychange, int xchange); +void gui_window_reparent(WINDOW_REC *window, MAIN_WINDOW_REC *parent); +void window_update_prompt(WINDOW_REC *window); void gui_window_newline(GUI_WINDOW_REC *gui, gboolean visible); -gint gui_window_update_bottom(GUI_WINDOW_REC *gui, gint lines); -void gui_window_scroll(WINDOW_REC *window, gint lines); +int gui_window_update_bottom(GUI_WINDOW_REC *gui, int lines); +void gui_window_scroll(WINDOW_REC *window, int lines); #endif diff --git a/src/fe-text/irssi.c b/src/fe-text/irssi.c index d427a208..2c95b87d 100644 --- a/src/fe-text/irssi.c +++ b/src/fe-text/irssi.c @@ -29,12 +29,11 @@ #include "screen.h" #include "gui-entry.h" -#include "gui-mainwindows.h" +#include "mainwindows.h" #include "gui-printtext.h" #include "gui-readline.h" #include "gui-special-vars.h" -#include "gui-statusbar.h" -#include "gui-statusbar-items.h" +#include "statusbar.h" #include "gui-textwidget.h" #include "gui-windows.h" @@ -59,109 +58,103 @@ static void sig_exit(void) /* redraw irssi's screen.. */ void irssi_redraw(void) { - clear(); - - /* current window */ - gui_window_redraw(active_win); - /* statusbar */ - gui_statusbar_redraw(-1); - /* entry line */ - gui_entry_redraw(); + clear(); + + /* windows */ + mainwindows_redraw(); + /* statusbar */ + statusbar_redraw(NULL); + /* entry line */ + gui_entry_redraw(); } static void textui_init(void) { - static struct poptOption options[] = { - POPT_AUTOHELP - { NULL, '\0', 0, NULL } - }; - - args_register(options); - - irssi_gui = IRSSI_GUI_TEXT; - core_init(); - irc_init(); - fe_common_core_init(); - fe_common_irc_init(); - signal_add("gui exit", (SIGNAL_FUNC) sig_exit); + static struct poptOption options[] = { + POPT_AUTOHELP + { NULL, '\0', 0, NULL } + }; + + args_register(options); + + irssi_gui = IRSSI_GUI_TEXT; + core_init(); + irc_init(); + fe_common_core_init(); + fe_common_irc_init(); + signal_add("gui exit", (SIGNAL_FUNC) sig_exit); } static void textui_finish_init(void) { - quitting = FALSE; - - screen_refresh_freeze(); - gui_entry_init(); - gui_mainwindows_init(); - gui_printtext_init(); - gui_readline_init(); - gui_special_vars_init(); - gui_textwidget_init(); - gui_windows_init(); - - fe_common_core_finish_init(); - fe_common_irc_finish_init(); - - gui_statusbar_init(); - gui_statusbar_items_init(); - - signal_emit("irssi init finished", 0); + quitting = FALSE; + + screen_refresh_freeze(); + gui_entry_init(); + mainwindows_init(); + gui_printtext_init(); + gui_readline_init(); + gui_special_vars_init(); + gui_textwidget_init(); + gui_windows_init(); + statusbar_init(); + + fe_common_core_finish_init(); + fe_common_irc_finish_init(); + + signal_emit("irssi init finished", 0); #ifdef HAVE_PERL - irssi_perl_init(); + irssi_perl_init(); #endif - screen_refresh_thaw(); + screen_refresh_thaw(); } static void textui_deinit(void) { - quitting = TRUE; - signal(SIGINT, SIG_DFL); + quitting = TRUE; + signal(SIGINT, SIG_DFL); - signal_remove("gui exit", (SIGNAL_FUNC) sig_exit); + signal_remove("gui exit", (SIGNAL_FUNC) sig_exit); #ifdef HAVE_PERL - irssi_perl_deinit(); + irssi_perl_deinit(); #endif - gui_textwidget_deinit(); - gui_special_vars_deinit(); - gui_statusbar_items_deinit(); - gui_statusbar_deinit(); - gui_printtext_deinit(); - gui_readline_deinit(); - gui_mainwindows_deinit(); - gui_windows_deinit(); - gui_entry_deinit(); - deinit_screen(); - - fe_common_irc_deinit(); - fe_common_core_deinit(); - irc_deinit(); - core_deinit(); + gui_textwidget_deinit(); + gui_special_vars_deinit(); + statusbar_deinit(); + gui_printtext_deinit(); + gui_readline_deinit(); + mainwindows_deinit(); + gui_windows_deinit(); + gui_entry_deinit(); + deinit_screen(); + + fe_common_irc_deinit(); + fe_common_core_deinit(); + irc_deinit(); + core_deinit(); } int main(int argc, char **argv) { #ifdef HAVE_SOCKS - SOCKSinit(argv[0]); + SOCKSinit(argv[0]); #endif - textui_init(); - args_execute(argc, argv); + textui_init(); + args_execute(argc, argv); - if (!init_screen()) - { - printf("Can't initialize screen handling, quitting.\n"); - return 1; - } + if (!init_screen()) + g_error(_("Can't initialize screen handling, quitting.\n")); - textui_finish_init(); - main_loop = g_main_new(TRUE); - g_main_run(main_loop); - g_main_destroy(main_loop); - textui_deinit(); + textui_finish_init(); + main_loop = g_main_new(TRUE); + g_main_run(main_loop); + g_main_destroy(main_loop); + textui_deinit(); #ifdef MEM_DEBUG - ig_mem_profile(); + ig_mem_profile(); #endif - return 0; + return 0; } diff --git a/src/fe-text/mainwindows.c b/src/fe-text/mainwindows.c new file mode 100644 index 00000000..35bf4ecd --- /dev/null +++ b/src/fe-text/mainwindows.c @@ -0,0 +1,606 @@ +/* + gui-mainwindows.c : irssi + + Copyright (C) 1999 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "module.h" +#include "module-formats.h" +#include "signals.h" +#include "commands.h" +#include "levels.h" +#include "misc.h" + +#include "screen.h" +#include "statusbar.h" +#include "gui-windows.h" + +#define WINDOW_MIN_SIZE 2 +#define NEW_WINDOW_SIZE (WINDOW_MIN_SIZE + 1) + +#define window_size(window) \ + ((window)->last_line - (window)->first_line+1) + +GSList *mainwindows; +MAIN_WINDOW_REC *active_mainwin; + +static int reserved_up, reserved_down; + +static MAIN_WINDOW_REC *find_window_with_room(void) +{ + MAIN_WINDOW_REC *biggest_rec; + GSList *tmp; + int space, biggest; + + biggest = 0; biggest_rec = NULL; + for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) { + MAIN_WINDOW_REC *rec = tmp->data; + + space = window_size(rec); + if (space >= WINDOW_MIN_SIZE+NEW_WINDOW_SIZE && space > biggest) { + biggest = space; + biggest_rec = rec; + } + } + + return biggest_rec; +} + +static void mainwindow_resize(MAIN_WINDOW_REC *window, int ychange, int xchange) +{ + GSList *tmp; + + if (ychange == 0 && !xchange) return; + + for (tmp = windows; tmp != NULL; tmp = tmp->next) { + WINDOW_REC *rec = tmp->data; + + if (rec->gui_data != NULL && WINDOW_GUI(rec)->parent == window) + gui_window_resize(rec, ychange, xchange); + } + + signal_emit("mainwindow resized", 1, window); +} + +MAIN_WINDOW_REC *mainwindow_create(void) +{ + MAIN_WINDOW_REC *rec, *parent; + int space; + + rec = g_new0(MAIN_WINDOW_REC, 1); + rec->statusbar_lines = 1; + + if (mainwindows == NULL) { + active_mainwin = rec; + + rec->first_line = reserved_up; + rec->last_line = LINES-1-reserved_down-rec->statusbar_lines; + } else { + parent = WINDOW_GUI(active_win)->parent; + if (window_size(parent) < WINDOW_MIN_SIZE+NEW_WINDOW_SIZE) + parent = find_window_with_room(); + if (parent == NULL) + return NULL; /* not enough space */ + + space = (window_size(parent)-parent->statusbar_lines)/2; + rec->first_line = parent->first_line; + rec->last_line = rec->first_line + space-rec->statusbar_lines; + parent->first_line = rec->last_line+1+rec->statusbar_lines; + + mainwindow_resize(parent, -space-1, FALSE); + } + + mainwindows = g_slist_append(mainwindows, rec); + signal_emit("mainwindow created", 1, rec); + return rec; +} + +static MAIN_WINDOW_REC *mainwindows_find_lower(int line) +{ + MAIN_WINDOW_REC *best; + GSList *tmp; + + best = NULL; + for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) { + MAIN_WINDOW_REC *rec = tmp->data; + + if (rec->first_line > line && + (best == NULL || rec->first_line < best->first_line)) + best = rec; + } + + return best; +} + +static MAIN_WINDOW_REC *mainwindows_find_upper(int line) +{ + MAIN_WINDOW_REC *best; + GSList *tmp; + + best = NULL; + for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) { + MAIN_WINDOW_REC *rec = tmp->data; + + if (rec->last_line < line && + (best == NULL || rec->last_line > best->last_line)) + best = rec; + } + + return best; +} + +static void mainwindows_add_space(int first_line, int last_line) +{ + MAIN_WINDOW_REC *rec; + int size; + + if (last_line < first_line) + return; + + size = last_line-first_line+1; + + rec = mainwindows_find_lower(last_line); + if (rec != NULL) { + rec->first_line = first_line; + mainwindow_resize(rec, size, FALSE); + return; + } + + rec = mainwindows_find_upper(first_line); + if (rec != NULL) { + rec->last_line = last_line-rec->statusbar_lines; + mainwindow_resize(rec, size, FALSE); + } +} + +static void gui_windows_remove_parent(MAIN_WINDOW_REC *window) +{ + MAIN_WINDOW_REC *new_parent; + GSList *tmp; + + new_parent = mainwindows->data; + for (tmp = windows; tmp != NULL; tmp = tmp->next) { + WINDOW_REC *rec = tmp->data; + + if (rec->gui_data != NULL && WINDOW_GUI(rec)->parent == window) + gui_window_reparent(rec, new_parent); + } +} + +void mainwindow_destroy(MAIN_WINDOW_REC *window) +{ + g_return_if_fail(window != NULL); + + mainwindows = g_slist_remove(mainwindows, window); + signal_emit("mainwindow destroyed", 1, window); + + if (!quitting && mainwindows != NULL) { + gui_windows_remove_parent(window); + mainwindows_add_space(window->first_line, window->last_line+window->statusbar_lines); + + mainwindows_redraw(); + statusbar_redraw(NULL); + } + g_free(window); + + if (active_mainwin == window) active_mainwin = NULL; +} + +void mainwindows_redraw(void) +{ + GSList *tmp; + + screen_refresh_freeze(); + for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) { + MAIN_WINDOW_REC *rec = tmp->data; + + gui_window_redraw(rec->active); + } + screen_refresh_thaw(); +} + +static int mainwindows_compare(MAIN_WINDOW_REC *w1, MAIN_WINDOW_REC *w2) +{ + return w1->first_line < w2->first_line ? -1 : 1; +} + +static int mainwindows_compare_reverse(MAIN_WINDOW_REC *w1, MAIN_WINDOW_REC *w2) +{ + return w1->first_line < w2->first_line ? 1 : -1; +} + +static GSList *mainwindows_get_sorted(int reverse) +{ + GSList *tmp, *list; + + list = NULL; + for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) { + list = g_slist_insert_sorted(list, tmp->data, (GCompareFunc) + (reverse ? mainwindows_compare_reverse : mainwindows_compare)); + } + + return list; +} + +static void mainwindows_resize_too_small(int ychange, int xchange) +{ + GSList *sorted, *tmp; + int space, moved; + + /* terminal is too small - just take the space whereever possible */ + sorted = mainwindows_get_sorted(FALSE); + moved = 0; + for (tmp = sorted; tmp != NULL; tmp = tmp->next) { + MAIN_WINDOW_REC *rec = tmp->data; + + space = window_size(rec); + if (ychange == 0 || space <= 0) { + if (moved > 0) { + rec->first_line -= moved; + rec->last_line -= moved; + signal_emit("mainwindow moved", 1, rec); + } + continue; + } + + if (space > -ychange) space = -ychange; + ychange += space; + rec->first_line -= moved; + moved += space; + rec->last_line -= space; + mainwindow_resize(rec, -space, xchange); + } + g_slist_free(sorted); +} + +static void mainwindows_resize_smaller(int ychange, int xchange) +{ + GSList *sorted, *tmp; + int space; + + space = 0; + for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) { + MAIN_WINDOW_REC *rec = tmp->data; + + space += window_size(rec)-WINDOW_MIN_SIZE; + } + + if (space < -ychange) { + /* not enough space, use different algorithm */ + mainwindows_resize_too_small(ychange, xchange); + return; + } + + /* resize windows that have space */ + sorted = mainwindows_get_sorted(TRUE); + for (tmp = sorted; tmp != NULL && ychange < 0; tmp = tmp->next) { + MAIN_WINDOW_REC *rec = tmp->data; + + space = window_size(rec)-WINDOW_MIN_SIZE; + if (space <= 0) { + rec->first_line += ychange; + rec->last_line += ychange; + signal_emit("mainwindow moved", 1, rec); + continue; + } + + if (space <= 0) space = 1; + if (space > -ychange) space = -ychange; + rec->last_line += ychange; + ychange += space; + rec->first_line += ychange; + + mainwindow_resize(rec, -space, xchange); + } + g_slist_free(sorted); +} + +static void mainwindows_resize_bigger(int ychange, int xchange) +{ + GSList *sorted, *tmp; + int moved, space; + + sorted = mainwindows_get_sorted(FALSE); + moved = 0; + for (tmp = sorted; tmp != NULL; tmp = tmp->next) { + MAIN_WINDOW_REC *rec = tmp->data; + + space = window_size(rec)-WINDOW_MIN_SIZE; + if (ychange == 0 || (space >= 0 && tmp->next != NULL)) { + if (moved > 0) { + rec->first_line += moved; + rec->last_line += moved; + signal_emit("mainwindow moved", 1, rec); + } + continue; + } + + if (space < 0 && tmp->next != NULL) { + /* space below minimum */ + space = -space; + if (space > ychange) space = ychange; + } else { + /* lowest window - give all the extra space for it */ + space = ychange; + } + ychange -= space; + rec->first_line += moved; + moved += space; + rec->last_line += moved; + + mainwindow_resize(rec, space, xchange); + } + g_slist_free(sorted); +} + +void mainwindows_resize(int ychange, int xchange) +{ + screen_refresh_freeze(); + if (ychange < 0) + mainwindows_resize_smaller(ychange, xchange); + else if (ychange > 0) + mainwindows_resize_bigger(ychange, xchange); + + irssi_redraw(); + screen_refresh_thaw(); +} + +int mainwindows_reserve_lines(int count, int up) +{ + MAIN_WINDOW_REC *window; + int ret; + + if (up) { + g_return_val_if_fail(count > 0 || reserved_up > count, -1); + + ret = reserved_up; + reserved_up += count; + + window = mainwindows_find_lower(-1); + if (window != NULL) window->first_line += count; + } else { + g_return_val_if_fail(count > 0 || reserved_down > count, -1); + + ret = reserved_down; + reserved_down += count; + + window = mainwindows_find_upper(LINES); + if (window != NULL) window->last_line -= count; + } + + if (window != NULL) + mainwindow_resize(window, -count, FALSE); + + return ret; +} + +static void mainwindows_resize_two(MAIN_WINDOW_REC *grow_win, MAIN_WINDOW_REC *shrink_win, int count) +{ + mainwindow_resize(grow_win, count, FALSE); + mainwindow_resize(shrink_win, -count, FALSE); + gui_window_redraw(grow_win->active); + gui_window_redraw(shrink_win->active); + statusbar_redraw(grow_win->statusbar); + statusbar_redraw(shrink_win->statusbar); +} + +static void cmd_window_grow(const char *data) +{ + MAIN_WINDOW_REC *window, *shrink_win; + int count; + + count = *data == '\0' ? 1 : atoi(data); + window = WINDOW_GUI(active_win)->parent; + + /* shrink lower window */ + shrink_win = mainwindows_find_lower(window->last_line); + if (shrink_win != NULL && window_size(shrink_win)-count >= WINDOW_MIN_SIZE) { + window->last_line += count; + shrink_win->first_line += count; + } else { + /* shrink upper window */ + shrink_win = mainwindows_find_upper(window->first_line); + if (shrink_win != NULL && window_size(shrink_win)-count >= WINDOW_MIN_SIZE) { + window->first_line -= count; + shrink_win->last_line -= count; + } else { + printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_WINDOW_TOO_SMALL); + return; + } + } + + mainwindows_resize_two(window, shrink_win, count); +} + +static void cmd_window_shrink(const char *data) +{ + MAIN_WINDOW_REC *window, *grow_win; + int count; + + count = *data == '\0' ? 1 : atoi(data); + + window = WINDOW_GUI(active_win)->parent; + if (window_size(window)-count < WINDOW_MIN_SIZE) { + printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_WINDOW_TOO_SMALL); + return; + } + + grow_win = mainwindows_find_lower(window->last_line); + if (grow_win != NULL) { + window->last_line -= count; + grow_win->first_line -= count; + } else { + grow_win = mainwindows_find_upper(window->first_line); + if (grow_win == NULL) return; + + window->first_line += count; + grow_win->last_line += count; + } + + mainwindows_resize_two(grow_win, window, count); +} + +static void cmd_window_size(const char *data) +{ + char sizestr[MAX_INT_STRLEN]; + int size; + + if (!is_numeric(data, 0)) return; + size = atoi(data); + + size -= window_size(WINDOW_GUI(active_win)->parent); + if (size == 0) return; + + ltoa(sizestr, size < 0 ? -size : size); + if (size < 0) + cmd_window_shrink(sizestr); + else + cmd_window_grow(sizestr); +} + +static void cmd_window_balance(void) +{ + GSList *sorted, *tmp; + int avail_size, unit_size, bigger_units; + int windows, last_line, old_size; + + windows = g_slist_length(mainwindows); + if (windows == 1) return; + + avail_size = LINES-reserved_up-reserved_down; + unit_size = avail_size/windows; + bigger_units = avail_size%windows; + + sorted = mainwindows_get_sorted(FALSE); + last_line = 0; + for (tmp = sorted; tmp != NULL; tmp = tmp->next) { + MAIN_WINDOW_REC *rec = tmp->data; + + old_size = window_size(rec); + rec->first_line = last_line+1; + rec->last_line = rec->first_line-1 + unit_size - + rec->statusbar_lines; + + if (bigger_units > 0) { + rec->last_line++; + bigger_units--; + } + last_line = rec->last_line + rec->statusbar_lines; + + mainwindow_resize(rec, window_size(rec)-old_size, FALSE); + } + g_slist_free(sorted); + + mainwindows_redraw(); + statusbar_redraw(NULL); +} + +static void cmd_window_hide(const char *data) +{ + WINDOW_REC *window; + + if (mainwindows->next == NULL) { + printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, IRCTXT_CANT_HIDE_LAST); + return; + } + + if (*data == '\0') + window = active_win; + else if (is_numeric(data, 0)) + window = window_find_refnum(atoi(data)); + else + window = window_find_item(active_win, data); + + if (window == NULL) return; + if (!is_window_visible(window)) return; + + mainwindow_destroy(WINDOW_GUI(window)->parent); + + if (active_mainwin == NULL) { + active_mainwin = WINDOW_GUI(active_win)->parent; + window_set_active(active_mainwin->active); + } +} + +static void cmd_window_show(const char *data) +{ + WINDOW_REC *window; + + if (*data == '\0') cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS); + + window = is_numeric(data, 0) ? + window_find_refnum(atoi(data)) : + window_find_item(active_win, data); + + if (window == NULL) return; + if (is_window_visible(window)) return; + + WINDOW_GUI(window)->parent = mainwindow_create(); + WINDOW_GUI(window)->parent->active = window; + + active_mainwin = NULL; + window_set_active(window); +} + +static void cmd_window_up(void) +{ + MAIN_WINDOW_REC *rec; + + rec = mainwindows_find_upper(active_mainwin->first_line); + if (rec != NULL) + window_set_active(rec->active); +} + +static void cmd_window_down(void) +{ + MAIN_WINDOW_REC *rec; + + rec = mainwindows_find_lower(active_mainwin->last_line); + if (rec != NULL) + window_set_active(rec->active); +} + +void mainwindows_init(void) +{ + mainwindows = NULL; + active_mainwin = NULL; + reserved_up = reserved_down = 0; + + /* for entry line */ + mainwindows_reserve_lines(1, FALSE); + + command_bind("window grow", NULL, (SIGNAL_FUNC) cmd_window_grow); + command_bind("window shrink", NULL, (SIGNAL_FUNC) cmd_window_shrink); + command_bind("window size", NULL, (SIGNAL_FUNC) cmd_window_size); + command_bind("window balance", NULL, (SIGNAL_FUNC) cmd_window_balance); + command_bind("window hide", NULL, (SIGNAL_FUNC) cmd_window_hide); + command_bind("window show", NULL, (SIGNAL_FUNC) cmd_window_show); + command_bind("window up", NULL, (SIGNAL_FUNC) cmd_window_up); + command_bind("window down", NULL, (SIGNAL_FUNC) cmd_window_down); +} + +void mainwindows_deinit(void) +{ + command_unbind("window grow", (SIGNAL_FUNC) cmd_window_grow); + command_unbind("window shrink", (SIGNAL_FUNC) cmd_window_shrink); + command_unbind("window size", (SIGNAL_FUNC) cmd_window_size); + command_unbind("window balance", (SIGNAL_FUNC) cmd_window_balance); + command_unbind("window hide", (SIGNAL_FUNC) cmd_window_hide); + command_unbind("window show", (SIGNAL_FUNC) cmd_window_show); + command_unbind("window up", (SIGNAL_FUNC) cmd_window_up); + command_unbind("window down", (SIGNAL_FUNC) cmd_window_down); +} diff --git a/src/fe-text/mainwindows.h b/src/fe-text/mainwindows.h new file mode 100644 index 00000000..467add2d --- /dev/null +++ b/src/fe-text/mainwindows.h @@ -0,0 +1,29 @@ +#ifndef __MAINWINDOWS_H +#define __MAINWINDOWS_H + +#include "windows.h" + +typedef struct { + WINDOW_REC *active; + + int first_line, last_line; + int statusbar_lines; + void *statusbar; + void *statusbar_channel_item; +} MAIN_WINDOW_REC; + +extern GSList *mainwindows; +extern MAIN_WINDOW_REC *active_mainwin; + +void mainwindows_init(void); +void mainwindows_deinit(void); + +MAIN_WINDOW_REC *mainwindow_create(void); +void mainwindow_destroy(MAIN_WINDOW_REC *window); + +void mainwindows_redraw(void); +void mainwindows_resize(int ychange, int xchange); + +int mainwindows_reserve_lines(int count, int up); + +#endif diff --git a/src/fe-text/module-formats.c b/src/fe-text/module-formats.c index a7576de9..9b38fecb 100644 --- a/src/fe-text/module-formats.c +++ b/src/fe-text/module-formats.c @@ -27,4 +27,7 @@ FORMAT_REC gui_text_formats[] = { "lastlog_start", "%_Lastlog:", 0 }, { "lastlog_end", "%_End of Lastlog", 0 }, + + { "window_too_small", "Not enough room to resize this window", 0 }, + { "cant_hide_last", "You can't hide the last window", 0 } }; diff --git a/src/fe-text/module-formats.h b/src/fe-text/module-formats.h index d8f7a3b8..32f219e2 100644 --- a/src/fe-text/module-formats.h +++ b/src/fe-text/module-formats.h @@ -1,10 +1,13 @@ #include "printtext.h" enum { - IRCTXT_MODULE_NAME, + IRCTXT_MODULE_NAME, - IRCTXT_LASTLOG_START, - IRCTXT_LASTLOG_END + IRCTXT_LASTLOG_START, + IRCTXT_LASTLOG_END, + + IRCTXT_WINDOW_TOO_SMALL, + IRCTXT_CANT_HIDE_LAST }; extern FORMAT_REC gui_text_formats[]; diff --git a/src/fe-text/screen.c b/src/fe-text/screen.c index 19c79f5a..5f197028 100644 --- a/src/fe-text/screen.c +++ b/src/fe-text/screen.c @@ -1,8 +1,7 @@ /* - screen.c : All virtual screen management, real screen management is in - con_???.c files. + screen.c : irssi - Copyright (C) 1999 Timo Sirainen + 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 @@ -25,7 +24,7 @@ #include "screen.h" #include "gui-readline.h" -#include "gui-windows.h" +#include "mainwindows.h" #ifdef HAVE_SYS_IOCTL_H #include @@ -38,52 +37,50 @@ #define MIN_SCREEN_WIDTH 20 -static gint scrx, scry; -gboolean use_colors; -static gint freeze_refresh; +static int scrx, scry; +static int use_colors; +static int freeze_refresh; #ifdef SIGWINCH static void sig_winch(int p) { #ifdef TIOCGWINSZ - struct winsize ws; - gint ychange, xchange; + struct winsize ws; + int ychange, xchange; - /* Get new window size */ - if (ioctl(0, TIOCGWINSZ, &ws) < 0) - return; + /* Get new window size */ + if (ioctl(0, TIOCGWINSZ, &ws) < 0) + return; - if (ws.ws_row == LINES && ws.ws_col == COLS) - { - /* Same size, abort. */ - return; - } + if (ws.ws_row == LINES && ws.ws_col == COLS) { + /* Same size, abort. */ + return; + } - if (ws.ws_col < MIN_SCREEN_WIDTH) - ws.ws_col = MIN_SCREEN_WIDTH; + if (ws.ws_col < MIN_SCREEN_WIDTH) + ws.ws_col = MIN_SCREEN_WIDTH; - /* Resize curses terminal */ - ychange = ws.ws_row-LINES; - xchange = ws.ws_col-COLS; + /* Resize curses terminal */ + ychange = ws.ws_row-LINES; + xchange = ws.ws_col-COLS; #ifdef HAVE_CURSES_RESIZETERM - resizeterm(ws.ws_row, ws.ws_col); + resizeterm(ws.ws_row, ws.ws_col); #else - deinit_screen(); - init_screen(); + deinit_screen(); + init_screen(); #endif - last_text_line += ychange; - gui_windows_resize(ychange, xchange != 0); + mainwindows_resize(ychange, xchange != 0); #endif } #endif -/* SIGINT != ^C .. any better way to make this work? */ +/* FIXME: SIGINT != ^C .. any better way to make this work? */ void sigint_handler(int p) { - ungetch(3); - readline(); + ungetch(3); + readline(); } static void read_settings(void) @@ -93,162 +90,141 @@ static void read_settings(void) } /* Initialize screen, detect screen length */ -gint init_screen(void) +int init_screen(void) { - gchar ansi_tab[8] = { 0, 4, 2, 6, 1, 5, 3, 7 }; - gint num; + char ansi_tab[8] = { 0, 4, 2, 6, 1, 5, 3, 7 }; + int num; - if (!initscr()) return 0; + if (!initscr()) return 0; - if (COLS < MIN_SCREEN_WIDTH) - COLS = MIN_SCREEN_WIDTH; + if (COLS < MIN_SCREEN_WIDTH) + COLS = MIN_SCREEN_WIDTH; - signal(SIGINT, sigint_handler); - cbreak(); noecho(); idlok(stdscr, 1); + signal(SIGINT, sigint_handler); + cbreak(); noecho(); idlok(stdscr, 1); #ifdef HAVE_CURSES_IDCOK - idcok(stdscr, 1); + idcok(stdscr, 1); #endif - intrflush(stdscr, FALSE); halfdelay(1); keypad(stdscr, 1); + intrflush(stdscr, FALSE); halfdelay(1); keypad(stdscr, 1); - settings_add_bool("lookandfeel", "colors", TRUE); + settings_add_bool("lookandfeel", "colors", TRUE); - use_colors = settings_get_bool("colors") && has_colors(); - if (has_colors()) start_color(); + use_colors = settings_get_bool("colors") && has_colors(); + if (has_colors()) start_color(); #ifdef HAVE_NCURSES_USE_DEFAULT_COLORS - /* this lets us to use the "default" background color for colors <= 7 so - background pixmaps etc. show up right */ - use_default_colors(); + /* this lets us to use the "default" background color for colors <= 7 so + background pixmaps etc. show up right */ + use_default_colors(); - for (num = 1; num < COLOR_PAIRS; num++) - init_pair(num, ansi_tab[num & 7], num <= 7 ? -1 : ansi_tab[num >> 3]); + for (num = 1; num < COLOR_PAIRS; num++) + init_pair(num, ansi_tab[num & 7], num <= 7 ? -1 : ansi_tab[num >> 3]); - init_pair(63, 0, -1); /* hm.. not THAT good idea, but probably more people - want dark grey than white on white.. */ + init_pair(63, 0, -1); /* hm.. not THAT good idea, but probably more + people want dark grey than white on white.. */ #else - for (num = 1; num < COLOR_PAIRS; num++) - init_pair(num, ansi_tab[num & 7], ansi_tab[num >> 3]); - init_pair(63, 0, 0); + for (num = 1; num < COLOR_PAIRS; num++) + init_pair(num, ansi_tab[num & 7], ansi_tab[num >> 3]); + init_pair(63, 0, 0); #endif - scrx = scry = 0; - if (last_text_line == 0) - { - first_text_line = 0; - last_text_line = LINES-1; - } + scrx = scry = 0; #ifdef SIGWINCH - signal(SIGWINCH, sig_winch); + signal(SIGWINCH, sig_winch); #endif - freeze_refresh = 0; - clear(); + freeze_refresh = 0; + clear(); - signal_add("setup changed", (SIGNAL_FUNC) read_settings); - return 1; + signal_add("setup changed", (SIGNAL_FUNC) read_settings); + return 1; } /* Deinitialize screen */ void deinit_screen(void) { - signal_remove("setup changed", (SIGNAL_FUNC) read_settings); - endwin(); + signal_remove("setup changed", (SIGNAL_FUNC) read_settings); + endwin(); } -void set_color(gint col) +void set_color(int col) { - gint attr; - - if (!use_colors) - { - if ((col & 0x70) != 0) - attr = A_REVERSE; - else - attr = 0; - } - else - { - if (col & ATTR_COLOR8) - attr = A_DIM | COLOR_PAIR(63); - else - attr = COLOR_PAIR((col&7) + (col&0x70)/2); - } - - if (col & 0x08) attr |= A_BOLD; - if (col & 0x80) attr |= A_BLINK; - - if (col & ATTR_UNDERLINE) attr |= A_UNDERLINE; - if (col & ATTR_REVERSE) attr |= A_REVERSE; - - attrset(attr); + int attr; + + if (!use_colors) + attr = (col & 0x70) ? A_REVERSE : 0; + else { + attr = (col & ATTR_COLOR8) ? + (A_DIM | COLOR_PAIR(63)) : + (COLOR_PAIR((col&7) + (col&0x70)/2)); + } + + if (col & 0x08) attr |= A_BOLD; + if (col & 0x80) attr |= A_BLINK; + + if (col & ATTR_UNDERLINE) attr |= A_UNDERLINE; + if (col & ATTR_REVERSE) attr |= A_REVERSE; + + attrset(attr); } -void set_bg(gint col) +void set_bg(int col) { - gint attr; - - if (!use_colors) - { - if ((col & 0x70) != 0) - attr = A_REVERSE; - else - attr = 0; - } - else - { - if (col == 8) - attr = A_DIM | COLOR_PAIR(63); - else - attr = COLOR_PAIR((col&7) + (col&0x70)/2); - } - - if (col & 0x08) attr |= A_BOLD; - if (col & 0x80) attr |= A_BLINK; - - bkgdset(' ' | attr); + int attr; + + if (!use_colors) + attr = (col & 0x70) ? A_REVERSE : 0; + else { + attr = (col == 8) ? + (A_DIM | COLOR_PAIR(63)) : + (COLOR_PAIR((col&7) + (col&0x70)/2)); + } + + if (col & 0x08) attr |= A_BOLD; + if (col & 0x80) attr |= A_BLINK; + + bkgdset(' ' | attr); } /* Scroll area up */ -void scroll_up(gint y1, gint y2) +void scroll_up(int y1, int y2) { - scrollok(stdscr, TRUE); - setscrreg(y1, y2); scrl(1); - scrollok(stdscr, FALSE); + scrollok(stdscr, TRUE); + setscrreg(y1, y2); scrl(1); + scrollok(stdscr, FALSE); } /* Scroll area down */ -void scroll_down(gint y1, gint y2) +void scroll_down(int y1, int y2) { - scrollok(stdscr, TRUE); - setscrreg(y1, y2); scrl(-1); - scrollok(stdscr, FALSE); + scrollok(stdscr, TRUE); + setscrreg(y1, y2); scrl(-1); + scrollok(stdscr, FALSE); } -void move_cursor(gint y, gint x) +void move_cursor(int y, int x) { - scry = y; - scrx = x; + scry = y; + scrx = x; } void screen_refresh_freeze(void) { - freeze_refresh++; + freeze_refresh++; } void screen_refresh_thaw(void) { - if (freeze_refresh > 0) - { - freeze_refresh--; - if (freeze_refresh == 0) screen_refresh(); - } + if (freeze_refresh > 0) { + freeze_refresh--; + if (freeze_refresh == 0) screen_refresh(); + } } void screen_refresh(void) { - if (freeze_refresh == 0) - { - move(scry, scrx); - refresh(); - } + if (freeze_refresh == 0) { + move(scry, scrx); + refresh(); + } } diff --git a/src/fe-text/statusbar-items.c b/src/fe-text/statusbar-items.c new file mode 100644 index 00000000..8b55f263 --- /dev/null +++ b/src/fe-text/statusbar-items.c @@ -0,0 +1,843 @@ +/* + gui-statusbar-items.c : irssi + + Copyright (C) 1999 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "module.h" +#include "signals.h" +#include "server.h" +#include "misc.h" +#include "settings.h" + +#include "irc.h" +#include "channels.h" +#include "query.h" +#include "irc-server.h" +#include "nicklist.h" + +#include "windows.h" +#include "window-items.h" + +#include "screen.h" +#include "printtext.h" +#include "statusbar.h" +#include "gui-windows.h" + +/* how often to redraw lagging time */ +#define LAG_REFRESH_TIME 10 +/* If we haven't been able to check lag for this long, "(??)" is added after + the lag */ +#define MAX_LAG_UNKNOWN_TIME 30 + +static STATUSBAR_REC *mainbar; +static MAIN_WINDOW_REC *mainbar_window; +static int use_colors; + +/* clock */ +static SBAR_ITEM_REC *clock_item; +static int clock_timetag; +static time_t clock_last; + +/* nick */ +static SBAR_ITEM_REC *nick_item; + +/* channel */ +static SBAR_ITEM_REC *channel_item; + +/* activity */ +static SBAR_ITEM_REC *activity_item; +static GList *activity_list; + +/* more */ +static SBAR_ITEM_REC *more_item; + +/* lag */ +static SBAR_ITEM_REC *lag_item; +static int lag_timetag, lag_min_show; +static time_t lag_last_draw; + +/* topic */ +static SBAR_ITEM_REC *topic_item; +static STATUSBAR_REC *topic_bar; + +/* redraw clock */ +static void statusbar_clock(SBAR_ITEM_REC *item, int ypos) +{ + struct tm *tm; + char str[6]; + + clock_last = time(NULL); + tm = localtime(&clock_last); + + g_snprintf(str, sizeof(str), "%02d:%02d", tm->tm_hour, tm->tm_min); + + move(ypos, item->xpos); + set_color((1 << 4)+3); addch('['); + set_color((1 << 4)+15); addstr(str); + set_color((1 << 4)+3); addch(']'); + + screen_refresh(); +} + +/* check if we need to redraw clock.. */ +static int statusbar_clock_timeout(void) +{ + struct tm *tm; + time_t t; + int min; + + tm = localtime(&clock_last); + min = tm->tm_min; + + t = time(NULL); + tm = localtime(&t); + + if (tm->tm_min != min) { + /* minute changed, redraw! */ + statusbar_item_redraw(clock_item); + } + return 1; +} + +/* redraw nick */ +static void statusbar_nick(SBAR_ITEM_REC *item, int ypos) +{ + CHANNEL_REC *channel; + IRC_SERVER_REC *server; + NICK_REC *nickrec; + int size_needed; + int umode_size; + gchar nick[10]; + + server = (IRC_SERVER_REC *) (active_win == NULL ? NULL : active_win->active_server); + + umode_size = server == NULL || server->usermode == NULL ? 0 : strlen(server->usermode)+3; + + /* nick */ + if (server == NULL || server->nick == NULL) + { + nick[0] = '\0'; + nickrec = NULL; + } + else + { + strncpy(nick, server->nick, 9); + nick[9] = '\0'; + + channel = irc_item_channel(active_win->active); + nickrec = channel == NULL ? NULL : nicklist_find(channel, server->nick); + } + + size_needed = 2 + strlen(nick) + umode_size + + (server != NULL && server->usermode_away ? 7 : 0) + + (nickrec != NULL && (nickrec->op || nickrec->voice) ? 1 : 0); /* @ + */ + + if (item->size != size_needed) + { + /* we need more (or less..) space! */ + statusbar_item_resize(item, size_needed); + return; + } + + /* size ok, draw the nick */ + move(ypos, item->xpos); + + set_color((1 << 4)+3); addch('['); + if (nickrec != NULL && (nickrec->op || nickrec->voice)) + { + set_color((1 << 4)+15); addch(nickrec->op ? '@' : '+'); + } + set_color((1 << 4)+7); addstr(nick); + if (umode_size) + { + set_color((1 << 4)+15); addch('('); + set_color((1 << 4)+3); addch('+'); + set_color((1 << 4)+7); addstr(server->usermode); + set_color((1 << 4)+15); addch(')'); + if (server->usermode_away) + { + set_color((1 << 4)+7); addstr(" ("); + set_color((1 << 4)+10); addstr("zZzZ"); + set_color((1 << 4)+7); addch(')'); + } + } + set_color((1 << 4)+3); addch(']'); + screen_refresh(); +} + +static void sig_statusbar_nick_redraw(void) +{ + statusbar_item_redraw(nick_item); +} + +static WINDOW_REC *mainwindow_find_sbar(SBAR_ITEM_REC *item) +{ + GSList *tmp; + + for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) { + MAIN_WINDOW_REC *rec = tmp->data; + + if (rec->statusbar_channel_item == item) + return rec->active; + } + + return active_win; +} + +/* redraw channel */ +static void statusbar_channel(SBAR_ITEM_REC *item, int ypos) +{ + WINDOW_REC *window; + WI_ITEM_REC *witem; + CHANNEL_REC *channel; + SERVER_REC *server; + gchar channame[21], winnum[MAX_INT_STRLEN], *mode; + int size_needed; + int mode_size; + + window = item->bar->pos != STATUSBAR_POS_MIDDLE ? active_win : + mainwindow_find_sbar(item); + server = window == NULL ? NULL : window->active_server; + + ltoa(winnum, window == NULL ? 0 : window->refnum); + + witem = window != NULL && irc_item_check(window->active) ? + window->active : NULL; + if (witem == NULL) + { + /* display server tag */ + channame[0] = '\0'; + mode = NULL; + mode_size = 0; + + size_needed = 3 + strlen(winnum) + (server == NULL ? 0 : strlen(server->tag)); + } + else + { + /* display channel + mode */ + strncpy(channame, witem->name, 20); channame[20] = '\0'; + + channel = irc_item_channel(witem); + if (channel == NULL) { + mode_size = 0; + mode = NULL; + } else { + mode = channel_get_mode(channel); + mode_size = strlen(mode); + if (mode_size > 0) mode_size += 3; /* (+) */ + } + + size_needed = 3 + strlen(winnum) + strlen(channame) + mode_size; + } + + if (item->size != size_needed) + { + /* we need more (or less..) space! */ + statusbar_item_resize(item, size_needed); + if (mode != NULL) g_free(mode); + return; + } + + move(ypos, item->xpos); + set_color((1 << 4)+3); addch('['); + + /* window number */ + set_color((1 << 4)+7); addstr(winnum); + set_color((1 << 4)+3); addch(':'); + + if (channame[0] == '\0' && server != NULL) + { + /* server tag */ + set_color((1 << 4)+7); addstr(server->tag); + } + else if (channame[0] != '\0') + { + /* channel + mode */ + set_color((1 << 4)+7); addstr(channame); + if (mode_size) + { + set_color((1 << 4)+15); addch('('); + set_color((1 << 4)+3); addch('+'); + set_color((1 << 4)+7); addstr(mode); + set_color((1 << 4)+15); addch(')'); + } + } + set_color((1 << 4)+3); addch(']'); + screen_refresh(); + + if (mode != NULL) g_free(mode); +} + +static void sig_statusbar_channel_redraw(void) +{ + statusbar_item_redraw(channel_item); +} + +static void sig_statusbar_channel_redraw_window(WINDOW_REC *window) +{ + if (is_window_visible(window)) + statusbar_item_redraw(channel_item); +} + +static void sig_statusbar_channel_redraw_window_item(WI_ITEM_REC *item) +{ + WINDOW_REC *window; + + window = window_item_window(item); + if (window->active == item && is_window_visible(window)) + statusbar_item_redraw(channel_item); +} + +static void draw_activity(gchar *title, gboolean act, gboolean det) +{ + WINDOW_REC *window; + GList *tmp; + gchar str[MAX_INT_STRLEN]; + gboolean first, is_det; + + set_color((1 << 4)+7); addstr(title); + + first = TRUE; + for (tmp = activity_list; tmp != NULL; tmp = tmp->next) + { + window = tmp->data; + + is_det = window->new_data == NEWDATA_MSG_FORYOU; + if (is_det && !det) continue; + if (!is_det && !act) continue; + + if (first) + first = FALSE; + else + { + set_color((1 << 4)+3); + addch(','); + } + + ltoa(str, window->refnum); + switch (window->new_data) + { + case NEWDATA_TEXT: + set_color((1 << 4)+3); + break; + case NEWDATA_MSG: + set_color((1 << 4)+15); + break; + case NEWDATA_MSG_FORYOU: + set_color((1 << 4)+13); + break; + } + addstr(str); + } +} + +/* redraw activity */ +static void statusbar_activity(SBAR_ITEM_REC *item, int ypos) +{ + WINDOW_REC *window; + GList *tmp; + gchar str[MAX_INT_STRLEN]; + int size_needed; + gboolean act, det; + + size_needed = 0; act = det = FALSE; + for (tmp = activity_list; tmp != NULL; tmp = tmp->next) + { + window = tmp->data; + + size_needed += 1+ltoa(str, window->refnum); + + if (!use_colors && window->new_data == NEWDATA_MSG_FORYOU) + det = TRUE; + else + act = TRUE; + } + + if (act) size_needed += 6; /* [Act: ], -1 */ + if (det) size_needed += 6; /* [Det: ], -1 */ + if (act && det) size_needed--; + + if (item->size != size_needed) + { + /* we need more (or less..) space! */ + statusbar_item_resize(item, size_needed); + return; + } + + if (item->size == 0) + return; + + move(ypos, item->xpos); + set_color((1 << 4)+3); addch('['); + if (act) draw_activity("Act: ", TRUE, !det); + if (act && det) addch(' '); + if (det) draw_activity("Det: ", FALSE, TRUE); + set_color((1 << 4)+3); addch(']'); + + screen_refresh(); +} + +static void sig_statusbar_activity_hilight(WINDOW_REC *window, gpointer oldlevel) +{ + GList *tmp; + int inspos; + + g_return_if_fail(window != NULL); + + if (settings_get_bool("actlist_moves")) + { + /* Move the window to the first in the activity list */ + if (g_list_find(activity_list, window) != NULL) + activity_list = g_list_remove(activity_list, window); + if (window->new_data != 0) + activity_list = g_list_prepend(activity_list, window); + statusbar_item_redraw(activity_item); + return; + } + + if (g_list_find(activity_list, window) != NULL) + { + /* already in activity list */ + if (window->new_data == 0) + { + /* remove from activity list */ + activity_list = g_list_remove(activity_list, window); + statusbar_item_redraw(activity_item); + } + else if (window->new_data != GPOINTER_TO_INT(oldlevel)) + { + /* different level as last time, just redraw it. */ + statusbar_item_redraw(activity_item); + } + return; + } + + if (window->new_data == 0) + return; + + /* add window to activity list .. */ + inspos = 0; + for (tmp = activity_list; tmp != NULL; tmp = tmp->next, inspos++) + { + WINDOW_REC *rec = tmp->data; + + if (window->refnum < rec->refnum) + { + activity_list = g_list_insert(activity_list, window, inspos); + break; + } + } + if (tmp == NULL) + activity_list = g_list_append(activity_list, window); + + statusbar_item_redraw(activity_item); +} + +static void sig_statusbar_activity_window_destroyed(WINDOW_REC *window) +{ + g_return_if_fail(window != NULL); + + if (g_list_find(activity_list, window) != NULL) + { + activity_list = g_list_remove(activity_list, window); + statusbar_item_redraw(activity_item); + } +} + +/* redraw -- more -- */ +static void statusbar_more(SBAR_ITEM_REC *item, int ypos) +{ + if (item->size != 10) return; + + move(ypos, item->xpos); + set_color((1 << 4)+15); addstr("-- more --"); + screen_refresh(); +} + +static void sig_statusbar_more_check_remove(WINDOW_REC *window) +{ + g_return_if_fail(window != NULL); + + if (!is_window_visible(window)) + return; + + if (more_item != NULL && WINDOW_GUI(window)->bottom) { + statusbar_item_remove(more_item); + more_item = NULL; + } +} + +static void sig_statusbar_more_check(WINDOW_REC *window) +{ + g_return_if_fail(window != NULL); + + if (!is_window_visible(window)) + return; + + if (!WINDOW_GUI(window)->bottom) { + if (more_item == NULL) + more_item = statusbar_item_create(mainbar, 10, FALSE, statusbar_more); + } else if (more_item != NULL) { + statusbar_item_remove(more_item); + more_item = NULL; + } +} + +static void statusbar_lag(SBAR_ITEM_REC *item, int ypos) +{ + IRC_SERVER_REC *server; + GString *str; + int size_needed, lag_unknown; + time_t now; + + now = time(NULL); + str = g_string_new(NULL); + + server = (IRC_SERVER_REC *) (active_win == NULL ? NULL : active_win->active_server); + if (server == NULL || server->lag_last_check == 0) + size_needed = 0; + else if (server->lag_sent == 0 || now-server->lag_sent < 5) { + lag_unknown = now-server->lag_last_check > MAX_LAG_UNKNOWN_TIME; + + if (server->lag < lag_min_show && !lag_unknown) + size_needed = 0; /* small lag, don't display */ + else { + g_string_sprintf(str, "%d.%02d", server->lag/1000, (server->lag % 1000)/10); + if (lag_unknown) + g_string_append(str, " (??)"); + size_needed = str->len+7; + } + } else { + /* big lag, still waiting .. */ + g_string_sprintf(str, "%ld (??)", now-server->lag_sent); + size_needed = str->len+7; + } + + if (item->size != size_needed) + { + /* we need more (or less..) space! */ + statusbar_item_resize(item, size_needed); + g_string_free(str, TRUE); + return; + } + + if (item->size != 0) + { + lag_last_draw = now; + move(ypos, item->xpos); + set_color((1 << 4)+3); addch('['); + set_color((1 << 4)+7); addstr("Lag: "); + + set_color((1 << 4)+15); addstr(str->str); + set_color((1 << 4)+3); addch(']'); + + screen_refresh(); + } + g_string_free(str, TRUE); +} + +static void sig_statusbar_lag_redraw(void) +{ + statusbar_item_redraw(lag_item); +} + +static int statusbar_lag_timeout(void) +{ + /* refresh statusbar every 10 seconds */ + if (time(NULL)-lag_last_draw < LAG_REFRESH_TIME) + return 1; + + statusbar_item_redraw(lag_item); + return 1; +} + +static void statusbar_topic(SBAR_ITEM_REC *item, int ypos) +{ + CHANNEL_REC *channel; + QUERY_REC *query; + char *str, *topic; + + if (item->size != COLS-2) { + /* get all space for topic */ + statusbar_item_resize(item, COLS-2); + return; + } + + move(ypos, item->xpos); + set_bg((1<<4)+7); clrtoeol(); set_bg(0); + + if (active_win == NULL) + return; + + topic = NULL; + channel = irc_item_channel(active_win->active); + query = irc_item_query(active_win->active); + if (channel != NULL && channel->topic != NULL) topic = channel->topic; + if (query != NULL && query->address != NULL) topic = query->address; + if (topic == NULL) return; + + topic = strip_codes(topic); + str = g_strdup_printf("%.*s", item->size, topic); + set_color((1<<4)+15); addstr(str); + g_free(str); + g_free(topic); + + screen_refresh(); +} + +static void sig_statusbar_topic_redraw(void) +{ + if (topic_item != NULL) statusbar_item_redraw(topic_item); +} + +static void sig_sidebars_redraw(void) +{ + GSList *tmp; + + for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) { + MAIN_WINDOW_REC *rec = tmp->data; + + if (rec->statusbar_channel_item != NULL) + statusbar_item_redraw(rec->statusbar_channel_item); + } +} + +static void topicbar_create(void) +{ + if (topic_bar != NULL) + return; + + topic_bar = statusbar_create(STATUSBAR_POS_UP, 0); + topic_item = statusbar_item_create(topic_bar, 0, FALSE, statusbar_topic); + statusbar_redraw(topic_bar); + + signal_add("window changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw); + signal_add("window item changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw); + signal_add("channel topic changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw); + signal_add("query address changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw); +} + +static void topicbar_destroy(void) +{ + if (topic_bar == NULL) + return; + + statusbar_destroy(topic_bar); + topic_item = NULL; + topic_bar = NULL; + + signal_remove("window changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw); + signal_remove("window item changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw); + signal_remove("channel topic changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw); + signal_remove("query address changed", (SIGNAL_FUNC) sig_statusbar_topic_redraw); +} + +static void mainbar_remove_items(void) +{ + statusbar_item_remove(clock_item); + statusbar_item_remove(nick_item); + statusbar_item_remove(channel_item); + statusbar_item_remove(activity_item); + statusbar_item_remove(lag_item); +} + +static void mainbar_add_items(MAIN_WINDOW_REC *window) +{ + mainbar = window->statusbar; + mainbar_window = window; + + clock_item = statusbar_item_create(mainbar, 7, FALSE, statusbar_clock); + nick_item = statusbar_item_create(mainbar, 2, FALSE, statusbar_nick); + channel_item = statusbar_item_create(mainbar, 2, FALSE, statusbar_channel); + activity_item = statusbar_item_create(mainbar, 0, FALSE, statusbar_activity); + lag_item = statusbar_item_create(mainbar, 0, FALSE, statusbar_lag); +} + +static void sidebar_add_items(MAIN_WINDOW_REC *window) +{ + window->statusbar_channel_item = + statusbar_item_create(window->statusbar, 3, FALSE, statusbar_channel); +} + +static void sidebar_remove_items(MAIN_WINDOW_REC *window) +{ + if (window->statusbar_channel_item != NULL) { + statusbar_item_remove(window->statusbar_channel_item); + window->statusbar_channel_item = NULL; + } +} + +static void sig_mainwindow_created(MAIN_WINDOW_REC *window) +{ + window->statusbar = statusbar_create(STATUSBAR_POS_MIDDLE, window->last_line+1); + sidebar_add_items(window); +} + +static void sig_mainwindow_destroyed(MAIN_WINDOW_REC *window) +{ + if (window == mainbar_window) { + mainbar = NULL; + mainbar_window = NULL; + } + + if (window->statusbar != NULL) + statusbar_destroy(window->statusbar); +} + +static void sig_main_statusbar_changed(WINDOW_REC *window) +{ + MAIN_WINDOW_REC *parent; + + if (window == NULL) + return; + + parent = WINDOW_GUI(window)->parent; + if (mainbar == parent->statusbar) + return; + + if (mainbar != NULL) { + mainbar_remove_items(); + sidebar_add_items(mainbar_window); + } + sidebar_remove_items(parent); + mainbar_add_items(parent); +} + +static void read_settings(void) +{ + use_colors = settings_get_bool("colors"); + if (settings_get_bool("topicbar")) + topicbar_create(); + else if (!settings_get_bool("topicbar")) + topicbar_destroy(); + + lag_min_show = settings_get_int("lag_min_show")*10; +} + +void statusbar_items_init(void) +{ + GSList *tmp; + + settings_add_int("misc", "lag_min_show", 100); + settings_add_bool("lookandfeel", "topicbar", TRUE); + settings_add_bool("lookandfeel", "actlist_moves", FALSE); + + /* clock */ + clock_timetag = g_timeout_add(1000, (GSourceFunc) statusbar_clock_timeout, NULL); + + /* nick */ + signal_add("server connected", (SIGNAL_FUNC) sig_statusbar_nick_redraw); + signal_add("channel wholist", (SIGNAL_FUNC) sig_statusbar_nick_redraw); + signal_add("window changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw); + signal_add("window item changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw); + signal_add("nick mode changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw); + signal_add("user mode changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw); + signal_add("server nick changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw); + signal_add("window server changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw); + signal_add("away mode changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw); + + /* channel */ + signal_add("window changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw); + signal_add("window item changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw_window); + signal_add("channel mode changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw_window_item); + signal_add("window server changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw_window); + signal_add("window refnum changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw_window); + + /* activity */ + activity_list = NULL; + signal_add("window activity", (SIGNAL_FUNC) sig_statusbar_activity_hilight); + signal_add("window destroyed", (SIGNAL_FUNC) sig_statusbar_activity_window_destroyed); + + /* more */ + more_item = NULL; + signal_add("gui page scrolled", (SIGNAL_FUNC) sig_statusbar_more_check_remove); + signal_add("window item changed", (SIGNAL_FUNC) sig_statusbar_more_check); + signal_add("gui print text", (SIGNAL_FUNC) sig_statusbar_more_check); + + /* lag */ + lag_timetag = g_timeout_add(1000*LAG_REFRESH_TIME, (GSourceFunc) statusbar_lag_timeout, NULL); + signal_add("server lag", (SIGNAL_FUNC) sig_statusbar_lag_redraw); + signal_add("window server changed", (SIGNAL_FUNC) sig_statusbar_lag_redraw); + + /* topic */ + topic_item = NULL; topic_bar = NULL; + signal_add("setup changed", (SIGNAL_FUNC) read_settings); + + read_settings(); + statusbar_redraw(NULL); + + /* middle bars */ + signal_add("mainwindow created", (SIGNAL_FUNC) sig_mainwindow_created); + signal_add("mainwindow destroyed", (SIGNAL_FUNC) sig_mainwindow_destroyed); + signal_add("window changed", (SIGNAL_FUNC) sig_main_statusbar_changed); + signal_add("window refnum changed", (SIGNAL_FUNC) sig_sidebars_redraw); + + /* add statusbars to existing windows */ + for (tmp = mainwindows; tmp != NULL; tmp = tmp->next) + sig_mainwindow_created(tmp->data); + sig_main_statusbar_changed(active_win); +} + +void statusbar_items_deinit(void) +{ + /* clock */ + g_source_remove(clock_timetag); + + /* nick */ + signal_remove("server connected", (SIGNAL_FUNC) sig_statusbar_nick_redraw); + signal_remove("channel wholist", (SIGNAL_FUNC) sig_statusbar_nick_redraw); + signal_remove("window changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw); + signal_remove("window item changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw); + signal_remove("nick mode changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw); + signal_remove("user mode changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw); + signal_remove("server nick changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw); + signal_remove("window server changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw); + signal_remove("away mode changed", (SIGNAL_FUNC) sig_statusbar_nick_redraw); + + /* channel */ + signal_remove("window changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw); + signal_remove("window item changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw_window); + signal_remove("channel mode changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw_window_item); + signal_remove("window server changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw_window); + signal_remove("window refnum changed", (SIGNAL_FUNC) sig_statusbar_channel_redraw_window); + + /* activity */ + signal_remove("window activity", (SIGNAL_FUNC) sig_statusbar_activity_hilight); + signal_remove("window destroyed", (SIGNAL_FUNC) sig_statusbar_activity_window_destroyed); + g_list_free(activity_list); + + /* more */ + signal_remove("gui page scrolled", (SIGNAL_FUNC) sig_statusbar_more_check_remove); + signal_remove("window item changed", (SIGNAL_FUNC) sig_statusbar_more_check); + signal_remove("gui print text", (SIGNAL_FUNC) sig_statusbar_more_check); + + /* lag */ + g_source_remove(lag_timetag); + signal_remove("server lag", (SIGNAL_FUNC) sig_statusbar_lag_redraw); + signal_remove("window server changed", (SIGNAL_FUNC) sig_statusbar_lag_redraw); + + /* topic */ + topicbar_destroy(); + signal_remove("setup changed", (SIGNAL_FUNC) read_settings); + + /* middle bars */ + signal_remove("mainwindow created", (SIGNAL_FUNC) sig_mainwindow_created); + signal_remove("mainwindow destroyed", (SIGNAL_FUNC) sig_mainwindow_destroyed); + signal_remove("window changed", (SIGNAL_FUNC) sig_main_statusbar_changed); + signal_remove("window refnum changed", (SIGNAL_FUNC) sig_sidebars_redraw); +} diff --git a/src/fe-text/statusbar.c b/src/fe-text/statusbar.c new file mode 100644 index 00000000..24e89107 --- /dev/null +++ b/src/fe-text/statusbar.c @@ -0,0 +1,266 @@ +/* + gui-statusbar.c : irssi + + Copyright (C) 1999 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "module.h" +#include "signals.h" +#include "server.h" + +#include "windows.h" + +#include "screen.h" +#include "statusbar.h" +#include "gui-windows.h" + +void statusbar_items_init(void); +void statusbar_items_deinit(void); + +static GSList *statusbars; +static int sbar_uppest, sbar_lowest, sbars_up, sbars_down; + +static void statusbar_item_destroy(SBAR_ITEM_REC *rec) +{ + rec->bar->items = g_slist_remove(rec->bar->items, rec); + g_free(rec); +} + +static void statusbar_redraw_line(STATUSBAR_REC *bar) +{ + static int recurses = 0, resized = FALSE; + STATUSBAR_FUNC func; + GSList *tmp; + int xpos, rxpos, old_resized; + + old_resized = resized; + resized = FALSE; + recurses++; + + xpos = 1; + for (tmp = bar->items; tmp != NULL; tmp = tmp->next) { + SBAR_ITEM_REC *rec = tmp->data; + + if (!rec->right_justify && xpos+rec->size < COLS) { + rec->xpos = xpos; + + func = rec->func; + func(rec, bar->ypos); + + if (resized) break; + if (rec->size > 0) xpos += rec->size+1; + } + } + + rxpos = COLS-1; + for (tmp = bar->items; tmp != NULL; tmp = tmp->next) { + SBAR_ITEM_REC *rec = tmp->data; + + if (rec->right_justify && rxpos-rec->size > xpos) { + rec->xpos = rxpos-rec->size; + + func = rec->func; + func(rec, bar->ypos); + + if (resized) break; + if (rec->size > 0) rxpos -= rec->size+1; + } + } + + resized = old_resized; + if (--recurses > 0) resized = TRUE; +} + +static void statusbar_redraw_all(void) +{ + GSList *tmp; + + screen_refresh_freeze(); + + for (tmp = statusbars; tmp != NULL; tmp = tmp->next) + statusbar_redraw(tmp->data); + + screen_refresh_thaw(); +} + +STATUSBAR_REC *statusbar_find(int pos, int line) +{ + GSList *tmp; + + for (tmp = statusbars; tmp != NULL; tmp = tmp->next) { + STATUSBAR_REC *rec = tmp->data; + + if (rec->pos == pos && rec->line == line) + return rec; + } + + return NULL; +} + +void statusbar_redraw(STATUSBAR_REC *bar) +{ + if (bar == NULL) { + statusbar_redraw_all(); + return; + } + + set_bg((1<<4)+15); + move(bar->ypos, 0); clrtoeol(); + set_bg(0); + + statusbar_redraw_line(bar); +} + +void statusbar_item_redraw(SBAR_ITEM_REC *item) +{ + STATUSBAR_FUNC func; + + g_return_if_fail(item != NULL); + + func = item->func; + func(item, item->bar->ypos); +} + +/* ypos is used only when pos == STATUSBAR_POS_MIDDLE */ +STATUSBAR_REC *statusbar_create(int pos, int ypos) +{ + STATUSBAR_REC *rec; + + rec = g_new0(STATUSBAR_REC, 1); + statusbars = g_slist_append(statusbars, rec); + + rec->pos = pos; + rec->line = pos == STATUSBAR_POS_MIDDLE ? ypos : + mainwindows_reserve_lines(1, pos == STATUSBAR_POS_UP); + rec->ypos = pos == STATUSBAR_POS_MIDDLE ? ypos : + pos == STATUSBAR_POS_UP ? rec->line : LINES-1-rec->line; + + if (pos == STATUSBAR_POS_UP) { + if (sbars_up == 0) sbar_uppest = rec->line; + sbars_up++; + rec->line -= sbar_uppest; + } else if (pos == STATUSBAR_POS_DOWN) { + if (sbars_down == 0) sbar_lowest = rec->line; + sbars_down++; + rec->line -= sbar_lowest; + } + + set_bg((1<<4)+15); + move(rec->ypos, 0); clrtoeol(); + set_bg(0); + + return rec; +} + +static void statusbars_pack(int pos, int line) +{ + GSList *tmp; + + for (tmp = statusbars; tmp != NULL; tmp = tmp->next) { + STATUSBAR_REC *rec = tmp->data; + + if (rec->pos == pos && rec->line > line) { + rec->line--; + rec->ypos += pos == STATUSBAR_POS_UP ? -1 : 1; + } + } +} + +void statusbar_destroy(STATUSBAR_REC *bar) +{ + g_return_if_fail(bar != NULL); + + if (bar->pos != STATUSBAR_POS_MIDDLE) + mainwindows_reserve_lines(-1, bar->pos == STATUSBAR_POS_UP); + + if (bar->pos == STATUSBAR_POS_UP) sbars_up--; + if (bar->pos == STATUSBAR_POS_DOWN) sbars_down--; + statusbars = g_slist_remove(statusbars, bar); + + while (bar->items != NULL) + statusbar_item_destroy(bar->items->data); + + if (bar->pos != STATUSBAR_POS_MIDDLE) + statusbars_pack(bar->pos, bar->pos); + g_free(bar); + + if (!quitting) statusbar_redraw_all(); +} + +SBAR_ITEM_REC *statusbar_item_create(STATUSBAR_REC *bar, int size, int right_justify, STATUSBAR_FUNC func) +{ + SBAR_ITEM_REC *rec; + + g_return_val_if_fail(bar != NULL, NULL); + g_return_val_if_fail(func != NULL, NULL); + + rec = g_new0(SBAR_ITEM_REC, 1); + rec->bar = bar; + bar->items = g_slist_append(bar->items, rec); + + rec->xpos = -1; + rec->size = size; + rec->right_justify = right_justify; + rec->func = func; + + return rec; +} + +void statusbar_item_resize(SBAR_ITEM_REC *item, int size) +{ + g_return_if_fail(item != NULL); + + item->size = size; + statusbar_redraw_all(); +} + +void statusbar_item_remove(SBAR_ITEM_REC *item) +{ + g_return_if_fail(item != NULL); + + statusbar_item_destroy(item); + if (!quitting) statusbar_redraw_all(); +} + +static void sig_mainwindow_resized(MAIN_WINDOW_REC *window) +{ + STATUSBAR_REC *rec; + + rec = window->statusbar; + rec->ypos = window->last_line+1; +} + +void statusbar_init(void) +{ + statusbars = NULL; + sbars_up = sbars_down = 0; + + statusbar_items_init(); + signal_add("mainwindow resized", (SIGNAL_FUNC) sig_mainwindow_resized); + signal_add("mainwindow moved", (SIGNAL_FUNC) sig_mainwindow_resized); +} + +void statusbar_deinit(void) +{ + statusbar_items_deinit(); + + while (statusbars != NULL) + statusbar_destroy(statusbars->data); + + signal_remove("mainwindow resized", (SIGNAL_FUNC) sig_mainwindow_resized); + signal_remove("mainwindow moved", (SIGNAL_FUNC) sig_mainwindow_resized); +} diff --git a/src/fe-text/statusbar.h b/src/fe-text/statusbar.h new file mode 100644 index 00000000..3ca133ef --- /dev/null +++ b/src/fe-text/statusbar.h @@ -0,0 +1,45 @@ +#ifndef __STATUSBAR_H +#define __STATUSBAR_H + +enum { + STATUSBAR_POS_UP, + STATUSBAR_POS_MIDDLE, + STATUSBAR_POS_DOWN +}; + +typedef struct { + int pos; + int line; + + int ypos; /* real position in screen at the moment */ + GSList *items; +} STATUSBAR_REC; + +typedef struct { + STATUSBAR_REC *bar; + + int xpos, size; + int right_justify; + void *func; +} SBAR_ITEM_REC; + +typedef void (*STATUSBAR_FUNC) (SBAR_ITEM_REC *item, int ypos); + +/* ypos is used only when pos == STATUSBAR_POS_MIDDLE */ +STATUSBAR_REC *statusbar_create(int pos, int ypos); +void statusbar_destroy(STATUSBAR_REC *bar); + +STATUSBAR_REC *statusbar_find(int pos, int line); + +SBAR_ITEM_REC *statusbar_item_create(STATUSBAR_REC *bar, int size, gboolean right_justify, STATUSBAR_FUNC func); +void statusbar_item_resize(SBAR_ITEM_REC *item, int size); +void statusbar_item_remove(SBAR_ITEM_REC *item); + +/* redraw statusbar, NULL = all */ +void statusbar_redraw(STATUSBAR_REC *bar); +void statusbar_item_redraw(SBAR_ITEM_REC *item); + +void statusbar_init(void); +void statusbar_deinit(void); + +#endif diff --git a/src/irc/core/bans.c b/src/irc/core/bans.c index 962c3c8d..4108f1bd 100644 --- a/src/irc/core/bans.c +++ b/src/irc/core/bans.c @@ -55,7 +55,7 @@ char *ban_get_mask(CHANNEL_REC *channel, const char *nick) host = strchr(++user, '@'); if (host == NULL) return str; - if ((int) (host-user) < 10) { + if ((int) (host-user) > 10) { /* too long user mask */ user[9] = '*'; g_memmove(user+10, host, strlen(host)+1); @@ -112,7 +112,7 @@ void ban_set_type(const char *type) void ban_set(CHANNEL_REC *channel, const char *bans) { GString *str; - char **ban, **banlist; + char **ban, **banlist, *realban; g_return_if_fail(bans != NULL); @@ -121,19 +121,20 @@ void ban_set(CHANNEL_REC *channel, const char *bans) for (ban = banlist; *ban != NULL; ban++) { if (strchr(*ban, '!') != NULL) { /* explicit ban */ - g_string_sprintfa(str, " %s", *ban); + g_string_sprintfa(str, "%s ", *ban); continue; } /* ban nick */ - *ban = ban_get_mask(channel, *ban); - if (*ban != NULL) { - g_string_sprintfa(str, " %s", *ban); - g_free(*ban); + realban = ban_get_mask(channel, *ban); + if (realban != NULL) { + g_string_sprintfa(str, "%s ", realban); + g_free(realban); } } g_strfreev(banlist); + g_string_truncate(str, str->len-1); channel_set_singlemode(channel->server, channel->name, str->str, "+b"); g_string_free(str, TRUE); } @@ -169,7 +170,7 @@ static void command_set_ban(const char *data, IRC_SERVER_REC *server, WI_IRC_REC if (server == NULL || !server->connected || !irc_server_check(server)) cmd_return_error(CMDERR_NOT_CONNECTED); - params = cmd_get_params(data, 3 | PARAM_FLAG_OPTCHAN | PARAM_FLAG_GETREST, + params = cmd_get_params(data, 2 | PARAM_FLAG_OPTCHAN | PARAM_FLAG_GETREST, item, &channel, &nicks); if (!ischannel(*channel)) cmd_param_error(CMDERR_NOT_JOINED); if (*nicks == '\0') cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); diff --git a/src/irc/core/channel-events.c b/src/irc/core/channel-events.c index 8f11ee47..8de80cbd 100644 --- a/src/irc/core/channel-events.c +++ b/src/irc/core/channel-events.c @@ -95,6 +95,27 @@ static void event_topic(const char *data, IRC_SERVER_REC *server) g_free(params); } +/* Find any unjoined channel that matches `channel'. Long channel names are + also a bit problematic, so find a channel where start of the name matches. */ +static CHANNEL_REC *channel_find_unjoined(IRC_SERVER_REC *server, const char *channel) +{ + GSList *tmp; + int len; + + len = strlen(channel); + for (tmp = server->channels; tmp != NULL; tmp = tmp->next) { + CHANNEL_REC *rec = tmp->data; + + if (rec->joined) continue; + + if (g_strncasecmp(channel, rec->name, len) == 0 && + (len > 20 || rec->name[len] == '\0')) + return rec; + } + + return NULL; +} + static void event_join(const char *data, IRC_SERVER_REC *server, const char *nick, const char *address) { char *params, *channel, *tmp; @@ -120,10 +141,8 @@ static void event_join(const char *data, IRC_SERVER_REC *server, const char *nic !channel here to !ABCDEchannel */ char *shortchan; - shortchan = g_strdup(channel); - sprintf(shortchan, "!%s", channel+6); - - chanrec = channel_find(server, shortchan); + shortchan = g_strdup_printf("!%s", channel+6); + chanrec = channel_find_unjoined(server, shortchan); if (chanrec != NULL) { g_free(chanrec->name); chanrec->name = g_strdup(channel); @@ -132,11 +151,16 @@ static void event_join(const char *data, IRC_SERVER_REC *server, const char *nic g_free(shortchan); } - chanrec = channel_find(server, channel); + chanrec = channel_find_unjoined(server, channel); if (chanrec == NULL) { /* didn't get here with /join command.. */ chanrec = channel_create(server, channel, TRUE); } + chanrec->joined = TRUE; + if (strcmp(chanrec->name, channel) != 0) { + g_free(chanrec->name); + chanrec->name = g_strdup(channel); + } g_free(params); } diff --git a/src/irc/core/channels-query.c b/src/irc/core/channels-query.c index 0691d3ef..d8516ff6 100644 --- a/src/irc/core/channels-query.c +++ b/src/irc/core/channels-query.c @@ -232,7 +232,7 @@ static void channel_send_query(IRC_SERVER_REC *server, int query) for (tmp = chans; tmp != NULL; tmp = tmp->next) { chanrec = tmp->data; - server_redirect_event((SERVER_REC *) server, chanrec->name, 4, + server_redirect_event((SERVER_REC *) server, chanrec->name, 2, "event 403", "chanquery mode abort", 1, "event 349", "chanquery eban end", 1, "event 348", "chanquery eban", 1, NULL); @@ -244,7 +244,7 @@ static void channel_send_query(IRC_SERVER_REC *server, int query) for (tmp = chans; tmp != NULL; tmp = tmp->next) { chanrec = tmp->data; - server_redirect_event((SERVER_REC *) server, chanrec->name, 4, + server_redirect_event((SERVER_REC *) server, chanrec->name, 2, "event 403", "chanquery mode abort", 1, "event 347", "chanquery ilist end", 1, "event 346", "chanquery ilist", 1, NULL); diff --git a/src/irc/core/channels-setup.c b/src/irc/core/channels-setup.c index c8400d4e..2991a8bc 100644 --- a/src/irc/core/channels-setup.c +++ b/src/irc/core/channels-setup.c @@ -26,6 +26,7 @@ #include "nicklist.h" #include "irc-server.h" #include "server-setup.h" +#include "special-vars.h" #include "lib-config/iconfig.h" #include "settings.h" @@ -33,30 +34,52 @@ GSList *setupchannels; #define ircnet_match(a, b) \ - ((a[0]) == '\0' || (b != NULL && g_strcasecmp(a, b) == 0)) + ((a) == NULL || (a[0]) == '\0' || (b != NULL && g_strcasecmp(a, b) == 0)) -SETUP_CHANNEL_REC *channels_setup_find(const char *channel, IRC_SERVER_REC *server) +static void channel_config_add(SETUP_CHANNEL_REC *channel) { - GSList *tmp; + CONFIG_NODE *node; - g_return_val_if_fail(channel != NULL, NULL); - g_return_val_if_fail(server != NULL, NULL); + node = iconfig_node_traverse("(channels", TRUE); + node = config_node_section(node, NULL, NODE_TYPE_BLOCK); + + config_node_set_str(node, "name", channel->name); + config_node_set_str(node, "ircnet", channel->ircnet); + if (channel->autojoin) + config_node_set_bool(node, "autojoin", TRUE); + config_node_set_str(node, "password", channel->password); + config_node_set_str(node, "botmasks", channel->botmasks); + config_node_set_str(node, "autosendcmd", channel->autosendcmd); + config_node_set_str(node, "background", channel->background); + config_node_set_str(node, "font", channel->font); +} - for (tmp = setupchannels; tmp != NULL; tmp = tmp->next) { - SETUP_CHANNEL_REC *rec = tmp->data; +static void channel_config_remove(SETUP_CHANNEL_REC *channel) +{ + CONFIG_NODE *node; - if (g_strcasecmp(rec->name, channel) == 0 && - ircnet_match(rec->ircnet, server->connrec->ircnet)) - return rec; + node = iconfig_node_traverse("channels", FALSE); + if (node != NULL) config_node_list_remove(node, g_slist_index(setupchannels, channel)); +} + +void channels_setup_create(SETUP_CHANNEL_REC *channel) +{ + if (g_slist_find(setupchannels, channel) != NULL) { + channel_config_remove(channel); + setupchannels = g_slist_remove(setupchannels, channel); } + setupchannels = g_slist_append(setupchannels, channel); - return NULL; + channel_config_add(channel); } void channels_setup_destroy(SETUP_CHANNEL_REC *channel) { g_return_if_fail(channel != NULL); + channel_config_remove(channel); + setupchannels = g_slist_remove(setupchannels, channel); + g_free(channel->name); g_free(channel->ircnet); g_free_not_null(channel->password); @@ -65,16 +88,30 @@ void channels_setup_destroy(SETUP_CHANNEL_REC *channel) g_free_not_null(channel->background); g_free_not_null(channel->font); g_free(channel); +} - setupchannels = g_slist_remove(setupchannels, channel); +SETUP_CHANNEL_REC *channels_setup_find(const char *channel, const char *ircnet) +{ + GSList *tmp; + + g_return_val_if_fail(channel != NULL, NULL); + + for (tmp = setupchannels; tmp != NULL; tmp = tmp->next) { + SETUP_CHANNEL_REC *rec = tmp->data; + + if (g_strcasecmp(rec->name, channel) == 0 && + ircnet_match(rec->ircnet, ircnet)) + return rec; + } + + return NULL; } /* connected to server, autojoin to channels. */ static void event_connected(IRC_SERVER_REC *server) { - GString *chans, *keys; + GString *chans; GSList *tmp; - int use_keys; g_return_if_fail(server != NULL); @@ -83,9 +120,6 @@ static void event_connected(IRC_SERVER_REC *server) /* join to the channels marked with autojoin in setup */ chans = g_string_new(NULL); - keys = g_string_new(NULL); - - use_keys = FALSE; for (tmp = setupchannels; tmp != NULL; tmp = tmp->next) { SETUP_CHANNEL_REC *rec = tmp->data; @@ -93,21 +127,14 @@ static void event_connected(IRC_SERVER_REC *server) continue; g_string_sprintfa(chans, "%s,", rec->name); - g_string_sprintfa(keys, "%s,", rec->password == NULL ? "x" : rec->password); - if (rec->password != NULL) - use_keys = TRUE; } if (chans->len > 0) { g_string_truncate(chans, chans->len-1); - g_string_truncate(keys, keys->len-1); - if (use_keys) g_string_sprintfa(chans, " %s", keys->str); - channels_join(server, chans->str, TRUE); } g_string_free(chans, TRUE); - g_string_free(keys, TRUE); } /* channel wholist received: send the auto send command */ @@ -115,17 +142,17 @@ static void channel_wholist(CHANNEL_REC *channel) { SETUP_CHANNEL_REC *rec; NICK_REC *nick; - char **bots, **bot, *str; + char **bots, **bot; g_return_if_fail(channel != NULL); - rec = channels_setup_find(channel->name, channel->server); + rec = channels_setup_find(channel->name, channel->server->connrec->ircnet); if (rec == NULL || rec->autosendcmd == NULL || !*rec->autosendcmd) return; if (rec->botmasks == NULL || !*rec->botmasks) { /* just send the command. */ - signal_emit("send command", 3, rec->autosendcmd, channel->server, channel); + eval_special_string(rec->autosendcmd, "", channel->server, channel); } /* find first available bot.. */ @@ -136,9 +163,7 @@ static void channel_wholist(CHANNEL_REC *channel) continue; /* got one! */ - str = g_strdup_printf(rec->autosendcmd, nick->nick); - signal_emit("send command", 3, str, channel->server, channel); - g_free(str); + eval_special_string(rec->autosendcmd, nick->nick, channel->server, channel); break; } g_strfreev(bots); diff --git a/src/irc/core/channels-setup.h b/src/irc/core/channels-setup.h index 0556019a..9cd2472c 100644 --- a/src/irc/core/channels-setup.h +++ b/src/irc/core/channels-setup.h @@ -20,8 +20,9 @@ extern GSList *setupchannels; void channels_setup_init(void); void channels_setup_deinit(void); +void channels_setup_create(SETUP_CHANNEL_REC *channel); void channels_setup_destroy(SETUP_CHANNEL_REC *channel); -SETUP_CHANNEL_REC *channels_setup_find(const char *channel, IRC_SERVER_REC *server); +SETUP_CHANNEL_REC *channels_setup_find(const char *channel, const char *ircnet); #endif diff --git a/src/irc/core/channels.c b/src/irc/core/channels.c index 9f01d57a..4c50ab7b 100644 --- a/src/irc/core/channels.c +++ b/src/irc/core/channels.c @@ -156,10 +156,12 @@ char *channel_get_mode(CHANNEL_REC *channel) void channels_join(IRC_SERVER_REC *server, const char *data, int automatic) { + SETUP_CHANNEL_REC *schannel; CHANNEL_REC *chanrec; GString *outchans, *outkeys; char *params, *channels, *keys; char **chanlist, **keylist, **tmp, **tmpkey, *channel; + int use_keys; g_return_if_fail(data != NULL); if (server == NULL || !server->connected || !irc_server_check(server)) @@ -174,19 +176,24 @@ void channels_join(IRC_SERVER_REC *server, const char *data, int automatic) outchans = g_string_new(NULL); outkeys = g_string_new(NULL); + use_keys = *keys != '\0'; tmpkey = keylist; for (tmp = chanlist; *tmp != NULL; tmp++) { channel = ischannel(**tmp) ? g_strdup(*tmp) : g_strdup_printf("#%s", *tmp); chanrec = channel_find(server, channel); - if (chanrec != NULL) { - /* already joined this channel */ - signal_emit("gui channel open", 1, chanrec); - } else { + if (chanrec == NULL) { + schannel = channels_setup_find(channel, server->connrec->ircnet); + g_string_sprintfa(outchans, "%s,", channel); - if (*keys != '\0') + if (schannel == NULL || schannel->password == NULL) g_string_sprintfa(outkeys, "%s,", get_join_key(*tmpkey)); + else { + /* get password from setup record */ + use_keys = TRUE; + g_string_sprintfa(outkeys, "%s,", schannel->password); + } channel_create(server, channel + (channel[0] == '!' && channel[1] == '!'), automatic); } @@ -197,7 +204,7 @@ void channels_join(IRC_SERVER_REC *server, const char *data, int automatic) } if (outchans->len > 0) { - irc_send_cmdv(server, *keys == '\0' ? "JOIN %s" : "JOIN %s %s", + irc_send_cmdv(server, use_keys ? "JOIN %s %s" : "JOIN %s", outchans->str, outkeys->str); } diff --git a/src/irc/core/channels.h b/src/irc/core/channels.h index 5cf53aa5..03ae1a6e 100644 --- a/src/irc/core/channels.h +++ b/src/irc/core/channels.h @@ -41,6 +41,7 @@ typedef struct { int wholist:1; /* WHO list got */ int synced:1; /* Channel synced - all queries done */ + int joined:1; /* Have we even received JOIN event for this channel? */ int left:1; /* You just left the channel */ int kicked:1; /* You just got kicked */ int destroying:1; diff --git a/src/irc/core/ctcp.c b/src/irc/core/ctcp.c index 5265c2be..55df8098 100644 --- a/src/irc/core/ctcp.c +++ b/src/irc/core/ctcp.c @@ -52,7 +52,7 @@ void ctcp_send_reply(IRC_SERVER_REC *server, const char *data) if (g_slist_length(server->ctcpqueue) < settings_get_int("max_ctcp_queue")) { /* Add to first in idle queue */ - tag = server_idle_add_first(server, data, NULL, 0, NULL); + tag = server_idle_add(server, data, NULL, 0, NULL); server->ctcpqueue = g_slist_append(server->ctcpqueue, GINT_TO_POINTER(tag)); } } diff --git a/src/irc/core/ignore.c b/src/irc/core/ignore.c index ab817ae1..274a8646 100644 --- a/src/irc/core/ignore.c +++ b/src/irc/core/ignore.c @@ -251,6 +251,7 @@ static void read_ignores(void) IGNORE_REC *rec; CONFIG_NODE *node; GSList *tmp; + char *str; while (ignores != NULL) ignore_destroy(ignores->data); @@ -269,8 +270,8 @@ static void read_ignores(void) rec->mask = g_strdup(config_node_get_str(node, "mask", NULL)); rec->pattern = g_strdup(config_node_get_str(node, "pattern", NULL)); - rec->level = level2bits(config_node_get_str(node, "level", 0)); - rec->except_level = level2bits(config_node_get_str(node, "except_level", 0)); + rec->level = level2bits(config_node_get_str(node, "level", "")); + rec->except_level = level2bits(config_node_get_str(node, "except_level", "")); rec->regexp = config_node_get_bool(node, "regexp", FALSE); rec->fullword = config_node_get_bool(node, "fullword", FALSE); diff --git a/src/irc/core/irc-commands.c b/src/irc/core/irc-commands.c index 8fcd4259..b06d9371 100644 --- a/src/irc/core/irc-commands.c +++ b/src/irc/core/irc-commands.c @@ -19,6 +19,7 @@ */ #include "module.h" +#include "network.h" #include "commands.h" #include "misc.h" #include "special-vars.h" @@ -46,23 +47,35 @@ static IRC_SERVER_REC *connect_server(const char *data) { IRC_SERVER_CONNECT_REC *conn; IRC_SERVER_REC *server; - char *params, *addr, *portstr, *password, *nick; - int port; + char *params, *args, *ircnet, *host, *addr, *portstr, *password, *nick; g_return_val_if_fail(data != NULL, NULL); - params = cmd_get_params(data, 4, &addr, &portstr, &password, &nick); + args = "ircnet host"; + params = cmd_get_params(data, 7 | PARAM_FLAG_MULTIARGS, + &args, &ircnet, &host, &addr, + &portstr, &password, &nick); + if (*addr == '+') addr++; if (*addr == '\0') return NULL; if (strcmp(password, "-") == 0) *password = '\0'; - port = 6667; - if (*portstr != '\0') - sscanf(portstr, "%d", &port); - /* connect to server */ - conn = irc_server_create_conn(addr, port, password, nick); + conn = irc_server_create_conn(addr, atoi(portstr), password, nick); + if (*ircnet != '\0') { + g_free_not_null(conn->ircnet); + conn->ircnet = g_strdup(ircnet); + } + if (*host != '\0') { + IPADDR ip; + + if (net_gethostname(host, &ip) == 0) { + if (conn->own_ip == NULL) + conn->own_ip = g_new(IPADDR, 1); + memcpy(conn->own_ip, &ip, sizeof(IPADDR)); + } + } server = irc_server_connect(conn); g_free(params); @@ -92,6 +105,9 @@ static void cmd_disconnect(const char *data, IRC_SERVER_REC *server) if (server == NULL || !irc_server_check(server)) cmd_param_error(CMDERR_NOT_CONNECTED); + if (*msg == '\0') msg = (char *) settings_get_str("quit_message"); + signal_emit("server quit", 2, server, msg); + ircserver = (IRC_SERVER_REC *) server; if (ircserver->handle != -1 && ircserver->buffer != NULL) { /* flush transmit queue */ @@ -100,8 +116,6 @@ static void cmd_disconnect(const char *data, IRC_SERVER_REC *server) ircserver->cmdqueue = NULL; ircserver->cmdcount = 0; - /* then send quit message */ - if (*msg == '\0') msg = (char *) settings_get_str("default_quit_message"); irc_send_cmdv(ircserver, "QUIT :%s", msg); } g_free(params); @@ -111,12 +125,20 @@ static void cmd_disconnect(const char *data, IRC_SERVER_REC *server) static void cmd_server(const char *data, IRC_SERVER_REC *server) { + char *params, *args, *ircnetarg, *hostarg, *addr; char *channels, *away_reason, *usermode, *ircnet; + int no_old_server; g_return_if_fail(data != NULL); - if (*data == '\0') cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS); - if (*data == '+' || server == NULL) { + args = "ircnet host"; + params = cmd_get_params(data, 4 | PARAM_FLAG_MULTIARGS, + &args, &ircnetarg, &hostarg, &addr); + if (*addr == '\0' || strcmp(addr, "+") == 0) + cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS); + + no_old_server = server == NULL; + if (*addr == '+' || server == NULL) { channels = away_reason = usermode = ircnet = NULL; } else { ircnet = g_strdup(server->connrec->ircnet); @@ -129,20 +151,21 @@ static void cmd_server(const char *data, IRC_SERVER_REC *server) cmd_disconnect("* Changing server", server); } - server = connect_server(data + (*data == '+' ? 1 : 0)); - if (*data == '+' || server == NULL || + server = connect_server(data); + if (*addr == '+' || server == NULL || (ircnet != NULL && server->connrec->ircnet != NULL && g_strcasecmp(ircnet, server->connrec->ircnet) != 0)) { g_free_not_null(channels); g_free_not_null(usermode); g_free_not_null(away_reason); - } else if (server != NULL) { + } else if (server != NULL && !no_old_server) { server->connrec->reconnection = TRUE; server->connrec->channels = channels; server->connrec->usermode = usermode; server->connrec->away_reason = away_reason; } g_free_not_null(ircnet); + g_free(params); } static void cmd_quit(const char *data) @@ -154,7 +177,7 @@ static void cmd_quit(const char *data) g_return_if_fail(data != NULL); quitmsg = *data != '\0' ? data : - settings_get_str("default_quit_message"); + settings_get_str("quit_message"); /* disconnect from every server */ for (tmp = servers; tmp != NULL; tmp = next) { @@ -646,7 +669,7 @@ static void cmd_knockout(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *i if (is_numeric(data, ' ')) { /* first argument is the timeout */ params = cmd_get_params(data, 3 | PARAM_FLAG_GETREST, &timeoutstr, &nick, &reason); - timeleft = atol(timeoutstr); + timeleft = atoi(timeoutstr); } else { timeleft = 0; params = cmd_get_params(data, 2 | PARAM_FLAG_GETREST, &nick, &reason); @@ -749,7 +772,7 @@ void irc_commands_init(void) { tmpstr = g_string_new(NULL); - settings_add_str("misc", "default_quit_message", "leaving"); + settings_add_str("misc", "quit_message", "leaving"); settings_add_int("misc", "knockout_time", 300); knockout_tag = g_timeout_add(KNOCKOUT_TIMECHECK, (GSourceFunc) knockout_timeout, NULL); diff --git a/src/irc/core/irc-log.c b/src/irc/core/irc-log.c index 3c9ef760..9871ee64 100644 --- a/src/irc/core/irc-log.c +++ b/src/irc/core/irc-log.c @@ -90,8 +90,8 @@ static void event_unaway(const char *data, IRC_SERVER_REC *server) void irc_log_init(void) { - settings_add_str("misc", "awaylog_file", "~/.irssi/away.log"); - settings_add_str("misc", "awaylog_level", "msgs hilight"); + settings_add_str("log", "awaylog_file", "~/.irssi/away.log"); + settings_add_str("log", "awaylog_level", "msgs hilight"); signal_add("print text stripped", (SIGNAL_FUNC) sig_log); signal_add("event 306", (SIGNAL_FUNC) event_away); diff --git a/src/irc/core/irc-server.c b/src/irc/core/irc-server.c index 2f9e9fb1..a21d9a1f 100644 --- a/src/irc/core/irc-server.c +++ b/src/irc/core/irc-server.c @@ -335,7 +335,7 @@ static int sig_set_user_mode(IRC_SERVER_REC *server) if (g_slist_find(servers, server) == NULL) return 0; /* got disconnected */ - mode = settings_get_str("default_user_mode"); + mode = settings_get_str("usermode"); newmode = server->usermode == NULL ? NULL : modes_join(server->usermode, mode); if (server->usermode == NULL || strcmp(newmode, server->usermode) != 0) @@ -369,7 +369,7 @@ static void event_connected(const char *data, IRC_SERVER_REC *server, const char if (!server->connrec->reconnection) { /* wait a second and then send the user mode */ - mode = settings_get_str("default_user_mode"); + mode = settings_get_str("usermode"); if (*mode != '\0') g_timeout_add(1000, (GSourceFunc) sig_set_user_mode, server); } @@ -414,7 +414,7 @@ static void event_empty(void) void irc_servers_init(void) { - settings_add_str("misc", "default_user_mode", DEFAULT_USER_MODE); + settings_add_str("misc", "usermode", DEFAULT_USER_MODE); settings_add_int("flood", "cmd_queue_speed", DEFAULT_CMD_QUEUE_SPEED); settings_add_int("flood", "cmds_max_at_once", DEFAULT_CMDS_MAX_AT_ONCE); diff --git a/src/irc/core/irc-server.h b/src/irc/core/irc-server.h index 21e3e73c..11172bea 100644 --- a/src/irc/core/irc-server.h +++ b/src/irc/core/irc-server.h @@ -120,6 +120,7 @@ typedef struct { GSList *lastmsgs; /* List of nicks who last send you msg */ GHashTable *splits; /* For keeping track of netsplits */ + GSList *split_servers; /* Servers that are currently in split */ time_t lag_sent; /* 0 or time when last lag query was sent to server */ time_t lag_last_check; /* last time we checked lag */ diff --git a/src/irc/core/irc.c b/src/irc/core/irc.c index c25f32b6..4e37d474 100644 --- a/src/irc/core/irc.c +++ b/src/irc/core/irc.c @@ -48,6 +48,7 @@ static void cmd_send(IRC_SERVER_REC *server, const char *cmd, int send_now, int /* just check that we don't send any longer commands than 512 bytes.. */ strncpy(str, cmd, 510); len = strlen(cmd); + if (len > 510) len = 510; str[len++] = 13; str[len++] = 10; str[len] = '\0'; ptr = str; diff --git a/src/irc/core/ircnet-setup.c b/src/irc/core/ircnet-setup.c index 0e19f3a5..8296a7e8 100644 --- a/src/irc/core/ircnet-setup.c +++ b/src/irc/core/ircnet-setup.c @@ -104,6 +104,7 @@ static void read_ircnets(void) void ircnets_setup_init(void) { + read_ircnets(); signal_add("setup reread", (SIGNAL_FUNC) read_ircnets); } diff --git a/src/irc/core/massjoin.c b/src/irc/core/massjoin.c index 3cd0d31a..51831a1a 100644 --- a/src/irc/core/massjoin.c +++ b/src/irc/core/massjoin.c @@ -20,7 +20,7 @@ #include "module.h" #include "signals.h" -#include "common-setup.h" +#include "settings.h" #include "channels.h" #include "irc.h" @@ -28,6 +28,7 @@ #include "irc-server.h" static int massjoin_tag; +static int massjoin_max_joins; /* Massjoin support - really useful when trying to do things (like op/deop) to people after netjoins. It sends @@ -210,7 +211,7 @@ static void server_check_massjoins(IRC_SERVER_REC *server, time_t max) continue; if (rec->massjoin_start < max || /* We've waited long enough */ - rec->massjoins-5 < rec->last_massjoins) { /* Less than 5 joins since last check */ + rec->massjoins-massjoin_max_joins < rec->last_massjoins) { /* Less than x joins since last check */ /* send them */ massjoin_send(rec); } else { @@ -226,21 +227,30 @@ static int sig_massjoin_timeout(void) GSList *tmp; time_t max; - max = time(NULL)-MAX_MASSJOIN_WAIT; + max = time(NULL)-settings_get_int("massjoin_max_wait"); for (tmp = servers; tmp != NULL; tmp = tmp->next) server_check_massjoins(tmp->data, max); return 1; } +static void read_settings(void) +{ + massjoin_max_joins = settings_get_int("massjoin_max_joins"); +} + void massjoin_init(void) { + settings_add_int("misc", "massjoin_max_wait", 5000); + settings_add_int("misc", "massjoin_max_joins", 3); massjoin_tag = g_timeout_add(1000, (GSourceFunc) sig_massjoin_timeout, NULL); + read_settings(); signal_add("event join", (SIGNAL_FUNC) event_join); signal_add("event part", (SIGNAL_FUNC) event_part); signal_add("event kick", (SIGNAL_FUNC) event_kick); signal_add("event quit", (SIGNAL_FUNC) event_quit); + signal_add("setup changed", (SIGNAL_FUNC) read_settings); } void massjoin_deinit(void) @@ -251,4 +261,5 @@ void massjoin_deinit(void) signal_remove("event part", (SIGNAL_FUNC) event_part); signal_remove("event kick", (SIGNAL_FUNC) event_kick); signal_remove("event quit", (SIGNAL_FUNC) event_quit); + signal_remove("setup changed", (SIGNAL_FUNC) read_settings); } diff --git a/src/irc/core/modes.c b/src/irc/core/modes.c index 9b5c8027..bd31d3ab 100644 --- a/src/irc/core/modes.c +++ b/src/irc/core/modes.c @@ -103,7 +103,7 @@ void parse_channel_modes(CHANNEL_REC *channel, const char *setby, const char *mo ptr = cmd_get_param(&modestr); if (*ptr == '\0') break; - if (strcmp(channel->server->nick, ptr) == 0) + if (g_strcasecmp(channel->server->nick, ptr) == 0) channel->chanop = type == '+' ? TRUE : FALSE; nick_mode_change(channel, ptr, '@', type == '+'); break; @@ -297,6 +297,9 @@ void channel_set_singlemode(IRC_SERVER_REC *server, const char *channel, const c nicklist = g_strsplit(nicks, " ", -1); for (nick = nicklist; *nick != NULL; nick++) { + if (*nick == '\0') + continue; + if (num == 0) { g_string_sprintf(str, "MODE %s %s", channel, mode); @@ -373,28 +376,94 @@ void channel_set_mode(IRC_SERVER_REC *server, const char *channel, const char *m g_free(orig); } -static void cmd_op(gchar *data, IRC_SERVER_REC *server, WI_IRC_REC *item) +static char *get_nicks(WI_IRC_REC *item, const char *data, int op, int voice) +{ + GString *str; + GSList *nicks, *tmp; + char **matches, **match, *ret; + + str = g_string_new(NULL); + matches = g_strsplit(data, " ", -1); + for (match = matches; *match != NULL; match++) { + if (strchr(*match, '*') == NULL && strchr(*match, '?') == NULL) { + /* no wildcards */ + g_string_sprintfa(str, "%s ", *match); + continue; + } + + /* wildcards */ + nicks = nicklist_find_multiple((CHANNEL_REC *) item, data); + for (tmp = nicks; tmp != NULL; tmp = tmp->next) { + NICK_REC *rec = tmp->data; + + if ((op == 1 && !rec->op) || (op == 0 && rec->op) || + (voice == 1 && !rec->voice) || (voice == 0 && rec->voice)) + continue; + + if (g_strcasecmp(rec->nick, item->server->nick) == 0) + continue; + + g_string_sprintfa(str, "%s ", rec->nick); + } + g_slist_free(nicks); + } + + g_string_truncate(str, str->len-1); + ret = str->str; + g_string_free(str, FALSE); + return ret; +} + +static void cmd_op(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item) { - if (!irc_item_channel(item)) return; - channel_set_singlemode(server, item->name, data, "+o"); + char *nicks; + + if (!irc_item_channel(item)) + return; + + nicks = get_nicks(item, data, 0, -1); + if (*nicks != '\0') + channel_set_singlemode(server, item->name, nicks, "+o"); + g_free(nicks); } static void cmd_deop(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item) { - if (!irc_item_channel(item)) return; - channel_set_singlemode(server, item->name, data, "-o"); + char *nicks; + + if (!irc_item_channel(item)) + return; + + nicks = get_nicks(item, data, 1, -1); + if (*nicks != '\0') + channel_set_singlemode(server, item->name, nicks, "-o"); + g_free(nicks); } static void cmd_voice(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item) { - if (!irc_item_channel(item)) return; - channel_set_singlemode(server, item->name, data, "+v"); + char *nicks; + + if (!irc_item_channel(item)) + return; + + nicks = get_nicks(item, data, 0, 0); + if (*nicks != '\0') + channel_set_singlemode(server, item->name, nicks, "+v"); + g_free(nicks); } static void cmd_devoice(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item) { - if (!irc_item_channel(item)) return; - channel_set_singlemode(server, item->name, data, "-v"); + char *nicks; + + if (!irc_item_channel(item)) + return; + + nicks = get_nicks(item, data, 0, 1); + if (*nicks != '\0') + channel_set_singlemode(server, item->name, nicks, "-v"); + g_free(nicks); } static void cmd_mode(const char *data, IRC_SERVER_REC *server, WI_IRC_REC *item) diff --git a/src/irc/core/netsplit.c b/src/irc/core/netsplit.c index b455f740..c5a4ff49 100644 --- a/src/irc/core/netsplit.c +++ b/src/irc/core/netsplit.c @@ -29,6 +29,46 @@ static int split_tag; +static NETSPLIT_SERVER_REC *netsplit_server_find(IRC_SERVER_REC *server, const char *servername, const char *destserver) +{ + GSList *tmp; + + for (tmp = server->split_servers; tmp != NULL; tmp = tmp->next) { + NETSPLIT_SERVER_REC *rec = tmp->data; + + if (g_strcasecmp(rec->server, servername) == 0 && + g_strcasecmp(rec->destserver, destserver) == 0) + return rec; + } + + return NULL; +} + +static NETSPLIT_SERVER_REC *netsplit_server_create(IRC_SERVER_REC *server, const char *servername, const char *destserver) +{ + NETSPLIT_SERVER_REC *rec; + + rec = netsplit_server_find(server, servername, destserver); + if (rec != NULL) return rec; + + rec = g_new0(NETSPLIT_SERVER_REC, 1); + rec->server = g_strdup(servername); + rec->destserver = g_strdup(destserver); + + server->split_servers = g_slist_append(server->split_servers, rec); + signal_emit("netsplit new server", 1, rec); + return rec; +} + +static void netsplit_destroy_server(IRC_SERVER_REC *server, NETSPLIT_SERVER_REC *rec) +{ + server->split_servers = g_slist_remove(server->split_servers, rec); + + g_free(rec->server); + g_free(rec->destserver); + g_free(rec); +} + static NETSPLIT_REC *netsplit_add(IRC_SERVER_REC *server, const char *nick, const char *address, const char *servers) { NETSPLIT_REC *rec; @@ -41,6 +81,7 @@ static NETSPLIT_REC *netsplit_add(IRC_SERVER_REC *server, const char *nick, cons g_return_val_if_fail(nick != NULL, NULL); g_return_val_if_fail(address != NULL, NULL); + /* get splitted servers */ dupservers = g_strdup(servers); p = strchr(dupservers, ' '); if (p == NULL) { @@ -54,9 +95,8 @@ static NETSPLIT_REC *netsplit_add(IRC_SERVER_REC *server, const char *nick, cons rec->address = g_strdup(address); rec->destroy = time(NULL)+NETSPLIT_MAX_REMEMBER; - /* get splitted servers */ - rec->server = g_strdup(dupservers); - rec->destserver = g_strdup(p); + rec->server = netsplit_server_create(server, dupservers, p); + rec->server->count++; g_free(dupservers); /* copy the channel nick records.. */ @@ -75,11 +115,12 @@ static NETSPLIT_REC *netsplit_add(IRC_SERVER_REC *server, const char *nick, cons } g_hash_table_insert(server->splits, rec->nick, rec); + signal_emit("netsplit add", 1, rec); return rec; } -static void netsplit_destroy(NETSPLIT_REC *rec) +static void netsplit_destroy(IRC_SERVER_REC *server, NETSPLIT_REC *rec) { GSList *tmp; @@ -93,16 +134,17 @@ static void netsplit_destroy(NETSPLIT_REC *rec) g_free(rec); } - g_free(rec->server); - g_free(rec->destserver); + if (--rec->server->count == 0) + netsplit_destroy_server(server, rec->server); + g_free(rec->nick); g_free(rec->address); g_free(rec); } -static void netsplit_destroy_hash(gpointer key, NETSPLIT_REC *rec) +static void netsplit_destroy_hash(void *key, NETSPLIT_REC *rec, IRC_SERVER_REC *server) { - netsplit_destroy(rec); + netsplit_destroy(server, rec); } NETSPLIT_REC *netsplit_find(IRC_SERVER_REC *server, const char *nick, const char *address) @@ -136,13 +178,15 @@ NICK_REC *netsplit_find_channel(IRC_SERVER_REC *server, const char *nick, const return NULL; } -static int is_split(const char *msg) +int quitmsg_is_split(const char *msg) { char *params, *host1, *host2, *p; int ok; g_return_val_if_fail(msg != NULL, FALSE); + if (msg[strlen(msg)-1] == ' ') msg[strlen(msg)-1] = '\0'; /*FIXME: remove - for debugging!*/ + /* must have only two words */ p = strchr(msg, ' '); if (p == NULL || strchr(p+1, ' ') != NULL) return FALSE; @@ -171,19 +215,19 @@ static int is_split(const char *msg) return ok; } -static void split_set_timeout(gpointer key, NETSPLIT_REC *rec, NETSPLIT_REC *orig) +static void split_set_timeout(void *key, NETSPLIT_REC *rec, NETSPLIT_REC *orig) { if (rec == orig) { /* original nick, destroy it in a few seconds.. */ rec->destroy = time(NULL)+4; - } else if (g_strcasecmp(rec->server, orig->server) == 0 && - g_strcasecmp(rec->destserver, orig->destserver) == 0) { + } else if (g_strcasecmp(rec->server->server, orig->server->server) == 0 && + g_strcasecmp(rec->server->destserver, orig->server->destserver) == 0) { /* same servers -> split over -> destroy old records sooner.. */ rec->destroy = time(NULL)+60; } } -static void event_join(gchar *data, IRC_SERVER_REC *server, gchar *nick, gchar *address) +static void event_join(const char *data, IRC_SERVER_REC *server, const char *nick, const char *address) { NETSPLIT_REC *rec; @@ -202,7 +246,7 @@ static void event_join(gchar *data, IRC_SERVER_REC *server, gchar *nick, gchar * } else { /* back from different address.. just destroy it. */ g_hash_table_remove(server->splits, rec->nick); - netsplit_destroy(rec); + netsplit_destroy(server, rec); } } @@ -211,7 +255,7 @@ static void event_quit(const char *data, IRC_SERVER_REC *server, const char *nic g_return_if_fail(data != NULL); if (*data == ':') data++; - if (g_strcasecmp(nick, server->nick) != 0 && is_split(data)) { + if (g_strcasecmp(nick, server->nick) != 0 && quitmsg_is_split(data)) { /* netsplit! */ netsplit_add(server, nick, address, data); } @@ -221,17 +265,17 @@ static void sig_disconnected(IRC_SERVER_REC *server) { g_return_if_fail(server != NULL); - g_hash_table_foreach(server->splits, (GHFunc) netsplit_destroy_hash, NULL); + g_hash_table_foreach(server->splits, (GHFunc) netsplit_destroy_hash, server); g_hash_table_destroy(server->splits); } -static int split_server_check(gpointer key, NETSPLIT_REC *rec, IRC_SERVER_REC *server) +static int split_server_check(void *key, NETSPLIT_REC *rec, IRC_SERVER_REC *server) { /* Check if this split record is too old.. */ if (rec->destroy > time(NULL)) return FALSE; - netsplit_destroy(rec); + netsplit_destroy(server, rec); return TRUE; } diff --git a/src/irc/core/netsplit.h b/src/irc/core/netsplit.h index c2d221da..c95b5c6f 100644 --- a/src/irc/core/netsplit.h +++ b/src/irc/core/netsplit.h @@ -4,10 +4,16 @@ #include "nicklist.h" typedef struct { - char *nick; - char *address; char *server; char *destserver; + int count; +} NETSPLIT_SERVER_REC; + +typedef struct { + NETSPLIT_SERVER_REC *server; + + char *nick; + char *address; GSList *channels; time_t destroy; @@ -24,4 +30,6 @@ void netsplit_deinit(void); NETSPLIT_REC *netsplit_find(IRC_SERVER_REC *server, const char *nick, const char *address); NICK_REC *netsplit_find_channel(IRC_SERVER_REC *server, const char *nick, const char *address, const char *channel); +int quitmsg_is_split(const char *msg); + #endif diff --git a/src/irc/core/nicklist.c b/src/irc/core/nicklist.c index a275d43e..b8947ee6 100644 --- a/src/irc/core/nicklist.c +++ b/src/irc/core/nicklist.c @@ -87,6 +87,22 @@ static NICK_REC *nicklist_find_wildcards(CHANNEL_REC *channel, const char *mask) return tmp == NULL ? NULL : nick; } +GSList *nicklist_find_multiple(CHANNEL_REC *channel, const char *mask) +{ + GSList *nicks, *tmp, *next; + + nicks = nicklist_getnicks(channel); + for (tmp = nicks; tmp != NULL; tmp = next) { + NICK_REC *nick = tmp->data; + + next = tmp->next; + if (!irc_mask_match_address(mask, nick->nick, nick->host == NULL ? "" : nick->host)) + nicks = g_slist_remove(nicks, tmp->data); + } + + return nicks; +} + /* Find nick record from list */ NICK_REC *nicklist_find(CHANNEL_REC *channel, const char *mask) { @@ -230,7 +246,7 @@ static void event_names_list(const char *data, IRC_SERVER_REC *server) while (*names != '\0' && *names != ' ') names++; if (*names != '\0') *names++ = '\0'; - if (*ptr == '@' && strcmp(server->nick, ptr+1) == 0) + if (*ptr == '@' && g_strcasecmp(server->nick, ptr+1) == 0) chanrec->chanop = TRUE; nicklist_insert(chanrec, ptr+isnickflag(*ptr), *ptr == '@', *ptr == '+', FALSE); @@ -390,7 +406,8 @@ static void event_nick_in_use(const char *data, IRC_SERVER_REC *server) } /* nick already in use - need to change it .. */ - if (strcmp(server->nick, server->connrec->nick) == 0) { + if (strcmp(server->nick, server->connrec->nick) == 0 && + server->connrec->alternate_nick != NULL) { /* first try, so try the alternative nick.. */ g_free(server->nick); server->nick = g_strdup(server->connrec->alternate_nick); diff --git a/src/irc/core/nicklist.h b/src/irc/core/nicklist.h index 8e83e97f..b5250d18 100644 --- a/src/irc/core/nicklist.h +++ b/src/irc/core/nicklist.h @@ -25,6 +25,8 @@ NICK_REC *nicklist_insert(CHANNEL_REC *channel, const char *nick, int op, int vo void nicklist_remove(CHANNEL_REC *channel, NICK_REC *nick); /* Find nick record from list */ NICK_REC *nicklist_find(CHANNEL_REC *channel, const char *mask); +/* Get list of nicks that match the mask */ +GSList *nicklist_find_multiple(CHANNEL_REC *channel, const char *mask); /* Get list of nicks */ GSList *nicklist_getnicks(CHANNEL_REC *channel); /* Get all the nick records of `nick'. Returns channel, nick, channel, ... */ diff --git a/src/irc/core/server-reconnect.c b/src/irc/core/server-reconnect.c index a00b32cf..3e1b993f 100644 --- a/src/irc/core/server-reconnect.c +++ b/src/irc/core/server-reconnect.c @@ -85,7 +85,7 @@ static int server_reconnect_timeout(void) static void sserver_connect(SETUP_SERVER_REC *rec, IRC_SERVER_CONNECT_REC *conn) { - conn->address = g_strdup(rec->server); + conn->address = g_strdup(rec->address); conn->port = rec->port; conn->password = rec->password == NULL ? NULL : g_strdup(rec->password); @@ -143,7 +143,6 @@ static void sig_reconnect(IRC_SERVER_REC *server) return; conn = g_new0(IRC_SERVER_CONNECT_REC, 1); - conn->reconnection = TRUE; server_connect_copy_skeleton(conn, server->connrec); /* save the server status */ @@ -152,6 +151,7 @@ static void sig_reconnect(IRC_SERVER_REC *server) conn->away_reason = g_strdup(server->connrec->away_reason); conn->usermode = g_strdup(server->connrec->usermode); } else { + conn->reconnection = TRUE; conn->channels = irc_server_get_channels(server); conn->away_reason = !server->usermode_away ? NULL : g_strdup(server->away_reason); @@ -213,7 +213,7 @@ static void sig_reconnect(IRC_SERVER_REC *server) for (tmp = setupservers; tmp != NULL; ) { SETUP_SERVER_REC *rec = tmp->data; - if (!found && g_strcasecmp(rec->server, server->connrec->address) == 0 && + if (!found && g_strcasecmp(rec->address, server->connrec->address) == 0 && server->connrec->port == rec->port) found = TRUE; else if (found && rec->ircnet != NULL && g_strcasecmp(conn->ircnet, rec->ircnet) == 0) { @@ -286,24 +286,36 @@ static RECONNECT_REC *reconnect_find_tag(int tag) } /* Try to reconnect immediately */ -static void cmd_reconnect(const char *data) +static void cmd_reconnect(const char *data, IRC_SERVER_REC *server) { IRC_SERVER_CONNECT_REC *conn; RECONNECT_REC *rec; + char *str; int tag; + if (*data == '\0') { + /* reconnect back to same server */ + if (server == NULL) cmd_return_error(CMDERR_NOT_CONNECTED); + str = g_strdup_printf("%s %d %s %s", server->connrec->address, + server->connrec->port, server->connrec->password, + server->connrec->nick); + signal_emit("command server", 2, str, server); + g_free(str); + return; + } + if (g_strncasecmp(data, "RECON-", 6) == 0) data += 6; - rec = sscanf(data, "%d", &tag) == 1 && tag > 0 ? - reconnect_find_tag(tag) : NULL; + tag = atoi(data); + rec = tag <= 0 ? NULL : reconnect_find_tag(tag); if (rec == NULL) signal_emit("server reconnect not found", 1, data); else { conn = rec->conn; server_reconnect_destroy(rec, FALSE); - irc_server_connect(rec->conn); + irc_server_connect(conn); } } diff --git a/src/irc/core/server-setup.c b/src/irc/core/server-setup.c index f56d839f..62c856cb 100644 --- a/src/irc/core/server-setup.c +++ b/src/irc/core/server-setup.c @@ -74,7 +74,7 @@ create_addr_conn(const char *address, int port, const char *password, conn->realname = g_strdup(settings_get_str("real_name")); /* proxy settings */ - if (settings_get_bool("toggle_use_ircproxy")) { + if (settings_get_bool("use_ircproxy")) { conn->proxy = g_strdup(settings_get_str("proxy_address")); conn->proxy_port = settings_get_int("proxy_port"); conn->proxy_string = g_strdup(settings_get_str("proxy_string")); @@ -91,6 +91,25 @@ create_addr_conn(const char *address, int port, const char *password, sserver = server_setup_find(address, -1); if (sserver == NULL) return conn; + if (sserver->own_ip != NULL) { + /* use already resolved IP */ + if (conn->own_ip == NULL) + conn->own_ip = g_new(IPADDR, 1); + memcpy(conn->own_ip, sserver->own_ip, sizeof(IPADDR)); + } else if (sserver->own_host != NULL) { + /* resolve the IP and use it */ + IPADDR ip; + + if (net_gethostname(sserver->own_host, &ip) == 0) { + if (conn->own_ip == NULL) + conn->own_ip = g_new(IPADDR, 1); + memcpy(conn->own_ip, &ip, sizeof(IPADDR)); + + sserver->own_ip = g_new(IPADDR, 1); + memcpy(sserver->own_ip, &ip, sizeof(IPADDR)); + } + } + sserver->last_connect = time(NULL); if (sserver->ircnet) conn->ircnet = g_strdup(sserver->ircnet); @@ -151,7 +170,7 @@ irc_server_create_conn(const char *dest, int port, const char *password, const c continue; if (n == 1 || !rec->last_failed || rec->last_connect < now-FAILED_RECONNECT_WAIT) - return create_addr_conn(rec->server, port, password, nick); + return create_addr_conn(rec->address, port, password, nick); } } @@ -168,7 +187,7 @@ SETUP_SERVER_REC *server_setup_find(const char *address, int port) for (tmp = setupservers; tmp != NULL; tmp = tmp->next) { SETUP_SERVER_REC *rec = tmp->data; - if (g_strcasecmp(rec->server, address) == 0 && + if (g_strcasecmp(rec->address, address) == 0 && (port == -1 || rec->port == port)) return rec; } @@ -223,19 +242,88 @@ static void init_userinfo(void) iconfig_set_str("settings", "alternate_nick", str); g_free(str); } + + /* host name */ + set = settings_get_str("hostname"); + if (set == NULL || *set == '\0') { + str = g_getenv("IRCHOST"); + if (str != NULL) { + iconfig_set_str("settings", "hostname", str); + g_free(str); + } + } +} + +void setupserver_config_add(SETUP_SERVER_REC *rec) +{ + CONFIG_NODE *node; + + node = iconfig_node_traverse("(servers", TRUE); + node = config_node_section(node, NULL, NODE_TYPE_BLOCK); + + config_node_set_str(node, "address", rec->address); + config_node_set_str(node, "ircnet", rec->ircnet); + + config_node_set_int(node, "port", rec->port); + config_node_set_str(node, "password", rec->password); + config_node_set_str(node, "own_host", rec->own_host); + + if (rec->autoconnect) + config_node_set_bool(node, "autoconnect", TRUE); + + if (rec->max_cmds_at_once > 0) + config_node_set_int(node, "cmds_max_at_once", rec->max_cmds_at_once); + if (rec->cmd_queue_speed > 0) + config_node_set_int(node, "cmd_queue_speed", rec->cmd_queue_speed); +} + +void setupserver_config_remove(SETUP_SERVER_REC *rec) +{ + CONFIG_NODE *node; + + node = iconfig_node_traverse("servers", FALSE); + if (node != NULL) config_node_list_remove(node, g_slist_index(setupservers, rec)); +} + +static void setupserver_destroy(SETUP_SERVER_REC *rec) +{ + setupservers = g_slist_remove(setupservers, rec); + + g_free_not_null(rec->own_host); + g_free_not_null(rec->own_ip); + g_free(rec->ircnet); + g_free(rec->address); + g_free(rec->password); + g_free(rec); +} + +void server_setup_add(SETUP_SERVER_REC *rec) +{ + if (g_slist_find(setupservers, rec) != NULL) { + setupserver_config_remove(rec); + setupservers = g_slist_append(setupservers, rec); + } + + setupservers = g_slist_append(setupservers, rec); + setupserver_config_add(rec); } -static SETUP_SERVER_REC *setupserver_add(CONFIG_NODE *node) +void server_setup_remove(SETUP_SERVER_REC *rec) +{ + setupserver_config_remove(rec); + setupserver_destroy(rec); +} + +static SETUP_SERVER_REC *setupserver_add_node(CONFIG_NODE *node) { SETUP_SERVER_REC *rec; - char *ircnet, *server; + char *server; int port; g_return_val_if_fail(node != NULL, NULL); - ircnet = config_node_get_str(node, "ircnet", NULL); - server = config_node_get_str(node, "server", NULL); - if (ircnet == NULL || server == NULL) return NULL; + server = config_node_get_str(node, "address", NULL); + if (server == NULL) return NULL; port = config_node_get_int(node, "port", 6667); if (server_setup_find(server, port) != NULL) { @@ -245,28 +333,19 @@ static SETUP_SERVER_REC *setupserver_add(CONFIG_NODE *node) } rec = g_new0(SETUP_SERVER_REC, 1); - rec->ircnet = g_strdup(ircnet); - rec->server = g_strdup(server); - rec->password = g_strdup(config_node_get_str(node, "password", "")); + rec->ircnet = g_strdup(config_node_get_str(node, "ircnet", NULL)); + rec->address = g_strdup(server); + rec->password = g_strdup(config_node_get_str(node, "password", NULL)); rec->port = port; rec->autoconnect = config_node_get_bool(node, "autoconnect", FALSE); rec->max_cmds_at_once = config_node_get_int(node, "cmds_max_at_once", 0); rec->cmd_queue_speed = config_node_get_int(node, "cmd_queue_speed", 0); + rec->own_host = g_strdup(config_node_get_str(node, "own_host", 0)); setupservers = g_slist_append(setupservers, rec); return rec; } -static void setupserver_destroy(SETUP_SERVER_REC *rec) -{ - setupservers = g_slist_remove(setupservers, rec); - - g_free(rec->ircnet); - g_free(rec->server); - g_free(rec->password); - g_free(rec); -} - static void read_servers(void) { CONFIG_NODE *node; @@ -276,10 +355,10 @@ static void read_servers(void) setupserver_destroy(setupservers->data); /* Read servers */ - node = iconfig_node_traverse("(setupservers", FALSE); + node = iconfig_node_traverse("servers", FALSE); if (node != NULL) { for (tmp = node->value; tmp != NULL; tmp = tmp->next) - setupserver_add(tmp->data); + setupserver_add_node(tmp->data); } } @@ -290,14 +369,14 @@ void servers_setup_init(void) settings_add_int("server", "server_reconnect_time", 300); settings_add_str("server", "hostname", ""); - settings_add_bool("server", "toggle_skip_motd", FALSE); + settings_add_bool("server", "skip_motd", FALSE); settings_add_str("server", "default_nick", NULL); settings_add_str("server", "alternate_nick", NULL); settings_add_str("server", "user_name", NULL); settings_add_str("server", "real_name", NULL); - settings_add_bool("ircproxy", "toggle_use_ircproxy", FALSE); + settings_add_bool("ircproxy", "use_ircproxy", FALSE); settings_add_str("ircproxy", "proxy_address", ""); settings_add_int("ircproxy", "proxy_port", 6667); settings_add_str("ircproxy", "proxy_string", "CONNECT %s %d"); diff --git a/src/irc/core/server-setup.h b/src/irc/core/server-setup.h index a3a3d4ff..5c893044 100644 --- a/src/irc/core/server-setup.h +++ b/src/irc/core/server-setup.h @@ -5,7 +5,7 @@ /* servers */ typedef struct { - char *server; + char *address; int port; char *ircnet; @@ -14,8 +14,8 @@ typedef struct { int max_cmds_at_once; /* override the default if > 0 */ int cmd_queue_speed; /* override the default if > 0 */ - char *own_address; /* address to use when connecting this server */ - IPADDR *own_ip; /* resolved own_address or full of zeros */ + char *own_host; /* address to use when connecting this server */ + IPADDR *own_ip; /* resolved own_address if not NULL */ time_t last_connect; /* to avoid reconnecting too fast.. */ int last_failed; /* if last connection attempt failed */ @@ -31,6 +31,9 @@ extern gboolean source_host_ok; /* Use source_host_ip .. */ IRC_SERVER_CONNECT_REC * irc_server_create_conn(const char *dest, int port, const char *password, const char *nick); +void server_setup_add(SETUP_SERVER_REC *rec); +void server_setup_remove(SETUP_SERVER_REC *rec); + /* Find matching server from setup. Set port to -1 if you don't care about it */ SETUP_SERVER_REC *server_setup_find(const char *address, int port); diff --git a/src/irc/dcc/Makefile.am b/src/irc/dcc/Makefile.am index b7cd30e9..6e2b68c7 100644 --- a/src/irc/dcc/Makefile.am +++ b/src/irc/dcc/Makefile.am @@ -9,6 +9,4 @@ libirc_dcc_la_SOURCES = \ dcc-files.c noinst_HEADERS = \ - dcc.h \ - dcc-chat.h \ - dcc-files.h + dcc.h diff --git a/src/irc/dcc/dcc-chat.c b/src/irc/dcc/dcc-chat.c index 5cddddfa..c01077d3 100644 --- a/src/irc/dcc/dcc-chat.c +++ b/src/irc/dcc/dcc-chat.c @@ -307,7 +307,7 @@ static void cmd_dcc_chat(gchar *data, IRC_SERVER_REC *server) if (server == NULL || !server->connected) cmd_return_error(CMDERR_NOT_CONNECTED); - if (!net_getsockname(server->handle, &addr, NULL)) + if (net_getsockname(server->handle, &addr, NULL) == -1) cmd_return_error(CMDERR_GETSOCKNAME); port = settings_get_int("dcc_port"); diff --git a/src/irc/dcc/dcc-chat.h b/src/irc/dcc/dcc-chat.h deleted file mode 100644 index 9ae9503f..00000000 --- a/src/irc/dcc/dcc-chat.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef __DCC_CHAT_H -#define __DCC_CHAT_H - -void dcc_chat_init(void); -void dcc_chat_deinit(void); - -#endif diff --git a/src/irc/dcc/dcc-files.c b/src/irc/dcc/dcc-files.c index 23b1cdce..da395196 100644 --- a/src/irc/dcc/dcc-files.c +++ b/src/irc/dcc/dcc-files.c @@ -432,7 +432,7 @@ static void dcc_send_init(DCC_REC *dcc) g_source_remove(dcc->tagread); close(dcc->handle); - dcc->fastsend = settings_get_bool("toggle_dcc_fast_send"); + dcc->fastsend = settings_get_bool("dcc_fast_send"); dcc->handle = handle; memcpy(&dcc->addr, &addr, sizeof(IPADDR)); net_ip2host(&dcc->addr, dcc->addrstr); diff --git a/src/irc/dcc/dcc-files.h b/src/irc/dcc/dcc-files.h deleted file mode 100644 index 3d12ffc1..00000000 --- a/src/irc/dcc/dcc-files.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef __DCC_FILES_H -#define __DCC_FILES_H - -void dcc_files_init(void); -void dcc_files_deinit(void); - -#endif diff --git a/src/irc/dcc/dcc.c b/src/irc/dcc/dcc.c index 41833744..1c02e65a 100644 --- a/src/irc/dcc/dcc.c +++ b/src/irc/dcc/dcc.c @@ -30,6 +30,12 @@ #include "dcc.h" +void dcc_chat_init(void); +void dcc_chat_deinit(void); + +void dcc_files_init(void); +void dcc_files_deinit(void); + #define DCC_TYPES 5 static gchar *dcc_types[] = @@ -55,7 +61,7 @@ DCC_REC *dcc_create(gint type, gint handle, gchar *nick, gchar *arg, IRC_SERVER_ dcc = g_new0(DCC_REC, 1); dcc->type = type == DCC_TYPE_CHAT ? module_get_uniq_id("IRC", WI_IRC_DCC_CHAT) : -1; - dcc->mirc_ctcp = settings_get_bool("toggle_dcc_mirc_ctcp"); + dcc->mirc_ctcp = settings_get_bool("dcc_mirc_ctcp"); dcc->created = time(NULL); dcc->chat = chat; dcc->dcc_type = type; @@ -307,7 +313,7 @@ static void dcc_ctcp_msg(gchar *data, IRC_SERVER_REC *server, gchar *sender, gch case DCC_TYPE_GET: cstr = settings_get_str("dcc_autoget_masks"); /* check that autoget masks match */ - if (settings_get_bool("toggle_dcc_autoget") && (*cstr == '\0' || irc_masks_match(cstr, sender, sendaddr)) && + if (settings_get_bool("dcc_autoget") && (*cstr == '\0' || irc_masks_match(cstr, sender, sendaddr)) && /* check file size limit, FIXME: it's possible to send a bogus file size and then just send what ever sized file.. */ (settings_get_int("dcc_max_autoget_size") <= 0 || (settings_get_int("dcc_max_autoget_size") > 0 && size <= settings_get_int("dcc_max_autoget_size")*1024))) { @@ -507,19 +513,19 @@ void dcc_init(void) dcc_conns = NULL; dcc_timeouttag = g_timeout_add(1000, (GSourceFunc) dcc_timeout_func, NULL); - settings_add_bool("dcc", "toggle_dcc_autorename", FALSE); - settings_add_bool("dcc", "toggle_dcc_autogete", FALSE); + settings_add_bool("dcc", "dcc_autorename", FALSE); + settings_add_bool("dcc", "dcc_autoget", FALSE); settings_add_int("dcc", "dcc_max_autoget_size", 1000); settings_add_str("dcc", "dcc_download_path", "~"); settings_add_int("dcc", "dcc_file_create_mode", 644); settings_add_str("dcc", "dcc_autoget_masks", ""); settings_add_str("dcc", "dcc_autochat_masks", ""); - settings_add_bool("dcc", "toggle_dcc_fast_send", TRUE); + settings_add_bool("dcc", "dcc_fast_send", TRUE); settings_add_str("dcc", "dcc_upload_path", "~"); - settings_add_bool("dcc", "toggle_dcc_mirc_ctcp", FALSE); - settings_add_bool("dcc", "toggle_dcc_autodisplay_dialog", TRUE); + settings_add_bool("dcc", "dcc_mirc_ctcp", FALSE); + settings_add_bool("dcc", "dcc_autodisplay_dialog", TRUE); settings_add_int("dcc", "dcc_block_size", 2048); settings_add_int("dcc", "dcc_port", 0); settings_add_int("dcc", "dcc_timeout", 300); @@ -531,10 +537,16 @@ void dcc_init(void) command_bind("dcc", NULL, (SIGNAL_FUNC) cmd_dcc); command_bind("dcc close", NULL, (SIGNAL_FUNC) cmd_dcc_close); signal_add("event 401", (SIGNAL_FUNC) event_no_such_nick); + + dcc_chat_init(); + dcc_files_init(); } void dcc_deinit(void) { + dcc_chat_deinit(); + dcc_files_deinit(); + signal_remove("server connected", (SIGNAL_FUNC) dcc_server_connected); signal_remove("server disconnected", (SIGNAL_FUNC) dcc_server_disconnected); signal_remove("ctcp reply dcc", (SIGNAL_FUNC) dcc_ctcp_reply); diff --git a/src/irc/flood/autoignore.c b/src/irc/flood/autoignore.c index 528ac618..da384dd9 100644 --- a/src/irc/flood/autoignore.c +++ b/src/irc/flood/autoignore.c @@ -217,11 +217,11 @@ int autoignore_remove(IRC_SERVER_REC *server, const char *mask, int level) return FALSE; } -static void sig_flood(IRC_SERVER_REC *server, const char *nick, const char *host, const char *levelstr) +static void sig_flood(IRC_SERVER_REC *server, const char *nick, const char *host, gpointer levelp) { int level, check_level; - level = level2bits(levelstr); + level = GPOINTER_TO_INT(levelp); check_level = level2bits(settings_get_str("autoignore_levels")); if (level & check_level) diff --git a/src/irc/flood/flood.c b/src/irc/flood/flood.c index 5522243e..7fb4773d 100644 --- a/src/irc/flood/flood.c +++ b/src/irc/flood/flood.c @@ -1,8 +1,7 @@ /* + flood.c : Flood protection - flood.c : Flood protection (see also ctcp.c) - - Copyright (C) 1999 Timo Sirainen + 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 @@ -32,36 +31,59 @@ #include "ignore.h" typedef struct { - char *nick; + char *target; int level; + int msgcount; + time_t first; +} FLOOD_ITEM_REC; + +typedef struct { + char *nick; + GSList *items; } FLOOD_REC; static int flood_tag; -static int flood_max_msgs; +static int flood_max_msgs, flood_timecheck; -static int flood_hash_deinit(const char *key, FLOOD_REC *rec) +static int flood_hash_deinit(const char *key, FLOOD_REC *flood, gpointer nowp) { + GSList *tmp, *next; + time_t now; + g_return_val_if_fail(key != NULL, FALSE); - g_return_val_if_fail(rec != NULL, FALSE); + g_return_val_if_fail(flood != NULL, FALSE); + + now = (time_t) GPOINTER_TO_INT(nowp); + for (tmp = flood->items; tmp != NULL; tmp = next) { + FLOOD_ITEM_REC *rec = tmp->data; - g_free(rec->nick); - g_free(rec); + next = tmp->next; + if (now-rec->first >= flood_timecheck) + flood->items = g_slist_remove(flood->items, rec); + } + + if (flood->items != NULL) + return FALSE; + + g_free(flood->nick); + g_free(flood); return TRUE; } -/* timeout function: flood protection */ static int flood_timeout(void) { MODULE_SERVER_REC *mserver; GSList *tmp; + time_t now; - /* remove everyone from flood list */ + /* remove the old people from flood lists */ + now = time(NULL); for (tmp = servers; tmp != NULL; tmp = tmp->next) { IRC_SERVER_REC *rec = tmp->data; mserver = MODULE_DATA(rec); - g_hash_table_foreach_remove(mserver->floodlist, (GHRFunc) flood_hash_deinit, NULL); + g_hash_table_foreach_remove(mserver->floodlist, (GHRFunc) flood_hash_deinit, GINT_TO_POINTER((int) now)); } return 1; } @@ -88,6 +110,8 @@ static void flood_deinit_server(IRC_SERVER_REC *server) mserver = MODULE_DATA(server); if (mserver != NULL && mserver->floodlist != NULL) { + flood_timecheck = 0; + g_hash_table_freeze(mserver->floodlist); g_hash_table_foreach(mserver->floodlist, (GHFunc) flood_hash_deinit, NULL); g_hash_table_thaw(mserver->floodlist); @@ -96,34 +120,55 @@ static void flood_deinit_server(IRC_SERVER_REC *server) g_free(mserver); } +static FLOOD_ITEM_REC *flood_find(FLOOD_REC *flood, int level, const char *target) +{ + GSList *tmp; + + for (tmp = flood->items; tmp != NULL; tmp = tmp->next) { + FLOOD_ITEM_REC *rec = tmp->data; + + if (rec->level == level && g_strcasecmp(rec->target, target) == 0) + return rec; + } + + return NULL; +} + /* All messages should go through here.. */ static void flood_newmsg(IRC_SERVER_REC *server, int level, const char *nick, const char *host, const char *target) { MODULE_SERVER_REC *mserver; - FLOOD_REC *rec; - char *levelstr; + FLOOD_REC *flood; + FLOOD_ITEM_REC *rec; g_return_if_fail(server != NULL); g_return_if_fail(nick != NULL); mserver = MODULE_DATA(server); - rec = g_hash_table_lookup(mserver->floodlist, nick); + flood = g_hash_table_lookup(mserver->floodlist, nick); + + rec = flood == NULL ? NULL : flood_find(flood, level, target); if (rec != NULL) { if (++rec->msgcount > flood_max_msgs) { /* flooding! */ - levelstr = bits2level(rec->level); - signal_emit("flood", 5, server, nick, host, levelstr, target); - g_free(levelstr); + signal_emit("flood", 5, server, nick, host, GINT_TO_POINTER(rec->level), target); } return; } - rec = g_new(FLOOD_REC, 1); + if (flood == NULL) { + flood = g_new0(FLOOD_REC, 1); + flood->nick = g_strdup(nick); + g_hash_table_insert(mserver->floodlist, flood->nick, flood); + } + + rec = g_new0(FLOOD_ITEM_REC, 1); rec->level = level; + rec->first = time(NULL); rec->msgcount = 1; - rec->nick = g_strdup(nick); + rec->target = g_strdup(target); - g_hash_table_insert(mserver->floodlist, rec->nick, rec); + flood->items = g_slist_append(flood->items, rec); } static void flood_privmsg(const char *data, IRC_SERVER_REC *server, const char *nick, const char *addr) @@ -141,7 +186,7 @@ static void flood_privmsg(const char *data, IRC_SERVER_REC *server, const char * params = event_get_params(data, 2, &target, &text); - if (*text == 1) { + if (*text == 1 && g_strncasecmp(text+1, "ACTION", 6) != 0) { /* CTCP */ if (!ignore_check(server, nick, addr, target, text, MSGLEVEL_CTCPS)) flood_newmsg(server, MSGLEVEL_CTCPS, nick, addr, target); @@ -176,24 +221,37 @@ static void flood_notice(const char *data, IRC_SERVER_REC *server, const char *n static void read_settings(void) { - if (flood_tag != -1) g_source_remove(flood_tag); - flood_tag = g_timeout_add(settings_get_int("flood_timecheck"), (GSourceFunc) flood_timeout, NULL); + int time; + flood_timecheck = settings_get_int("flood_timecheck"); flood_max_msgs = settings_get_int("flood_max_msgs"); + + time = flood_timecheck > 500 ? 500 : + (flood_timecheck > 0 && flood_timecheck < 100) ? 100 : + flood_timecheck; + + if (flood_tag != -1) { + g_source_remove(flood_tag); + flood_tag = -1; + } + + if (time > 0 && flood_max_msgs > 0) { + flood_tag = g_timeout_add(time, (GSourceFunc) flood_timeout, NULL); + signal_add("event privmsg", (SIGNAL_FUNC) flood_privmsg); + signal_add("event notice", (SIGNAL_FUNC) flood_notice); + } } void flood_init(void) { - settings_add_int("flood", "flood_timecheck", 1000); - settings_add_int("flood", "flood_max_msgs", 5); + settings_add_int("flood", "flood_timecheck", 5000); + settings_add_int("flood", "flood_max_msgs", 4); flood_tag = -1; read_settings(); signal_add("setup changed", (SIGNAL_FUNC) read_settings); signal_add_first("server connected", (SIGNAL_FUNC) flood_init_server); signal_add("server disconnected", (SIGNAL_FUNC) flood_deinit_server); - signal_add("event privmsg", (SIGNAL_FUNC) flood_privmsg); - signal_add("event notice", (SIGNAL_FUNC) flood_notice); autoignore_init(); } @@ -202,11 +260,13 @@ void flood_deinit(void) { autoignore_deinit(); - if (flood_tag != -1) g_source_remove(flood_tag); + if (flood_tag != -1) { + g_source_remove(flood_tag); + signal_remove("event privmsg", (SIGNAL_FUNC) flood_privmsg); + signal_remove("event notice", (SIGNAL_FUNC) flood_notice); + } signal_remove("setup changed", (SIGNAL_FUNC) read_settings); signal_remove("server connected", (SIGNAL_FUNC) flood_init_server); signal_remove("server disconnected", (SIGNAL_FUNC) flood_deinit_server); - signal_remove("event privmsg", (SIGNAL_FUNC) flood_privmsg); - signal_remove("event notice", (SIGNAL_FUNC) flood_notice); } diff --git a/src/irc/notifylist/notify-commands.c b/src/irc/notifylist/notify-commands.c index 9ae5a076..af022dcd 100644 --- a/src/irc/notifylist/notify-commands.c +++ b/src/irc/notifylist/notify-commands.c @@ -42,7 +42,7 @@ static void cmd_notify(gchar *data) if (stristr(args, "-idle") == NULL) idle_check_time = 0; else { - idle_check_time = is_numeric(idletime, 0) ? (atol(idletime)*60) : + idle_check_time = is_numeric(idletime, 0) ? (atoi(idletime)*60) : (settings_get_int("notify_idle_time")*60); } diff --git a/src/irc/notifylist/notify-whois.c b/src/irc/notifylist/notify-whois.c index 439a8af8..c8191b57 100644 --- a/src/irc/notifylist/notify-whois.c +++ b/src/irc/notifylist/notify-whois.c @@ -78,7 +78,7 @@ static void event_whois_idle(const char *data, IRC_SERVER_REC *server) g_return_if_fail(data != NULL); params = event_get_params(data, 3, NULL, &nick, &secstr); - secs = atol(secstr); + secs = atoi(secstr); notify = notifylist_find(nick, server->connrec->ircnet); nickrec = notify_nick_find(server, nick); diff --git a/src/perl/irssi-perl.c b/src/perl/irssi-perl.c index 49373684..e4f616e9 100644 --- a/src/perl/irssi-perl.c +++ b/src/perl/irssi-perl.c @@ -68,7 +68,9 @@ static void perl_signal_destroy(PERL_SIGNAL_REC *rec) { GHashTable *table; GSList *siglist; - void *signal_idp; + void *signal_idp; + + g_return_if_fail(rec != NULL); table = rec->last ? last_signals : first_signals; signal_idp = GINT_TO_POINTER(rec->signal_id); @@ -138,13 +140,14 @@ static void irssi_perl_start(void) static void signal_destroy_hash(void *key, GSList *list) { - GSList *next; - while (list != NULL) { - next = list->next; + PERL_SIGNAL_REC *rec = list->data; + + list = g_slist_remove(list, rec); - perl_signal_destroy(list->data); - list = next; + g_free(rec->signal); + g_free(rec->func); + g_free(rec); } } @@ -154,6 +157,17 @@ static void irssi_perl_stop(void) g_hash_table_destroy(first_signals); g_hash_table_foreach(last_signals, (GHFunc) signal_destroy_hash, NULL); g_hash_table_destroy(last_signals); + first_signals = last_signals = NULL; + + if (signal_grabbed) { + signal_grabbed = FALSE; + signal_remove("signal", (SIGNAL_FUNC) sig_signal); + } + + if (siglast_grabbed) { + siglast_grabbed = FALSE; + signal_remove("last signal", (SIGNAL_FUNC) sig_lastsignal); + } while (perl_timeouts != NULL) perl_timeout_destroy(perl_timeouts->data); @@ -222,12 +236,37 @@ static void cmd_flush(const char *data) irssi_perl_start(); } +static int perl_signal_find(const char *signal, const char *func, int last) +{ + GHashTable *table; + GSList *siglist; + int signal_id; + + table = last ? last_signals : first_signals; + + signal_id = module_get_uniq_id_str("signals", signal); + siglist = g_hash_table_lookup(table, GINT_TO_POINTER(signal_id)); + + while (siglist != NULL) { + PERL_SIGNAL_REC *rec = siglist->data; + + if (strcmp(rec->func, func) == 0) + return TRUE; + siglist = siglist->next; + } + + return FALSE; +} + static void perl_signal_to(const char *signal, const char *func, int last) { PERL_SIGNAL_REC *rec; GHashTable *table; GSList *siglist; - void *signal_idp; + void *signal_idp; + + if (perl_signal_find(signal, func, last)) + return; rec = g_new(PERL_SIGNAL_REC, 1); rec->signal_id = module_get_uniq_id_str("signals", signal); diff --git a/src/perl/xs/Irssi-core.xs b/src/perl/xs/Irssi-core.xs index b7cdcb6d..324637ae 100644 --- a/src/perl/xs/Irssi-core.xs +++ b/src/perl/xs/Irssi-core.xs @@ -88,8 +88,18 @@ command_bind(cmd, category, func) char *func CODE: char *signal; + GSList *tmp; - command_bind(cmd, *category ? category : "Perl scripts' commands", NULL); + /* Don't add the command twice */ + if (*category == '\0') category = "Perl scripts' commands"; + for (tmp = commands; tmp != NULL; tmp = tmp->next) { + COMMAND_REC *rec = tmp->data; + + if (g_strcasecmp(rec->cmd, cmd) == 0 && + g_strcasecmp(rec->category, category) == 0) + break; + } + if (tmp == NULL) command_bind(cmd, category, NULL); signal = g_strconcat("command ", cmd, NULL); perl_signal_add(signal, func); g_free(signal); @@ -101,7 +111,6 @@ command_unbind(cmd, func) CODE: char *signal; - command_unbind(cmd, NULL); signal = g_strconcat("command ", cmd, NULL); perl_signal_remove(signal, func); g_free(signal); diff --git a/src/perl/xs/Irssi-netsplit.xs b/src/perl/xs/Irssi-netsplit.xs index 0c1e998f..428cb61a 100644 --- a/src/perl/xs/Irssi-netsplit.xs +++ b/src/perl/xs/Irssi-netsplit.xs @@ -22,13 +22,30 @@ void values(netsplit) Irssi::Netsplit netsplit PREINIT: - HV *hv; + HV *hv, *stash; PPCODE: hv = newHV(); hv_store(hv, "nick", 4, new_pv(netsplit->nick), 0); hv_store(hv, "address", 7, new_pv(netsplit->address), 0); - hv_store(hv, "server", 6, new_pv(netsplit->server), 0); - hv_store(hv, "destserver", 10, new_pv(netsplit->destserver), 0); hv_store(hv, "destroy", 7, newSViv(netsplit->destroy), 0); + + stash = gv_stashpv("Irssi::Netsplitserver", 0); + hv_store(hv, "server", 6, sv_bless(newRV_noinc(newSViv(GPOINTER_TO_INT(netsplit->server))), stash), 0); /*FIXME: add GSList *channels;*/ XPUSHs(sv_2mortal(newRV_noinc((SV*)hv))); + +#******************************* +MODULE = Irssi PACKAGE = Irssi::Netsplitserver +#******************************* + +void +values(rec) + Irssi::Netsplitserver rec +PREINIT: + HV *hv; +PPCODE: + hv = newHV(); + hv_store(hv, "server", 6, new_pv(rec->server), 0); + hv_store(hv, "destserver", 10, new_pv(rec->destserver), 0); + hv_store(hv, "count", 5, newSViv(rec->count), 0); + XPUSHs(sv_2mortal(newRV_noinc((SV*)hv))); diff --git a/src/perl/xs/Irssi-server.xs b/src/perl/xs/Irssi-server.xs index 326b8d99..f53527ec 100644 --- a/src/perl/xs/Irssi-server.xs +++ b/src/perl/xs/Irssi-server.xs @@ -53,7 +53,7 @@ void values(server) Irssi::Server server PREINIT: - HV *hv, *stash; + HV *hv; char *type; PPCODE: type = "IRC"; diff --git a/src/perl/xs/module.h b/src/perl/xs/module.h index 350f3de0..3a55f787 100644 --- a/src/perl/xs/module.h +++ b/src/perl/xs/module.h @@ -44,6 +44,7 @@ typedef RECONNECT_REC *Irssi__Reconnect; typedef NICK_REC *Irssi__Nick; typedef BAN_REC *Irssi__Ban; typedef NETSPLIT_REC *Irssi__Netsplit; +typedef NETSPLIT_SERVER_REC *Irssi__Netsplitserver; typedef IGNORE_REC *Irssi__Ignore; typedef DCC_REC *Irssi__Dcc; diff --git a/src/perl/xs/typemap b/src/perl/xs/typemap index 0e61ce06..5173ebe4 100644 --- a/src/perl/xs/typemap +++ b/src/perl/xs/typemap @@ -9,6 +9,7 @@ Irssi::Nick T_PTROBJ Irssi::Ban T_PTROBJ Irssi::Dcc T_PTROBJ Irssi::Netsplit T_PTROBJ +Irssi::Netsplitserver T_PTROBJ Irssi::Autoignore T_PTROBJ Irssi::Log T_PTROBJ Irssi::Rawlog T_PTROBJ -- cgit v1.2.3