summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
authorSebastien Helleu <flashcode@flashtux.org>2007-10-31 17:00:31 +0100
committerSebastien Helleu <flashcode@flashtux.org>2007-10-31 17:00:31 +0100
commiteb2835fa24d510a46f8616855624f7ac1ddd19b8 (patch)
tree558e2ea1916ea5873c166167bbdd493f2cdcc40b /src/core
parent7fd804eab584711da59aec59a84dbb3c5429c652 (diff)
downloadweechat-eb2835fa24d510a46f8616855624f7ac1ddd19b8.zip
Moved files from src/common to core, gui and plugins directories
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt28
-rw-r--r--src/core/Makefile.am48
-rw-r--r--src/core/wee-alias.c376
-rw-r--r--src/core/wee-alias.h47
-rw-r--r--src/core/wee-backtrace.c176
-rw-r--r--src/core/wee-backtrace.h27
-rw-r--r--src/core/wee-command.c4521
-rw-r--r--src/core/wee-command.h86
-rw-r--r--src/core/wee-config.c2597
-rw-r--r--src/core/wee-config.h291
-rw-r--r--src/core/wee-list.c241
-rw-r--r--src/core/wee-list.h43
-rw-r--r--src/core/wee-log.c233
-rw-r--r--src/core/wee-log.h31
-rw-r--r--src/core/wee-upgrade.c1867
-rw-r--r--src/core/wee-upgrade.h205
-rw-r--r--src/core/wee-utf8.c426
-rw-r--r--src/core/wee-utf8.h50
-rw-r--r--src/core/wee-util.c730
-rw-r--r--src/core/wee-util.h41
-rw-r--r--src/core/weechat.c884
-rw-r--r--src/core/weechat.h121
22 files changed, 13069 insertions, 0 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
new file mode 100644
index 000000000..8f48d90b2
--- /dev/null
+++ b/src/core/CMakeLists.txt
@@ -0,0 +1,28 @@
+# Copyright (c) 2003-2007 FlashCode <flashcode@flashtux.org>
+#
+# 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 3 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, see <http://www.gnu.org/licenses/>.
+#
+
+SET(LIB_MAIN_SRC weechat.c weechat.h alias.c alias.h backtrace.c backtrace.h
+command.c command.h completion.c completion.h weelist.c weelist.h weeconfig.c
+weeconfig.h history.c history.h hotlist.c hotlist.h log.c log.h fifo.c fifo.h
+session.c session.h utf8.c utf8.h util.c util.h)
+
+# Check for flock support
+INCLUDE(CheckSymbolExists)
+CHECK_INCLUDE_FILES("sys/file.h" HAVE_SYS_FILE_H)
+CHECK_SYMBOL_EXISTS(flock "sys/file.h" HAVE_FLOCK)
+
+INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR})
+ADD_LIBRARY(weechat_main STATIC ${LIB_MAIN_SRC})
diff --git a/src/core/Makefile.am b/src/core/Makefile.am
new file mode 100644
index 000000000..ca0701c73
--- /dev/null
+++ b/src/core/Makefile.am
@@ -0,0 +1,48 @@
+# Copyright (c) 2003-2007 FlashCode <flashcode@flashtux.org>
+#
+# 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 3 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, see <http://www.gnu.org/licenses/>.
+#
+
+INCLUDES = -DLOCALEDIR=\"$(datadir)/locale\" $(GNUTLS_CFLAGS)
+
+noinst_LIBRARIES = lib_weechat_main.a
+
+lib_weechat_main_a_SOURCES = weechat.c \
+ weechat.h \
+ alias.c \
+ alias.h \
+ backtrace.c \
+ backtrace.h \
+ command.c \
+ command.h \
+ completion.c \
+ completion.h \
+ weelist.c \
+ weelist.h \
+ weeconfig.c \
+ weeconfig.h \
+ history.c \
+ history.h \
+ hotlist.c \
+ hotlist.h \
+ log.c \
+ log.h \
+ fifo.c \
+ fifo.h \
+ session.c \
+ session.h \
+ utf8.c \
+ utf8.h \
+ util.c \
+ util.h
diff --git a/src/core/wee-alias.c b/src/core/wee-alias.c
new file mode 100644
index 000000000..4a8919f35
--- /dev/null
+++ b/src/core/wee-alias.c
@@ -0,0 +1,376 @@
+/*
+ * Copyright (c) 2003-2007 by FlashCode <flashcode@flashtux.org>
+ * See README for License detail, AUTHORS for developers list.
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/* alias.c: WeeChat alias */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "weechat.h"
+#include "alias.h"
+#include "util.h"
+#include "../protocols/irc/irc.h"
+
+
+t_weechat_alias *weechat_alias = NULL;
+t_weechat_alias *weechat_last_alias = NULL;
+
+
+/*
+ * alias_search: search an alias
+ */
+
+t_weechat_alias *
+alias_search (char *alias_name)
+{
+ t_weechat_alias *ptr_alias;
+
+ for (ptr_alias = weechat_alias; ptr_alias; ptr_alias = ptr_alias->next_alias)
+ {
+ if (ascii_strcasecmp (alias_name, ptr_alias->alias_name) == 0)
+ return ptr_alias;
+ }
+ return NULL;
+}
+
+/*
+ * alias_find_pos: find position for an alias (for sorting aliases)
+ */
+
+t_weechat_alias *
+alias_find_pos (char *alias_name)
+{
+ t_weechat_alias *ptr_alias;
+
+ for (ptr_alias = weechat_alias; ptr_alias; ptr_alias = ptr_alias->next_alias)
+ {
+ if (ascii_strcasecmp (alias_name, ptr_alias->alias_name) < 0)
+ return ptr_alias;
+ }
+ return NULL;
+}
+
+/*
+ * alias_insert_sorted: insert alias into sorted list
+ */
+
+void
+alias_insert_sorted (t_weechat_alias *alias)
+{
+ t_weechat_alias *pos_alias;
+
+ pos_alias = alias_find_pos (alias->alias_name);
+
+ if (weechat_alias)
+ {
+ if (pos_alias)
+ {
+ /* insert alias into the list (before alias found) */
+ alias->prev_alias = pos_alias->prev_alias;
+ alias->next_alias = pos_alias;
+ if (pos_alias->prev_alias)
+ pos_alias->prev_alias->next_alias = alias;
+ else
+ weechat_alias = alias;
+ pos_alias->prev_alias = alias;
+ }
+ else
+ {
+ /* add alias to the end */
+ alias->prev_alias = weechat_last_alias;
+ alias->next_alias = NULL;
+ weechat_last_alias->next_alias = alias;
+ weechat_last_alias = alias;
+ }
+ }
+ else
+ {
+ alias->prev_alias = NULL;
+ alias->next_alias = NULL;
+ weechat_alias = alias;
+ weechat_last_alias = alias;
+ }
+}
+
+/*
+ * alias_new: create new alias and add it to alias list
+ */
+
+t_weechat_alias *
+alias_new (char *alias_name, char *alias_command)
+{
+ t_weechat_alias *new_alias, *ptr_alias;
+
+ while (alias_name[0] == '/')
+ {
+ alias_name++;
+ }
+
+ if (ascii_strcasecmp (alias_name, "builtin") == 0)
+ return NULL;
+
+ ptr_alias = alias_search (alias_name);
+ if (ptr_alias)
+ {
+ if (ptr_alias->alias_command)
+ free (ptr_alias->alias_command);
+ ptr_alias->alias_command = strdup (alias_command);
+ return ptr_alias;
+ }
+
+ if ((new_alias = ((t_weechat_alias *) malloc (sizeof (t_weechat_alias)))))
+ {
+ new_alias->alias_name = strdup (alias_name);
+ new_alias->alias_command = (char *) malloc (strlen (alias_command) + 1);
+ new_alias->running = 0;
+ if (new_alias->alias_command)
+ strcpy (new_alias->alias_command, alias_command);
+ alias_insert_sorted (new_alias);
+ return new_alias;
+ }
+ else
+ return NULL;
+}
+
+/*
+ * alias_get_final_command: get final command pointed by an alias
+ */
+
+char *
+alias_get_final_command (t_weechat_alias *alias)
+{
+ t_weechat_alias *ptr_alias;
+ char *result;
+
+ if (alias->running)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s circular reference when calling alias \"/%s\"\n"),
+ WEECHAT_ERROR, alias->alias_name);
+ return NULL;
+ }
+
+ ptr_alias = alias_search ((alias->alias_command[0] == '/') ?
+ alias->alias_command + 1 : alias->alias_command);
+ if (ptr_alias)
+ {
+ alias->running = 1;
+ result = alias_get_final_command (ptr_alias);
+ alias->running = 0;
+ return result;
+ }
+ return (alias->alias_command[0] == '/') ?
+ alias->alias_command + 1 : alias->alias_command;
+}
+
+/*
+ * alias_add_word: add word to string and increment length
+ * This function should NOT be called directly.
+ */
+
+void
+alias_add_word (char **alias, int *length, char *word)
+{
+ int length_word;
+
+ if (!word)
+ return;
+
+ length_word = strlen (word);
+ if (length_word == 0)
+ return;
+
+ if (*alias == NULL)
+ {
+ *alias = (char *) malloc (length_word + 1);
+ strcpy (*alias, word);
+ }
+ else
+ {
+ *alias = realloc (*alias, strlen (*alias) + length_word + 1);
+ strcat (*alias, word);
+ }
+ *length += length_word;
+}
+
+/*
+ * alias_replace_args: replace arguments ($1, $2, .. or $*) in alias arguments
+ */
+
+char *
+alias_replace_args (char *alias_args, char *user_args)
+{
+ char **argv, *start, *pos, *res;
+ int argc, length_res, args_count;
+
+ argv = explode_string (user_args, " ", 0, &argc);
+
+ res = NULL;
+ length_res = 0;
+ args_count = 0;
+ start = alias_args;
+ pos = start;
+ while (pos && pos[0])
+ {
+ if ((pos[0] == '\\') && (pos[1] == '$'))
+ {
+ pos[0] = '\0';
+ alias_add_word (&res, &length_res, start);
+ alias_add_word (&res, &length_res, "$");
+ pos[0] = '\\';
+ start = pos + 2;
+ pos = start;
+ }
+ else
+ {
+ if (pos[0] == '$')
+ {
+ if (pos[1] == '*')
+ {
+ args_count++;
+ pos[0] = '\0';
+ alias_add_word (&res, &length_res, start);
+ alias_add_word (&res, &length_res, user_args);
+ pos[0] = '$';
+ start = pos + 2;
+ pos = start;
+ }
+ else
+ {
+ if ((pos[1] >= '1') && (pos[1] <= '9'))
+ {
+ args_count++;
+ pos[0] = '\0';
+ alias_add_word (&res, &length_res, start);
+ if (pos[1] - '0' <= argc)
+ alias_add_word (&res, &length_res, argv[pos[1] - '1']);
+ pos[0] = '$';
+ start = pos + 2;
+ pos = start;
+ }
+ else
+ pos++;
+ }
+ }
+ else
+ pos++;
+ }
+ }
+
+ if (start < pos)
+ alias_add_word (&res, &length_res, start);
+
+ if ((args_count == 0) && user_args && user_args[0])
+ {
+ alias_add_word (&res, &length_res, " ");
+ alias_add_word (&res, &length_res, user_args);
+ }
+
+ if (argv)
+ free_exploded_string (argv);
+
+ return res;
+}
+
+/*
+ * alias_replace_vars: replace special vars ($nick, $channel, $server) in a string
+ */
+
+char *
+alias_replace_vars (t_irc_server *server, t_irc_channel *channel, char *string)
+{
+ char *var_nick, *var_channel, *var_server;
+ char empty_string[1] = { '\0' };
+ char *res, *temp;
+
+ var_nick = (server && server->nick) ? server->nick : empty_string;
+ var_channel = (channel) ? channel->name : empty_string;
+ var_server = (server) ? server->name : empty_string;
+
+ /* replace nick */
+ temp = weechat_strreplace (string, "$nick", var_nick);
+ if (!temp)
+ return NULL;
+ res = temp;
+
+ /* replace channel */
+ temp = weechat_strreplace (res, "$channel", var_channel);
+ free (res);
+ if (!temp)
+ return NULL;
+ res = temp;
+
+ /* replace server */
+ temp = weechat_strreplace (res, "$server", var_server);
+ free (res);
+ if (!temp)
+ return NULL;
+ res = temp;
+
+ /* return result */
+ return res;
+}
+
+/*
+ * alias_free: free an alias and reomve it from list
+ */
+
+void
+alias_free (t_weechat_alias *alias)
+{
+ t_weechat_alias *new_weechat_alias;
+
+ /* remove alias from list */
+ if (weechat_last_alias == alias)
+ weechat_last_alias = alias->prev_alias;
+ if (alias->prev_alias)
+ {
+ (alias->prev_alias)->next_alias = alias->next_alias;
+ new_weechat_alias = weechat_alias;
+ }
+ else
+ new_weechat_alias = alias->next_alias;
+
+ if (alias->next_alias)
+ (alias->next_alias)->prev_alias = alias->prev_alias;
+
+ /* free data */
+ if (alias->alias_name)
+ free (alias->alias_name);
+ if (alias->alias_command)
+ free (alias->alias_command);
+ free (alias);
+ weechat_alias = new_weechat_alias;
+}
+
+/*
+ * alias_free_all: free all alias
+ */
+
+void
+alias_free_all ()
+{
+ while (weechat_alias)
+ alias_free (weechat_alias);
+}
diff --git a/src/core/wee-alias.h b/src/core/wee-alias.h
new file mode 100644
index 000000000..759330ddd
--- /dev/null
+++ b/src/core/wee-alias.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2003-2007 by FlashCode <flashcode@flashtux.org>
+ * See README for License detail, AUTHORS for developers list.
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef __WEECHAT_ALIAS_H
+#define __WEECHAT_ALIAS_H 1
+
+#include "../protocols/irc/irc.h"
+
+typedef struct t_weechat_alias t_weechat_alias;
+
+struct t_weechat_alias
+{
+ char *alias_name;
+ char *alias_command;
+ int running;
+ t_weechat_alias *prev_alias;
+ t_weechat_alias *next_alias;
+};
+
+extern t_weechat_alias *weechat_alias;
+extern t_weechat_alias *weechat_last_alias;
+
+extern t_weechat_alias *alias_search (char *);
+extern t_weechat_alias *alias_new (char *, char *);
+extern char *alias_get_final_command (t_weechat_alias *);
+extern char *alias_replace_args (char *, char *);
+extern char *alias_replace_vars (t_irc_server *, t_irc_channel *, char *);
+extern void alias_free (t_weechat_alias *);
+extern void alias_free_all ();
+
+#endif /* alias.h */
diff --git a/src/core/wee-backtrace.c b/src/core/wee-backtrace.c
new file mode 100644
index 000000000..d6d0b8b08
--- /dev/null
+++ b/src/core/wee-backtrace.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright (c) 2003-2007 by FlashCode <flashcode@flashtux.org>
+ * See README for License detail, AUTHORS for developers list.
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/* backtrace.c: display backtrace after a segfault */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+
+#ifndef __USE_GNU
+#define __USE_GNU
+#endif
+
+#include <dlfcn.h>
+
+#ifdef HAVE_BACKTRACE
+#include <execinfo.h>
+#endif
+
+#include "weechat.h"
+#include "backtrace.h"
+#include "log.h"
+#include "util.h"
+
+
+/*
+ * weechat_backtrace_printf: display a backtrace line (on stderr and in WeeChat log)
+ */
+
+void
+weechat_backtrace_printf (char *message, ...)
+{
+ static char buffer[4096];
+ va_list argptr;
+
+ va_start (argptr, message);
+ vsnprintf (buffer, sizeof (buffer) - 1, message, argptr);
+ va_end (argptr);
+
+ weechat_iconv_fprintf (stderr, "%s", buffer);
+ weechat_log_printf ("%s", buffer);
+}
+
+/*
+ * weechat_backtrace_addr2line: display function name and line with a backtrace address
+ */
+
+void
+weechat_backtrace_addr2line (int number, void *address, char *symbol)
+{
+#ifdef HAVE_BACKTRACE
+ int rc;
+ Dl_info info;
+ const void *addr;
+ FILE *output;
+ char cmd_line[1024];
+ char line[1024], *ptr_line, *pos;
+ char function_name[1024];
+ int file_line;
+
+ rc = dladdr (address, &info);
+ if ((rc == 0) || !info.dli_fname || !info.dli_fname[0])
+ {
+ weechat_backtrace_printf ("%03d %s\n", number, symbol);
+ return;
+ }
+
+ addr = address;
+ if (info.dli_fbase >= (const void *) 0x40000000)
+ addr = (void *)((unsigned long)((const char *) addr) - (unsigned long) info.dli_fbase);
+
+ snprintf (cmd_line, sizeof (cmd_line),
+ "addr2line --functions --demangle -e $(which %s) %p",
+ info.dli_fname, addr);
+ output = popen (cmd_line, "r");
+ if (!output)
+ {
+ weechat_backtrace_printf ("%03d %s\n", number, symbol);
+ return;
+ }
+ function_name[0] = '\0';
+ file_line = 0;
+ while (!feof (output))
+ {
+ ptr_line = fgets (line, sizeof (line) - 1, output);
+ if (ptr_line && ptr_line[0])
+ {
+ pos = strchr (ptr_line, '\n');
+ if (pos)
+ pos[0] = '\0';
+ if (strchr (ptr_line, ':'))
+ {
+ file_line = 1;
+ weechat_backtrace_printf ("%03d %s%s%s%s\n",
+ number,
+ ptr_line,
+ (function_name[0]) ? " [function " : "",
+ function_name,
+ (function_name[0]) ? "]" : "");
+ function_name[0] = '\0';
+ }
+ else
+ {
+ if (function_name[0])
+ weechat_backtrace_printf ("%03d %s",
+ number, function_name);
+ snprintf (function_name, sizeof (function_name),
+ "%s", ptr_line);
+ }
+ }
+ }
+ if (function_name[0])
+ weechat_backtrace_printf ("%03d %s\n",
+ number, function_name);
+ pclose (output);
+#else
+ /* make C compiler happy */
+ (void) number;
+ (void) address;
+ (void) symbol;
+#endif
+}
+
+/*
+ * weechat_backtrace: display backtrace (called when a SIGSEGV is received)
+ */
+
+void
+weechat_backtrace ()
+{
+#ifdef HAVE_BACKTRACE
+ void *trace[BACKTRACE_MAX];
+ int trace_size, i;
+ char **symbols;
+#endif
+
+ weechat_backtrace_printf ("======= WeeChat backtrace =======\n");
+ weechat_backtrace_printf ("(written by %s, compiled on %s %s)\n",
+ PACKAGE_STRING, __DATE__, __TIME__);
+
+#ifdef HAVE_BACKTRACE
+ trace_size = backtrace (trace, BACKTRACE_MAX);
+ symbols = backtrace_symbols (trace, trace_size);
+
+ for (i = 0; i < trace_size; i++)
+ {
+ weechat_backtrace_addr2line (i + 1, trace[i], symbols[i]);
+ }
+#else
+ weechat_backtrace_printf (" No backtrace info (no debug info available "
+ "or no backtrace possible on your system).\n");
+#endif
+
+ weechat_backtrace_printf ("======= End of backtrace =======\n");
+}
diff --git a/src/core/wee-backtrace.h b/src/core/wee-backtrace.h
new file mode 100644
index 000000000..80a2c8f41
--- /dev/null
+++ b/src/core/wee-backtrace.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2003-2007 by FlashCode <flashcode@flashtux.org>
+ * See README for License detail, AUTHORS for developers list.
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef __WEECHAT_BACKTACE_H
+#define __WEECHAT_BACKTACE_H 1
+
+#define BACKTRACE_MAX 128
+
+extern void weechat_backtrace ();
+
+#endif /* backtrace.h */
diff --git a/src/core/wee-command.c b/src/core/wee-command.c
new file mode 100644
index 000000000..337a961a2
--- /dev/null
+++ b/src/core/wee-command.c
@@ -0,0 +1,4521 @@
+/*
+ * Copyright (c) 2003-2007 by FlashCode <flashcode@flashtux.org>
+ * See README for License detail, AUTHORS for developers list.
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/* command.c: WeeChat internal commands */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "weechat.h"
+#include "command.h"
+#include "alias.h"
+#include "fifo.h"
+#include "log.h"
+#include "session.h"
+#include "utf8.h"
+#include "util.h"
+#include "weelist.h"
+#include "weeconfig.h"
+#include "../protocols/irc/irc.h"
+#include "../gui/gui.h"
+
+#ifdef PLUGINS
+#include "../plugins/plugins.h"
+#endif
+
+
+/* WeeChat internal commands */
+
+t_weechat_command weechat_commands[] =
+{ { "alias", N_("create an alias for a command"),
+ N_("[alias_name [command [arguments]]]"),
+ N_("alias_name: name of alias\n"
+ " command: command name (WeeChat or IRC command, many commands "
+ "can be separated by semicolons)\n"
+ " arguments: arguments for command\n\n"
+ "Note: in command, special variables $1, $2,..,$9 are replaced by "
+ "arguments given by user, and $* is replaced by all arguments.\n"
+ "Variables $nick, $channel and $server are replaced by current "
+ "nick/channel/server."),
+ "%- %A", 0, MAX_ARGS, 1, NULL, weechat_cmd_alias },
+ { "buffer", N_("manage buffers"),
+ N_("[action [args] | number | [[server] [channel]]]"),
+ N_(" action: action to do:\n"
+ " move: move buffer in the list (may be relative, for example -1)\n"
+ " close: close buffer (optional arg is part message, for a channel)\n"
+ " list: list open buffers (no parameter implies this list)\n"
+ " notify: set notify level for buffer (0=never, 1=highlight, 2=1+msg, "
+ "3=2+join/part)\n"
+ " (when executed on server buffer, this sets default notify "
+ "level for whole server)\n"
+ " scroll: scroll in history (may be relative, and may end by a letter: "
+ "s=sec, m=min, h=hour, d=day, M=month, y=year); if there is "
+ "only letter, then scroll to beginning of this item\n\n"
+ " number: jump to buffer by number\n"
+ "server,\n"
+ "channel: jump to buffer by server and/or channel name\n\n"
+ "Examples:\n"
+ " move buffer: /buffer move 5\n"
+ " close buffer: /buffer close this is part msg\n"
+ " set notify: /buffer notify 2\n"
+ " scroll 1 day up: /buffer scroll 1d == /buffer scroll -1d == /buffer scroll -24h\n"
+ "scroll to beginning\n"
+ " of this day: /buffer scroll d\n"
+ " scroll 15 min down: /buffer scroll +15m\n"
+ " scroll 20 msgs up: /buffer scroll -20\n"
+ " jump to #weechat: /buffer #weechat"),
+ "move|close|list|notify|scroll|%S|%C %S|%C", 0, MAX_ARGS, 0, NULL, weechat_cmd_buffer },
+ { "builtin", N_("launch WeeChat/IRC builtin command (do not look at plugins handlers or aliases)"),
+ N_("command"),
+ N_("command: command to execute (a '/' is automatically added if not found at beginning of command)\n"),
+ "%w|%i", 0, MAX_ARGS, 1, NULL, weechat_cmd_builtin },
+ { "clear", N_("clear window(s)"),
+ N_("[-all | number [number ...]]"),
+ N_(" -all: clear all buffers\n"
+ "number: clear buffer by number"),
+ "-all", 0, MAX_ARGS, 0, weechat_cmd_clear, NULL },
+ { "connect", N_("connect to server(s)"),
+ N_("[-all [-nojoin] | servername [servername ...] [-nojoin] | hostname "
+ "[-port port] [-ipv6] [-ssl]]"),
+ N_(" -all: connect to all servers\n"
+ "servername: internal server name to connect\n"
+ " -nojoin: do not join any channel (even if autojoin is enabled on server)\n"
+ " hostname: hostname to connect, creating temporary server\n"
+ " port: port for server (integer, default is 6667)\n"
+ " ipv6: use IPv6 protocol\n"
+ " ssl: use SSL protocol"),
+ "%S|-all|-nojoin|%*", 0, MAX_ARGS, 0, weechat_cmd_connect, NULL },
+ { "disconnect", N_("disconnect from server(s)"),
+ N_("[-all | servername [servername ...]]"),
+ N_(" -all: disconnect from all servers\n"
+ "servername: server name to disconnect"),
+ "%S|-all", 0, MAX_ARGS, 0, weechat_cmd_disconnect, NULL },
+ { "dcc", N_("starts DCC (file or chat) or close chat"),
+ N_("action [nickname [file]]"),
+ N_(" action: 'send' (file) or 'chat' or 'close' (chat)\n"
+ "nickname: nickname to send file or chat\n"
+ " file: filename (on local host)"),
+ "chat|send|close %n %f", 1, MAX_ARGS, 0, NULL, weechat_cmd_dcc },
+ { "debug", N_("print debug messages"),
+ N_("dump | buffer | windows"),
+ N_(" dump: save memory dump in WeeChat log file (same dump is written when WeeChat crashes)\n"
+ " buffer: dump buffer content with hexadecimal values in log file\n"
+ "windows: display windows tree"),
+ "dump|buffer|windows", 1, 1, 0, weechat_cmd_debug, NULL },
+ { "help", N_("display help about commands"),
+ N_("[command]"),
+ N_("command: name of a WeeChat or IRC command"),
+ "%w|%i|%h", 0, 1, 0, weechat_cmd_help, NULL },
+ { "history", N_("show buffer command history"),
+ N_("[clear | value]"),
+ N_("clear: clear history\n"
+ "value: number of history entries to show"),
+ "clear", 0, 1, 0, weechat_cmd_history, NULL },
+ { "ignore", N_("ignore IRC messages and/or hosts"),
+ N_("[mask [[type | command] [channel [server]]]]"),
+ N_(" mask: nick or host mask to ignore\n"
+ " type: type of message to ignore (action, ctcp, dcc, pv)\n"
+ "command: IRC command\n"
+ "channel: name of channel for ignore\n"
+ " server: name of server for ignore\n\n"
+ "For each argument, '*' means all.\n"
+ "Without argument, /ignore command lists all defined ignore."),
+ "*|%n *|action|ctcp|dcc|pv|%I *|%c *|%s",
+ 0, 4, 0, weechat_cmd_ignore, NULL },
+ { "key", N_("bind/unbind keys"),
+ N_("[key [function/command]] [unbind key] [functions] [call function [\"args\"]] [reset -yes]"),
+ N_(" key: display or bind this key to an internal function or a command "
+ "(beginning by \"/\")\n"
+ " unbind: unbind a key\n"
+ "functions: list internal functions for key bindings\n"
+ " call: call a function by name (with optional arguments)\n"
+ " reset: restore bindings to the default values and delete ALL "
+ "personal bindings (use carefully!)"),
+ "unbind|functions|call|reset %k", 0, MAX_ARGS, 0, NULL, weechat_cmd_key },
+/* { "panel", N_("manage panels"),
+ N_("[list | add type position size | resize # size | close # | move #1 #2]"),
+ N_(" list: list open panels (no parameter implies this list)\n"
+ " add: add a panel, type is global|local, position is top|bottom|left|right\n"
+ " resize: resize a panel with a new size (may be relative, for example -1)\n"
+ " close: close a panel by number\n"
+ " move: move a panel to another number (may be relative, for example -1)"),
+ "list|add|close|move global|local top|bottom|left|right",
+ 0, MAX_ARGS, 0, weechat_cmd_panel, NULL },*/
+ { "plugin", N_("list/load/unload plugins"),
+ N_("[list [name]] | [listfull [name]] | [load filename] | [autoload] | [reload [name]] | [unload [name]]"),
+ N_(" list: list loaded plugins\n"
+ "listfull: list loaded plugins with detailed info for each plugin\n"
+ " load: load a plugin\n"
+ "autoload: autoload plugins in system or user directory\n"
+ " reload: reload one plugin (if no name given, unload all plugins, then autoload plugins)\n"
+ " unload: unload one or all plugins\n\n"
+ "Without argument, /plugin command lists loaded plugins."),
+ "list|listfull|load|autoload|reload|unload %P", 0, 2, 0, weechat_cmd_plugin, NULL },
+ { "reconnect", N_("reconnect to server(s)"),
+ N_("[-all [-nojoin] | servername [servername ...] [-nojoin]]"),
+ N_(" -all: reconnect to all servers\n"
+ "servername: server name to reconnect\n"
+ " -nojoin: do not join any channel (even if autojoin is enabled on server)"),
+ "%S|-all|-nojoin|%*", 0, MAX_ARGS, 0, weechat_cmd_reconnect, NULL },
+ { "save", N_("save config to disk"),
+ N_("[file]"), N_("file: filename for writing config"),
+ NULL, 0, 1, 0, weechat_cmd_save, NULL },
+ { "server", N_("list, add or remove servers"),
+ N_("[list [servername]] | [listfull [servername]] | [add servername "
+ "hostname [-port port] [-temp] [-auto | -noauto] [-ipv6] [-ssl] "
+ "[-pwd password] [-nicks nick1 nick2 nick3] [-username username] "
+ "[-realname realname] [-command command] [-autojoin channel[,channel]] ] "
+ "| [copy servername newservername] | [rename servername newservername] "
+ "| [keep servername] | [del servername]"),
+ N_(" list: list servers (no parameter implies this list)\n"
+ " listfull: list servers with detailed info for each server\n"
+ " add: create a new server\n"
+ "servername: server name, for internal and display use\n"
+ " hostname: name or IP address of server\n"
+ " port: port for server (integer, default is 6667)\n"
+ " temp: create temporary server (not saved in config file)\n"
+ " auto: automatically connect to server when WeeChat starts\n"
+ " noauto: do not connect to server when WeeChat starts (default)\n"
+ " ipv6: use IPv6 protocol\n"
+ " ssl: use SSL protocol\n"
+ " password: password for server\n"
+ " nick1: first nick for server\n"
+ " nick2: alternate nick for server\n"
+ " nick3: second alternate nick for server\n"
+ " username: user name\n"
+ " realname: real name of user\n"
+ " copy: duplicate a server\n"
+ " rename: rename a server\n"
+ " keep: keep server in config file (for temporary servers only)\n"
+ " del: delete a server\n"
+ " deloutq: delete messages out queue for all servers (all messages "
+ "WeeChat is currently sending)"),
+ "add|copy|rename|keep|del|deloutq|list|listfull %S %S",
+ 0, MAX_ARGS, 0, weechat_cmd_server, NULL },
+ { "set", N_("set config options"),
+ N_("[option [ = value]]"),
+ N_("option: name of an option (if name is full "
+ "and no value is given, then help is displayed on option)\n"
+ " value: value for option\n\n"
+ "Option may be: servername.server_xxx where \"servername\" is an "
+ "internal server name and \"xxx\" an option for this server."),
+ "%o = %v", 0, MAX_ARGS, 0, NULL, weechat_cmd_set },
+ { "setp", N_("set plugin config options"),
+ N_("[option [ = value]]"),
+ N_("option: name of a plugin option\n"
+ " value: value for option\n\n"
+ "Option is format: plugin.option, example: perl.myscript.item1"),
+ "%O = %V", 0, MAX_ARGS, 0, NULL, weechat_cmd_setp },
+ { "unalias", N_("remove an alias"),
+ N_("alias_name"), N_("alias_name: name of alias to remove"),
+ "%a", 1, 1, 0, NULL, weechat_cmd_unalias },
+ { "unignore", N_("unignore IRC messages and/or hosts"),
+ N_("[number | [mask [[type | command] [channel [server]]]]]"),
+ N_(" number: # of ignore to unignore (number is displayed by list of ignore)\n"
+ " mask: nick or host mask to unignore\n"
+ " type: type of message to unignore (action, ctcp, dcc, pv)\n"
+ "command: IRC command\n"
+ "channel: name of channel for unignore\n"
+ " server: name of server for unignore\n\n"
+ "For each argument, '*' means all.\n"
+ "Without argument, /unignore command lists all defined ignore."),
+ "*|%n *|action|ctcp|dcc|pv|%I *|%c *|%s",
+ 0, 4, 0, weechat_cmd_unignore, NULL },
+ { "upgrade", N_("upgrade WeeChat without disconnecting from servers"),
+ N_("[path_to_binary]"),
+ N_("path_to_binary: path to WeeChat binary (default is current binary)\n\n"
+ "This command run again a WeeChat binary, so it should have been compiled "
+ "or installed with a package manager before running this command."),
+ "%f", 0, 1, 0, weechat_cmd_upgrade, NULL },
+ { "uptime", N_("show WeeChat uptime"),
+ N_("[-o]"),
+ N_("-o: send uptime on current channel as an IRC message"),
+ "-o", 0, 1, 0, weechat_cmd_uptime, NULL },
+ { "window", N_("manage windows"),
+ N_("[list | -1 | +1 | b# | up | down | left | right | splith [pct] "
+ "| splitv [pct] | resize pct | merge [all]]"),
+ N_(" list: list open windows (no parameter implies this list)\n"
+ " -1: jump to previous window\n"
+ " +1: jump to next window\n"
+ " b#: jump to next window displaying buffer number #\n"
+ " up: switch to window above current one\n"
+ " down: switch to window below current one\n"
+ " left: switch to window on the left\n"
+ " right: switch to window on the right\n"
+ "splith: split current window horizontally\n"
+ "splitv: split current window vertically\n"
+ "resize: resize window size, new size is <pct> pourcentage of parent window\n"
+ " merge: merge window with another (all = keep only one window)\n\n"
+ "For splith and splitv, pct is a pourcentage which represents "
+ "size of new window, computed with current window as size reference. "
+ "For example 25 means create a new window with size = current_size / 4"),
+ "list|-1|+1|up|down|left|right|splith|splitv|resize|merge all",
+ 0, 2, 0, weechat_cmd_window, NULL },
+ { NULL, NULL, NULL, NULL, NULL, 0, 0, 0, NULL, NULL }
+};
+
+t_weelist *index_commands;
+t_weelist *last_index_command;
+
+
+/*
+ * command_index_build: build an index of commands (internal, irc and alias)
+ * This list will be sorted, and used for completion
+ */
+
+void
+command_index_build ()
+{
+ int i;
+
+ index_commands = NULL;
+ last_index_command = NULL;
+ i = 0;
+ while (weechat_commands[i].command_name)
+ {
+ (void) weelist_add (&index_commands, &last_index_command,
+ weechat_commands[i].command_name,
+ WEELIST_POS_SORT);
+ i++;
+ }
+ i = 0;
+ while (irc_commands[i].command_name)
+ {
+ if (irc_commands[i].cmd_function_args || irc_commands[i].cmd_function_1arg)
+ (void) weelist_add (&index_commands, &last_index_command,
+ irc_commands[i].command_name,
+ WEELIST_POS_SORT);
+ i++;
+ }
+}
+
+/*
+ * command_index_free: remove all commands in index
+ */
+
+void
+command_index_free ()
+{
+ while (index_commands)
+ {
+ weelist_remove (&index_commands, &last_index_command, index_commands);
+ }
+}
+
+/*
+ * command_used_by_weechat: return 1 if command is used by weechat
+ * (weechat command, IRC command or alias)
+ */
+
+int
+command_used_by_weechat (char *command)
+{
+ t_weechat_alias *ptr_alias;
+ int i;
+
+ /* look for alias */
+ for (ptr_alias = weechat_alias; ptr_alias;
+ ptr_alias = ptr_alias->next_alias)
+ {
+ if (ascii_strcasecmp (ptr_alias->alias_name, command) == 0)
+ return 1;
+ }
+
+ /* look for WeeChat command */
+ for (i = 0; weechat_commands[i].command_name; i++)
+ {
+ if (ascii_strcasecmp (weechat_commands[i].command_name, command) == 0)
+ return 1;
+ }
+
+ /* look for IRC command */
+ for (i = 0; irc_commands[i].command_name; i++)
+ {
+ if ((ascii_strcasecmp (irc_commands[i].command_name, command) == 0) &&
+ ((irc_commands[i].cmd_function_args) ||
+ (irc_commands[i].cmd_function_1arg)))
+ return 1;
+ }
+
+ /* no command/alias found */
+ return 0;
+}
+
+/*
+ * exec_weechat_command: executes a command (WeeChat internal or IRC)
+ * if only_builtin == 1, then try only WeeChat/IRC commands
+ * (not plugins neither aliases)
+ * returns: 1 if command was executed succesfully
+ * 0 if error (command not executed)
+ */
+
+int
+exec_weechat_command (t_irc_server *server, t_irc_channel *channel, char *string,
+ int only_builtin)
+{
+ int i, rc, argc, argc2, return_code, length1, length2;
+ char *command, *pos, *ptr_args, *ptr_args2;
+ char **argv, **argv2, *alias_command;
+ char **commands, **ptr_cmd, **ptr_next_cmd;
+ char *args_replaced, *vars_replaced, *new_ptr_cmd;
+ char *unknown_command;
+ int some_args_replaced;
+ t_weechat_alias *ptr_alias;
+
+ if ((!string) || (!string[0]) || (string[0] != '/'))
+ return 0;
+
+ command = strdup (string);
+
+ /* look for end of command */
+ ptr_args = NULL;
+
+ pos = &command[strlen (command) - 1];
+ if (pos[0] == ' ')
+ {
+ while ((pos > command) && (pos[0] == ' '))
+ pos--;
+ pos[1] = '\0';
+ }
+
+ pos = strchr (command, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ ptr_args = pos;
+ if (!ptr_args[0])
+ ptr_args = NULL;
+ }
+
+#ifdef PLUGINS
+ if (only_builtin)
+ rc = -1;
+ else
+ {
+ vars_replaced = alias_replace_vars (server, channel, ptr_args);
+ rc = plugin_cmd_handler_exec ((server) ? server->name : "", command + 1,
+ (vars_replaced) ? vars_replaced : ptr_args);
+ if (vars_replaced)
+ free (vars_replaced);
+ }
+#else
+ rc = -1;
+#endif
+ switch (rc)
+ {
+ case 0: /* plugin handler KO */
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s command \"%s\" failed\n"),
+ WEECHAT_ERROR, command + 1);
+ break;
+ case 1: /* plugin handler OK, executed */
+ break;
+ default: /* plugin handler not found */
+ argv = explode_string (ptr_args, " ", 0, &argc);
+
+ /* look for alias */
+ if (!only_builtin)
+ {
+ for (ptr_alias = weechat_alias; ptr_alias;
+ ptr_alias = ptr_alias->next_alias)
+ {
+ if (ascii_strcasecmp (ptr_alias->alias_name, command + 1) == 0)
+ {
+ if (ptr_alias->running == 1)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s circular reference when calling alias \"/%s\"\n"),
+ WEECHAT_ERROR, ptr_alias->alias_name);
+ }
+ else
+ {
+ /* an alias can contain many commands separated by ';' */
+ commands = split_multi_command (ptr_alias->alias_command, ';');
+ if (commands)
+ {
+ some_args_replaced = 0;
+ ptr_alias->running = 1;
+ for (ptr_cmd=commands; *ptr_cmd; ptr_cmd++)
+ {
+ ptr_next_cmd = ptr_cmd;
+ ptr_next_cmd++;
+
+ vars_replaced = alias_replace_vars (server, channel, *ptr_cmd);
+ new_ptr_cmd = (vars_replaced) ? vars_replaced : *ptr_cmd;
+ args_replaced = alias_replace_args (new_ptr_cmd, ptr_args);
+ if (args_replaced)
+ {
+ some_args_replaced = 1;
+ if (*ptr_cmd[0] == '/')
+ (void) exec_weechat_command (server, channel, args_replaced, only_builtin);
+ else
+ {
+ alias_command = (char *) malloc (1 + strlen(args_replaced) + 1);
+ if (alias_command)
+ {
+ strcpy (alias_command, "/");
+ strcat (alias_command, args_replaced);
+ (void) exec_weechat_command (server, channel, alias_command, only_builtin);
+ free (alias_command);
+ }
+ }
+ free (args_replaced);
+ }
+ else
+ {
+ /* if alias has arguments, they are now
+ arguments of the last command in the list (if no $1,$2,..$*) was found */
+ if ((*ptr_next_cmd == NULL) && ptr_args && (!some_args_replaced))
+ {
+ length1 = strlen (new_ptr_cmd);
+ length2 = strlen (ptr_args);
+
+ alias_command = (char *) malloc ( 1 + length1 + 1 + length2 + 1);
+ if (alias_command)
+ {
+ if (*ptr_cmd[0] != '/')
+ strcpy (alias_command, "/");
+ else
+ strcpy (alias_command, "");
+
+ strcat (alias_command, new_ptr_cmd);
+ strcat (alias_command, " ");
+ strcat (alias_command, ptr_args);
+
+ (void) exec_weechat_command (server, channel, alias_command, only_builtin);
+ free (alias_command);
+ }
+ }
+ else
+ {
+ if (*ptr_cmd[0] == '/')
+ (void) exec_weechat_command (server, channel, new_ptr_cmd, only_builtin);
+ else
+ {
+ alias_command = (char *) malloc (1 + strlen (new_ptr_cmd) + 1);
+ if (alias_command)
+ {
+ strcpy (alias_command, "/");
+ strcat (alias_command, new_ptr_cmd);
+ (void) exec_weechat_command (server, channel, alias_command, only_builtin);
+ free (alias_command);
+ }
+ }
+ }
+ }
+ if (vars_replaced)
+ free (vars_replaced);
+ }
+ ptr_alias->running = 0;
+ free_multi_command (commands);
+ }
+ }
+ free_exploded_string (argv);
+ free (command);
+ return 1;
+ }
+ }
+ }
+
+ /* look for WeeChat command */
+ for (i = 0; weechat_commands[i].command_name; i++)
+ {
+ if (ascii_strcasecmp (weechat_commands[i].command_name, command + 1) == 0)
+ {
+ if ((argc < weechat_commands[i].min_arg)
+ || (argc > weechat_commands[i].max_arg))
+ {
+ if (weechat_commands[i].min_arg ==
+ weechat_commands[i].max_arg)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ NG_("%s wrong argument count for %s command \"%s\" "
+ "(expected: %d arg)\n",
+ "%s wrong argument count for %s command \"%s\" "
+ "(expected: %d args)\n",
+ weechat_commands[i].max_arg),
+ WEECHAT_ERROR, PACKAGE_NAME,
+ command + 1,
+ weechat_commands[i].max_arg);
+ }
+ else
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ NG_("%s wrong argument count for %s command \"%s\" "
+ "(expected: between %d and %d arg)\n",
+ "%s wrong argument count for %s command \"%s\" "
+ "(expected: between %d and %d args)\n",
+ weechat_commands[i].max_arg),
+ WEECHAT_ERROR, PACKAGE_NAME,
+ command + 1,
+ weechat_commands[i].min_arg,
+ weechat_commands[i].max_arg);
+ }
+ }
+ else
+ {
+ ptr_args2 = (ptr_args) ? (char *)gui_color_encode ((unsigned char *)ptr_args,
+ (weechat_commands[i].conversion
+ && cfg_irc_colors_send)) : NULL;
+ if (weechat_commands[i].cmd_function_args)
+ {
+ argv2 = explode_string ((ptr_args2) ? ptr_args2 : ptr_args,
+ " ", 0, &argc2);
+ return_code = (int) (weechat_commands[i].cmd_function_args)
+ (server, channel, argc2, argv2);
+ free_exploded_string (argv2);
+ }
+ else
+ return_code = (int) (weechat_commands[i].cmd_function_1arg)
+ (server, channel, (ptr_args2) ? ptr_args2 : ptr_args);
+ if (return_code < 0)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s command \"%s\" failed\n"),
+ WEECHAT_ERROR, command + 1);
+ }
+ if (ptr_args2)
+ free (ptr_args2);
+ }
+ free_exploded_string (argv);
+ free (command);
+ return 1;
+ }
+ }
+
+ /* look for IRC command */
+ for (i = 0; irc_commands[i].command_name; i++)
+ {
+ if ((ascii_strcasecmp (irc_commands[i].command_name, command + 1) == 0) &&
+ ((irc_commands[i].cmd_function_args) ||
+ (irc_commands[i].cmd_function_1arg)))
+ {
+ if ((argc < irc_commands[i].min_arg)
+ || (argc > irc_commands[i].max_arg))
+ {
+ if (irc_commands[i].min_arg == irc_commands[i].max_arg)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf
+ (NULL,
+ NG_("%s wrong argument count for IRC command \"%s\" "
+ "(expected: %d arg)\n",
+ "%s wrong argument count for IRC command \"%s\" "
+ "(expected: %d args)\n",
+ irc_commands[i].max_arg),
+ WEECHAT_ERROR,
+ command + 1,
+ irc_commands[i].max_arg);
+ }
+ else
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf
+ (NULL,
+ NG_("%s wrong argument count for IRC command \"%s\" "
+ "(expected: between %d and %d arg)\n",
+ "%s wrong argument count for IRC command \"%s\" "
+ "(expected: between %d and %d args)\n",
+ irc_commands[i].max_arg),
+ WEECHAT_ERROR,
+ command + 1,
+ irc_commands[i].min_arg, irc_commands[i].max_arg);
+ }
+ }
+ else
+ {
+ if ((irc_commands[i].needs_connection) &&
+ ((!server) || (!server->is_connected)))
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s command \"%s\" needs a server connection!\n"),
+ WEECHAT_ERROR, irc_commands[i].command_name);
+ free (command);
+ return 0;
+ }
+ if (channel && channel->dcc_chat)
+ {
+ irc_display_prefix (server, channel->buffer, GUI_PREFIX_ERROR);
+ gui_printf (channel->buffer,
+ _("%s command \"%s\" can not be "
+ "executed on DCC CHAT buffer\n"),
+ WEECHAT_ERROR,
+ irc_commands[i].command_name);
+ free (command);
+ return 0;
+ }
+ ptr_args2 = (ptr_args) ? (char *)gui_color_encode ((unsigned char *)ptr_args,
+ (irc_commands[i].conversion
+ && cfg_irc_colors_send)) : NULL;
+ if (irc_commands[i].cmd_function_args)
+ {
+ argv2 = explode_string ((ptr_args2) ? ptr_args2 : ptr_args,
+ " ", 0, &argc2);
+ return_code = (int) (irc_commands[i].cmd_function_args)
+ (server, channel, argc2, argv2);
+ free_exploded_string (argv2);
+ }
+ else
+ return_code = (int) (irc_commands[i].cmd_function_1arg)
+ (server, channel, (ptr_args2) ? ptr_args2 : ptr_args);
+ if (return_code < 0)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s command \"%s\" failed\n"),
+ WEECHAT_ERROR, command + 1);
+ }
+ if (ptr_args2)
+ free (ptr_args2);
+ }
+ free_exploded_string (argv);
+ free (command);
+ return 1;
+ }
+ }
+
+ /* should we send unknown command to IRC server? */
+ if (cfg_irc_send_unknown_commands)
+ {
+ if (ptr_args)
+ unknown_command = (char *)malloc (strlen (command + 1) + 1 + strlen (ptr_args) + 1);
+ else
+ unknown_command = (char *)malloc (strlen (command + 1) + 1);
+
+ if (unknown_command)
+ {
+ strcpy (unknown_command, command + 1);
+ if (ptr_args)
+ {
+ strcat (unknown_command, " ");
+ strcat (unknown_command, ptr_args);
+ }
+ irc_send_cmd_quote (server, channel, unknown_command);
+ free (unknown_command);
+ }
+ }
+ else
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s unknown command \"%s\" (type /help for help). "
+ "To send unknown commands to IRC server, enable option "
+ "irc_send_unknown_commands.\n"),
+ WEECHAT_ERROR,
+ command + 1);
+ }
+
+ free_exploded_string (argv);
+ }
+ free (command);
+ return 0;
+}
+
+/*
+ * user_message_display: display user message
+ */
+
+void
+user_message_display (t_irc_server *server, t_gui_buffer *buffer, char *text)
+{
+ t_irc_nick *ptr_nick;
+
+ if ((GUI_CHANNEL(buffer)->type == IRC_CHANNEL_TYPE_PRIVATE)
+ || (GUI_CHANNEL(buffer)->type == IRC_CHANNEL_TYPE_DCC_CHAT))
+ {
+ irc_display_nick (buffer, NULL, server->nick,
+ GUI_MSG_TYPE_NICK, 1, GUI_COLOR_WIN_NICK_SELF, 0);
+ gui_printf_type (buffer,
+ GUI_MSG_TYPE_MSG,
+ "%s%s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ text);
+ }
+ else
+ {
+ ptr_nick = irc_nick_search (GUI_CHANNEL(buffer), server->nick);
+ if (ptr_nick)
+ {
+ irc_display_nick (buffer, ptr_nick, NULL,
+ GUI_MSG_TYPE_NICK, 1, -1, 0);
+ gui_printf_type (buffer,
+ GUI_MSG_TYPE_MSG,
+ "%s%s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ text);
+ }
+ else
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf (server->buffer,
+ _("%s cannot find nick for sending message\n"),
+ WEECHAT_ERROR);
+ }
+ }
+}
+
+/*
+ * user_message: send a PRIVMSG message, and split it if > 512 bytes
+ */
+
+void
+user_message (t_irc_server *server, t_gui_buffer *buffer, char *text)
+{
+ int max_length;
+ char *pos, *pos_next, *pos_max, *next, saved_char, *last_space;
+
+ if (!text || !text[0])
+ return;
+
+ if (!server->is_connected)
+ {
+ irc_display_prefix (server, buffer, GUI_PREFIX_ERROR);
+ gui_printf (buffer, _("%s you are not connected to server\n"),
+ WEECHAT_ERROR);
+ return;
+ }
+
+ next = NULL;
+ last_space = NULL;
+ saved_char = '\0';
+
+ max_length = 512 - 16 - 65 - 10 - strlen (server->nick) -
+ strlen (GUI_CHANNEL(buffer)->name);
+
+ if (max_length > 0)
+ {
+ if ((int)strlen (text) > max_length)
+ {
+ pos = text;
+ pos_max = text + max_length;
+ while (pos && pos[0])
+ {
+ if (pos[0] == ' ')
+ last_space = pos;
+ pos_next = utf8_next_char (pos);
+ if (pos_next > pos_max)
+ break;
+ pos = pos_next;
+ }
+ if (last_space && (last_space < pos))
+ pos = last_space + 1;
+ saved_char = pos[0];
+ pos[0] = '\0';
+ next = pos;
+ }
+ }
+
+ irc_server_sendf_queued (server, "PRIVMSG %s :%s",
+ GUI_CHANNEL(buffer)->name, text);
+ user_message_display (server, buffer, text);
+
+ if (next)
+ {
+ next[0] = saved_char;
+ user_message (server, buffer, next);
+ }
+}
+
+/*
+ * is_command: return 1 if line is a command, 0 otherwise
+ */
+
+int
+is_command (char *line)
+{
+ char *pos_slash, *pos_space;
+
+ if (strncmp (line, "/*", 2) == 0)
+ return 0;
+
+ pos_slash = strchr (line + 1, '/');
+ pos_space = strchr (line + 1, ' ');
+
+ return (line[0] == '/')
+ && (!pos_slash || (pos_space && pos_slash > pos_space));
+}
+
+/*
+ * user_command: interprets user command (if beginning with '/')
+ * any other text is sent to the server, if connected
+ */
+
+void
+user_command (t_irc_server *server, t_irc_channel *channel, char *command, int only_builtin)
+{
+ t_gui_buffer *buffer;
+ char *new_cmd, *ptr_cmd, *pos;
+ char *command_with_colors;
+
+ if ((!command) || (!command[0]) || (command[0] == '\r') || (command[0] == '\n'))
+ return;
+
+#ifdef PLUGINS
+ new_cmd = plugin_modifier_exec (PLUGIN_MODIFIER_IRC_USER,
+ (server) ? server->name : "",
+ command);
+#else
+ new_cmd = NULL;
+#endif
+
+ /* no changes in new command */
+ if (new_cmd && (strcmp (command, new_cmd) == 0))
+ {
+ free (new_cmd);
+ new_cmd = NULL;
+ }
+
+ /* message not dropped? */
+ if (!new_cmd || new_cmd[0])
+ {
+ /* use new command (returned by plugin) */
+ ptr_cmd = (new_cmd) ? new_cmd : command;
+
+ while (ptr_cmd && ptr_cmd[0])
+ {
+ pos = strchr (ptr_cmd, '\n');
+ if (pos)
+ pos[0] = '\0';
+
+ gui_buffer_find_context (server, channel, NULL, &buffer);
+
+ if (is_command (ptr_cmd))
+ {
+ /* WeeChat internal command (or IRC command) */
+ (void) exec_weechat_command (server, channel, ptr_cmd, only_builtin);
+ }
+ else
+ {
+ if ((ptr_cmd[0] == '/') && (ptr_cmd[1] == '/'))
+ ptr_cmd++;
+
+ if (server && (!GUI_BUFFER_IS_SERVER(buffer)))
+ {
+ command_with_colors = (char *)gui_color_encode ((unsigned char *)ptr_cmd,
+ cfg_irc_colors_send);
+
+ if (GUI_CHANNEL(buffer)->dcc_chat)
+ {
+ if (((t_irc_dcc *)(GUI_CHANNEL(buffer)->dcc_chat))->sock < 0)
+ {
+ irc_display_prefix (server, buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (buffer, "%s DCC CHAT is closed\n",
+ WEECHAT_ERROR);
+ }
+ else
+ {
+ irc_dcc_chat_sendf ((t_irc_dcc *)(GUI_CHANNEL(buffer)->dcc_chat),
+ "%s\r\n",
+ (command_with_colors) ? command_with_colors : ptr_cmd);
+ user_message_display (server, buffer,
+ (command_with_colors) ?
+ command_with_colors : ptr_cmd);
+ }
+ }
+ else
+ user_message (server, buffer,
+ (command_with_colors) ? command_with_colors : ptr_cmd);
+
+ if (command_with_colors)
+ free (command_with_colors);
+ }
+ else
+ {
+ irc_display_prefix (NULL, (server) ? server->buffer : NULL, GUI_PREFIX_ERROR);
+ gui_printf_nolog ((server) ? server->buffer : NULL,
+ _("This window is not a channel!\n"));
+ }
+ }
+
+ if (pos)
+ {
+ pos[0] = '\n';
+ ptr_cmd = pos + 1;
+ }
+ else
+ ptr_cmd = NULL;
+ }
+ }
+}
+
+/*
+ * weechat_cmd_alias: display or create alias
+ */
+
+int
+weechat_cmd_alias (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ char *pos;
+ t_weechat_alias *ptr_alias;
+
+ /* make C compiler happy */
+ (void) server;
+ (void) channel;
+
+ if (arguments && arguments[0])
+ {
+ while (arguments[0] == '/')
+ {
+ arguments++;
+ }
+
+ /* Define new alias */
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ if (!pos[0])
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL, _("%s missing arguments for \"%s\" command\n"),
+ WEECHAT_ERROR, "alias");
+ return -1;
+ }
+ if (!alias_new (arguments, pos))
+ return -1;
+ if (weelist_add (&index_commands, &last_index_command, arguments,
+ WEELIST_POS_SORT))
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_INFO);
+ gui_printf (NULL, _("Alias \"%s\" => \"%s\" created\n"),
+ arguments, pos);
+ }
+ else
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL, _("Failed to create alias \"%s\" => \"%s\" "
+ "(not enough memory)\n"),
+ arguments, pos);
+ return -1;
+ }
+ }
+ else
+ {
+ ptr_alias = alias_search (arguments);
+ if (ptr_alias)
+ {
+ gui_printf (NULL, "\n");
+ gui_printf (NULL, _("Alias:\n"));
+ gui_printf (NULL, " %s %s=>%s %s\n",
+ ptr_alias->alias_name,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ ptr_alias->alias_command);
+ }
+ else
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_INFO);
+ gui_printf (NULL, _("No alias found.\n"));
+ }
+ }
+ }
+ else
+ {
+ /* List all aliases */
+ if (weechat_alias)
+ {
+ gui_printf (NULL, "\n");
+ gui_printf (NULL, _("List of aliases:\n"));
+ for (ptr_alias = weechat_alias; ptr_alias;
+ ptr_alias = ptr_alias->next_alias)
+ {
+ gui_printf (NULL, " %s %s=>%s %s\n",
+ ptr_alias->alias_name,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ ptr_alias->alias_command);
+ }
+ }
+ else
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_INFO);
+ gui_printf (NULL, _("No alias defined.\n"));
+ }
+ }
+ return 0;
+}
+
+/*
+ * weechat_cmd_buffer_display_info: display info about a buffer
+ */
+
+void
+weechat_cmd_buffer_display_info (t_gui_buffer *buffer)
+{
+ switch (buffer->type)
+ {
+ case GUI_BUFFER_TYPE_STANDARD:
+ if (GUI_BUFFER_IS_SERVER(buffer))
+ {
+ if (GUI_SERVER(buffer))
+ gui_printf (NULL, _("%sServer: %s%s\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_SERVER),
+ GUI_SERVER(buffer)->name);
+ else
+ gui_printf (NULL, _("%snot connected\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT));
+ }
+ else if (GUI_BUFFER_IS_CHANNEL (buffer))
+ gui_printf (NULL, _("%sChannel: %s%s %s(server: %s%s%s)\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ GUI_CHANNEL(buffer)->name,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_SERVER),
+ GUI_SERVER(buffer)->name,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT));
+ else if (GUI_BUFFER_IS_PRIVATE (buffer))
+ gui_printf (NULL, _("%sPrivate with: %s%s %s(server: %s%s%s)\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ GUI_CHANNEL(buffer)->name,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_SERVER),
+ GUI_SERVER(buffer)->name,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT));
+ else
+ gui_printf (NULL, _("%sunknown\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT));
+ break;
+ case GUI_BUFFER_TYPE_DCC:
+ gui_printf (NULL, "%sDCC\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL));
+ break;
+ case GUI_BUFFER_TYPE_RAW_DATA:
+ gui_printf (NULL, _("%sraw IRC data\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL));
+ break;
+ default:
+ gui_printf (NULL, _("%sunknown\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT));
+ break;
+ }
+}
+
+/*
+ * weechat_cmd_buffer: manage buffers
+ */
+
+int
+weechat_cmd_buffer (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ t_gui_window *window;
+ t_gui_buffer *buffer, *ptr_buffer;
+ t_irc_server *ptr_server;
+ t_irc_channel *ptr_channel;
+ long number;
+ char *error, *pos, **argv;
+ int argc, target_buffer, count;
+
+ gui_buffer_find_context (server, channel, &window, &buffer);
+
+ argv = explode_string (arguments, " ", 0, &argc);
+
+ if ((argc == 0) || ((argc == 1) && (ascii_strcasecmp (argv[0], "list") == 0)))
+ {
+ /* list open buffers */
+
+ gui_printf (NULL, "\n");
+ gui_printf (NULL, _("Open buffers:\n"));
+
+ for (ptr_buffer = gui_buffers; ptr_buffer; ptr_buffer = ptr_buffer->next_buffer)
+ {
+ gui_printf (NULL, "%s[%s%d%s] ",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ ptr_buffer->number,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK));
+ weechat_cmd_buffer_display_info (ptr_buffer);
+ }
+ }
+ else
+ {
+ if (ascii_strcasecmp (argv[0], "move") == 0)
+ {
+ /* move buffer to another number in the list */
+
+ if (argc < 2)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL, _("%s missing arguments for \"%s\" command\n"),
+ WEECHAT_ERROR, "buffer");
+ free_exploded_string (argv);
+ return -1;
+ }
+
+ error = NULL;
+ number = strtol (((argv[1][0] == '+') || (argv[1][0] == '-')) ? argv[1] + 1 : argv[1],
+ &error, 10);
+ if ((error) && (error[0] == '\0'))
+ {
+ if (argv[1][0] == '+')
+ gui_buffer_move_to_number (buffer,
+ buffer->number + ((int) number));
+ else if (argv[1][0] == '-')
+ gui_buffer_move_to_number (buffer,
+ buffer->number - ((int) number));
+ else
+ gui_buffer_move_to_number (buffer, (int) number);
+ }
+ else
+ {
+ /* invalid number */
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL, _("%s incorrect buffer number\n"),
+ WEECHAT_ERROR);
+ free_exploded_string (argv);
+ return -1;
+ }
+ }
+ else if (ascii_strcasecmp (argv[0], "close") == 0)
+ {
+ /* close buffer (server or channel/private) */
+
+ if ((!buffer->next_buffer)
+ && (buffer == gui_buffers)
+ && ((!buffer->all_servers)
+ || (!GUI_SERVER(buffer))))
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s can not close the single buffer\n"),
+ WEECHAT_ERROR);
+ free_exploded_string (argv);
+ return -1;
+ }
+ if (GUI_BUFFER_IS_SERVER(buffer))
+ {
+ if (GUI_SERVER(buffer))
+ {
+ if (GUI_SERVER(buffer)->channels)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s can not close server buffer while channels "
+ "are open\n"),
+ WEECHAT_ERROR);
+ free_exploded_string (argv);
+ return -1;
+ }
+ irc_server_disconnect (GUI_SERVER(buffer), 0);
+ ptr_server = GUI_SERVER(buffer);
+ if (!buffer->all_servers)
+ {
+ gui_buffer_free (buffer, 1);
+ ptr_server->buffer = NULL;
+ }
+ else
+ {
+ ptr_server->buffer = NULL;
+ buffer->server = NULL;
+ gui_window_switch_server (window);
+ }
+ gui_status_draw (gui_current_window->buffer, 1);
+ gui_input_draw (gui_current_window->buffer, 1);
+ }
+ }
+ else
+ {
+ if (GUI_CHANNEL(buffer)
+ && (GUI_CHANNEL(buffer)->type == IRC_CHANNEL_TYPE_DCC_CHAT))
+ {
+ ptr_server = GUI_SERVER(buffer);
+ ptr_channel = GUI_CHANNEL(buffer);
+ gui_buffer_free (ptr_channel->buffer, 1);
+ irc_channel_free (ptr_server, ptr_channel);
+ gui_status_draw (gui_current_window->buffer, 1);
+ gui_input_draw (gui_current_window->buffer, 1);
+ }
+ else
+ {
+ if (GUI_SERVER(buffer))
+ {
+ if (GUI_SERVER(buffer)->is_connected
+ && GUI_CHANNEL(buffer)
+ && GUI_CHANNEL(buffer)->nicks)
+ {
+ pos = strstr (arguments, "close ");
+ if (pos)
+ pos += 6;
+ GUI_CHANNEL(buffer)->close = 1;
+ irc_send_cmd_part (GUI_SERVER(buffer),
+ GUI_CHANNEL(buffer),
+ pos);
+ }
+ else
+ {
+ ptr_channel = GUI_CHANNEL(buffer);
+ ptr_server = GUI_SERVER(buffer);
+ gui_buffer_free (buffer, 1);
+ if (ptr_channel)
+ irc_channel_free (ptr_server, ptr_channel);
+ }
+ }
+ else
+ gui_buffer_free (buffer, 1);
+ gui_status_draw (gui_current_window->buffer, 1);
+ }
+ }
+ }
+ else if (ascii_strcasecmp (argv[0], "notify") == 0)
+ {
+ if (argc < 2)
+ {
+ gui_printf (NULL, "\n");
+
+ /* display default notify level for all connected servers */
+ gui_printf (NULL, _("Default notify levels for servers:"));
+ count = 0;
+ for (ptr_server = irc_servers; ptr_server;
+ ptr_server = ptr_server->next_server)
+ {
+ if (ptr_server->buffer)
+ {
+ gui_printf (NULL, " %s:%d",
+ ptr_server->name,
+ irc_server_get_default_notify_level (ptr_server));
+ count++;
+ }
+ }
+ if (count == 0)
+ gui_printf (NULL, " -");
+ gui_printf (NULL, "\n");
+
+ /* display notify level for all buffers */
+ gui_printf (NULL, _("Notify levels:"));
+ for (ptr_buffer = gui_buffers; ptr_buffer;
+ ptr_buffer = ptr_buffer->next_buffer)
+ {
+ gui_printf (NULL, " %d.%s:",
+ ptr_buffer->number,
+ (ptr_buffer->type == GUI_BUFFER_TYPE_DCC) ? "DCC" :
+ ((ptr_buffer->type == GUI_BUFFER_TYPE_RAW_DATA) ? _("Raw IRC data") :
+ ((GUI_BUFFER_IS_SERVER(ptr_buffer) && GUI_SERVER(ptr_buffer)) ? GUI_SERVER(ptr_buffer)->name :
+ ((GUI_CHANNEL(ptr_buffer)) ? (GUI_CHANNEL(ptr_buffer)->name) : "-"))));
+ if ((!GUI_BUFFER_IS_CHANNEL(ptr_buffer))
+ && (!GUI_BUFFER_IS_PRIVATE(ptr_buffer)))
+ gui_printf (NULL, "-");
+ else
+ gui_printf (NULL, "%d", ptr_buffer->notify_level);
+ }
+ gui_printf (NULL, "\n");
+ }
+ else
+ {
+ /* set notify level for buffer */
+ error = NULL;
+ number = strtol (argv[1], &error, 10);
+ if ((error) && (error[0] == '\0'))
+ {
+ if ((number < GUI_NOTIFY_LEVEL_MIN) || (number > GUI_NOTIFY_LEVEL_MAX))
+ {
+ /* invalid highlight level */
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL, _("%s incorrect notify level (must be between %d and %d)\n"),
+ WEECHAT_ERROR, GUI_NOTIFY_LEVEL_MIN, GUI_NOTIFY_LEVEL_MAX);
+ free_exploded_string (argv);
+ return -1;
+ }
+ if (!GUI_SERVER(buffer)
+ || ((!GUI_BUFFER_IS_SERVER(buffer))
+ && (!GUI_BUFFER_IS_CHANNEL(buffer))
+ && (!GUI_BUFFER_IS_PRIVATE(buffer))))
+ {
+ /* invalid buffer type (only ok on server, channel or private) */
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s incorrect buffer for notify "
+ "(must be server, channel or private)\n"),
+ WEECHAT_ERROR);
+ free_exploded_string (argv);
+ return -1;
+ }
+ if (GUI_BUFFER_IS_SERVER(buffer))
+ {
+ irc_server_set_default_notify_level (GUI_SERVER(buffer),
+ number);
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_INFO);
+ gui_printf (NULL, _("New default notify level for server %s%s%s: %s%d %s"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_SERVER),
+ GUI_SERVER(buffer)->name,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ number,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT));
+ }
+ else
+ {
+ irc_channel_set_notify_level (GUI_SERVER(buffer),
+ GUI_CHANNEL(buffer),
+ number);
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_INFO);
+ gui_printf (NULL, _("New notify level for %s%s%s: %s%d %s"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ GUI_CHANNEL(buffer)->name,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ number,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT));
+ }
+ switch (number)
+ {
+ case 0:
+ gui_printf (NULL, _("(hotlist: never)\n"));
+ break;
+ case 1:
+ gui_printf (NULL, _("(hotlist: highlights)\n"));
+ break;
+ case 2:
+ gui_printf (NULL, _("(hotlist: highlights + messages)\n"));
+ break;
+ case 3:
+ gui_printf (NULL, _("(hotlist: highlights + messages + join/part (all))\n"));
+ break;
+ default:
+ gui_printf (NULL, "\n");
+ break;
+ }
+ config_change_notify_levels ();
+ }
+ else
+ {
+ /* invalid number */
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL, _("%s incorrect notify level (must be between %d and %d)\n"),
+ WEECHAT_ERROR, GUI_NOTIFY_LEVEL_MIN, GUI_NOTIFY_LEVEL_MAX);
+ free_exploded_string (argv);
+ return -1;
+ }
+ }
+ }
+ else if (ascii_strcasecmp (argv[0], "scroll") == 0)
+ {
+ if (argc >= 2)
+ gui_buffer_scroll (window, argv[1]);
+ }
+ else
+ {
+ /* jump to buffer by number or server/channel name */
+
+ if (argv[0][0] == '-')
+ {
+ /* relative jump '-' */
+ error = NULL;
+ number = strtol (argv[0] + 1, &error, 10);
+ if ((error) && (error[0] == '\0'))
+ {
+ target_buffer = buffer->number - (int) number;
+ if (target_buffer < 1)
+ target_buffer = (last_gui_buffer) ?
+ last_gui_buffer->number + target_buffer : 1;
+ gui_buffer_switch_by_number (window,
+ target_buffer);
+ }
+ }
+ else if (argv[0][0] == '+')
+ {
+ /* relative jump '+' */
+ error = NULL;
+ number = strtol (argv[0] + 1, &error, 10);
+ if ((error) && (error[0] == '\0'))
+ {
+ target_buffer = buffer->number + (int) number;
+ if (last_gui_buffer && target_buffer > last_gui_buffer->number)
+ target_buffer -= last_gui_buffer->number;
+ gui_buffer_switch_by_number (window,
+ target_buffer);
+ }
+ }
+ else
+ {
+ /* absolute jump by number, or by server/channel name */
+ error = NULL;
+ number = strtol (argv[0], &error, 10);
+ if ((error) && (error[0] == '\0'))
+ gui_buffer_switch_by_number (window, (int) number);
+ else
+ {
+ ptr_buffer = NULL;
+ if (argc > 1)
+ ptr_buffer = gui_buffer_search (argv[0], argv[1]);
+ else
+ {
+ ptr_server = irc_server_search (argv[0]);
+ if (ptr_server)
+ ptr_buffer = gui_buffer_search (argv[0], NULL);
+ else
+ ptr_buffer = gui_buffer_search (NULL, argv[0]);
+ }
+ if (ptr_buffer)
+ {
+ gui_window_switch_to_buffer (window, ptr_buffer);
+ gui_window_redraw_buffer (ptr_buffer);
+ }
+ }
+ }
+
+ }
+ }
+ free_exploded_string (argv);
+ return 0;
+}
+
+/*
+ * weechat_cmd_builtin: launch WeeChat/IRC builtin command
+ */
+
+int
+weechat_cmd_builtin (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ char *command;
+ int length;
+
+ if (arguments && arguments[0])
+ {
+ if (arguments[0] == '/')
+ user_command (server, channel, arguments, 1);
+ else
+ {
+ length = strlen (arguments) + 2;
+ command = (char *)malloc (length);
+ if (command)
+ {
+ snprintf (command, length, "/%s", arguments);
+ user_command (server, channel, command, 1);
+ free (command);
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * weechat_cmd_clear: display or create alias
+ */
+
+int
+weechat_cmd_clear (t_irc_server *server, t_irc_channel *channel,
+ int argc, char **argv)
+{
+ t_gui_buffer *buffer;
+ char *error;
+ long number;
+ int i;
+
+ if (argc > 0)
+ {
+ if (ascii_strcasecmp (argv[0], "-all") == 0)
+ gui_buffer_clear_all ();
+ else
+ {
+ for (i = 0; i < argc; i++)
+ {
+ error = NULL;
+ number = strtol (argv[i], &error, 10);
+ if ((error) && (error[0] == '\0'))
+ {
+ buffer = gui_buffer_search_by_number (number);
+ if (!buffer)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s buffer number \"%s\" not found for \"%s\" command\n"),
+ WEECHAT_ERROR, argv[i], "clear");
+ return -1;
+ }
+ gui_buffer_clear (buffer);
+ }
+ else
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s unknown option for \"%s\" command\n"),
+ WEECHAT_ERROR, "clear");
+ return -1;
+ }
+ }
+ }
+ }
+ else
+ {
+ gui_buffer_find_context (server, channel, NULL, &buffer);
+ gui_buffer_clear (buffer);
+ }
+
+ return 0;
+}
+
+/*
+ * weechat_cmd_connect_one_server: connect to one server
+ * return 0 if error, 1 if ok
+ */
+
+int
+weechat_cmd_connect_one_server (t_gui_window *window, t_irc_server *server,
+ int no_join)
+{
+ if (server->is_connected)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s already connected to server \"%s\"!\n"),
+ WEECHAT_ERROR, server->name);
+ return 0;
+ }
+ if (server->child_pid > 0)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s currently connecting to server \"%s\"!\n"),
+ WEECHAT_ERROR, server->name);
+ return 0;
+ }
+ if (!server->buffer)
+ {
+ if (!gui_buffer_new (window, server, NULL,
+ GUI_BUFFER_TYPE_STANDARD, 1))
+ return 0;
+ }
+ if (irc_server_connect (server, no_join))
+ {
+ server->reconnect_start = 0;
+ server->reconnect_join = (server->channels) ? 1 : 0;
+ gui_status_draw (server->buffer, 1);
+ }
+
+ /* connect ok */
+ return 1;
+}
+
+/*
+ * weechat_cmd_connect: connect to server(s)
+ */
+
+int
+weechat_cmd_connect (t_irc_server *server, t_irc_channel *channel,
+ int argc, char **argv)
+{
+ t_gui_window *window;
+ t_gui_buffer *buffer;
+ t_irc_server *ptr_server, server_tmp;
+ int i, nb_connect, connect_ok, all_servers, no_join, port, ipv6, ssl;
+ char *error;
+ long number;
+
+ gui_buffer_find_context (server, channel, &window, &buffer);
+
+ nb_connect = 0;
+ connect_ok = 1;
+ port = IRC_DEFAULT_PORT;
+ ipv6 = 0;
+ ssl = 0;
+
+ all_servers = 0;
+ no_join = 0;
+ for (i = 0; i < argc; i++)
+ {
+ if (ascii_strcasecmp (argv[i], "-all") == 0)
+ all_servers = 1;
+ if (ascii_strcasecmp (argv[i], "-nojoin") == 0)
+ no_join = 1;
+ if (ascii_strcasecmp (argv[i], "-ipv6") == 0)
+ ipv6 = 1;
+ if (ascii_strcasecmp (argv[i], "-ssl") == 0)
+ ssl = 1;
+ if (ascii_strcasecmp (argv[i], "-port") == 0)
+ {
+ if (i == (argc - 1))
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s missing argument for \"%s\" option\n"),
+ WEECHAT_ERROR, "-port");
+ return -1;
+ }
+ error = NULL;
+ number = strtol (argv[++i], &error, 10);
+ if ((error) && (error[0] == '\0'))
+ port = number;
+ }
+ }
+
+ if (all_servers)
+ {
+ for (ptr_server = irc_servers; ptr_server;
+ ptr_server = ptr_server->next_server)
+ {
+ nb_connect++;
+ if (!ptr_server->is_connected && (ptr_server->child_pid == 0))
+ {
+ if (!weechat_cmd_connect_one_server (window, ptr_server,
+ no_join))
+ connect_ok = 0;
+ }
+ }
+ }
+ else
+ {
+ for (i = 0; i < argc; i++)
+ {
+ if (argv[i][0] != '-')
+ {
+ nb_connect++;
+ ptr_server = irc_server_search (argv[i]);
+ if (ptr_server)
+ {
+ if (!weechat_cmd_connect_one_server (window, ptr_server,
+ no_join))
+ connect_ok = 0;
+ }
+ else
+ {
+ irc_server_init (&server_tmp);
+ server_tmp.name = strdup (argv[i]);
+ server_tmp.address = strdup (argv[i]);
+ server_tmp.port = port;
+ server_tmp.ipv6 = ipv6;
+ server_tmp.ssl = ssl;
+ ptr_server = irc_server_new (server_tmp.name,
+ server_tmp.autoconnect,
+ server_tmp.autoreconnect,
+ server_tmp.autoreconnect_delay,
+ 1, /* temp server */
+ server_tmp.address,
+ server_tmp.port,
+ server_tmp.ipv6,
+ server_tmp.ssl,
+ server_tmp.password,
+ server_tmp.nick1,
+ server_tmp.nick2,
+ server_tmp.nick3,
+ server_tmp.username,
+ server_tmp.realname,
+ server_tmp.hostname,
+ server_tmp.command,
+ 1, /* command_delay */
+ server_tmp.autojoin,
+ 1, /* autorejoin */
+ NULL);
+ if (ptr_server)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_INFO);
+ gui_printf (NULL, _("Server %s%s%s created (temporary server, NOT SAVED!)\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_SERVER),
+ server_tmp.name,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT));
+ if (!weechat_cmd_connect_one_server (window, ptr_server, 0))
+ connect_ok = 0;
+ }
+ else
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s unable to create server \"%s\"\n"),
+ WEECHAT_ERROR, argv[i]);
+ }
+ }
+ }
+ else
+ {
+ if (ascii_strcasecmp (argv[i], "-port") == 0)
+ i++;
+ }
+ }
+ }
+
+ if (nb_connect == 0)
+ connect_ok = weechat_cmd_connect_one_server (window, server, no_join);
+
+ if (!connect_ok)
+ return -1;
+
+ return 0;
+}
+
+/*
+ * weechat_cmd_dcc: DCC control (file or chat)
+ */
+
+int
+weechat_cmd_dcc (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ t_gui_buffer *buffer;
+ char *pos_nick, *pos_file;
+
+ gui_buffer_find_context (server, channel, NULL, &buffer);
+
+ /* DCC SEND file */
+ if (strncasecmp (arguments, "send", 4) == 0)
+ {
+ pos_nick = strchr (arguments, ' ');
+ if (!pos_nick)
+ {
+ irc_display_prefix (NULL, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s wrong argument count for \"%s\" command\n"),
+ WEECHAT_ERROR, "dcc send");
+ return -1;
+ }
+ while (pos_nick[0] == ' ')
+ pos_nick++;
+
+ pos_file = strchr (pos_nick, ' ');
+ if (!pos_file)
+ {
+ irc_display_prefix (NULL, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s wrong argument count for \"%s\" command\n"),
+ WEECHAT_ERROR, "dcc send");
+ return -1;
+ }
+ pos_file[0] = '\0';
+ pos_file++;
+ while (pos_file[0] == ' ')
+ pos_file++;
+
+ irc_dcc_send_request (server, IRC_DCC_FILE_SEND, pos_nick, pos_file);
+ }
+ /* DCC CHAT */
+ else if (strncasecmp (arguments, "chat", 4) == 0)
+ {
+ pos_nick = strchr (arguments, ' ');
+ if (!pos_nick)
+ {
+ irc_display_prefix (NULL, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s wrong argument count for \"%s\" command\n"),
+ WEECHAT_ERROR, "dcc chat");
+ return -1;
+ }
+ while (pos_nick[0] == ' ')
+ pos_nick++;
+
+ irc_dcc_send_request (server, IRC_DCC_CHAT_SEND, pos_nick, NULL);
+ }
+ /* close DCC CHAT */
+ else if (ascii_strcasecmp (arguments, "close") == 0)
+ {
+ if (GUI_BUFFER_IS_PRIVATE(buffer) &&
+ GUI_CHANNEL(buffer)->dcc_chat)
+ {
+ irc_dcc_close ((t_irc_dcc *)(GUI_CHANNEL(buffer)->dcc_chat),
+ IRC_DCC_ABORTED);
+ irc_dcc_redraw (1);
+ }
+ }
+ /* unknown DCC action */
+ else
+ {
+ irc_display_prefix (NULL, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s wrong arguments for \"%s\" command\n"),
+ WEECHAT_ERROR, "dcc");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * weechat_cmd_debug_display_windows: display tree of windows
+ */
+
+void
+weechat_cmd_debug_display_windows (t_gui_window_tree *tree, int indent)
+{
+ int i;
+
+ if (tree)
+ {
+ for (i = 0; i < indent; i++)
+ gui_printf_nolog (NULL, " ");
+
+ if (tree->window)
+ {
+ /* leaf */
+ gui_printf_nolog (NULL, "leaf: %X (parent:%X), win=%X, child1=%X, child2=%X, %d,%d %dx%d, %d%%x%d%%\n",
+ tree, tree->parent_node, tree->window,
+ tree->child1, tree->child2,
+ tree->window->win_x, tree->window->win_y,
+ tree->window->win_width, tree->window->win_height,
+ tree->window->win_width_pct, tree->window->win_height_pct);
+ }
+ else
+ {
+ /* node */
+ gui_printf_nolog (NULL, "node: %X (parent:%X), win=%X, child1=%X, child2=%X)\n",
+ tree, tree->parent_node, tree->window,
+ tree->child1, tree->child2);
+ }
+
+ if (tree->child1)
+ weechat_cmd_debug_display_windows (tree->child1, indent + 1);
+ if (tree->child2)
+ weechat_cmd_debug_display_windows (tree->child2, indent + 1);
+ }
+}
+
+/*
+ * weechat_cmd_debug: print debug messages
+ */
+
+int
+weechat_cmd_debug (t_irc_server *server, t_irc_channel *channel,
+ int argc, char **argv)
+{
+ t_gui_buffer *buffer;
+
+ /* make C compiler happy */
+ (void) server;
+ (void) channel;
+
+ gui_buffer_find_context (server, channel, NULL, &buffer);
+
+ if (argc != 1)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s wrong argument count for \"%s\" command\n"),
+ WEECHAT_ERROR, "debug");
+ return -1;
+ }
+
+ if (ascii_strcasecmp (argv[0], "dump") == 0)
+ {
+ weechat_dump (0);
+ }
+ else if (ascii_strcasecmp (argv[0], "buffer") == 0)
+ {
+ gui_buffer_dump_hexa (buffer);
+ }
+ else if (ascii_strcasecmp (argv[0], "windows") == 0)
+ {
+ gui_printf_nolog (NULL, "\n");
+ gui_printf_nolog (NULL, "DEBUG: windows tree:\n");
+ weechat_cmd_debug_display_windows (gui_windows_tree, 1);
+ }
+ else
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s unknown option for \"%s\" command\n"),
+ WEECHAT_ERROR, "debug");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * weechat_cmd_disconnect_one_server: disconnect from a server
+ * return 0 if error, 1 if ok
+ */
+
+int
+weechat_cmd_disconnect_one_server (t_irc_server *server)
+{
+ if ((!server->is_connected) && (server->child_pid == 0)
+ && (server->reconnect_start == 0))
+ {
+ irc_display_prefix (NULL, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf (server->buffer,
+ _("%s not connected to server \"%s\"!\n"),
+ WEECHAT_ERROR, server->name);
+ return 0;
+ }
+ if (server->reconnect_start > 0)
+ {
+ irc_display_prefix (NULL, server->buffer, GUI_PREFIX_INFO);
+ gui_printf (server->buffer,
+ _("Auto-reconnection is cancelled\n"));
+ }
+ irc_send_quit_server (server, NULL);
+ irc_server_disconnect (server, 0);
+ gui_status_draw (server->buffer, 1);
+
+ /* disconnect ok */
+ return 1;
+}
+
+/*
+ * weechat_cmd_disconnect: disconnect from server(s)
+ */
+
+int
+weechat_cmd_disconnect (t_irc_server *server, t_irc_channel *channel,
+ int argc, char **argv)
+{
+ t_gui_buffer *buffer;
+ t_irc_server *ptr_server;
+ int i, disconnect_ok;
+
+ gui_buffer_find_context (server, channel, NULL, &buffer);
+
+ if (argc == 0)
+ disconnect_ok = weechat_cmd_disconnect_one_server (server);
+ else
+ {
+ disconnect_ok = 1;
+
+ if (ascii_strcasecmp (argv[0], "-all") == 0)
+ {
+ for (ptr_server = irc_servers; ptr_server;
+ ptr_server = ptr_server->next_server)
+ {
+ if ((ptr_server->is_connected) || (ptr_server->child_pid != 0)
+ || (ptr_server->reconnect_start != 0))
+ {
+ if (!weechat_cmd_disconnect_one_server (ptr_server))
+ disconnect_ok = 0;
+ }
+ }
+ }
+ else
+ {
+ for (i = 0; i < argc; i++)
+ {
+ ptr_server = irc_server_search (argv[i]);
+ if (ptr_server)
+ {
+ if (!weechat_cmd_disconnect_one_server (ptr_server))
+ disconnect_ok = 0;
+ }
+ else
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL, _("%s server \"%s\" not found\n"),
+ WEECHAT_ERROR, argv[i]);
+ disconnect_ok = 0;
+ }
+ }
+ }
+ }
+
+ if (!disconnect_ok)
+ return -1;
+
+ return 0;
+}
+
+/*
+ * weechat_cmd_help: display help
+ */
+
+int
+weechat_cmd_help (t_irc_server *server, t_irc_channel *channel,
+ int argc, char **argv)
+{
+ int i;
+#ifdef PLUGINS
+ t_weechat_plugin *ptr_plugin;
+ t_plugin_handler *ptr_handler;
+#endif
+
+ /* make C compiler happy */
+ (void) server;
+ (void) channel;
+
+ switch (argc)
+ {
+ case 0:
+ gui_printf (NULL, "\n");
+ gui_printf (NULL, _("%s internal commands:\n"), PACKAGE_NAME);
+ for (i = 0; weechat_commands[i].command_name; i++)
+ {
+ gui_printf (NULL, " %s%s %s- %s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ weechat_commands[i].command_name,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ _(weechat_commands[i].command_description));
+ }
+ gui_printf (NULL, "\n");
+ gui_printf (NULL, _("IRC commands:\n"));
+ for (i = 0; irc_commands[i].command_name; i++)
+ {
+ if (irc_commands[i].cmd_function_args || irc_commands[i].cmd_function_1arg)
+ {
+ gui_printf (NULL, " %s%s %s- %s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ irc_commands[i].command_name,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ _(irc_commands[i].command_description));
+ }
+ }
+#ifdef PLUGINS
+ gui_printf (NULL, "\n");
+ gui_printf (NULL, _("Plugin commands:\n"));
+ for (ptr_plugin = weechat_plugins; ptr_plugin;
+ ptr_plugin = ptr_plugin->next_plugin)
+ {
+ for (ptr_handler = ptr_plugin->handlers;
+ ptr_handler; ptr_handler = ptr_handler->next_handler)
+ {
+ if (ptr_handler->type == PLUGIN_HANDLER_COMMAND)
+ {
+ gui_printf (NULL, " %s%s",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ ptr_handler->command);
+ if (ptr_handler->description
+ && ptr_handler->description[0])
+ gui_printf (NULL, " %s- %s",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ ptr_handler->description);
+ gui_printf (NULL, "\n");
+ }
+ }
+ }
+#endif
+ break;
+ case 1:
+#ifdef PLUGINS
+ for (ptr_plugin = weechat_plugins; ptr_plugin;
+ ptr_plugin = ptr_plugin->next_plugin)
+ {
+ for (ptr_handler = ptr_plugin->handlers;
+ ptr_handler; ptr_handler = ptr_handler->next_handler)
+ {
+ if ((ptr_handler->type == PLUGIN_HANDLER_COMMAND)
+ && (ascii_strcasecmp (ptr_handler->command, argv[0]) == 0))
+ {
+ gui_printf (NULL, "\n");
+ gui_printf (NULL, "[p]");
+ gui_printf (NULL, " %s/%s",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ ptr_handler->command);
+ if (ptr_handler->arguments &&
+ ptr_handler->arguments[0])
+ gui_printf (NULL, " %s%s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ ptr_handler->arguments);
+ else
+ gui_printf (NULL, "\n");
+ if (ptr_handler->description &&
+ ptr_handler->description[0])
+ gui_printf (NULL, "\n%s\n",
+ ptr_handler->description);
+ if (ptr_handler->arguments_description &&
+ ptr_handler->arguments_description[0])
+ gui_printf (NULL, "\n%s\n",
+ ptr_handler->arguments_description);
+ return 0;
+ }
+ }
+ }
+#endif
+ for (i = 0; weechat_commands[i].command_name; i++)
+ {
+ if (ascii_strcasecmp (weechat_commands[i].command_name, argv[0]) == 0)
+ {
+ gui_printf (NULL, "\n");
+ gui_printf (NULL, "[w]");
+ gui_printf (NULL, " %s/%s",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ weechat_commands[i].command_name);
+ if (weechat_commands[i].arguments &&
+ weechat_commands[i].arguments[0])
+ gui_printf (NULL, " %s%s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ _(weechat_commands[i].arguments));
+ else
+ gui_printf (NULL, "\n");
+ if (weechat_commands[i].command_description &&
+ weechat_commands[i].command_description[0])
+ gui_printf (NULL, "\n%s\n",
+ _(weechat_commands[i].command_description));
+ if (weechat_commands[i].arguments_description &&
+ weechat_commands[i].arguments_description[0])
+ gui_printf (NULL, "\n%s\n",
+ _(weechat_commands[i].arguments_description));
+ return 0;
+ }
+ }
+ for (i = 0; irc_commands[i].command_name; i++)
+ {
+ if ((ascii_strcasecmp (irc_commands[i].command_name, argv[0]) == 0)
+ && (irc_commands[i].cmd_function_args || irc_commands[i].cmd_function_1arg))
+ {
+ gui_printf (NULL, "\n");
+ gui_printf (NULL, "[i]");
+ gui_printf (NULL, " %s/%s",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ irc_commands[i].command_name);
+ if (irc_commands[i].arguments &&
+ irc_commands[i].arguments[0])
+ gui_printf (NULL, " %s%s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ _(irc_commands[i].arguments));
+ else
+ gui_printf (NULL, "\n");
+ if (irc_commands[i].command_description &&
+ irc_commands[i].command_description[0])
+ gui_printf (NULL, "\n%s\n",
+ _(irc_commands[i].command_description));
+ if (irc_commands[i].arguments_description &&
+ irc_commands[i].arguments_description[0])
+ gui_printf (NULL, "\n%s\n",
+ _(irc_commands[i].arguments_description));
+ return 0;
+ }
+ }
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("No help available, \"%s\" is an unknown command\n"),
+ argv[0]);
+ break;
+ }
+ return 0;
+}
+
+/*
+ * weechat_cmd_history: display current buffer history
+ */
+
+int
+weechat_cmd_history (t_irc_server *server, t_irc_channel *channel,
+ int argc, char **argv)
+{
+ t_gui_buffer *buffer;
+ t_history *ptr_history;
+ int n;
+ int n_total;
+ int n_user;
+
+ gui_buffer_find_context (server, channel, NULL, &buffer);
+
+ n_user = cfg_history_display_default;
+
+ if (argc == 1)
+ {
+ if (ascii_strcasecmp (argv[0], "clear") == 0)
+ {
+ history_buffer_free (buffer);
+ return 0;
+ }
+ else
+ n_user = atoi (argv[0]);
+ }
+
+ if (buffer->history)
+ {
+ n_total = 1;
+ for (ptr_history = buffer->history;
+ ptr_history->next_history;
+ ptr_history = ptr_history->next_history)
+ {
+ n_total++;
+ }
+ for (n = 0; ptr_history; ptr_history = ptr_history->prev_history, n++)
+ {
+ if ((n_user > 0) && ((n_total - n_user) > n))
+ continue;
+ irc_display_prefix (NULL, buffer, GUI_PREFIX_INFO);
+ gui_printf_nolog (buffer, "%s\n", ptr_history->text);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * weechat_cmd_ignore_display: display an ignore entry
+ */
+
+void
+weechat_cmd_ignore_display (char *text, t_irc_ignore *ptr_ignore)
+{
+ if (text)
+ gui_printf (NULL, "%s%s ",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ text);
+
+ gui_printf (NULL, _("%son %s%s%s/%s%s%s:%s ignoring %s%s%s from %s%s\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ ptr_ignore->server_name,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ ptr_ignore->channel_name,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ ptr_ignore->type,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_HOST),
+ ptr_ignore->mask);
+}
+
+/*
+ * weechat_cmd_ignore: ignore IRC commands and/or hosts
+ */
+
+int
+weechat_cmd_ignore (t_irc_server *server, t_irc_channel *channel,
+ int argc, char **argv)
+{
+ t_gui_buffer *buffer;
+ t_irc_ignore *ptr_ignore;
+ int i;
+
+ gui_buffer_find_context (server, channel, NULL, &buffer);
+
+ ptr_ignore = NULL;
+ switch (argc)
+ {
+ case 0:
+ /* List all ignore */
+ if (irc_ignore)
+ {
+ gui_printf (NULL, "\n");
+ gui_printf (NULL, _("List of ignore:\n"));
+ i = 0;
+ for (ptr_ignore = irc_ignore; ptr_ignore;
+ ptr_ignore = ptr_ignore->next_ignore)
+ {
+ i++;
+ gui_printf (NULL, "%s[%s%d%s] ",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ i,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK));
+ weechat_cmd_ignore_display (NULL, ptr_ignore);
+ }
+ }
+ else
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_INFO);
+ gui_printf (NULL, _("No ignore defined.\n"));
+ }
+ return 0;
+ break;
+ case 1:
+ ptr_ignore = irc_ignore_add (argv[0], "*", "*",
+ (GUI_SERVER(buffer)) ?
+ GUI_SERVER(buffer)->name : "*");
+ break;
+ case 2:
+ ptr_ignore = irc_ignore_add (argv[0], argv[1], "*",
+ (GUI_SERVER(buffer)) ?
+ GUI_SERVER(buffer)->name : "*");
+ break;
+ case 3:
+ ptr_ignore = irc_ignore_add (argv[0], argv[1], argv[2],
+ (GUI_SERVER(buffer)) ?
+ GUI_SERVER(buffer)->name : "*");
+ break;
+ case 4:
+ ptr_ignore = irc_ignore_add (argv[0], argv[1], argv[2], argv[3]);
+ break;
+ }
+ if (ptr_ignore)
+ {
+ gui_printf (NULL, "\n");
+ weechat_cmd_ignore_display (_("New ignore:"), ptr_ignore);
+ return 0;
+ }
+ else
+ return -1;
+}
+
+/*
+ * weechat_cmd_key_display: display a key binding
+ */
+
+void
+weechat_cmd_key_display (t_gui_key *key, int new_key)
+{
+ char *expanded_name;
+
+ expanded_name = gui_keyboard_get_expanded_name (key->key);
+ if (new_key)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_INFO);
+ gui_printf (NULL, _("New key binding: %s"),
+ (expanded_name) ? expanded_name : key->key);
+ }
+ else
+ gui_printf (NULL, " %20s", (expanded_name) ? expanded_name : key->key);
+ gui_printf (NULL, "%s => %s%s%s%s%s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ (key->function) ?
+ gui_keyboard_function_search_by_ptr (key->function) : key->command,
+ (key->args) ? " \"" : "",
+ (key->args) ? key->args : "",
+ (key->args) ? "\"" : "");
+ if (expanded_name)
+ free (expanded_name);
+}
+
+/*
+ * weechat_cmd_key: bind/unbind keys
+ */
+
+int
+weechat_cmd_key (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ t_gui_window *window;
+ t_gui_buffer *buffer;
+ char *pos, *pos_args, *args_tmp, *internal_code;
+ int i, length;
+ t_gui_key *ptr_key;
+ void (*ptr_function)(t_gui_window *, char *);
+
+ gui_buffer_find_context (server, channel, &window, &buffer);
+
+ if (arguments)
+ {
+ while (arguments[0] == ' ')
+ arguments++;
+ }
+
+ if (!arguments || (arguments[0] == '\0'))
+ {
+ gui_printf (NULL, "\n");
+ gui_printf (NULL, _("Key bindings:\n"));
+ for (ptr_key = gui_keys; ptr_key; ptr_key = ptr_key->next_key)
+ {
+ weechat_cmd_key_display (ptr_key, 0);
+ }
+ }
+ else if (ascii_strncasecmp (arguments, "unbind ", 7) == 0)
+ {
+ arguments += 7;
+ while (arguments[0] == ' ')
+ arguments++;
+ if (gui_keyboard_unbind (arguments))
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_INFO);
+ gui_printf (NULL, _("Key \"%s\" unbound\n"), arguments);
+ }
+ else
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s unable to unbind key \"%s\"\n"),
+ WEECHAT_ERROR, arguments);
+ return -1;
+ }
+ }
+ else if (ascii_strcasecmp (arguments, "functions") == 0)
+ {
+ gui_printf (NULL, "\n");
+ gui_printf (NULL, _("Internal key functions:\n"));
+ i = 0;
+ while (gui_key_functions[i].function_name)
+ {
+ gui_printf (NULL, "%25s %s\n",
+ gui_key_functions[i].function_name,
+ _(gui_key_functions[i].description));
+ i++;
+ }
+ }
+ else if (ascii_strncasecmp (arguments, "call ", 5) == 0)
+ {
+ arguments += 5;
+ while (arguments[0] == ' ')
+ arguments++;
+ pos = strchr (arguments, ' ');
+ if (pos)
+ pos[0] = '\0';
+ ptr_function = gui_keyboard_function_search_by_name (arguments);
+ if (pos)
+ pos[0] = ' ';
+ if (ptr_function)
+ {
+ pos_args = pos;
+ args_tmp = NULL;
+ if (pos_args)
+ {
+ pos_args++;
+ while (pos_args[0] == ' ')
+ pos_args++;
+ if (pos_args[0] == '"')
+ {
+ length = strlen (pos_args);
+ if ((length > 1) && (pos_args[length - 1] == '"'))
+ args_tmp = strndup (pos_args + 1, length - 2);
+ else
+ args_tmp = strdup (pos_args);
+ }
+ else
+ args_tmp = strdup (pos_args);
+ }
+ (void)(*ptr_function)(window, args_tmp);
+ if (args_tmp)
+ free (args_tmp);
+ }
+ else
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s unknown key function \"%s\"\n"),
+ WEECHAT_ERROR, arguments);
+ return -1;
+ }
+ }
+ else if (ascii_strncasecmp (arguments, "reset", 5) == 0)
+ {
+ arguments += 5;
+ while (arguments[0] == ' ')
+ arguments++;
+ if (ascii_strcasecmp (arguments, "-yes") == 0)
+ {
+ gui_keyboard_free_all ();
+ gui_keyboard_init ();
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_INFO);
+ gui_printf (NULL, _("Default key bindings restored\n"));
+ }
+ else
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s \"-yes\" argument is required for keys reset (security reason)\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ }
+ else
+ {
+ while (arguments[0] == ' ')
+ arguments++;
+ pos = strchr (arguments, ' ');
+ if (!pos)
+ {
+ ptr_key = NULL;
+ internal_code = gui_keyboard_get_internal_code (arguments);
+ if (internal_code)
+ ptr_key = gui_keyboard_search (internal_code);
+ if (ptr_key)
+ {
+ gui_printf (NULL, "\n");
+ gui_printf (NULL, _("Key:\n"));
+ weechat_cmd_key_display (ptr_key, 0);
+ }
+ else
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_INFO);
+ gui_printf (NULL, _("No key found.\n"));
+ }
+ if (internal_code)
+ free (internal_code);
+ return 0;
+ }
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ ptr_key = gui_keyboard_bind (arguments, pos);
+ if (ptr_key)
+ weechat_cmd_key_display (ptr_key, 1);
+ else
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s unable to bind key \"%s\"\n"),
+ WEECHAT_ERROR, arguments);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * weechat_cmd_panel_display_info: display infos about a panel
+ */
+
+void
+weechat_cmd_panel_display_info (t_gui_panel *panel)
+{
+ gui_printf (NULL, " %s%2d%s. ",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ panel->number,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT));
+ gui_printf (NULL, "%s%s%s ",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ panel->name,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT));
+ gui_printf (NULL, "(%s%s/%s",
+ (panel->panel_window) ? _("global") : _("local"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT));
+ switch (panel->position)
+ {
+ case GUI_PANEL_TOP:
+ gui_printf (NULL, "%s", _("top"));
+ break;
+ case GUI_PANEL_BOTTOM:
+ gui_printf (NULL, "%s", _("bottom"));
+ break;
+ case GUI_PANEL_LEFT:
+ gui_printf (NULL, "%s", _("left"));
+ break;
+ case GUI_PANEL_RIGHT:
+ gui_printf (NULL, "%s", _("right"));
+ break;
+ }
+ gui_printf (NULL, "%s/%s%d)\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ panel->size);
+}
+
+/*
+ * weechat_cmd_panel: manage panels
+ */
+
+int
+weechat_cmd_panel (t_irc_server *server, t_irc_channel *channel,
+ int argc, char **argv)
+{
+ t_gui_panel *ptr_panel;
+
+ /* make C compiler happy */
+ (void) server;
+ (void) channel;
+
+ gui_printf (NULL, "\n/panel command is under development!\n");
+
+ if ((argc == 0) || ((argc == 1) && (ascii_strcasecmp (argv[0], "list") == 0)))
+ {
+ /* list open panels */
+
+ gui_printf (NULL, "\n");
+ gui_printf (NULL, _("Open panels:\n"));
+
+ for (ptr_panel = gui_panels; ptr_panel; ptr_panel = ptr_panel->next_panel)
+ {
+ weechat_cmd_panel_display_info (ptr_panel);
+ }
+ }
+ else
+ {
+ }
+ return 0;
+}
+
+/*
+ * weechat_cmd_plugin_list: list loaded plugins
+ */
+
+void
+weechat_cmd_plugin_list (char *name, int full)
+{
+#ifdef PLUGINS
+ t_weechat_plugin *ptr_plugin;
+ int plugins_found;
+ t_plugin_handler *ptr_handler;
+ int handler_found;
+ t_plugin_modifier *ptr_modifier;
+ int modifier_found;
+
+ gui_printf (NULL, "\n");
+ if (!name)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_PLUGIN);
+ gui_printf (NULL, _("Plugins loaded:\n"));
+ }
+
+ plugins_found = 0;
+
+ for (ptr_plugin = weechat_plugins; ptr_plugin;
+ ptr_plugin = ptr_plugin->next_plugin)
+ {
+ if (!name || (ascii_strcasestr (ptr_plugin->name, name)))
+ {
+ plugins_found++;
+
+ /* plugin info */
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_PLUGIN);
+ gui_printf (NULL, " %s%s%s v%s - %s (%s)\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ ptr_plugin->name,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ ptr_plugin->version,
+ ptr_plugin->description,
+ ptr_plugin->filename);
+
+ if (full)
+ {
+ /* message handlers */
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_PLUGIN);
+ gui_printf (NULL, _(" message handlers:\n"));
+ handler_found = 0;
+ for (ptr_handler = ptr_plugin->handlers;
+ ptr_handler; ptr_handler = ptr_handler->next_handler)
+ {
+ if (ptr_handler->type == PLUGIN_HANDLER_MESSAGE)
+ {
+ handler_found = 1;
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_PLUGIN);
+ gui_printf (NULL, _(" IRC(%s)\n"),
+ ptr_handler->irc_command);
+ }
+ }
+ if (!handler_found)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_PLUGIN);
+ gui_printf (NULL, _(" (no message handler)\n"));
+ }
+
+ /* command handlers */
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_PLUGIN);
+ gui_printf (NULL, _(" command handlers:\n"));
+ handler_found = 0;
+ for (ptr_handler = ptr_plugin->handlers;
+ ptr_handler; ptr_handler = ptr_handler->next_handler)
+ {
+ if (ptr_handler->type == PLUGIN_HANDLER_COMMAND)
+ {
+ handler_found = 1;
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_PLUGIN);
+ gui_printf (NULL, " /%s",
+ ptr_handler->command);
+ if (ptr_handler->description
+ && ptr_handler->description[0])
+ gui_printf (NULL, " (%s)",
+ ptr_handler->description);
+ gui_printf (NULL, "\n");
+ }
+ }
+ if (!handler_found)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_PLUGIN);
+ gui_printf (NULL, _(" (no command handler)\n"));
+ }
+
+ /* timer handlers */
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_PLUGIN);
+ gui_printf (NULL, _(" timer handlers:\n"));
+ handler_found = 0;
+ for (ptr_handler = ptr_plugin->handlers;
+ ptr_handler; ptr_handler = ptr_handler->next_handler)
+ {
+ if (ptr_handler->type == PLUGIN_HANDLER_TIMER)
+ {
+ handler_found = 1;
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_PLUGIN);
+ gui_printf (NULL, _(" %d seconds\n"),
+ ptr_handler->interval);
+ }
+ }
+ if (!handler_found)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_PLUGIN);
+ gui_printf (NULL, _(" (no timer handler)\n"));
+ }
+
+ /* keyboard handlers */
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_PLUGIN);
+ gui_printf (NULL, _(" keyboard handlers:\n"));
+ handler_found = 0;
+ for (ptr_handler = ptr_plugin->handlers;
+ ptr_handler; ptr_handler = ptr_handler->next_handler)
+ {
+ if (ptr_handler->type == PLUGIN_HANDLER_KEYBOARD)
+ handler_found++;
+ }
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_PLUGIN);
+ if (!handler_found)
+ gui_printf (NULL, _(" (no keyboard handler)\n"));
+ else
+ gui_printf (NULL, _(" %d defined\n"),
+ handler_found);
+
+ /* event handlers */
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_PLUGIN);
+ gui_printf (NULL, _(" event handlers:\n"));
+ handler_found = 0;
+ for (ptr_handler = ptr_plugin->handlers;
+ ptr_handler; ptr_handler = ptr_handler->next_handler)
+ {
+ if (ptr_handler->type == PLUGIN_HANDLER_EVENT)
+ handler_found++;
+ }
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_PLUGIN);
+ if (!handler_found)
+ gui_printf (NULL, _(" (no event handler)\n"));
+ else
+ gui_printf (NULL, _(" %d defined\n"),
+ handler_found);
+
+ /* modifiers */
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_PLUGIN);
+ gui_printf (NULL, _(" modifiers:\n"));
+ modifier_found = 0;
+ for (ptr_modifier = ptr_plugin->modifiers;
+ ptr_modifier; ptr_modifier = ptr_modifier->next_modifier)
+ {
+ modifier_found++;
+ }
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_PLUGIN);
+ if (!modifier_found)
+ gui_printf (NULL, _(" (no modifier)\n"));
+ else
+ gui_printf (NULL, _(" %d defined\n"),
+ modifier_found);
+ }
+ }
+ }
+ if (plugins_found == 0)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_PLUGIN);
+ if (name)
+ gui_printf (NULL, _("No plugin found.\n"));
+ else
+ gui_printf (NULL, _(" (no plugin)\n"));
+ }
+#else
+ /* make C compiler happy */
+ (void) name;
+ (void) full;
+#endif
+}
+
+/*
+ * weechat_cmd_plugin: list/load/unload WeeChat plugins
+ */
+
+int
+weechat_cmd_plugin (t_irc_server *server, t_irc_channel *channel,
+ int argc, char **argv)
+{
+#ifdef PLUGINS
+ /* make C compiler happy */
+ (void) server;
+ (void) channel;
+
+ switch (argc)
+ {
+ case 0:
+ weechat_cmd_plugin_list (NULL, 0);
+ break;
+ case 1:
+ if (ascii_strcasecmp (argv[0], "list") == 0)
+ weechat_cmd_plugin_list (NULL, 0);
+ else if (ascii_strcasecmp (argv[0], "listfull") == 0)
+ weechat_cmd_plugin_list (NULL, 1);
+ else if (ascii_strcasecmp (argv[0], "autoload") == 0)
+ plugin_auto_load ();
+ else if (ascii_strcasecmp (argv[0], "reload") == 0)
+ {
+ plugin_unload_all ();
+ plugin_auto_load ();
+ }
+ else if (ascii_strcasecmp (argv[0], "unload") == 0)
+ plugin_unload_all ();
+ break;
+ case 2:
+ if (ascii_strcasecmp (argv[0], "list") == 0)
+ weechat_cmd_plugin_list (argv[1], 0);
+ else if (ascii_strcasecmp (argv[0], "listfull") == 0)
+ weechat_cmd_plugin_list (argv[1], 1);
+ else if (ascii_strcasecmp (argv[0], "load") == 0)
+ plugin_load (argv[1]);
+ else if (ascii_strcasecmp (argv[0], "reload") == 0)
+ plugin_reload_name (argv[1]);
+ else if (ascii_strcasecmp (argv[0], "unload") == 0)
+ plugin_unload_name (argv[1]);
+ else
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s unknown option for \"%s\" command\n"),
+ WEECHAT_ERROR, "plugin");
+ }
+ break;
+ default:
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s wrong argument count for \"%s\" command\n"),
+ WEECHAT_ERROR, "plugin");
+ }
+#else
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("Command \"%s\" is not available, WeeChat was built "
+ "without plugins support.\n"),
+ "plugin");
+ /* make C compiler happy */
+ (void) server;
+ (void) channel;
+ (void) argc;
+ (void) argv;
+#endif /* PLUGINS */
+
+ return 0;
+}
+
+/*
+ * weechat_cmd_reconnect_one_server: reconnect to a server
+ * return 0 if error, 1 if ok
+ */
+
+int
+weechat_cmd_reconnect_one_server (t_irc_server *server, int no_join)
+{
+ if ((!server->is_connected) && (server->child_pid == 0))
+ {
+ irc_display_prefix (NULL, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf (server->buffer,
+ _("%s not connected to server \"%s\"!\n"),
+ WEECHAT_ERROR, server->name);
+ return 0;
+ }
+ irc_send_quit_server (server, NULL);
+ irc_server_disconnect (server, 0);
+ if (irc_server_connect (server, no_join))
+ {
+ server->reconnect_start = 0;
+ server->reconnect_join = (server->channels) ? 1 : 0;
+ }
+ gui_status_draw (server->buffer, 1);
+
+ /* reconnect ok */
+ return 1;
+}
+
+/*
+ * weechat_cmd_reconnect: reconnect to server(s)
+ */
+
+int
+weechat_cmd_reconnect (t_irc_server *server, t_irc_channel *channel,
+ int argc, char **argv)
+{
+ t_gui_buffer *buffer;
+ t_irc_server *ptr_server;
+ int i, nb_reconnect, reconnect_ok, all_servers, no_join;
+
+ gui_buffer_find_context (server, channel, NULL, &buffer);
+
+ nb_reconnect = 0;
+ reconnect_ok = 1;
+
+ all_servers = 0;
+ no_join = 0;
+ for (i = 0; i < argc; i++)
+ {
+ if (ascii_strcasecmp (argv[i], "-all") == 0)
+ all_servers = 1;
+ if (ascii_strcasecmp (argv[i], "-nojoin") == 0)
+ no_join = 1;
+ }
+
+ if (all_servers)
+ {
+ for (ptr_server = irc_servers; ptr_server;
+ ptr_server = ptr_server->next_server)
+ {
+ nb_reconnect++;
+ if ((ptr_server->is_connected) || (ptr_server->child_pid != 0))
+ {
+ if (!weechat_cmd_reconnect_one_server (ptr_server, no_join))
+ reconnect_ok = 0;
+ }
+ }
+ }
+ else
+ {
+ for (i = 0; i < argc; i++)
+ {
+ if (argv[i][0] != '-')
+ {
+ nb_reconnect++;
+ ptr_server = irc_server_search (argv[i]);
+ if (ptr_server)
+ {
+ if (!weechat_cmd_reconnect_one_server (ptr_server, no_join))
+ reconnect_ok = 0;
+ }
+ else
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL, _("%s server \"%s\" not found\n"),
+ WEECHAT_ERROR, argv[i]);
+ reconnect_ok = 0;
+ }
+ }
+ }
+ }
+
+ if (nb_reconnect == 0)
+ reconnect_ok = weechat_cmd_reconnect_one_server (server, no_join);
+
+ if (!reconnect_ok)
+ return -1;
+
+ return 0;
+}
+
+/*
+ * weechat_cmd_save: save WeeChat and plugins options to disk
+ */
+
+int
+weechat_cmd_save (t_irc_server *server, t_irc_channel *channel,
+ int argc, char **argv)
+{
+ /* make C compiler happy */
+ (void) server;
+ (void) channel;
+
+ if (config_write ((argc == 1) ? argv[0] : NULL) == 0)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_INFO);
+ gui_printf_nolog (NULL, _("Configuration file saved\n"));
+ }
+ else
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf_nolog (NULL, _("%s failed to save configuration file\n"),
+ WEECHAT_ERROR);
+ }
+
+#ifdef PLUGINS
+ if (plugin_config_write () == 0)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_INFO);
+ gui_printf_nolog (NULL, _("Plugins options saved\n"));
+ }
+ else
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf_nolog (NULL, _("%s failed to save plugins options\n"),
+ WEECHAT_ERROR);
+ }
+#endif
+
+ return 0;
+}
+
+/*
+ * weechat_cmd_server: list, add or remove server(s)
+ */
+
+int
+weechat_cmd_server (t_irc_server *server, t_irc_channel *channel,
+ int argc, char **argv)
+{
+ t_gui_window *window;
+ t_gui_buffer *buffer;
+ int i, detailed_list, one_server_found;
+ t_irc_server server_tmp, *ptr_server, *server_found, *new_server;
+ t_gui_buffer *ptr_buffer;
+ char *server_name, *error;
+ long number;
+
+ gui_buffer_find_context (server, channel, &window, &buffer);
+
+ if ((argc == 0)
+ || (ascii_strcasecmp (argv[0], "list") == 0)
+ || (ascii_strcasecmp (argv[0], "listfull") == 0))
+ {
+ /* list servers */
+ server_name = NULL;
+ detailed_list = 0;
+ for (i = 0; i < argc; i++)
+ {
+ if (ascii_strcasecmp (argv[i], "list") == 0)
+ continue;
+ if (ascii_strcasecmp (argv[i], "listfull") == 0)
+ {
+ detailed_list = 1;
+ continue;
+ }
+ if (!server_name)
+ server_name = argv[i];
+ }
+ if (!server_name)
+ {
+ if (irc_servers)
+ {
+ gui_printf (NULL, "\n");
+ gui_printf (NULL, _("All servers:\n"));
+ for (ptr_server = irc_servers; ptr_server;
+ ptr_server = ptr_server->next_server)
+ {
+ irc_display_server (ptr_server, detailed_list);
+ }
+ }
+ else
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_INFO);
+ gui_printf (NULL, _("No server.\n"));
+ }
+ }
+ else
+ {
+ one_server_found = 0;
+ for (ptr_server = irc_servers; ptr_server;
+ ptr_server = ptr_server->next_server)
+ {
+ if (ascii_strcasestr (ptr_server->name, server_name))
+ {
+ if (!one_server_found)
+ {
+ gui_printf (NULL, "\n");
+ gui_printf (NULL, _("Servers with '%s':\n"),
+ server_name);
+ }
+ one_server_found = 1;
+ irc_display_server (ptr_server, detailed_list);
+ }
+ }
+ if (!one_server_found)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_INFO);
+ gui_printf (NULL, _("No server with '%s' found.\n"),
+ server_name);
+ }
+ }
+ }
+ else
+ {
+ if (ascii_strcasecmp (argv[0], "add") == 0)
+ {
+ if (argc < 3)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s missing parameters for \"%s\" command\n"),
+ WEECHAT_ERROR, "server");
+ return -1;
+ }
+
+ if (irc_server_name_already_exists (argv[1]))
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s server \"%s\" already exists, can't create it!\n"),
+ WEECHAT_ERROR, argv[1]);
+ return -1;
+ }
+
+ /* init server struct */
+ irc_server_init (&server_tmp);
+
+ server_tmp.name = strdup (argv[1]);
+ server_tmp.address = strdup (argv[2]);
+ server_tmp.port = IRC_DEFAULT_PORT;
+
+ /* parse arguments */
+ for (i = 3; i < argc; i++)
+ {
+ if (argv[i][0] == '-')
+ {
+ if (ascii_strcasecmp (argv[i], "-temp") == 0)
+ server_tmp.temp_server = 1;
+ if (ascii_strcasecmp (argv[i], "-auto") == 0)
+ server_tmp.autoconnect = 1;
+ if (ascii_strcasecmp (argv[i], "-noauto") == 0)
+ server_tmp.autoconnect = 0;
+ if (ascii_strcasecmp (argv[i], "-ipv6") == 0)
+ server_tmp.ipv6 = 1;
+ if (ascii_strcasecmp (argv[i], "-ssl") == 0)
+ server_tmp.ssl = 1;
+ if (ascii_strcasecmp (argv[i], "-port") == 0)
+ {
+ if (i == (argc - 1))
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s missing argument for \"%s\" option\n"),
+ WEECHAT_ERROR, "-port");
+ irc_server_destroy (&server_tmp);
+ return -1;
+ }
+ error = NULL;
+ number = strtol (argv[++i], &error, 10);
+ if ((error) && (error[0] == '\0'))
+ server_tmp.port = number;
+ }
+ if (ascii_strcasecmp (argv[i], "-pwd") == 0)
+ {
+ if (i == (argc - 1))
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s missing argument for \"%s\" option\n"),
+ WEECHAT_ERROR, "-pwd");
+ irc_server_destroy (&server_tmp);
+ return -1;
+ }
+ server_tmp.password = strdup (argv[++i]);
+ }
+ if (ascii_strcasecmp (argv[i], "-nicks") == 0)
+ {
+ if (i >= (argc - 3))
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s missing argument for \"%s\" option\n"),
+ WEECHAT_ERROR, "-nicks");
+ irc_server_destroy (&server_tmp);
+ return -1;
+ }
+ server_tmp.nick1 = strdup (argv[++i]);
+ server_tmp.nick2 = strdup (argv[++i]);
+ server_tmp.nick3 = strdup (argv[++i]);
+ }
+ if (ascii_strcasecmp (argv[i], "-username") == 0)
+ {
+ if (i == (argc - 1))
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s missing argument for \"%s\" option\n"),
+ WEECHAT_ERROR, "-username");
+ irc_server_destroy (&server_tmp);
+ return -1;
+ }
+ server_tmp.username = strdup (argv[++i]);
+ }
+ if (ascii_strcasecmp (argv[i], "-realname") == 0)
+ {
+ if (i == (argc - 1))
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s missing argument for \"%s\" option\n"),
+ WEECHAT_ERROR, "-realname");
+ irc_server_destroy (&server_tmp);
+ return -1;
+ }
+ server_tmp.realname = strdup (argv[++i]);
+ }
+ if (ascii_strcasecmp (argv[i], "-command") == 0)
+ {
+ if (i == (argc - 1))
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s missing argument for \"%s\" option\n"),
+ WEECHAT_ERROR, "-command");
+ irc_server_destroy (&server_tmp);
+ return -1;
+ }
+ server_tmp.command = strdup (argv[++i]);
+ }
+ if (ascii_strcasecmp (argv[i], "-autojoin") == 0)
+ {
+ if (i == (argc - 1))
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s missing argument for \"%s\" option\n"),
+ WEECHAT_ERROR, "-autojoin");
+ irc_server_destroy (&server_tmp);
+ return -1;
+ }
+ server_tmp.autojoin = strdup (argv[++i]);
+ }
+ }
+ }
+
+ /* create new server */
+ new_server = irc_server_new (server_tmp.name,
+ server_tmp.autoconnect,
+ server_tmp.autoreconnect,
+ server_tmp.autoreconnect_delay,
+ server_tmp.temp_server,
+ server_tmp.address,
+ server_tmp.port,
+ server_tmp.ipv6,
+ server_tmp.ssl,
+ server_tmp.password,
+ server_tmp.nick1,
+ server_tmp.nick2,
+ server_tmp.nick3,
+ server_tmp.username,
+ server_tmp.realname,
+ server_tmp.hostname,
+ server_tmp.command,
+ 1, /* command_delay */
+ server_tmp.autojoin,
+ 1, /* autorejoin */
+ NULL);
+ if (new_server)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_INFO);
+ gui_printf (NULL, _("Server %s%s%s created\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_SERVER),
+ server_tmp.name,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT));
+ }
+ else
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s unable to create server\n"),
+ WEECHAT_ERROR);
+ irc_server_destroy (&server_tmp);
+ return -1;
+ }
+
+ if (new_server->autoconnect)
+ {
+ (void) gui_buffer_new (window, new_server, NULL,
+ GUI_BUFFER_TYPE_STANDARD, 1);
+ irc_server_connect (new_server, 0);
+ }
+
+ irc_server_destroy (&server_tmp);
+ }
+ else if (ascii_strcasecmp (argv[0], "copy") == 0)
+ {
+ if (argc < 3)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s missing server name for \"%s\" command\n"),
+ WEECHAT_ERROR, "server copy");
+ return -1;
+ }
+
+ /* look for server by name */
+ server_found = irc_server_search (argv[1]);
+ if (!server_found)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s server \"%s\" not found for \"%s\" command\n"),
+ WEECHAT_ERROR, argv[1], "server copy");
+ return -1;
+ }
+
+ /* check if target name already exists */
+ if (irc_server_search (argv[2]))
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s server \"%s\" already exists for \"%s\" command\n"),
+ WEECHAT_ERROR, argv[2], "server copy");
+ return -1;
+ }
+
+ /* duplicate server */
+ new_server = irc_server_duplicate (server_found, argv[2]);
+ if (new_server)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_INFO);
+ gui_printf (NULL, _("Server %s%s%s has been copied to %s%s\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_SERVER),
+ argv[1],
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_SERVER),
+ argv[2]);
+ gui_window_redraw_all_buffers ();
+ return 0;
+ }
+
+ return -1;
+ }
+ else if (ascii_strcasecmp (argv[0], "rename") == 0)
+ {
+ if (argc < 3)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s missing server name for \"%s\" command\n"),
+ WEECHAT_ERROR, "server rename");
+ return -1;
+ }
+
+ /* look for server by name */
+ server_found = irc_server_search (argv[1]);
+ if (!server_found)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s server \"%s\" not found for \"%s\" command\n"),
+ WEECHAT_ERROR, argv[1], "server rename");
+ return -1;
+ }
+
+ /* check if target name already exists */
+ if (irc_server_search (argv[2]))
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s server \"%s\" already exists for \"%s\" command\n"),
+ WEECHAT_ERROR, argv[2], "server rename");
+ return -1;
+ }
+
+ /* rename server */
+ if (irc_server_rename (server_found, argv[2]))
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_INFO);
+ gui_printf (NULL, _("Server %s%s%s has been renamed to %s%s\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_SERVER),
+ argv[1],
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_SERVER),
+ argv[2]);
+ gui_window_redraw_all_buffers ();
+ return 0;
+ }
+
+ return -1;
+ }
+ else if (ascii_strcasecmp (argv[0], "keep") == 0)
+ {
+ if (argc < 2)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s missing server name for \"%s\" command\n"),
+ WEECHAT_ERROR, "server keep");
+ return -1;
+ }
+
+ /* look for server by name */
+ server_found = irc_server_search (argv[1]);
+ if (!server_found)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s server \"%s\" not found for \"%s\" command\n"),
+ WEECHAT_ERROR, argv[1], "server keep");
+ return -1;
+ }
+
+ /* check that it is temporary server */
+ if (!server_found->temp_server)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s server \"%s\" is not a temporary server\n"),
+ WEECHAT_ERROR, argv[1]);
+ return -1;
+ }
+
+ /* remove temporary flag on server */
+ server_found->temp_server = 0;
+
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_INFO);
+ gui_printf (NULL, _("Server %s%s%s is not temporary any more\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_SERVER),
+ argv[1],
+ GUI_COLOR(GUI_COLOR_WIN_CHAT));
+
+ return 0;
+ }
+ else if (ascii_strcasecmp (argv[0], "del") == 0)
+ {
+ if (argc < 2)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s missing server name for \"%s\" command\n"),
+ WEECHAT_ERROR, "server del");
+ return -1;
+ }
+
+ /* look for server by name */
+ server_found = irc_server_search (argv[1]);
+ if (!server_found)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s server \"%s\" not found for \"%s\" command\n"),
+ WEECHAT_ERROR, argv[1], "server del");
+ return -1;
+ }
+ if (server_found->is_connected)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s you can not delete server \"%s\" because you are connected to. "
+ "Try /disconnect %s before.\n"),
+ WEECHAT_ERROR, argv[1], argv[1]);
+ return -1;
+ }
+
+ for (ptr_buffer = gui_buffers; ptr_buffer; ptr_buffer = ptr_buffer->next_buffer)
+ {
+ if (GUI_SERVER(ptr_buffer) == server_found)
+ {
+ ptr_buffer->server = NULL;
+ ptr_buffer->channel = NULL;
+ }
+ }
+
+ server_name = strdup (server_found->name);
+
+ irc_server_free (server_found);
+
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_INFO);
+ gui_printf (NULL, _("Server %s%s%s has been deleted\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_SERVER),
+ server_name,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT));
+ if (server_name)
+ free (server_name);
+
+ gui_window_redraw_buffer (buffer);
+
+ return 0;
+ }
+ else if (ascii_strcasecmp (argv[0], "deloutq") == 0)
+ {
+ for (ptr_server = irc_servers; ptr_server;
+ ptr_server = ptr_server->next_server)
+ {
+ irc_server_outqueue_free_all (ptr_server);
+ }
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_INFO);
+ gui_printf_nolog (NULL, _("Messages outqueue DELETED for all servers. "
+ "Some messages from you or WeeChat may "
+ "have been lost!\n"));
+ return 0;
+ }
+ else
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s unknown option for \"%s\" command\n"),
+ WEECHAT_ERROR, "server");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * weechat_cmd_set_display_option: display config option
+ */
+
+void
+weechat_cmd_set_display_option (t_config_option *option, char *prefix, void *value)
+{
+ char *color_name, *value2;
+
+ gui_printf (NULL, " %s%s%s%s = ",
+ (prefix) ? prefix : "",
+ (prefix) ? "." : "",
+ option->option_name,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK));
+ if (!value)
+ {
+ if (option->option_type == OPTION_TYPE_STRING)
+ value = option->ptr_string;
+ else
+ value = option->ptr_int;
+ }
+ switch (option->option_type)
+ {
+ case OPTION_TYPE_BOOLEAN:
+ gui_printf (NULL, "%s%s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_HOST),
+ (*((int *)value)) ? "ON" : "OFF");
+ break;
+ case OPTION_TYPE_INT:
+ gui_printf (NULL, "%s%d\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_HOST),
+ *((int *)value));
+ break;
+ case OPTION_TYPE_INT_WITH_STRING:
+ gui_printf (NULL, "%s%s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_HOST),
+ option->array_values[*((int *)value)]);
+ break;
+ case OPTION_TYPE_COLOR:
+ color_name = gui_color_get_name (*((int *)value));
+ gui_printf (NULL, "%s%s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_HOST),
+ (color_name) ? color_name : _("(unknown)"));
+ break;
+ case OPTION_TYPE_STRING:
+ if (*((char **)value))
+ {
+ value2 = strdup (*((char **)value));
+ if (value2)
+ {
+ if (cfg_log_hide_nickserv_pwd)
+ {
+ irc_display_hide_password (value2, 1);
+ if (strcmp (*((char **)value), value2) != 0)
+ gui_printf (NULL, _("%s(password hidden) "),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT));
+ }
+ gui_printf (NULL, "%s\"%s%s%s\"",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_HOST),
+ value2,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK));
+ free (value2);
+ }
+ }
+ else
+ gui_printf (NULL, "%s\"\"",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK));
+ gui_printf (NULL, "\n");
+ break;
+ }
+}
+
+/*
+ * weechat_cmd_set: set config options
+ */
+
+int
+weechat_cmd_set (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ char *option, *value, *pos;
+ int i, j, section_displayed;
+ t_config_option *ptr_option;
+ t_irc_server *ptr_server;
+ char option_name[256];
+ void *ptr_option_value;
+ int last_section, last_option, number_found;
+
+ /* make C compiler happy */
+ (void) server;
+ (void) channel;
+
+ option = NULL;
+ value = NULL;
+ if (arguments && arguments[0])
+ {
+ option = arguments;
+ value = strchr (option, '=');
+ if (value)
+ {
+ value[0] = '\0';
+
+ /* remove spaces before '=' */
+ pos = value - 1;
+ while ((pos > option) && (pos[0] == ' '))
+ {
+ pos[0] = '\0';
+ pos--;
+ }
+
+ /* skip spaces after '=' */
+ value++;
+ while (value[0] && (value[0] == ' '))
+ {
+ value++;
+ }
+
+ /* remove simple or double quotes
+ and spaces at the end */
+ if (strlen(value) > 1)
+ {
+ pos = value + strlen (value) - 1;
+ while ((pos > value) && (pos[0] == ' '))
+ {
+ pos[0] = '\0';
+ pos--;
+ }
+ pos = value + strlen (value) - 1;
+ if (((value[0] == '\'') &&
+ (pos[0] == '\'')) ||
+ ((value[0] == '"') &&
+ (pos[0] == '"')))
+ {
+ pos[0] = '\0';
+ value++;
+ }
+ }
+ }
+ }
+
+ if (value)
+ {
+ pos = strrchr (option, '.');
+ if (pos)
+ {
+ /* server config option modification */
+ pos[0] = '\0';
+ ptr_server = irc_server_search (option);
+ if (!ptr_server)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s server \"%s\" not found\n"),
+ WEECHAT_ERROR, option);
+ }
+ else
+ {
+ switch (config_set_server_value (ptr_server, pos + 1, value))
+ {
+ case 0:
+ gui_printf (NULL, "\n");
+ gui_printf (NULL, "%s[%s%s %s%s%s]\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ config_sections[CONFIG_SECTION_SERVER].section_name,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_SERVER),
+ ptr_server->name,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK));
+ for (i = 0; weechat_options[CONFIG_SECTION_SERVER][i].option_name; i++)
+ {
+ if (strcmp (weechat_options[CONFIG_SECTION_SERVER][i].option_name, pos + 1) == 0)
+ break;
+ }
+ if (weechat_options[CONFIG_SECTION_SERVER][i].option_name)
+ {
+ ptr_option_value = config_get_server_option_ptr (ptr_server,
+ weechat_options[CONFIG_SECTION_SERVER][i].option_name);
+ weechat_cmd_set_display_option (&weechat_options[CONFIG_SECTION_SERVER][i],
+ ptr_server->name,
+ ptr_option_value);
+ }
+ config_change_buffer_content ();
+ break;
+ case -1:
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL, _("%s config option \"%s\" not found\n"),
+ WEECHAT_ERROR, pos + 1);
+ break;
+ case -2:
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL, _("%s incorrect value for option \"%s\"\n"),
+ WEECHAT_ERROR, pos + 1);
+ break;
+ }
+ }
+ pos[0] = '.';
+ }
+ else
+ {
+ ptr_option = config_option_search (option);
+ if (ptr_option)
+ {
+ if (ptr_option->handler_change == NULL)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s option \"%s\" can not be changed while WeeChat is running\n"),
+ WEECHAT_ERROR, option);
+ }
+ else
+ {
+ if (config_option_set_value (ptr_option, value) == 0)
+ {
+ gui_printf (NULL, "\n");
+ gui_printf (NULL, "%s[%s%s%s]\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ config_get_section (ptr_option),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK));
+ weechat_cmd_set_display_option (ptr_option, NULL, NULL);
+ (void) (ptr_option->handler_change());
+ }
+ else
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL, _("%s incorrect value for option \"%s\"\n"),
+ WEECHAT_ERROR, option);
+ }
+ }
+ }
+ else
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL, _("%s config option \"%s\" not found\n"),
+ WEECHAT_ERROR, option);
+ }
+ }
+ }
+ else
+ {
+ last_section = -1;
+ last_option = -1;
+ number_found = 0;
+ for (i = 0; i < CONFIG_NUMBER_SECTIONS; i++)
+ {
+ section_displayed = 0;
+ if ((i != CONFIG_SECTION_KEYS) && (i != CONFIG_SECTION_ALIAS)
+ && (i != CONFIG_SECTION_IGNORE) && (i != CONFIG_SECTION_SERVER))
+ {
+ for (j = 0; weechat_options[i][j].option_name; j++)
+ {
+ if ((!option) ||
+ ((option) && (option[0])
+ && (strstr (weechat_options[i][j].option_name, option)
+ != NULL)))
+ {
+ if (!section_displayed)
+ {
+ gui_printf (NULL, "\n");
+ gui_printf (NULL, "%s[%s%s%s]\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ config_sections[i].section_name,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK));
+ section_displayed = 1;
+ }
+ weechat_cmd_set_display_option (&weechat_options[i][j], NULL, NULL);
+ last_section = i;
+ last_option = j;
+ number_found++;
+ }
+ }
+ }
+ }
+ for (ptr_server = irc_servers; ptr_server;
+ ptr_server = ptr_server->next_server)
+ {
+ section_displayed = 0;
+ for (i = 0; weechat_options[CONFIG_SECTION_SERVER][i].option_name; i++)
+ {
+ snprintf (option_name, sizeof (option_name), "%s.%s",
+ ptr_server->name,
+ weechat_options[CONFIG_SECTION_SERVER][i].option_name);
+ if ((!option) ||
+ ((option) && (option[0])
+ && (strstr (option_name, option) != NULL)))
+ {
+ if (!section_displayed)
+ {
+ gui_printf (NULL, "\n");
+ gui_printf (NULL, "%s[%s%s %s%s%s]\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ config_sections[CONFIG_SECTION_SERVER].section_name,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_SERVER),
+ ptr_server->name,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK));
+ section_displayed = 1;
+ }
+ ptr_option_value = config_get_server_option_ptr (ptr_server,
+ weechat_options[CONFIG_SECTION_SERVER][i].option_name);
+ if (ptr_option_value)
+ {
+ weechat_cmd_set_display_option (&weechat_options[CONFIG_SECTION_SERVER][i],
+ ptr_server->name,
+ ptr_option_value);
+ last_section = CONFIG_SECTION_SERVER;
+ last_option = i;
+ number_found++;
+ }
+ }
+ }
+ }
+ if (number_found == 0)
+ {
+ if (option)
+ gui_printf (NULL, _("No config option found with \"%s\"\n"),
+ option);
+ else
+ gui_printf (NULL, _("No config option found\n"));
+ }
+ else
+ {
+ if ((number_found == 1) && (last_section >= 0) && (last_option >= 0))
+ {
+ gui_printf (NULL, "\n");
+ gui_printf (NULL, _("%sDetail:\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL));
+ switch (weechat_options[last_section][last_option].option_type)
+ {
+ case OPTION_TYPE_BOOLEAN:
+ gui_printf (NULL, _(" . type boolean (values: 'on' or 'off')\n"));
+ gui_printf (NULL, _(" . default value: '%s'\n"),
+ (weechat_options[last_section][last_option].default_int == BOOL_TRUE) ?
+ "on" : "off");
+ break;
+ case OPTION_TYPE_INT:
+ gui_printf (NULL, _(" . type integer (values: between %d and %d)\n"),
+ weechat_options[last_section][last_option].min,
+ weechat_options[last_section][last_option].max);
+ gui_printf (NULL, _(" . default value: %d\n"),
+ weechat_options[last_section][last_option].default_int);
+ break;
+ case OPTION_TYPE_INT_WITH_STRING:
+ gui_printf (NULL, _(" . type string (values: "));
+ i = 0;
+ while (weechat_options[last_section][last_option].array_values[i])
+ {
+ gui_printf (NULL, "'%s'",
+ weechat_options[last_section][last_option].array_values[i]);
+ if (weechat_options[last_section][last_option].array_values[i + 1])
+ gui_printf (NULL, ", ");
+ i++;
+ }
+ gui_printf (NULL, ")\n");
+ gui_printf (NULL, _(" . default value: '%s'\n"),
+ (weechat_options[last_section][last_option].default_string) ?
+ weechat_options[last_section][last_option].default_string : _("empty"));
+ break;
+ case OPTION_TYPE_COLOR:
+ gui_printf (NULL, _(" . type color (Curses or Gtk color, look at WeeChat doc)\n"));
+ gui_printf (NULL, _(" . default value: '%s'\n"),
+ (weechat_options[last_section][last_option].default_string) ?
+ weechat_options[last_section][last_option].default_string : _("empty"));
+ break;
+ case OPTION_TYPE_STRING:
+ switch (weechat_options[last_section][last_option].max)
+ {
+ case 0:
+ gui_printf (NULL, _(" . type string (any string)\n"));
+ break;
+ case 1:
+ gui_printf (NULL, _(" . type: char (any char)\n"));
+ break;
+ default:
+ gui_printf (NULL, _(" . type string (any string, limit: %d chars)\n"),
+ weechat_options[last_section][last_option].max);
+ break;
+ }
+ gui_printf (NULL, _(" . default value: '%s'\n"),
+ (weechat_options[last_section][last_option].default_string) ?
+ weechat_options[last_section][last_option].default_string : _("empty"));
+ break;
+ }
+ gui_printf (NULL, _(" . description: %s\n"),
+ _(weechat_options[last_section][last_option].long_description));
+ }
+ else
+ {
+ gui_printf (NULL, "\n");
+ gui_printf (NULL, "%s%d %s",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ number_found,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT));
+ if (option)
+ gui_printf (NULL, _("config option(s) found with \"%s\"\n"),
+ option);
+ else
+ gui_printf (NULL, _("config option(s) found\n"));
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * weechat_cmd_setp: set plugin options
+ */
+
+int
+weechat_cmd_setp (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+#ifdef PLUGINS
+ char *option, *value, *pos, *ptr_name;
+ t_plugin_option *ptr_option;
+ int number_found;
+
+ /* make C compiler happy */
+ (void) server;
+ (void) channel;
+
+ option = NULL;
+ value = NULL;
+ if (arguments && arguments[0])
+ {
+ option = arguments;
+ value = strchr (option, '=');
+ if (value)
+ {
+ value[0] = '\0';
+
+ /* remove spaces before '=' */
+ pos = value - 1;
+ while ((pos > option) && (pos[0] == ' '))
+ {
+ pos[0] = '\0';
+ pos--;
+ }
+
+ /* skip spaces after '=' */
+ value++;
+ while (value[0] && (value[0] == ' '))
+ {
+ value++;
+ }
+
+ /* remove simple or double quotes
+ and spaces at the end */
+ if (strlen(value) > 1)
+ {
+ pos = value + strlen (value) - 1;
+ while ((pos > value) && (pos[0] == ' '))
+ {
+ pos[0] = '\0';
+ pos--;
+ }
+ pos = value + strlen (value) - 1;
+ if (((value[0] == '\'') &&
+ (pos[0] == '\'')) ||
+ ((value[0] == '"') &&
+ (pos[0] == '"')))
+ {
+ pos[0] = '\0';
+ value++;
+ }
+ }
+ }
+ }
+
+ if (value)
+ {
+ ptr_name = NULL;
+ ptr_option = plugin_config_search_internal (option);
+ if (ptr_option)
+ ptr_name = ptr_option->name;
+ else
+ {
+ pos = strchr (option, '.');
+ if (pos)
+ pos[0] = '\0';
+ if (!pos || !pos[1] || (!plugin_search (option)))
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL, _("%s plugin \"%s\" not found\n"),
+ WEECHAT_ERROR, option);
+ }
+ else
+ ptr_name = option;
+ if (pos)
+ pos[0] = '.';
+ }
+ if (ptr_name)
+ {
+ if (plugin_config_set_internal (ptr_name, value))
+ {
+ gui_printf (NULL, "\n %s%s = \"%s%s%s\"\n",
+ ptr_name,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_HOST),
+ value,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK));
+ }
+ else
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL, _("%s incorrect value for plugin option \"%s\"\n"),
+ WEECHAT_ERROR, ptr_name);
+ }
+ }
+ }
+ else
+ {
+ number_found = 0;
+ for (ptr_option = plugin_options; ptr_option;
+ ptr_option = ptr_option->next_option)
+ {
+ if ((!option) ||
+ ((option) && (option[0])
+ && (strstr (ptr_option->name, option) != NULL)))
+ {
+ if (number_found == 0)
+ gui_printf (NULL, "\n");
+ gui_printf (NULL, " %s%s = \"%s%s%s\"\n",
+ ptr_option->name,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_HOST),
+ ptr_option->value,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK));
+ number_found++;
+ }
+ }
+ if (number_found == 0)
+ {
+ if (option)
+ gui_printf (NULL, _("No plugin option found with \"%s\"\n"),
+ option);
+ else
+ gui_printf (NULL, _("No plugin option found\n"));
+ }
+ else
+ {
+ gui_printf (NULL, "\n");
+ gui_printf (NULL, "%s%d %s",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ number_found,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT));
+ if (option)
+ gui_printf (NULL, _("plugin option(s) found with \"%s\"\n"),
+ option);
+ else
+ gui_printf (NULL, _("plugin option(s) found\n"));
+ }
+ }
+#else
+ /* make C compiler happy */
+ (void) server;
+ (void) channel;
+ (void) arguments;
+
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("Command \"%s\" is not available, WeeChat was built "
+ "without plugins support.\n"),
+ "setp");
+#endif
+
+ return 0;
+}
+
+/*
+ * cmd_unalias: remove an alias
+ */
+
+int
+weechat_cmd_unalias (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ t_weelist *ptr_weelist;
+ t_weechat_alias *ptr_alias;
+
+ /* make C compiler happy */
+ (void) server;
+ (void) channel;
+
+ if (arguments[0] == '/')
+ arguments++;
+
+ ptr_weelist = weelist_search (index_commands, arguments);
+ if (!ptr_weelist)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL, _("%s alias or command \"%s\" not found\n"),
+ WEECHAT_ERROR, arguments);
+ return -1;
+ }
+
+ weelist_remove (&index_commands, &last_index_command, ptr_weelist);
+ ptr_alias = alias_search (arguments);
+ if (ptr_alias)
+ alias_free (ptr_alias);
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_INFO);
+ gui_printf (NULL, _("Alias \"%s\" removed\n"),
+ arguments);
+ return 0;
+}
+
+/*
+ * weechat_cmd_unignore: unignore IRC commands and/or hosts
+ */
+
+int
+weechat_cmd_unignore (t_irc_server *server, t_irc_channel *channel,
+ int argc, char **argv)
+{
+ t_gui_buffer *buffer;
+ char *error;
+ int number, ret;
+
+ gui_buffer_find_context (server, channel, NULL, &buffer);
+
+ ret = 0;
+ switch (argc)
+ {
+ case 0:
+ /* List all ignore */
+ weechat_cmd_ignore (server, channel, argc, argv);
+ return 0;
+ break;
+ case 1:
+ error = NULL;
+ number = strtol (argv[0], &error, 10);
+ if ((error) && (error[0] == '\0'))
+ ret = irc_ignore_search_free_by_number (number);
+ else
+ ret = irc_ignore_search_free (argv[0], "*", "*",
+ (GUI_SERVER(buffer)) ?
+ GUI_SERVER(buffer)->name : "*");
+ break;
+ case 2:
+ ret = irc_ignore_search_free (argv[0], argv[1], "*",
+ (GUI_SERVER(buffer)) ?
+ GUI_SERVER(buffer)->name : "*");
+ break;
+ case 3:
+ ret = irc_ignore_search_free (argv[0], argv[1], argv[2],
+ (GUI_SERVER(buffer)) ?
+ GUI_SERVER(buffer)->name : "*");
+ break;
+ case 4:
+ ret = irc_ignore_search_free (argv[0], argv[1], argv[2], argv[3]);
+ break;
+ }
+
+ if (ret)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_INFO);
+ gui_printf (NULL,
+ NG_("%s%d%s ignore was removed.\n",
+ "%s%d%s ignore were removed.\n",
+ ret),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ ret,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT));
+ }
+ else
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL, _("%s no ignore found\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * weechat_cmd_upgrade: upgrade WeeChat
+ */
+
+int
+weechat_cmd_upgrade (t_irc_server *server, t_irc_channel *channel,
+ int argc, char **argv)
+{
+ t_irc_server *ptr_server;
+ int filename_length;
+ char *filename, *ptr_binary;
+ char *exec_args[7] = { NULL, "-a", "--dir", NULL, "--session", NULL, NULL };
+
+ /* make C compiler happy */
+ (void) server;
+ (void) channel;
+
+ ptr_binary = (argc > 0) ? argv[0] : weechat_argv0;
+
+ for (ptr_server = irc_servers; ptr_server;
+ ptr_server = ptr_server->next_server)
+ {
+ if (ptr_server->child_pid != 0)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf_nolog (NULL,
+ _("%s can't upgrade: connection to at least "
+ "one server is pending\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ /* TODO: remove this test, and fix gnutls save/load in session */
+ if (ptr_server->is_connected && ptr_server->ssl_connected)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf_nolog (NULL,
+ _("%s can't upgrade: connection to at least "
+ "one SSL server is active "
+ "(should be fixed in a future version)\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ if (ptr_server->outqueue)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf_nolog (NULL,
+ _("%s can't upgrade: anti-flood is active on "
+ "at least one server (sending many lines)\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ }
+
+ filename_length = strlen (weechat_home) + strlen (WEECHAT_SESSION_NAME) + 2;
+ filename = (char *) malloc (filename_length * sizeof (char));
+ if (!filename)
+ return -2;
+ snprintf (filename, filename_length, "%s%s" WEECHAT_SESSION_NAME,
+ weechat_home, DIR_SEPARATOR);
+
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_INFO);
+ gui_printf_nolog (NULL, _("Upgrading WeeChat...\n"));
+
+ if (!session_save (filename))
+ {
+ free (filename);
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf_nolog (NULL,
+ _("%s unable to save session in file\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+
+ exec_args[0] = strdup (ptr_binary);
+ exec_args[3] = strdup (weechat_home);
+ exec_args[5] = strdup (filename);
+
+ /* unload plugins, save config, then upgrade */
+#ifdef PLUGINS
+ plugin_end ();
+#endif
+ if (cfg_look_save_on_exit)
+ (void) config_write (NULL);
+ gui_main_end ();
+ fifo_remove ();
+ weechat_log_close ();
+
+ execvp (exec_args[0], exec_args);
+
+ /* this code should not be reached if execvp is ok */
+#ifdef PLUGINS
+ plugin_init (1);
+#endif
+
+ weechat_iconv_fprintf (stderr,
+ _("%s exec failed (program: \"%s\"), exiting WeeChat\n"),
+ WEECHAT_ERROR,
+ exec_args[0]);
+
+ free (exec_args[0]);
+ free (exec_args[3]);
+ free (filename);
+
+ exit (EXIT_FAILURE);
+
+ /* never executed */
+ return -1;
+}
+
+/*
+ * weechat_cmd_uptime: display WeeChat uptime
+ */
+
+int
+weechat_cmd_uptime (t_irc_server *server, t_irc_channel *channel,
+ int argc, char **argv)
+{
+ t_gui_buffer *buffer;
+ time_t running_time;
+ int day, hour, min, sec;
+ char string[256];
+
+ gui_buffer_find_context (server, channel, NULL, &buffer);
+
+ running_time = time (NULL) - weechat_start_time;
+ day = running_time / (60 * 60 * 24);
+ hour = (running_time % (60 * 60 * 24)) / (60 * 60);
+ min = ((running_time % (60 * 60 * 24)) % (60 * 60)) / 60;
+ sec = ((running_time % (60 * 60 * 24)) % (60 * 60)) % 60;
+
+ if ((argc == 1) && (strcmp (argv[0], "-o") == 0)
+ && ((GUI_BUFFER_IS_CHANNEL(buffer))
+ || (GUI_BUFFER_IS_PRIVATE(buffer))))
+ {
+ snprintf (string, sizeof (string),
+ _("WeeChat uptime: %d %s %02d:%02d:%02d, started on %s"),
+ day,
+ NG_("day", "days", day),
+ hour,
+ min,
+ sec,
+ ctime (&weechat_start_time));
+ string[strlen (string) - 1] = '\0';
+ user_command (server, channel, string, 0);
+ }
+ else
+ {
+ irc_display_prefix (NULL, buffer, GUI_PREFIX_INFO);
+ gui_printf_nolog (buffer,
+ _("WeeChat uptime: %s%d %s%s "
+ "%s%02d%s:%s%02d%s:%s%02d%s, "
+ "started on %s%s"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ day,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ NG_("day", "days", day),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ hour,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ min,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ sec,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ ctime (&weechat_start_time));
+ }
+
+ return 0;
+}
+
+/*
+ * weechat_cmd_window: manage windows
+ */
+
+int
+weechat_cmd_window (t_irc_server *server, t_irc_channel *channel,
+ int argc, char **argv)
+{
+ t_gui_window *window, *ptr_win;
+ t_gui_buffer *buffer;
+ int i;
+ char *error;
+ long number;
+
+ gui_buffer_find_context (server, channel, &window, &buffer);
+
+ if ((argc == 0) || ((argc == 1) && (ascii_strcasecmp (argv[0], "list") == 0)))
+ {
+ /* list open windows */
+
+ gui_printf (NULL, "\n");
+ gui_printf (NULL, _("Open windows:\n"));
+
+ i = 1;
+ for (ptr_win = gui_windows; ptr_win; ptr_win = ptr_win->next_window)
+ {
+ gui_printf (NULL, "%s[%s%d%s] (%s%d:%d%s;%s%dx%d%s) ",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ i,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ ptr_win->win_x,
+ ptr_win->win_y,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ ptr_win->win_width,
+ ptr_win->win_height,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK));
+
+ weechat_cmd_buffer_display_info (ptr_win->buffer);
+
+ i++;
+ }
+ }
+ else
+ {
+ if (ascii_strcasecmp (argv[0], "splith") == 0)
+ {
+ /* split window horizontally */
+ if (argc > 1)
+ {
+ error = NULL;
+ number = strtol (argv[1], &error, 10);
+ if ((error) && (error[0] == '\0')
+ && (number > 0) && (number < 100))
+ gui_window_split_horiz (window, number);
+ }
+ else
+ gui_window_split_horiz (window, 50);
+ }
+ else if (ascii_strcasecmp (argv[0], "splitv") == 0)
+ {
+ /* split window vertically */
+ if (argc > 1)
+ {
+ error = NULL;
+ number = strtol (argv[1], &error, 10);
+ if ((error) && (error[0] == '\0')
+ && (number > 0) && (number < 100))
+ gui_window_split_vertic (window, number);
+ }
+ else
+ gui_window_split_vertic (window, 50);
+ }
+ else if (ascii_strcasecmp (argv[0], "resize") == 0)
+ {
+ /* resize window */
+ if (argc > 1)
+ {
+ error = NULL;
+ number = strtol (argv[1], &error, 10);
+ if ((error) && (error[0] == '\0')
+ && (number > 0) && (number < 100))
+ gui_window_resize (window, number);
+ }
+ }
+ else if (ascii_strcasecmp (argv[0], "merge") == 0)
+ {
+ if (argc >= 2)
+ {
+ if (ascii_strcasecmp (argv[1], "all") == 0)
+ gui_window_merge_all (window);
+ else
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s unknown option for \"%s\" command\n"),
+ WEECHAT_ERROR, "window merge");
+ return -1;
+ }
+ }
+ else
+ {
+ if (!gui_window_merge (window))
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s can not merge windows, "
+ "there's no other window with same size "
+ "near current one.\n"),
+ WEECHAT_ERROR);
+ return -1;
+ }
+ }
+ }
+ else if (ascii_strncasecmp (argv[0], "b", 1) == 0)
+ {
+ /* jump to window by buffer number */
+ error = NULL;
+ number = strtol (argv[0] + 1, &error, 10);
+ if ((error) && (error[0] == '\0'))
+ gui_window_switch_by_buffer (window, number);
+ }
+ else if (ascii_strcasecmp (argv[0], "-1") == 0)
+ gui_window_switch_previous (window);
+ else if (ascii_strcasecmp (argv[0], "+1") == 0)
+ gui_window_switch_next (window);
+ else if (ascii_strcasecmp (argv[0], "up") == 0)
+ gui_window_switch_up (window);
+ else if (ascii_strcasecmp (argv[0], "down") == 0)
+ gui_window_switch_down (window);
+ else if (ascii_strcasecmp (argv[0], "left") == 0)
+ gui_window_switch_left (window);
+ else if (ascii_strcasecmp (argv[0], "right") == 0)
+ gui_window_switch_right (window);
+ else
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s unknown option for \"%s\" command\n"),
+ WEECHAT_ERROR, "window");
+ return -1;
+ }
+ }
+ return 0;
+}
diff --git a/src/core/wee-command.h b/src/core/wee-command.h
new file mode 100644
index 000000000..644491dd0
--- /dev/null
+++ b/src/core/wee-command.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2003-2007 by FlashCode <flashcode@flashtux.org>
+ * See README for License detail, AUTHORS for developers list.
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef __WEECHAT_COMMAND_H
+#define __WEECHAT_COMMAND_H 1
+
+#include "weelist.h"
+#include "../protocols/irc/irc.h"
+#include "../gui/gui.h"
+
+#define MAX_ARGS 8192
+
+typedef struct t_weechat_command t_weechat_command;
+
+struct t_weechat_command
+{
+ char *command_name; /* WeeChat (internal) command name */
+ char *command_description; /* command description (for /help) */
+ char *arguments; /* command arguments (for /help) */
+ char *arguments_description; /* arguments description (for /help) */
+ char *completion_template; /* template for completion */
+ /* NULL=no completion, ""=default (nick) */
+ int min_arg, max_arg; /* min & max number of arguments */
+ int conversion; /* = 1 if cmd args are converted (charset */
+ /* and color) before execution */
+ int (*cmd_function_args)(t_irc_server *, t_irc_channel *, int, char **);
+ /* function called when user enters cmd */
+ int (*cmd_function_1arg)(t_irc_server *, t_irc_channel *, char *);
+ /* function called when user enters cmd */
+};
+
+extern t_weechat_command weechat_commands[];
+
+extern t_weelist *index_commands;
+extern t_weelist *last_index_command;
+
+extern void command_index_build ();
+extern void command_index_free ();
+extern int command_used_by_weechat (char *);
+extern char **split_multi_command (char *, char);
+extern void free_multi_command (char **);
+extern int exec_weechat_command (t_irc_server *, t_irc_channel *, char *, int);
+extern void user_command (t_irc_server *, t_irc_channel *, char *, int);
+extern int weechat_cmd_alias (t_irc_server *, t_irc_channel *, char *);
+extern int weechat_cmd_buffer (t_irc_server *, t_irc_channel *, char *);
+extern int weechat_cmd_builtin (t_irc_server *, t_irc_channel *, char *);
+extern int weechat_cmd_clear (t_irc_server *, t_irc_channel *, int, char **);
+extern int weechat_cmd_connect (t_irc_server *, t_irc_channel *, int, char **);
+extern int weechat_cmd_dcc (t_irc_server *, t_irc_channel *, char *);
+extern int weechat_cmd_debug (t_irc_server *, t_irc_channel *, int, char **);
+extern int weechat_cmd_disconnect (t_irc_server *, t_irc_channel *, int, char **);
+extern int weechat_cmd_help (t_irc_server *, t_irc_channel *, int, char **);
+extern int weechat_cmd_history (t_irc_server *, t_irc_channel *, int, char **);
+extern void weechat_cmd_ignore_display (char *, t_irc_ignore *);
+extern int weechat_cmd_ignore (t_irc_server *, t_irc_channel *, int, char **);
+extern int weechat_cmd_key (t_irc_server *, t_irc_channel *, char *);
+extern int weechat_cmd_panel (t_irc_server *, t_irc_channel *, int, char **);
+extern int weechat_cmd_plugin (t_irc_server *, t_irc_channel *, int, char **);
+extern int weechat_cmd_reconnect (t_irc_server *, t_irc_channel *, int, char **);
+extern int weechat_cmd_save (t_irc_server *, t_irc_channel *, int, char **);
+extern int weechat_cmd_server (t_irc_server *, t_irc_channel *, int, char **);
+extern int weechat_cmd_set (t_irc_server *, t_irc_channel *, char *);
+extern int weechat_cmd_setp (t_irc_server *, t_irc_channel *, char *);
+extern int weechat_cmd_unalias (t_irc_server *, t_irc_channel *, char *);
+extern int weechat_cmd_unignore (t_irc_server *, t_irc_channel *, int, char **);
+extern int weechat_cmd_upgrade (t_irc_server *, t_irc_channel *, int, char **);
+extern int weechat_cmd_uptime (t_irc_server *, t_irc_channel *, int, char **);
+extern int weechat_cmd_window (t_irc_server *, t_irc_channel *, int, char **);
+
+#endif /* command.h */
diff --git a/src/core/wee-config.c b/src/core/wee-config.c
new file mode 100644
index 000000000..b4f1c8f46
--- /dev/null
+++ b/src/core/wee-config.c
@@ -0,0 +1,2597 @@
+/*
+ * Copyright (c) 2003-2007 by FlashCode <flashcode@flashtux.org>
+ * See README for License detail, AUTHORS for developers list.
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/* weeconfig.c: WeeChat configuration */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <time.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "weechat.h"
+#include "weeconfig.h"
+#include "alias.h"
+#include "command.h"
+#include "fifo.h"
+#include "hotlist.h"
+#include "log.h"
+#include "utf8.h"
+#include "util.h"
+#include "../protocols/irc/irc.h"
+#include "../gui/gui.h"
+
+
+/* config sections */
+
+t_config_section config_sections[CONFIG_NUMBER_SECTIONS] =
+{ { CONFIG_SECTION_LOOK, "look" },
+ { CONFIG_SECTION_COLORS, "colors" },
+ { CONFIG_SECTION_HISTORY, "history" },
+ { CONFIG_SECTION_LOG, "log" },
+ { CONFIG_SECTION_IRC, "irc" },
+ { CONFIG_SECTION_DCC, "dcc" },
+ { CONFIG_SECTION_PROXY, "proxy" },
+ { CONFIG_SECTION_PLUGINS, "plugins" },
+ { CONFIG_SECTION_KEYS, "keys" },
+ { CONFIG_SECTION_ALIAS, "alias" },
+ { CONFIG_SECTION_IGNORE, "ignore" },
+ { CONFIG_SECTION_SERVER, "server" }
+};
+
+/* config, look & feel section */
+
+int cfg_look_save_on_exit;
+int cfg_look_set_title;
+int cfg_look_startup_logo;
+int cfg_look_startup_version;
+char *cfg_look_weechat_slogan;
+int cfg_look_one_server_buffer;
+int cfg_look_scroll_amount;
+int cfg_look_open_near_server;
+char *cfg_look_buffer_timestamp;
+int cfg_look_color_nicks_number;
+int cfg_look_color_actions;
+int cfg_look_nicklist;
+int cfg_look_nicklist_position;
+char *cfg_look_nicklist_position_values[] =
+{ "left", "right", "top", "bottom", NULL };
+int cfg_look_nicklist_min_size;
+int cfg_look_nicklist_max_size;
+int cfg_look_nicklist_separator;
+int cfg_look_nickmode;
+int cfg_look_nickmode_empty;
+char *cfg_look_no_nickname;
+char *cfg_look_nick_prefix;
+char *cfg_look_nick_suffix;
+int cfg_look_align_nick;
+char *cfg_look_align_nick_values[] =
+{ "none", "left", "right", NULL };
+int cfg_look_align_other;
+int cfg_look_align_size;
+int cfg_look_align_size_max;
+int cfg_look_align_text_offset;
+char *cfg_look_nick_completor;
+char *cfg_look_nick_completion_ignore;
+int cfg_look_nick_completion_smart;
+int cfg_look_nick_complete_first;
+int cfg_look_infobar;
+char *cfg_look_infobar_timestamp;
+int cfg_look_infobar_seconds;
+int cfg_look_infobar_delay_highlight;
+int cfg_look_hotlist_names_count;
+int cfg_look_hotlist_names_level;
+int cfg_look_hotlist_names_length;
+int cfg_look_hotlist_sort;
+char *cfg_look_hotlist_sort_values[] =
+{ "group_time_asc", "group_time_desc",
+ "group_number_asc", "group_number_desc",
+ "number_asc", "number_desc" };
+int cfg_look_day_change;
+char *cfg_look_day_change_timestamp;
+char *cfg_look_read_marker;
+char *cfg_look_input_format;
+int cfg_look_paste_max_lines;
+
+t_config_option weechat_options_look[] =
+{ { "look_save_on_exit", N_("save config file on exit"),
+ N_("save config file on exit"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_look_save_on_exit, NULL, config_change_save_on_exit },
+ { "look_set_title", N_("set title for window (terminal for Curses GUI) with name and version"),
+ N_("set title for window (terminal for Curses GUI) with name and version"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_look_set_title, NULL, config_change_title },
+ { "look_startup_logo", N_("display WeeChat logo at startup"),
+ N_("display WeeChat logo at startup"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_look_startup_logo, NULL, config_change_noop },
+ { "look_startup_version", N_("display WeeChat version at startup"),
+ N_("display WeeChat version at startup"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_look_startup_version, NULL, config_change_noop },
+ { "look_weechat_slogan", N_("WeeChat slogan"),
+ N_("WeeChat slogan (if empty, slogan is not used)"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "the geekest IRC client!", NULL, NULL, &cfg_look_weechat_slogan, config_change_noop },
+ { "look_one_server_buffer", N_("use same buffer for all servers"),
+ N_("use same buffer for all servers"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_FALSE,
+ NULL, NULL, &cfg_look_one_server_buffer, NULL, config_change_one_server_buffer },
+ { "look_open_near_server", N_("open new channels/privates near server"),
+ N_("open new channels/privates near server"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_FALSE,
+ NULL, NULL, &cfg_look_open_near_server, NULL, config_change_noop },
+ { "look_scroll_amount", N_("how many lines to scroll by with scroll_up and scroll_down"),
+ N_("how many lines to scroll by with scroll_up and scroll_down"),
+ OPTION_TYPE_INT, 1, INT_MAX, 3,
+ NULL, NULL, &cfg_look_scroll_amount, NULL, config_change_buffer_content },
+ { "look_buffer_timestamp", N_("timestamp for buffers"),
+ N_("timestamp for buffers"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "[%H:%M:%S]", NULL, NULL, &cfg_look_buffer_timestamp, config_change_buffer_content },
+ { "look_color_nicks_number", N_("number of colors to use for nicks colors"),
+ N_("number of colors to use for nicks colors"),
+ OPTION_TYPE_INT, 1, 10, 10,
+ NULL, NULL, &cfg_look_color_nicks_number, NULL, config_change_nicks_colors },
+ { "look_color_actions", N_("display actions with different colors"),
+ N_("display actions with different colors"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_look_color_actions, NULL, config_change_noop },
+ { "look_nicklist", N_("display nicklist window"),
+ N_("display nicklist window (for channel windows)"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_look_nicklist, NULL, config_change_buffers },
+ { "look_nicklist_position", N_("nicklist position"),
+ N_("nicklist position (top, left, right (default), bottom)"),
+ OPTION_TYPE_INT_WITH_STRING, 0, 0, 0,
+ "right", cfg_look_nicklist_position_values, &cfg_look_nicklist_position, NULL, config_change_buffers },
+ { "look_nicklist_min_size", N_("min size for nicklist"),
+ N_("min size for nicklist (width or height, depending on look_nicklist_position "
+ "(0 = no min size))"),
+ OPTION_TYPE_INT, 0, 100, 0,
+ NULL, NULL, &cfg_look_nicklist_min_size, NULL, config_change_buffers },
+ { "look_nicklist_max_size", N_("max size for nicklist"),
+ N_("max size for nicklist (width or height, depending on look_nicklist_position "
+ "(0 = no max size; if min = max and > 0, then size is fixed))"),
+ OPTION_TYPE_INT, 0, 100, 0,
+ NULL, NULL, &cfg_look_nicklist_max_size, NULL, config_change_buffers },
+ { "look_nicklist_separator", N_("separator between chat and nicklist"),
+ N_("separator between chat and nicklist"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_look_nicklist_separator, NULL, config_change_buffers },
+ { "look_no_nickname", N_("text to display instead of nick when not connected"),
+ N_("text to display instead of nick when not connected"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "-cmd-", NULL, NULL, &cfg_look_no_nickname, config_change_buffer_content },
+ { "look_nickmode", N_("display nick mode ((half)op/voice) before each nick"),
+ N_("display nick mode ((half)op/voice) before each nick"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_look_nickmode, NULL, config_change_buffers },
+ { "look_nickmode_empty", N_("display space if nick mode is not (half)op/voice"),
+ N_("display space if nick mode is not (half)op/voice"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_FALSE,
+ NULL, NULL, &cfg_look_nickmode_empty, NULL, config_change_buffers },
+ { "look_nick_prefix", N_("text to display before nick in chat window"),
+ N_("text to display before nick in chat window"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "", NULL, NULL, &cfg_look_nick_prefix, config_change_noop },
+ { "look_nick_suffix", N_("text to display after nick in chat window"),
+ N_("text to display after nick in chat window"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ " |", NULL, NULL, &cfg_look_nick_suffix, config_change_noop },
+ { "look_align_nick", N_("nick alignment (fixed size for nicks in chat window)"),
+ N_("nick alignment (fixed size for nicks in chat window (none, left, right))"),
+ OPTION_TYPE_INT_WITH_STRING, 0, 0, 0,
+ "right", cfg_look_align_nick_values, &cfg_look_align_nick, NULL, config_change_noop },
+ { "look_align_other", N_("alignment for other messages (not beginning with a nick)"),
+ N_("alignment for other messages (not beginning with a nick)"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_look_align_other, NULL, config_change_noop },
+ { "look_align_size", N_("size for aligning nick and other messages"),
+ N_("size for aligning nick and other messages"),
+ OPTION_TYPE_INT, 8, 64, 14,
+ NULL, NULL, &cfg_look_align_size, NULL, config_change_noop },
+ { "look_align_size_max", N_("max size for aligning nick and other messages"),
+ N_("max size for aligning nick and other messages (should be >= to "
+ "look_align_size)"),
+ OPTION_TYPE_INT, 8, 64, 20,
+ NULL, NULL, &cfg_look_align_size_max, NULL, config_change_noop },
+ { "look_align_text_offset", N_("offset for aligning lines of messages "
+ "(except first lines)"),
+ N_("offset for aligning lines of messages (except first lines), default is "
+ "-1 (align after nick), a null or positive value is offset after "
+ "beginning of line"),
+ OPTION_TYPE_INT, -1, 64, -1,
+ NULL, NULL, &cfg_look_align_text_offset, NULL, config_change_buffers },
+ { "look_nick_completor", N_("the string inserted after nick completion"),
+ N_("the string inserted after nick completion"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ ":", NULL, NULL, &cfg_look_nick_completor, config_change_noop },
+ { "look_nick_completion_ignore", N_("chars ignored for nick completion"),
+ N_("chars ignored for nick completion"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "[]-^", NULL, NULL, &cfg_look_nick_completion_ignore, config_change_noop },
+ { "look_nick_completion_smart", N_("smart completion for nicks"),
+ N_("smart completion for nicks (completes with last speakers first)"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_look_nick_completion_smart, NULL, config_change_noop },
+ { "look_nick_complete_first", N_("complete only with first nick found"),
+ N_("complete only with first nick found"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_FALSE,
+ NULL, NULL, &cfg_look_nick_complete_first, NULL, config_change_noop },
+ { "look_infobar", N_("enable info bar"),
+ N_("enable info bar"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_look_infobar, NULL, config_change_buffers },
+ { "look_infobar_timestamp", N_("timestamp for time in infobar"),
+ N_("timestamp for time in infobar"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "%B, %A %d %Y", NULL, NULL, &cfg_look_infobar_timestamp, config_change_buffer_content },
+ { "look_infobar_seconds", N_("display seconds in infobar time"),
+ N_("display seconds in infobar time"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_look_infobar_seconds, NULL, config_change_buffer_content },
+ { "look_infobar_delay_highlight", N_("delay (in seconds) for highlight messages in infobar"),
+ N_("delay (in seconds) for highlight messages in infobar "
+ "(0 = disable highlight notifications in infobar)"),
+ OPTION_TYPE_INT, 0, INT_MAX, 7,
+ NULL, NULL, &cfg_look_infobar_delay_highlight, NULL, config_change_noop },
+ { "look_hotlist_names_count", N_("max number of names in hotlist"),
+ N_("max number of names in hotlist (0 = no name displayed, only buffer numbers)"),
+ OPTION_TYPE_INT, 0, 32, 3,
+ NULL, NULL, &cfg_look_hotlist_names_count, NULL, config_change_buffer_content },
+ { "look_hotlist_names_level", N_("level for displaying names in hotlist"),
+ N_("level for displaying names in hotlist (combination of: 1=join/part, 2=message, "
+ "4=private, 8=highlight, for example: 12=private+highlight)"),
+ OPTION_TYPE_INT, 1, 15, 12,
+ NULL, NULL, &cfg_look_hotlist_names_level, NULL, config_change_buffer_content },
+ { "look_hotlist_names_length", N_("max length of names in hotlist"),
+ N_("max length of names in hotlist (0 = no limit)"),
+ OPTION_TYPE_INT, 0, 32, 0,
+ NULL, NULL, &cfg_look_hotlist_names_length, NULL, config_change_buffer_content },
+ { "look_hotlist_sort", N_("hotlist sort type"),
+ N_("hotlist sort type (group_time_asc (default), group_time_desc, "
+ "group_number_asc, group_number_desc, number_asc, number_desc)"),
+ OPTION_TYPE_INT_WITH_STRING, 0, 0, 0,
+ "group_time_asc", cfg_look_hotlist_sort_values, &cfg_look_hotlist_sort, NULL, config_change_hotlist },
+ { "look_day_change", N_("display special message when day changes"),
+ N_("display special message when day changes"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_look_day_change, NULL, config_change_noop },
+ { "look_day_change_timestamp", N_("timestamp for date displayed when day changed"),
+ N_("timestamp for date displayed when day changed"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "%a, %d %b %Y", NULL, NULL, &cfg_look_day_change_timestamp, config_change_noop },
+ { "look_read_marker", N_("use a marker on servers/channels to show first unread line"),
+ N_("use a marker on servers/channels to show first unread line"),
+ OPTION_TYPE_STRING, 0, 1, 0,
+ " ", NULL, NULL, &cfg_look_read_marker, config_change_read_marker },
+ { "look_input_format", N_("format for input prompt"),
+ N_("format for input prompt ('%c' is replaced by channel or server, "
+ "'%n' by nick and '%m' by nick modes)"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "[%n(%m)] ", NULL, NULL, &cfg_look_input_format, config_change_buffer_content },
+ { "look_paste_max_lines", N_("max number of lines for paste without asking user"),
+ N_("max number of lines for paste without asking user (0 = disable this feature)"),
+ OPTION_TYPE_INT, 0, INT_MAX, 3,
+ NULL, NULL, &cfg_look_paste_max_lines, NULL, &config_change_noop },
+ { NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }
+};
+
+/* config, colors section */
+
+int cfg_col_real_white;
+int cfg_col_separator;
+int cfg_col_title;
+int cfg_col_title_more;
+int cfg_col_title_bg;
+int cfg_col_chat;
+int cfg_col_chat_time;
+int cfg_col_chat_time_sep;
+int cfg_col_chat_prefix1;
+int cfg_col_chat_prefix2;
+int cfg_col_chat_server;
+int cfg_col_chat_join;
+int cfg_col_chat_part;
+int cfg_col_chat_nick;
+int cfg_col_chat_host;
+int cfg_col_chat_channel;
+int cfg_col_chat_dark;
+int cfg_col_chat_highlight;
+int cfg_col_chat_bg;
+int cfg_col_chat_read_marker;
+int cfg_col_chat_read_marker_bg;
+int cfg_col_status;
+int cfg_col_status_delimiters;
+int cfg_col_status_channel;
+int cfg_col_status_data_msg;
+int cfg_col_status_data_private;
+int cfg_col_status_data_highlight;
+int cfg_col_status_data_other;
+int cfg_col_status_more;
+int cfg_col_status_bg;
+int cfg_col_infobar;
+int cfg_col_infobar_delimiters;
+int cfg_col_infobar_highlight;
+int cfg_col_infobar_bg;
+int cfg_col_input;
+int cfg_col_input_server;
+int cfg_col_input_channel;
+int cfg_col_input_nick;
+int cfg_col_input_delimiters;
+int cfg_col_input_text_not_found;
+int cfg_col_input_actions;
+int cfg_col_input_bg;
+int cfg_col_nick;
+int cfg_col_nick_away;
+int cfg_col_nick_chanowner;
+int cfg_col_nick_chanadmin;
+int cfg_col_nick_op;
+int cfg_col_nick_halfop;
+int cfg_col_nick_voice;
+int cfg_col_nick_user;
+int cfg_col_nick_more;
+int cfg_col_nick_sep;
+int cfg_col_nick_self;
+int cfg_col_nick_colors[GUI_COLOR_WIN_NICK_NUMBER];
+int cfg_col_nick_private;
+int cfg_col_nick_bg;
+int cfg_col_nicklist_bg;
+int cfg_col_dcc_selected;
+int cfg_col_dcc_waiting;
+int cfg_col_dcc_connecting;
+int cfg_col_dcc_active;
+int cfg_col_dcc_done;
+int cfg_col_dcc_failed;
+int cfg_col_dcc_aborted;
+
+t_config_option weechat_options_colors[] =
+{ /* general color settings */
+ { "col_real_white", N_("if set, uses real white color"),
+ N_("if set, uses real white color, disabled by default for terms with white "
+ "background (if you never use white background, you should turn on "
+ "this option to see real white instead of default term foreground color)"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_FALSE,
+ NULL, NULL, &cfg_col_real_white, NULL, config_change_color },
+ { "col_separator", N_("color for window separators (when splited)"),
+ N_("color for window separators (when splited)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "blue", NULL, &cfg_col_separator, NULL, &config_change_color },
+ /* title window */
+ { "col_title", N_("color for title bar"),
+ N_("color for title bar"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "default", NULL, &cfg_col_title, NULL, &config_change_color },
+ { "col_title_more", N_("color for '+' when scrolling topic"),
+ N_("color for '+' when scrolling topic"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "lightmagenta", NULL, &cfg_col_title_more, NULL, &config_change_color },
+ { "col_title_bg", N_("background for title bar"),
+ N_("background for title bar"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "blue", NULL, &cfg_col_title_bg, NULL, &config_change_color },
+
+ /* chat window */
+ { "col_chat", N_("color for chat text"),
+ N_("color for chat text"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "default", NULL, &cfg_col_chat, NULL, &config_change_color },
+ { "col_chat_time", N_("color for time"),
+ N_("color for time in chat window"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "default", NULL, &cfg_col_chat_time, NULL, &config_change_color },
+ { "col_chat_time_sep", N_("color for time separator"),
+ N_("color for time separator (chat window)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "brown", NULL, &cfg_col_chat_time_sep, NULL, &config_change_color },
+ { "col_chat_prefix1", N_("color for 1st and 3rd char of prefix"),
+ N_("color for 1st and 3rd char of prefix"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "lightcyan", NULL, &cfg_col_chat_prefix1, NULL, &config_change_color },
+ { "col_chat_prefix2", N_("color for middle char of prefix"),
+ N_("color for middle char of prefix"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "white", NULL, &cfg_col_chat_prefix2, NULL, &config_change_color },
+ { "col_chat_server", N_("color for server name"),
+ N_("color for server name"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "brown", NULL, &cfg_col_chat_server, NULL, &config_change_color },
+ { "col_chat_join", N_("color for join arrow (prefix)"),
+ N_("color for join arrow (prefix)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "lightgreen", NULL, &cfg_col_chat_join, NULL, &config_change_color },
+ { "col_chat_part", N_("color for part/quit arrow (prefix)"),
+ N_("color for part/quit arrow (prefix)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "lightred", NULL, &cfg_col_chat_part, NULL, &config_change_color },
+ { "col_chat_nick", N_("color for nicks in actions"),
+ N_("color for nicks in actions (chat window)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "lightcyan", NULL, &cfg_col_chat_nick, NULL, &config_change_color },
+ { "col_chat_host", N_("color for hostnames"),
+ N_("color for hostnames (chat window)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "cyan", NULL, &cfg_col_chat_host, NULL, &config_change_color },
+ { "col_chat_channel", N_("color for channel names in actions"),
+ N_("color for channel names in actions (chat window)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "white", NULL, &cfg_col_chat_channel, NULL, &config_change_color },
+ { "col_chat_dark", N_("color for dark separators"),
+ N_("color for dark separators (chat window)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "green", NULL, &cfg_col_chat_dark, NULL, &config_change_color },
+ { "col_chat_highlight", N_("color for highlighted nick"),
+ N_("color for highlighted nick (chat window)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "yellow", NULL, &cfg_col_chat_highlight, NULL, &config_change_color },
+ { "col_chat_bg", N_("background for chat"),
+ N_("background for chat window"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "default", NULL, &cfg_col_chat_bg, NULL, &config_change_color },
+ { "col_chat_read_marker", N_("color for unread data marker"),
+ N_("color for unread data marker"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "yellow", NULL, &cfg_col_chat_read_marker, NULL, &config_change_color },
+ { "col_chat_read_marker_bg", N_("background for unread data marker"),
+ N_("background for unread data marker"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "magenta", NULL, &cfg_col_chat_read_marker_bg, NULL, &config_change_color },
+
+ /* status window */
+ { "col_status", N_("color for status bar"),
+ N_("color for status bar"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "default", NULL, &cfg_col_status, NULL, &config_change_color },
+ { "col_status_delimiters", N_("color for status bar delimiters"),
+ N_("color for status bar delimiters"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "cyan", NULL, &cfg_col_status_delimiters, NULL, &config_change_color },
+ { "col_status_channel", N_("color for current channel in status bar"),
+ N_("color for current channel in status bar"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "white", NULL, &cfg_col_status_channel, NULL, &config_change_color },
+ { "col_status_data_msg", N_("color for window with new messages"),
+ N_("color for window with new messages (status bar)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "yellow", NULL, &cfg_col_status_data_msg, NULL, &config_change_color },
+ { "col_status_private", N_("color for window with private message"),
+ N_("color for window with private message (status bar)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "lightmagenta", NULL, &cfg_col_status_data_private, NULL, &config_change_color },
+ { "col_status_highlight", N_("color for window with highlight"),
+ N_("color for window with highlight (status bar)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "lightred", NULL, &cfg_col_status_data_highlight, NULL, &config_change_color },
+ { "col_status_data_other", N_("color for window with new data (not messages)"),
+ N_("color for window with new data (not messages) (status bar)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "default", NULL, &cfg_col_status_data_other, NULL, &config_change_color },
+ { "col_status_more", N_("color for \"-MORE-\" text"),
+ N_("color for window with new data (status bar)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "white", NULL, &cfg_col_status_more, NULL, &config_change_color },
+ { "col_status_bg", N_("background for status window"),
+ N_("background for status window"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "blue", NULL, &cfg_col_status_bg, NULL, &config_change_color },
+
+ /* infobar window */
+ { "col_infobar", N_("color for info bar text"),
+ N_("color for info bar text"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "black", NULL, &cfg_col_infobar, NULL, &config_change_color },
+ { "col_infobar_delimiters", N_("color for infobar delimiters"),
+ N_("color for infobar delimiters"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "blue", NULL, &cfg_col_infobar_delimiters, NULL, &config_change_color },
+ { "col_infobar_highlight", N_("color for info bar highlight notification"),
+ N_("color for info bar highlight notification"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "white", NULL, &cfg_col_infobar_highlight, NULL, &config_change_color },
+ { "col_infobar_bg", N_("background for info bar window"),
+ N_("background for info bar window"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "cyan", NULL, &cfg_col_infobar_bg, NULL, &config_change_color },
+
+ /* input window */
+ { "col_input", N_("color for input text"),
+ N_("color for input text"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "default", NULL, &cfg_col_input, NULL, &config_change_color },
+ { "col_input_server", N_("color for input text (server name)"),
+ N_("color for input text (server name)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "brown", NULL, &cfg_col_input_server, NULL, &config_change_color },
+ { "col_input_channel", N_("color for input text (channel name)"),
+ N_("color for input text (channel name)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "white", NULL, &cfg_col_input_channel, NULL, &config_change_color },
+ { "col_input_nick", N_("color for input text (nick name)"),
+ N_("color for input text (nick name)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "lightcyan", NULL, &cfg_col_input_nick, NULL, &config_change_color },
+ { "col_input_delimiters", N_("color for input text (delimiters)"),
+ N_("color for input text (delimiters)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "cyan", NULL, &cfg_col_input_delimiters, NULL, &config_change_color },
+ { "col_input_text_not_found", N_("color for text not found"),
+ N_("color for text not found"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "red", NULL, &cfg_col_input_text_not_found, NULL, &config_change_color },
+ { "col_input_actions", N_("color for actions in input window"),
+ N_("color for actions in input window"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "lightgreen", NULL, &cfg_col_input_actions, NULL, &config_change_color },
+ { "col_input_bg", N_("background for input window"),
+ N_("background for input window"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "default", NULL, &cfg_col_input_bg, NULL, &config_change_color },
+
+ /* nick window */
+ { "col_nick", N_("color for nicknames"),
+ N_("color for nicknames"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "default", NULL, &cfg_col_nick, NULL, &config_change_color },
+ { "col_nick_away", N_("color for away nicknames"),
+ N_("color for away nicknames"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "cyan", NULL, &cfg_col_nick_away, NULL, &config_change_color },
+ { "col_nick_chanowner", N_("color for chan owner symbol"),
+ N_("color for chan owner symbol (specific to unrealircd)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "lightgreen", NULL, &cfg_col_nick_chanowner, NULL, &config_change_color },
+ { "col_nick_chanadmin", N_("color for chan admin symbol"),
+ N_("color for chan admin symbol (specific to unrealircd)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "lightgreen", NULL, &cfg_col_nick_chanadmin, NULL, &config_change_color },
+ { "col_nick_op", N_("color for operator symbol"),
+ N_("color for operator symbol"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "lightgreen", NULL, &cfg_col_nick_op, NULL, &config_change_color },
+ { "col_nick_halfop", N_("color for half-operator symbol"),
+ N_("color for half-operator symbol"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "lightmagenta", NULL, &cfg_col_nick_halfop, NULL, &config_change_color },
+ { "col_nick_voice", N_("color for voice symbol"),
+ N_("color for voice symbol"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "yellow", NULL, &cfg_col_nick_voice, NULL, &config_change_color },
+ { "col_nick_user", N_("color for user symbol"),
+ N_("color for user symbol"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "blue", NULL, &cfg_col_nick_user, NULL, &config_change_color },
+ { "col_nick_more", N_("color for '+' when scrolling nicks"),
+ N_("color for '+' when scrolling nicks"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "lightmagenta", NULL, &cfg_col_nick_more, NULL, &config_change_color },
+ { "col_nick_sep", N_("color for nick separator"),
+ N_("color for nick separator"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "blue", NULL, &cfg_col_nick_sep, NULL, &config_change_color },
+ { "col_nick_self", N_("color for local nick"),
+ N_("color for local nick"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "white", NULL, &cfg_col_nick_self, NULL, &config_change_color },
+ { "col_nick_color1", N_("color for nick"),
+ N_("color for nick"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "cyan", NULL, &cfg_col_nick_colors[0], NULL, &config_change_color },
+ { "col_nick_color2", N_("color for nick"),
+ N_("color for nick"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "magenta", NULL, &cfg_col_nick_colors[1], NULL, &config_change_color },
+ { "col_nick_color3", N_("color for nick"),
+ N_("color for nick"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "green", NULL, &cfg_col_nick_colors[2], NULL, &config_change_color },
+ { "col_nick_color4", N_("color for nick"),
+ N_("color for nick"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "brown", NULL, &cfg_col_nick_colors[3], NULL, &config_change_color },
+ { "col_nick_color5", N_("color for nick"),
+ N_("color for nick"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "lightblue", NULL, &cfg_col_nick_colors[4], NULL, &config_change_color },
+ { "col_nick_color6", N_("color for nick"),
+ N_("color for nick"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "default", NULL, &cfg_col_nick_colors[5], NULL, &config_change_color },
+ { "col_nick_color7", N_("color for nick"),
+ N_("color for nick"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "lightcyan", NULL, &cfg_col_nick_colors[6], NULL, &config_change_color },
+ { "col_nick_color8", N_("color for nick"),
+ N_("color for nick"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "lightmagenta", NULL, &cfg_col_nick_colors[7], NULL, &config_change_color },
+ { "col_nick_color9", N_("color for nick"),
+ N_("color for nick"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "lightgreen", NULL, &cfg_col_nick_colors[8], NULL, &config_change_color },
+ { "col_nick_color10", N_("color for nick"),
+ N_("color for nick"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "blue", NULL, &cfg_col_nick_colors[9], NULL, &config_change_color },
+ { "col_nick_private", N_("color for other nick in private window"),
+ N_("color for other nick in private window"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "default", NULL, &cfg_col_nick_private, NULL, &config_change_color },
+ { "col_nick_bg", N_("background for nicknames"),
+ N_("background for nicknames"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "default", NULL, &cfg_col_nick_bg, NULL, &config_change_color },
+
+ /* DCC */
+ { "col_chat_dcc_selected", N_("color for selected DCC"),
+ N_("color for selected DCC (chat window)"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "white", NULL, &cfg_col_dcc_selected, NULL, &config_change_color },
+ { "col_dcc_waiting", N_("color for \"waiting\" dcc status"),
+ N_("color for \"waiting\" dcc status"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "lightcyan", NULL, &cfg_col_dcc_waiting, NULL, &config_change_color },
+ { "col_dcc_connecting", N_("color for \"connecting\" dcc status"),
+ N_("color for \"connecting\" dcc status"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "yellow", NULL, &cfg_col_dcc_connecting, NULL, &config_change_color },
+ { "col_dcc_active", N_("color for \"active\" dcc status"),
+ N_("color for \"active\" dcc status"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "lightblue", NULL, &cfg_col_dcc_active, NULL, &config_change_color },
+ { "col_dcc_done", N_("color for \"done\" dcc status"),
+ N_("color for \"done\" dcc status"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "lightgreen", NULL, &cfg_col_dcc_done, NULL, &config_change_color },
+ { "col_dcc_failed", N_("color for \"failed\" dcc status"),
+ N_("color for \"failed\" dcc status"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "lightred", NULL, &cfg_col_dcc_failed, NULL, &config_change_color },
+ { "col_dcc_aborted", N_("color for \"aborted\" dcc status"),
+ N_("color for \"aborted\" dcc status"),
+ OPTION_TYPE_COLOR, 0, 0, 0,
+ "lightred", NULL, &cfg_col_dcc_aborted, NULL, &config_change_color },
+
+ { NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }
+};
+
+/* config, history section */
+
+int cfg_history_max_lines;
+int cfg_history_max_commands;
+int cfg_history_display_default;
+
+t_config_option weechat_options_history[] =
+{ { "history_max_lines", N_("max lines in history (per window)"),
+ N_("maximum number of lines in history "
+ "for one server/channel/private window (0 = unlimited)"),
+ OPTION_TYPE_INT, 0, INT_MAX, 4096,
+ NULL, NULL, &cfg_history_max_lines, NULL, &config_change_noop },
+ { "history_max_commands", N_("max user commands in history"),
+ N_("maximum number of user commands in history (0 = unlimited)"),
+ OPTION_TYPE_INT, 0, INT_MAX, 100,
+ NULL, NULL, &cfg_history_max_commands, NULL, &config_change_noop },
+ { "history_display_default", N_("max commands to display"),
+ N_("maximum number of commands to display by default in history listing (0 = unlimited)"),
+ OPTION_TYPE_INT, 0, INT_MAX, 5,
+ NULL, NULL, &cfg_history_display_default, NULL, &config_change_noop },
+ { NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }
+};
+
+/* config, log section */
+
+int cfg_log_auto_server;
+int cfg_log_auto_channel;
+int cfg_log_auto_private;
+int cfg_log_plugin_msg;
+char *cfg_log_path;
+char *cfg_log_timestamp;
+int cfg_log_hide_nickserv_pwd;
+
+t_config_option weechat_options_log[] =
+{ { "log_auto_server", N_("automatically log server messages"),
+ N_("automatically log server messages"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_FALSE,
+ NULL, NULL, &cfg_log_auto_server, NULL, &config_change_log },
+ { "log_auto_channel", N_("automatically log channel chats"),
+ N_("automatically log channel chats"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_FALSE,
+ NULL, NULL, &cfg_log_auto_channel, NULL, &config_change_log },
+ { "log_auto_private", N_("automatically log private chats"),
+ N_("automatically log private chats"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_FALSE,
+ NULL, NULL, &cfg_log_auto_private, NULL, &config_change_log },
+ { "log_plugin_msg", N_("log messages from plugins (scripts)"),
+ N_("log messages from plugins (scripts)"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_FALSE,
+ NULL, NULL, &cfg_log_plugin_msg, NULL, &config_change_noop },
+ { "log_path", N_("path for log files"),
+ N_("path for WeeChat log files ('%h' will be replaced by WeeChat home, "
+ "~/.weechat by default)"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "%h/logs/", NULL, NULL, &cfg_log_path, &config_change_noop },
+ { "log_timestamp", N_("timestamp for log"),
+ N_("timestamp for log (see man strftime for date/time specifiers)"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "%Y %b %d %H:%M:%S", NULL, NULL, &cfg_log_timestamp, &config_change_noop },
+ { "log_hide_nickserv_pwd", N_("hide password displayed by nickserv"),
+ N_("hide password displayed by nickserv"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_log_hide_nickserv_pwd, NULL, &config_change_noop },
+ { NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }
+};
+
+/* config, irc section */
+
+int cfg_irc_display_away;
+int cfg_irc_show_away_once;
+char *cfg_irc_display_away_values[] =
+{ "off", "local", "channel", NULL };
+char *cfg_irc_default_msg_part;
+char *cfg_irc_default_msg_quit;
+int cfg_irc_notice_as_pv;
+int cfg_irc_away_check;
+int cfg_irc_away_check_max_nicks;
+int cfg_irc_lag_check;
+int cfg_irc_lag_min_show;
+int cfg_irc_lag_disconnect;
+int cfg_irc_anti_flood;
+int cfg_irc_fifo_pipe;
+char *cfg_irc_highlight;
+int cfg_irc_colors_receive;
+int cfg_irc_colors_send;
+int cfg_irc_send_unknown_commands;
+
+t_config_option weechat_options_irc[] =
+{ { "irc_display_away", N_("display message for away"),
+ N_("display message when (un)marking as away"),
+ OPTION_TYPE_INT_WITH_STRING, 0, 0, 0,
+ "off", cfg_irc_display_away_values, &cfg_irc_display_away, NULL, &config_change_noop },
+ { "irc_show_away_once", N_("show remote away message only once in private"),
+ N_("show remote away message only once in private"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_irc_show_away_once, NULL, &config_change_noop },
+ { "irc_default_msg_part", N_("default part message (leaving channel)"),
+ N_("default part message (leaving channel) ('%v' will be replaced by "
+ "WeeChat version in string)"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "WeeChat %v", NULL, NULL, &cfg_irc_default_msg_part, &config_change_noop },
+ { "irc_default_msg_quit", N_("default quit message"),
+ N_("default quit message ('%v' will be replaced by WeeChat version in string)"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "WeeChat %v", NULL, NULL, &cfg_irc_default_msg_quit, &config_change_noop },
+ { "irc_notice_as_pv", N_("display notices as private messages"),
+ N_("display notices as private messages"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_FALSE,
+ NULL, NULL, &cfg_irc_notice_as_pv, NULL, &config_change_noop },
+ { "irc_away_check", N_("interval between two checks for away"),
+ N_("interval between two checks for away (in minutes, 0 = never check)"),
+ OPTION_TYPE_INT, 0, INT_MAX, 0,
+ NULL, NULL, &cfg_irc_away_check, NULL, &config_change_away_check },
+ { "irc_away_check_max_nicks", N_("max number of nicks for away check"),
+ N_("do not check away nicks on channels with high number of nicks (0 = unlimited)"),
+ OPTION_TYPE_INT, 0, INT_MAX, 0,
+ NULL, NULL, &cfg_irc_away_check_max_nicks, NULL, &config_change_away_check },
+ { "irc_lag_check", N_("interval between two checks for lag"),
+ N_("interval between two checks for lag (in seconds)"),
+ OPTION_TYPE_INT, 30, INT_MAX, 60,
+ NULL, NULL, &cfg_irc_lag_check, NULL, &config_change_noop },
+ { "irc_lag_min_show", N_("minimum lag to show"),
+ N_("minimum lag to show (in seconds)"),
+ OPTION_TYPE_INT, 0, INT_MAX, 1,
+ NULL, NULL, &cfg_irc_lag_min_show, NULL, &config_change_noop },
+ { "irc_lag_disconnect", N_("disconnect after important lag"),
+ N_("disconnect after important lag (in minutes, 0 = never disconnect)"),
+ OPTION_TYPE_INT, 0, INT_MAX, 5,
+ NULL, NULL, &cfg_irc_lag_disconnect, NULL, &config_change_noop },
+ { "irc_anti_flood", N_("anti-flood"),
+ N_("anti-flood: # seconds between two user messages (0 = no anti-flood)"),
+ OPTION_TYPE_INT, 0, 5, 2,
+ NULL, NULL, &cfg_irc_anti_flood, NULL, &config_change_noop },
+ { "irc_fifo_pipe", N_("create a FIFO pipe for remote control"),
+ N_("create a FIFO pipe for remote control"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_FALSE,
+ NULL, NULL, &cfg_irc_fifo_pipe, NULL, &config_change_fifo_pipe },
+ { "irc_highlight", N_("list of words to highlight"),
+ N_("comma separated list of words to highlight (case insensitive comparison, "
+ "words may begin or end with \"*\" for partial match)"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "", NULL, NULL, &cfg_irc_highlight, &config_change_noop },
+ { "irc_colors_receive", N_("when off, colors codes are ignored in "
+ "incoming messages"),
+ N_("when off, colors codes are ignored in incoming messages"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_irc_colors_receive, NULL, config_change_noop },
+ { "irc_colors_send", N_("allow user to send colors"),
+ N_("allow user to send colors with special codes (^Cb=bold, ^Ccxx=color, "
+ "^Ccxx,yy=color+background, ^Cu=underline, ^Cr=reverse)"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_irc_colors_send, NULL, config_change_noop },
+ { "irc_send_unknown_commands", N_("send unknown commands to IRC server"),
+ N_("send unknown commands to IRC server"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_FALSE,
+ NULL, NULL, &cfg_irc_send_unknown_commands, NULL, &config_change_noop },
+ { NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }
+};
+
+/* config, dcc section */
+
+int cfg_dcc_auto_accept_files;
+int cfg_dcc_auto_accept_chats;
+int cfg_dcc_timeout;
+int cfg_dcc_blocksize;
+int cfg_dcc_fast_send;
+char *cfg_dcc_port_range;
+char *cfg_dcc_own_ip;
+char *cfg_dcc_download_path;
+char *cfg_dcc_upload_path;
+int cfg_dcc_convert_spaces;
+int cfg_dcc_auto_rename;
+int cfg_dcc_auto_resume;
+
+t_config_option weechat_options_dcc[] =
+{ { "dcc_auto_accept_files", N_("automatically accept dcc files"),
+ N_("automatically accept incoming dcc files"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_FALSE,
+ NULL, NULL, &cfg_dcc_auto_accept_files, NULL, &config_change_noop },
+ { "dcc_auto_accept_chats", N_("automatically accept dcc chats"),
+ N_("automatically accept dcc chats (use carefully!)"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_FALSE,
+ NULL, NULL, &cfg_dcc_auto_accept_chats, NULL, &config_change_noop },
+ { "dcc_timeout", N_("timeout for dcc request"),
+ N_("timeout for dcc request (in seconds)"),
+ OPTION_TYPE_INT, 5, INT_MAX, 300,
+ NULL, NULL, &cfg_dcc_timeout, NULL, &config_change_noop },
+ { "dcc_blocksize", N_("block size for dcc packets"),
+ N_("block size for dcc packets in bytes (default: 65536)"),
+ OPTION_TYPE_INT, IRC_DCC_MIN_BLOCKSIZE, IRC_DCC_MAX_BLOCKSIZE, 65536,
+ NULL, NULL, &cfg_dcc_blocksize, NULL, &config_change_noop },
+ { "dcc_fast_send", N_("does not wait for ACK when sending file"),
+ N_("does not wait for ACK when sending file"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_dcc_fast_send, NULL, &config_change_noop },
+ { "dcc_port_range", N_("allowed ports for outgoing dcc"),
+ N_("restricts outgoing dcc to use only ports in the given range "
+ "(useful for NAT) (syntax: a single port, ie. 5000 or a port "
+ "range, ie. 5000-5015, empty value means any port)"),
+ OPTION_TYPE_STRING, 0, 0, 0, "",
+ NULL, NULL, &cfg_dcc_port_range, &config_change_noop },
+ { "dcc_own_ip", N_("IP address for outgoing dcc"),
+ N_("IP or DNS address used for outgoing dcc "
+ "(if empty, local interface IP is used)"),
+ OPTION_TYPE_STRING, 0, 0, 0, "",
+ NULL, NULL, &cfg_dcc_own_ip, &config_change_noop },
+ { "dcc_download_path", N_("path for incoming files with dcc"),
+ N_("path for writing incoming files with dcc (default: user home)"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "%h/dcc", NULL, NULL, &cfg_dcc_download_path, &config_change_noop },
+ { "dcc_upload_path", N_("default path for sending files with dcc"),
+ N_("path for reading files when sending thru dcc (when no path is specified)"),
+ OPTION_TYPE_STRING, 0, 0, 0, "~",
+ NULL, NULL, &cfg_dcc_upload_path, &config_change_noop },
+ { "dcc_convert_spaces", N_("convert spaces to underscores when sending files"),
+ N_("convert spaces to underscores when sending files"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_dcc_convert_spaces, NULL, &config_change_noop },
+ { "dcc_auto_rename", N_("automatically rename dcc files if already exists"),
+ N_("rename incoming files if already exists (add '.1', '.2', ...)"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_dcc_auto_rename, NULL, &config_change_noop },
+ { "dcc_auto_resume", N_("automatically resume aborted transfers"),
+ N_("automatically resume dcc transfer if connection with remote host is loosed"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &cfg_dcc_auto_resume, NULL, &config_change_noop },
+ { NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }
+};
+
+/* config, proxy section */
+
+int cfg_proxy_use;
+int cfg_proxy_type;
+int cfg_proxy_ipv6;
+char *cfg_proxy_type_values[] =
+{ "http", "socks4", "socks5", NULL };
+char *cfg_proxy_address;
+int cfg_proxy_port;
+char *cfg_proxy_username;
+char *cfg_proxy_password;
+
+t_config_option weechat_options_proxy[] =
+{ { "proxy_use", N_("use proxy"),
+ N_("use a proxy server to connect to irc server"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_FALSE,
+ NULL, NULL, &cfg_proxy_use, NULL, &config_change_noop },
+ { "proxy_type", N_("proxy type"),
+ N_("proxy type (http (default), socks4, socks5)"),
+ OPTION_TYPE_INT_WITH_STRING, 0, 0, 0,
+ "http", cfg_proxy_type_values, &cfg_proxy_type, NULL, &config_change_noop },
+ { "proxy_ipv6", N_("use ipv6 proxy"),
+ N_("connect to proxy in ipv6"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_FALSE,
+ NULL, NULL, &cfg_proxy_ipv6, NULL, &config_change_noop },
+ { "proxy_address", N_("proxy address"),
+ N_("proxy server address (IP or hostname)"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "", NULL, NULL, &cfg_proxy_address, &config_change_noop },
+ { "proxy_port", N_("port for proxy"),
+ N_("port for connecting to proxy server"),
+ OPTION_TYPE_INT, 0, 65535, 3128,
+ NULL, NULL, &cfg_proxy_port, NULL, &config_change_noop },
+ { "proxy_username", N_("proxy username"),
+ N_("username for proxy server"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "", NULL, NULL, &cfg_proxy_username, &config_change_noop },
+ { "proxy_password", N_("proxy password"),
+ N_("password for proxy server"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "", NULL, NULL, &cfg_proxy_password, &config_change_noop },
+ { NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }
+};
+
+/* config, plugins section */
+
+char *cfg_plugins_path;
+char *cfg_plugins_autoload;
+char *cfg_plugins_extension;
+
+t_config_option weechat_options_plugins[] =
+{ { "plugins_path", N_("path for searching plugins"),
+ N_("path for searching plugins ('%h' will be replaced by WeeChat home, "
+ "~/.weechat by default)"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "%h/plugins", NULL, NULL, &cfg_plugins_path, &config_change_noop },
+ { "plugins_autoload", N_("list of plugins to load automatically"),
+ N_("comma separated list of plugins to load automatically at startup, "
+ "\"*\" means all plugins found "
+ "(names may be partial, for example \"perl\" is ok for \"libperl.so\")"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "*", NULL, NULL, &cfg_plugins_autoload, &config_change_noop },
+ { "plugins_extension", N_("standard plugins extension in filename"),
+ N_("standard plugins extension in filename, used for autoload "
+ "(if empty, then all files are loaded when autoload is \"*\")"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+#ifdef WIN32
+ ".dll",
+#else
+ ".so",
+#endif
+ NULL, NULL, &cfg_plugins_extension, &config_change_noop },
+ { NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }
+};
+
+/* config, server section */
+
+static t_irc_server cfg_server;
+
+t_config_option weechat_options_server[] =
+{ { "server_name", N_("server name"),
+ N_("name associated to IRC server (for display only)"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "", NULL, NULL, &(cfg_server.name), NULL },
+ { "server_autoconnect", N_("automatically connect to server"),
+ N_("automatically connect to server when WeeChat is starting"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &(cfg_server.autoconnect), NULL, NULL },
+ { "server_autoreconnect", N_("automatically reconnect to server"),
+ N_("automatically reconnect to server when disconnected"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &(cfg_server.autoreconnect), NULL, NULL },
+ { "server_autoreconnect_delay", N_("delay before trying again to reconnect"),
+ N_("delay (in seconds) before trying again to reconnect to server"),
+ OPTION_TYPE_INT, 0, 65535, 30,
+ NULL, NULL, &(cfg_server.autoreconnect_delay), NULL, NULL },
+ { "server_address", N_("server address or hostname"),
+ N_("IP address or hostname of IRC server"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "", NULL, NULL, &(cfg_server.address), NULL },
+ { "server_port", N_("port for IRC server"),
+ N_("port for connecting to server"),
+ OPTION_TYPE_INT, 0, 65535, 6667,
+ NULL, NULL, &(cfg_server.port), NULL, NULL },
+ { "server_ipv6", N_("use IPv6 protocol for server communication"),
+ N_("use IPv6 protocol for server communication"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_FALSE,
+ NULL, NULL, &(cfg_server.ipv6), NULL, NULL },
+ { "server_ssl", N_("use SSL for server communication"),
+ N_("use SSL for server communication"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_FALSE,
+ NULL, NULL, &(cfg_server.ssl), NULL, NULL },
+ { "server_password", N_("server password"),
+ N_("password for IRC server"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "", NULL, NULL, &(cfg_server.password), NULL },
+ { "server_nick1", N_("nickname for server"),
+ N_("nickname to use on IRC server"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "", NULL, NULL, &(cfg_server.nick1), NULL },
+ { "server_nick2", N_("alternate nickname for server"),
+ N_("alternate nickname to use on IRC server (if nickname is already used)"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "", NULL, NULL, &(cfg_server.nick2), NULL },
+ { "server_nick3", N_("2nd alternate nickname for server"),
+ N_("2nd alternate nickname to use on IRC server (if alternate nickname is already used)"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "", NULL, NULL, &(cfg_server.nick3), NULL },
+ { "server_username", N_("user name for server"),
+ N_("user name to use on IRC server"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "", NULL, NULL, &(cfg_server.username), NULL },
+ { "server_realname", N_("real name for server"),
+ N_("real name to use on IRC server"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "", NULL, NULL, &(cfg_server.realname), NULL },
+ { "server_hostname", N_("custom hostname/IP for server"),
+ N_("custom hostname/IP for server (optional, if empty local hostname is used)"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "", NULL, NULL, &(cfg_server.hostname), NULL },
+ { "server_command", N_("command(s) to run when connected to server"),
+ N_("command(s) to run when connected to server (many commands should be "
+ "separated by ';', use '\\;' for a semicolon, special variables $nick, "
+ "$channel and $server are replaced by their value)"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "", NULL, NULL, &(cfg_server.command), NULL },
+ { "server_command_delay", N_("delay (in seconds) after command was executed"),
+ N_("delay (in seconds) after command was executed (example: give some time for authentication)"),
+ OPTION_TYPE_INT, 0, 3600, 0,
+ NULL, NULL, &(cfg_server.command_delay), NULL, NULL },
+ { "server_autojoin", N_("list of channels to join when connected to server"),
+ N_("comma separated list of channels to join when connected to server (example: \"#chan1,#chan2,#chan3 key1,key2\")"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "", NULL, NULL, &(cfg_server.autojoin), NULL },
+ { "server_autorejoin", N_("automatically rejoin channels when kicked"),
+ N_("automatically rejoin channels when kicked"),
+ OPTION_TYPE_BOOLEAN, BOOL_FALSE, BOOL_TRUE, BOOL_TRUE,
+ NULL, NULL, &(cfg_server.autorejoin), NULL, NULL },
+ { "server_notify_levels", N_("notify levels for channels of this server"),
+ N_("comma separated list of notify levels for channels of this server "
+ "(format: #channel:1,..), a channel name '*' is reserved for server "
+ "default notify level"),
+ OPTION_TYPE_STRING, 0, 0, 0,
+ "", NULL, NULL, &(cfg_server.notify_levels), config_change_notify_levels },
+ { NULL, NULL, NULL, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL }
+};
+
+/* all weechat options */
+
+t_config_option *weechat_options[CONFIG_NUMBER_SECTIONS] =
+{ weechat_options_look, weechat_options_colors, weechat_options_history,
+ weechat_options_log, weechat_options_irc, weechat_options_dcc,
+ weechat_options_proxy, weechat_options_plugins, NULL, NULL, NULL,
+ weechat_options_server
+};
+
+
+/*
+ * config_get_pos_array_values: return position of a string in an array of values
+ * return -1 if not found, otherwise position
+ */
+
+int
+config_get_pos_array_values (char **array, char *string)
+{
+ int i;
+
+ i = 0;
+ while (array[i])
+ {
+ if (ascii_strcasecmp (array[i], string) == 0)
+ return i;
+ i++;
+ }
+ /* string not found in array */
+ return -1;
+}
+
+/*
+ * config_get_section: get section name from option pointer
+ */
+
+char *
+config_get_section (t_config_option *ptr_option)
+{
+ int i, j;
+
+ for (i = 0; i < CONFIG_NUMBER_SECTIONS; i++)
+ {
+ if ((i != CONFIG_SECTION_KEYS) && (i != CONFIG_SECTION_ALIAS)
+ && (i != CONFIG_SECTION_IGNORE) && (i != CONFIG_SECTION_SERVER))
+ {
+ for (j = 0; weechat_options[i][j].option_name; j++)
+ {
+ /* if option found, return pointer to section name */
+ if (ptr_option == &weechat_options[i][j])
+ return config_sections[i].section_name;
+ }
+ }
+ }
+ /* option not found */
+ return NULL;
+}
+
+/*
+ * config_change_noop: called when an option is changed by /set command
+ * and that no special action is needed after that
+ */
+
+void
+config_change_noop ()
+{
+ /* do nothing */
+}
+
+/*
+ * config_change_save_on_exit: called when "save_on_exit" flag is changed
+ */
+
+void
+config_change_save_on_exit ()
+{
+ if (!cfg_look_save_on_exit)
+ {
+ gui_printf (NULL, "\n");
+ gui_printf (NULL, _("%s you should now issue /save to write "
+ "\"save_on_exit\" option in config file.\n"),
+ WEECHAT_WARNING);
+ }
+}
+
+/*
+ * config_change_title: called when title is changed
+ */
+
+void
+config_change_title ()
+{
+ if (cfg_look_set_title)
+ gui_window_set_title ();
+ else
+ gui_window_reset_title ();
+}
+
+/*
+ * config_change_buffers: called when buffers change (for example nicklist)
+ */
+
+void
+config_change_buffers ()
+{
+ gui_window_refresh_windows ();
+}
+
+/*
+ * config_change_buffer_content: called when content of a buffer changes
+ */
+
+void
+config_change_buffer_content ()
+{
+ gui_window_redraw_buffer (gui_current_window->buffer);
+}
+
+/*
+ * config_change_hotlist: called when hotlist changes
+ */
+
+void
+config_change_hotlist ()
+{
+ hotlist_resort ();
+ gui_status_draw (gui_current_window->buffer, 1);
+}
+
+/*
+ * config_change_read_marker: called when read marker is changed
+ */
+
+void
+config_change_read_marker ()
+{
+ gui_window_redraw_all_buffers ();
+}
+
+/*
+ * config_change_one_server_buffer: called when the "one server buffer"
+ * setting is changed
+ */
+
+void
+config_change_one_server_buffer ()
+{
+ if (cfg_look_one_server_buffer)
+ gui_buffer_merge_servers (gui_current_window);
+ else
+ gui_buffer_split_server (gui_current_window);
+}
+
+/*
+ * config_change_color: called when a color is changed by /set command
+ */
+
+void
+config_change_color ()
+{
+ gui_color_init_pairs ();
+ gui_color_rebuild_weechat ();
+ gui_window_refresh_windows ();
+}
+
+/*
+ * config_change_nicks_colors: called when number of nicks color changed
+ */
+
+void
+config_change_nicks_colors ()
+{
+ t_irc_server *ptr_server;
+ t_irc_channel *ptr_channel;
+ t_irc_nick *ptr_nick;
+
+ for (ptr_server = irc_servers; ptr_server;
+ ptr_server = ptr_server->next_server)
+ {
+ if (ptr_server->is_connected)
+ {
+ for (ptr_channel = ptr_server->channels; ptr_channel;
+ ptr_channel = ptr_channel->next_channel)
+ {
+ for (ptr_nick = ptr_channel->nicks; ptr_nick;
+ ptr_nick = ptr_nick->next_nick)
+ {
+ if (ptr_nick->color != GUI_COLOR_WIN_NICK_SELF)
+ ptr_nick->color = irc_nick_find_color (ptr_nick);
+ }
+ }
+ }
+ }
+}
+
+/*
+ * config_change_away_check: called when away check is changed
+ */
+
+void
+config_change_away_check ()
+{
+ if (cfg_irc_away_check == 0)
+ {
+ /* reset away flag for all nicks/chans/servers */
+ irc_server_remove_away ();
+ }
+ irc_check_away = cfg_irc_away_check * 60;
+}
+
+/*
+ * config_change_fifo_pipe: called when FIFO pipe is changed
+ */
+
+void
+config_change_fifo_pipe ()
+{
+ if (cfg_irc_fifo_pipe)
+ {
+ if (weechat_fifo == -1)
+ fifo_create ();
+ }
+ else
+ {
+ if (weechat_fifo != -1)
+ fifo_remove ();
+ }
+}
+
+/*
+ * config_change_notify_levels: called when notify levels is changed for a server
+ */
+
+void
+config_change_notify_levels ()
+{
+ t_gui_buffer *ptr_buffer;
+
+ for (ptr_buffer = gui_buffers; ptr_buffer; ptr_buffer = ptr_buffer->next_buffer)
+ {
+ if (GUI_BUFFER_IS_CHANNEL(ptr_buffer) || GUI_BUFFER_IS_PRIVATE(ptr_buffer))
+ ptr_buffer->notify_level =
+ irc_channel_get_notify_level (GUI_SERVER(ptr_buffer), GUI_CHANNEL(ptr_buffer));
+ }
+}
+
+/*
+ * config_change_log: called when log settings are changed (for server/channel/private logging)
+ */
+
+void
+config_change_log ()
+{
+ t_gui_buffer *ptr_buffer;
+
+ for (ptr_buffer = gui_buffers; ptr_buffer;
+ ptr_buffer = ptr_buffer->next_buffer)
+ {
+ if (GUI_BUFFER_IS_SERVER(ptr_buffer))
+ {
+ if (cfg_log_auto_server && !ptr_buffer->log_file)
+ gui_log_start (ptr_buffer);
+ else if (!cfg_log_auto_server && ptr_buffer->log_file)
+ gui_log_end (ptr_buffer);
+ }
+ if (GUI_BUFFER_IS_CHANNEL(ptr_buffer))
+ {
+ if (cfg_log_auto_channel && !ptr_buffer->log_file)
+ gui_log_start (ptr_buffer);
+ else if (!cfg_log_auto_channel && ptr_buffer->log_file)
+ gui_log_end (ptr_buffer);
+ }
+ if (GUI_BUFFER_IS_PRIVATE(ptr_buffer))
+ {
+ if (cfg_log_auto_private && !ptr_buffer->log_file)
+ gui_log_start (ptr_buffer);
+ else if (!cfg_log_auto_private && ptr_buffer->log_file)
+ gui_log_end (ptr_buffer);
+ }
+ }
+}
+
+/*
+ * config_option_get_boolean_value: get boolean value with user text
+ * return: BOOL_FALSE or BOOL_TRUE
+ */
+
+int
+config_option_get_boolean_value (char *text)
+{
+ if ((ascii_strcasecmp (text, "on") == 0)
+ || (ascii_strcasecmp (text, "yes") == 0)
+ || (ascii_strcasecmp (text, "y") == 0)
+ || (ascii_strcasecmp (text, "true") == 0)
+ || (ascii_strcasecmp (text, "t") == 0)
+ || (ascii_strcasecmp (text, "1") == 0))
+ return BOOL_TRUE;
+
+ if ((ascii_strcasecmp (text, "off") == 0)
+ || (ascii_strcasecmp (text, "no") == 0)
+ || (ascii_strcasecmp (text, "n") == 0)
+ || (ascii_strcasecmp (text, "false") == 0)
+ || (ascii_strcasecmp (text, "f") == 0)
+ || (ascii_strcasecmp (text, "0") == 0))
+ return BOOL_FALSE;
+
+ /* invalid text */
+ return -1;
+}
+
+/*
+ * config_option_set_value: set new value for an option
+ * return: 0 if success
+ * -1 if error (bad value)
+ */
+
+int
+config_option_set_value (t_config_option *option, char *value)
+{
+ int int_value;
+
+ switch (option->option_type)
+ {
+ case OPTION_TYPE_BOOLEAN:
+ int_value = config_option_get_boolean_value (value);
+ switch (int_value)
+ {
+ case BOOL_TRUE:
+ *(option->ptr_int) = BOOL_TRUE;
+ break;
+ case BOOL_FALSE:
+ *(option->ptr_int) = BOOL_FALSE;
+ break;
+ default:
+ return -1;
+ }
+ break;
+ case OPTION_TYPE_INT:
+ int_value = atoi (value);
+ if ((int_value < option->min) || (int_value > option->max))
+ return -1;
+ *(option->ptr_int) = int_value;
+ break;
+ case OPTION_TYPE_INT_WITH_STRING:
+ int_value = config_get_pos_array_values (option->array_values,
+ value);
+ if (int_value < 0)
+ return -1;
+ *(option->ptr_int) = int_value;
+ break;
+ case OPTION_TYPE_COLOR:
+ if (!gui_color_assign (option->ptr_int, value))
+ return -1;
+ break;
+ case OPTION_TYPE_STRING:
+ if ((option->max > 0) && (utf8_strlen (value) > option->max))
+ return -1;
+ if (*(option->ptr_string))
+ free (*(option->ptr_string));
+ *(option->ptr_string) = strdup (value);
+ break;
+ }
+ return 0;
+}
+
+/*
+ * config_option_list_remove: remove an item from a list for an option
+ * (for options with value like: "abc:1,def:blabla")
+ */
+
+void
+config_option_list_remove (char **string, char *item)
+{
+ char *name, *pos, *pos2;
+
+ if (!string || !(*string))
+ return;
+
+ name = (char *) malloc (strlen (item) + 2);
+ strcpy (name, item);
+ strcat (name, ":");
+ pos = ascii_strcasestr (*string, name);
+ free (name);
+ if (pos)
+ {
+ pos2 = pos + strlen (item);
+ if (pos2[0] == ':')
+ {
+ pos2++;
+ if (pos2[0])
+ {
+ while (pos2[0] && (pos2[0] != ','))
+ pos2++;
+ if (pos2[0] == ',')
+ pos2++;
+ if (!pos2[0] && (pos != (*string)))
+ pos--;
+ strcpy (pos, pos2);
+ if (!(*string)[0])
+ {
+ free (*string);
+ *string = NULL;
+ }
+ else
+ (*string) = (char *) realloc (*string, strlen (*string) + 1);
+ }
+ }
+ }
+}
+
+/*
+ * config_option_list_set: set an item from a list for an option
+ * (for options with value like: "abc:1,def:blabla")
+ */
+
+void
+config_option_list_set (char **string, char *item, char *value)
+{
+ config_option_list_remove (string, item);
+
+ if (!(*string))
+ {
+ (*string) = (char *) malloc (strlen (item) + 1 + strlen (value) + 1);
+ (*string)[0] = '\0';
+ }
+ else
+ (*string) = (char *) realloc (*string,
+ strlen (*string) + 1 +
+ strlen (item) + 1 + strlen (value) + 1);
+
+ if ((*string)[0])
+ strcat (*string, ",");
+ strcat (*string, item);
+ strcat (*string, ":");
+ strcat (*string, value);
+}
+
+/*
+ * config_option_list_get_value: return position of item value in the list
+ * (for options with value like: "abc:1,def:blabla")
+ */
+
+void
+config_option_list_get_value (char **string, char *item,
+ char **pos_found, int *length)
+{
+ char *name, *pos, *pos2, *pos_comma;
+
+ *pos_found = NULL;
+ *length = 0;
+
+ if (!string || !(*string))
+ return;
+
+ name = (char *) malloc (strlen (item) + 2);
+ strcpy (name, item);
+ strcat (name, ":");
+ pos = ascii_strcasestr (*string, name);
+ free (name);
+ if (pos)
+ {
+ pos2 = pos + strlen (item);
+ if (pos2[0] == ':')
+ {
+ pos2++;
+ *pos_found = pos2;
+ pos_comma = strchr (pos2, ',');
+ if (pos_comma)
+ *length = pos_comma - pos2;
+ else
+ *length = strlen (pos2);
+ }
+ }
+}
+
+/*
+ * config_get_server_option_ptr: get a pointer to a server config option
+ */
+
+void *
+config_get_server_option_ptr (t_irc_server *server, char *option_name)
+{
+ if (ascii_strcasecmp (option_name, "server_name") == 0)
+ return (void *)(&server->name);
+ if (ascii_strcasecmp (option_name, "server_autoconnect") == 0)
+ return (void *)(&server->autoconnect);
+ if (ascii_strcasecmp (option_name, "server_autoreconnect") == 0)
+ return (void *)(&server->autoreconnect);
+ if (ascii_strcasecmp (option_name, "server_autoreconnect_delay") == 0)
+ return (void *)(&server->autoreconnect_delay);
+ if (ascii_strcasecmp (option_name, "server_address") == 0)
+ return (void *)(&server->address);
+ if (ascii_strcasecmp (option_name, "server_port") == 0)
+ return (void *)(&server->port);
+ if (ascii_strcasecmp (option_name, "server_ipv6") == 0)
+ return (void *)(&server->ipv6);
+ if (ascii_strcasecmp (option_name, "server_ssl") == 0)
+ return (void *)(&server->ssl);
+ if (ascii_strcasecmp (option_name, "server_password") == 0)
+ return (void *)(&server->password);
+ if (ascii_strcasecmp (option_name, "server_nick1") == 0)
+ return (void *)(&server->nick1);
+ if (ascii_strcasecmp (option_name, "server_nick2") == 0)
+ return (void *)(&server->nick2);
+ if (ascii_strcasecmp (option_name, "server_nick3") == 0)
+ return (void *)(&server->nick3);
+ if (ascii_strcasecmp (option_name, "server_username") == 0)
+ return (void *)(&server->username);
+ if (ascii_strcasecmp (option_name, "server_realname") == 0)
+ return (void *)(&server->realname);
+ if (ascii_strcasecmp (option_name, "server_hostname") == 0)
+ return (void *)(&server->hostname);
+ if (ascii_strcasecmp (option_name, "server_command") == 0)
+ return (void *)(&server->command);
+ if (ascii_strcasecmp (option_name, "server_command_delay") == 0)
+ return (void *)(&server->command_delay);
+ if (ascii_strcasecmp (option_name, "server_autojoin") == 0)
+ return (void *)(&server->autojoin);
+ if (ascii_strcasecmp (option_name, "server_autorejoin") == 0)
+ return (void *)(&server->autorejoin);
+ if (ascii_strcasecmp (option_name, "server_notify_levels") == 0)
+ return (void *)(&server->notify_levels);
+ /* option not found */
+ return NULL;
+}
+
+/*
+ * config_set_server_value: set new value for an option
+ * return: 0 if success
+ * -1 if option not found
+ * -2 if bad value
+ */
+
+int
+config_set_server_value (t_irc_server *server, char *option_name,
+ char *value)
+{
+ t_config_option *ptr_option;
+ int i;
+ void *ptr_data;
+ int int_value;
+
+ ptr_data = config_get_server_option_ptr (server, option_name);
+ if (!ptr_data)
+ return -1;
+
+ ptr_option = NULL;
+ for (i = 0; weechat_options[CONFIG_SECTION_SERVER][i].option_name; i++)
+ {
+ /* if option found, return pointer */
+ if (ascii_strcasecmp (weechat_options[CONFIG_SECTION_SERVER][i].option_name, option_name) == 0)
+ {
+ ptr_option = &weechat_options[CONFIG_SECTION_SERVER][i];
+ break;
+ }
+ }
+ if (!ptr_option)
+ return -1;
+
+ switch (ptr_option->option_type)
+ {
+ case OPTION_TYPE_BOOLEAN:
+ int_value = config_option_get_boolean_value (value);
+ switch (int_value)
+ {
+ case BOOL_TRUE:
+ *((int *)(ptr_data)) = BOOL_TRUE;
+ break;
+ case BOOL_FALSE:
+ *((int *)(ptr_data)) = BOOL_FALSE;
+ break;
+ default:
+ return -2;
+ }
+ break;
+ case OPTION_TYPE_INT:
+ int_value = atoi (value);
+ if ((int_value < ptr_option->min) || (int_value > ptr_option->max))
+ return -2;
+ *((int *)(ptr_data)) = int_value;
+ break;
+ case OPTION_TYPE_INT_WITH_STRING:
+ int_value = config_get_pos_array_values (ptr_option->array_values,
+ value);
+ if (int_value < 0)
+ return -2;
+ *((int *)(ptr_data)) = int_value;
+ break;
+ case OPTION_TYPE_COLOR:
+ if (!gui_color_assign ((int *)ptr_data, value))
+ return -2;
+ break;
+ case OPTION_TYPE_STRING:
+ if (*((char **)ptr_data))
+ free (*((char **)ptr_data));
+ *((char **)ptr_data) = strdup (value);
+ break;
+ }
+ if (ptr_option->handler_change != NULL)
+ (void) (ptr_option->handler_change());
+ return 0;
+}
+
+/*
+ * config_option_search: look for an option and return pointer to this option
+ * if option is not found, NULL is returned
+ */
+
+t_config_option *
+config_option_search (char *option_name)
+{
+ int i, j;
+
+ for (i = 0; i < CONFIG_NUMBER_SECTIONS; i++)
+ {
+ if ((i != CONFIG_SECTION_KEYS) && (i != CONFIG_SECTION_ALIAS)
+ && (i != CONFIG_SECTION_IGNORE) && (i != CONFIG_SECTION_SERVER))
+ {
+ for (j = 0; weechat_options[i][j].option_name; j++)
+ {
+ /* if option found, return pointer */
+ if (ascii_strcasecmp (weechat_options[i][j].option_name, option_name) == 0)
+ return &weechat_options[i][j];
+ }
+ }
+ }
+ /* option not found */
+ return NULL;
+}
+
+/*
+ * config_option_search_option_value: look for type and value of an option
+ * (including server options)
+ * if option is not found, NULL is returned
+ */
+
+void
+config_option_search_option_value (char *option_name, t_config_option **option,
+ void **option_value)
+{
+ t_config_option *ptr_option;
+ t_irc_server *ptr_server;
+ int i;
+ void *ptr_value;
+ char *pos;
+
+ ptr_option = NULL;
+ ptr_value = NULL;
+
+ ptr_option = config_option_search (option_name);
+ if (!ptr_option)
+ {
+ pos = strchr (option_name, '.');
+ if (pos)
+ {
+ pos[0] = '\0';
+ ptr_server = irc_server_search (option_name);
+ if (ptr_server)
+ {
+ for (i = 0; weechat_options[CONFIG_SECTION_SERVER][i].option_name; i++)
+ {
+ if (strcmp (weechat_options[CONFIG_SECTION_SERVER][i].option_name,
+ pos + 1) == 0)
+ {
+ ptr_option = &weechat_options[CONFIG_SECTION_SERVER][i];
+ ptr_value = config_get_server_option_ptr (ptr_server, pos + 1);
+ break;
+ }
+ }
+ }
+ pos[0] = '.';
+ }
+ }
+ else
+ {
+ switch (ptr_option->option_type)
+ {
+ case OPTION_TYPE_BOOLEAN:
+ case OPTION_TYPE_INT:
+ case OPTION_TYPE_INT_WITH_STRING:
+ case OPTION_TYPE_COLOR:
+ ptr_value = (void *)(ptr_option->ptr_int);
+ break;
+ case OPTION_TYPE_STRING:
+ ptr_value = (void *)(ptr_option->ptr_string);
+ break;
+ }
+ }
+
+ if (ptr_option)
+ {
+ *option = ptr_option;
+ *option_value = ptr_value;
+ }
+}
+
+/*
+ * config_set_value: set new value for an option (found by name)
+ * return: 0 if success
+ * -1 if bad value for option
+ * -2 if option is not found
+ */
+
+int
+config_set_value (char *option_name, char *value)
+{
+ t_config_option *ptr_option;
+
+ ptr_option = config_option_search (option_name);
+ if (ptr_option)
+ return config_option_set_value (ptr_option, value);
+ else
+ return -2;
+}
+
+/*
+ * config_allocate_server: allocate a new server
+ */
+
+int
+config_allocate_server (char *filename, int line_number)
+{
+ if (!cfg_server.name
+ || !cfg_server.address
+ || cfg_server.port < 0
+ || !cfg_server.nick1
+ || !cfg_server.nick2
+ || !cfg_server.nick3
+ || !cfg_server.username
+ || !cfg_server.realname)
+ {
+ irc_server_free_all ();
+ gui_printf (NULL,
+ _("%s %s, line %d: new server, but previous was incomplete\n"),
+ WEECHAT_WARNING, filename, line_number);
+ return 0;
+
+ }
+ if (irc_server_name_already_exists (cfg_server.name))
+ {
+ irc_server_free_all ();
+ gui_printf (NULL,
+ _("%s %s, line %d: server '%s' already exists\n"),
+ WEECHAT_WARNING, filename, line_number, cfg_server.name);
+ return 0;
+ }
+ if (!irc_server_new (cfg_server.name,
+ cfg_server.autoconnect, cfg_server.autoreconnect,
+ cfg_server.autoreconnect_delay, 0, cfg_server.address,
+ cfg_server.port, cfg_server.ipv6, cfg_server.ssl,
+ cfg_server.password, cfg_server.nick1, cfg_server.nick2,
+ cfg_server.nick3, cfg_server.username, cfg_server.realname,
+ cfg_server.hostname, cfg_server.command,
+ cfg_server.command_delay, cfg_server.autojoin,
+ cfg_server.autorejoin, cfg_server.notify_levels))
+ {
+ irc_server_free_all ();
+ gui_printf (NULL,
+ _("%s %s, line %d: unable to create server\n"),
+ WEECHAT_WARNING, filename, line_number);
+ return 0;
+ }
+
+ irc_server_destroy (&cfg_server);
+ irc_server_init (&cfg_server);
+
+ return 1;
+}
+
+/*
+ * config_default_values: initialize config variables with default values
+ */
+
+void
+config_default_values ()
+{
+ int i, j, int_value;
+
+ for (i = 0; i < CONFIG_NUMBER_SECTIONS; i++)
+ {
+ if ((i != CONFIG_SECTION_KEYS) && (i != CONFIG_SECTION_ALIAS)
+ && (i != CONFIG_SECTION_IGNORE) && (i != CONFIG_SECTION_SERVER))
+ {
+ for (j = 0; weechat_options[i][j].option_name; j++)
+ {
+ switch (weechat_options[i][j].option_type)
+ {
+ case OPTION_TYPE_BOOLEAN:
+ case OPTION_TYPE_INT:
+ *weechat_options[i][j].ptr_int =
+ weechat_options[i][j].default_int;
+ break;
+ case OPTION_TYPE_INT_WITH_STRING:
+ int_value = config_get_pos_array_values (
+ weechat_options[i][j].array_values,
+ weechat_options[i][j].default_string);
+ if (int_value < 0)
+ gui_printf (NULL,
+ _("%s unable to assign default int with string (\"%s\")\n"),
+ WEECHAT_WARNING, weechat_options[i][j].default_string);
+ else
+ *weechat_options[i][j].ptr_int =
+ int_value;
+ break;
+ case OPTION_TYPE_COLOR:
+ if (!gui_color_assign (
+ weechat_options[i][j].ptr_int,
+ weechat_options[i][j].default_string))
+ gui_printf (NULL,
+ _("%s unable to assign default color (\"%s\")\n"),
+ WEECHAT_WARNING, weechat_options[i][j].default_string);
+ break;
+ case OPTION_TYPE_STRING:
+ *weechat_options[i][j].ptr_string =
+ strdup (weechat_options[i][j].default_string);
+ break;
+ }
+ }
+ }
+ }
+}
+
+/*
+ * config_read: read WeeChat configuration
+ * returns: 0 = successful
+ * -1 = config file file not found
+ * < -1 = other error (fatal)
+ */
+
+int
+config_read ()
+{
+ int filename_length;
+ char *filename;
+ FILE *file;
+ int section, line_number, i, option_number;
+ int server_found;
+ char line[1024], *ptr_line, *ptr_line2, *pos, *pos2;
+
+ filename_length = strlen (weechat_home) + strlen (WEECHAT_CONFIG_NAME) + 2;
+ filename = (char *) malloc (filename_length * sizeof (char));
+ if (!filename)
+ return -2;
+ snprintf (filename, filename_length, "%s%s" WEECHAT_CONFIG_NAME,
+ weechat_home, DIR_SEPARATOR);
+ if ((file = fopen (filename, "r")) == NULL)
+ {
+ gui_printf (NULL, _("%s config file \"%s\" not found.\n"),
+ WEECHAT_WARNING, filename);
+ free (filename);
+ return -1;
+ }
+
+ config_default_values ();
+ irc_server_init (&cfg_server);
+
+ /* read config file */
+ section = CONFIG_SECTION_NONE;
+ server_found = 0;
+ line_number = 0;
+ while (!feof (file))
+ {
+ ptr_line = fgets (line, sizeof (line) - 1, file);
+ line_number++;
+ if (ptr_line)
+ {
+ /* encode line to internal charset */
+ ptr_line2 = weechat_iconv_to_internal (NULL, ptr_line);
+ if (ptr_line2)
+ {
+ snprintf (line, sizeof (line) - 1, "%s", ptr_line2);
+ free (ptr_line2);
+ }
+
+ /* skip spaces */
+ while (ptr_line[0] == ' ')
+ ptr_line++;
+ /* not a comment and not an empty line */
+ if ((ptr_line[0] != '#') && (ptr_line[0] != '\r')
+ && (ptr_line[0] != '\n'))
+ {
+ /* beginning of section */
+ if (ptr_line[0] == '[')
+ {
+ pos = strchr (line, ']');
+ if (pos == NULL)
+ gui_printf (NULL,
+ _("%s %s, line %d: invalid syntax, missing \"]\"\n"),
+ WEECHAT_WARNING, filename, line_number);
+ else
+ {
+ pos[0] = '\0';
+ pos = ptr_line + 1;
+ section = CONFIG_SECTION_NONE;
+ for (i = 0; config_sections[i].section_name; i++)
+ {
+ if (strcmp (config_sections[i].section_name, pos) == 0)
+ {
+ section = i;
+ break;
+ }
+ }
+ if (section == CONFIG_SECTION_NONE)
+ gui_printf (NULL,
+ _("%s %s, line %d: unknown section identifier (\"%s\")\n"),
+ WEECHAT_WARNING, filename, line_number, pos);
+ else
+ {
+ if (server_found)
+ {
+ /* if server already started => create it */
+ config_allocate_server (filename, line_number);
+ }
+ server_found = (section == CONFIG_SECTION_SERVER) ? 1 : 0;
+ }
+ }
+ }
+ else
+ {
+ if (section == CONFIG_SECTION_NONE)
+ {
+ gui_printf (NULL,
+ _("%s %s, line %d: invalid section for option, line is ignored\n"),
+ WEECHAT_WARNING, filename, line_number);
+ }
+ else
+ {
+ pos = strchr (line, '=');
+ if (pos == NULL)
+ gui_printf (NULL,
+ _("%s %s, line %d: invalid syntax, missing \"=\"\n"),
+ WEECHAT_WARNING, filename, line_number);
+ else
+ {
+ pos[0] = '\0';
+ pos++;
+
+ /* remove spaces before '=' */
+ pos2 = pos - 2;
+ while ((pos2 > line) && (pos2[0] == ' '))
+ {
+ pos2[0] = '\0';
+ pos2--;
+ }
+
+ /* skip spaces after '=' */
+ while (pos[0] && (pos[0] == ' '))
+ {
+ pos++;
+ }
+
+ /* remove CR/LF */
+ pos2 = strchr (pos, '\r');
+ if (pos2 != NULL)
+ pos2[0] = '\0';
+ pos2 = strchr (pos, '\n');
+ if (pos2 != NULL)
+ pos2[0] = '\0';
+
+ /* remove simple or double quotes
+ and spaces at the end */
+ if (strlen(pos) > 1)
+ {
+ pos2 = pos + strlen (pos) - 1;
+ while ((pos2 > pos) && (pos2[0] == ' '))
+ {
+ pos2[0] = '\0';
+ pos2--;
+ }
+ pos2 = pos + strlen (pos) - 1;
+ if (((pos[0] == '\'') &&
+ (pos2[0] == '\'')) ||
+ ((pos[0] == '"') &&
+ (pos2[0] == '"')))
+ {
+ pos2[0] = '\0';
+ pos++;
+ }
+ }
+
+ if (section == CONFIG_SECTION_KEYS)
+ {
+ if (pos[0])
+ {
+ /* bind key (overwrite any binding with same key) */
+ gui_keyboard_bind (line, pos);
+ }
+ else
+ {
+ /* unbin key if no value given */
+ gui_keyboard_unbind (line);
+ }
+ }
+ else if (section == CONFIG_SECTION_ALIAS)
+ {
+ /* create new alias */
+ if (alias_new (line, pos))
+ weelist_add (&index_commands, &last_index_command,
+ line, WEELIST_POS_SORT);
+ }
+ else if (section == CONFIG_SECTION_IGNORE)
+ {
+ /* create new ignore */
+ if (ascii_strcasecmp (line, "ignore") != 0)
+ gui_printf (NULL,
+ _("%s %s, line %d: invalid option \"%s\"\n"),
+ WEECHAT_WARNING, filename, line_number, line);
+ else
+ {
+ if (!irc_ignore_add_from_config (pos))
+ gui_printf (NULL,
+ _("%s %s, line %d: invalid ignore options \"%s\"\n"),
+ WEECHAT_WARNING, filename, line_number, pos);
+ }
+ }
+ else
+ {
+ option_number = -1;
+ for (i = 0;
+ weechat_options[section][i].option_name; i++)
+ {
+ if (strcmp
+ (weechat_options[section][i].option_name,
+ ptr_line) == 0)
+ {
+ option_number = i;
+ break;
+ }
+ }
+ if (option_number < 0)
+ gui_printf (NULL,
+ _("%s %s, line %d: invalid option \"%s\"\n"),
+ WEECHAT_WARNING, filename, line_number, ptr_line);
+ else
+ {
+ if (config_option_set_value (&weechat_options[section][option_number], pos) < 0)
+ {
+ switch (weechat_options[section]
+ [option_number].option_type)
+ {
+ case OPTION_TYPE_BOOLEAN:
+ gui_printf (NULL,
+ _("%s %s, line %d: invalid value for "
+ "option '%s'\n"
+ "Expected: boolean value: "
+ "'off' or 'on'\n"),
+ WEECHAT_WARNING, filename,
+ line_number, ptr_line);
+ break;
+ case OPTION_TYPE_INT:
+ gui_printf (NULL,
+ _("%s %s, line %d: invalid value for "
+ "option '%s'\n"
+ "Expected: integer between %d "
+ "and %d\n"),
+ WEECHAT_WARNING, filename,
+ line_number, ptr_line,
+ weechat_options[section][option_number].min,
+ weechat_options[section][option_number].max);
+ break;
+ case OPTION_TYPE_INT_WITH_STRING:
+ gui_printf (NULL,
+ _("%s %s, line %d: invalid value for "
+ "option '%s'\n"
+ "Expected: one of these strings: "),
+ WEECHAT_WARNING, filename,
+ line_number, ptr_line);
+ i = 0;
+ while (weechat_options[section][option_number].array_values[i])
+ {
+ gui_printf (NULL, "\"%s\" ",
+ weechat_options[section][option_number].array_values[i]);
+ i++;
+ }
+ gui_printf (NULL, "\n");
+ break;
+ case OPTION_TYPE_COLOR:
+ gui_printf (NULL,
+ _("%s %s, line %d: invalid color "
+ "name for option '%s'\n"),
+ WEECHAT_WARNING, filename,
+ line_number,
+ ptr_line);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (server_found)
+ {
+ if (!config_allocate_server (filename, line_number))
+ {
+ fclose (file);
+ free (filename);
+ return -2;
+ }
+ }
+
+ fclose (file);
+ free (filename);
+
+ return 0;
+}
+
+
+/*
+ * config_create_default: create default WeeChat config
+ * return: 0 if ok
+ * < 0 if error
+ */
+
+int
+config_create_default ()
+{
+ int filename_length;
+ char *filename;
+ FILE *file;
+ int i, j;
+ time_t current_time;
+ struct passwd *my_passwd;
+ char *realname, *pos;
+ t_gui_key *ptr_key;
+ char *expanded_name, *function_name;
+
+ filename_length = strlen (weechat_home) +
+ strlen (WEECHAT_CONFIG_NAME) + 2;
+ filename =
+ (char *) malloc (filename_length * sizeof (char));
+ if (!filename)
+ return -2;
+ snprintf (filename, filename_length, "%s%s" WEECHAT_CONFIG_NAME,
+ weechat_home, DIR_SEPARATOR);
+ if ((file = fopen (filename, "w")) == NULL)
+ {
+ gui_printf (NULL, _("%s cannot create file \"%s\"\n"),
+ WEECHAT_ERROR, filename);
+ free (filename);
+ return -1;
+ }
+
+ weechat_iconv_fprintf (stdout, _("%s: creating default config file...\n"), PACKAGE_NAME);
+ weechat_log_printf (_("Creating default config file\n"));
+
+ current_time = time (NULL);
+ weechat_iconv_fprintf (file, _("#\n# %s configuration file, created by "
+ "%s v%s on %s"),
+ PACKAGE_NAME, PACKAGE_NAME, PACKAGE_VERSION,
+ ctime (&current_time));
+ weechat_iconv_fprintf (file, _("# WARNING! Be careful when editing this file, "
+ "WeeChat writes this file when exiting.\n#\n"));
+
+ for (i = 0; i < CONFIG_NUMBER_SECTIONS; i++)
+ {
+ if ((i != CONFIG_SECTION_KEYS) && (i != CONFIG_SECTION_ALIAS)
+ && (i != CONFIG_SECTION_IGNORE) && (i != CONFIG_SECTION_SERVER))
+ {
+ weechat_iconv_fprintf (file, "\n[%s]\n", config_sections[i].section_name);
+ for (j = 0; weechat_options[i][j].option_name; j++)
+ {
+ switch (weechat_options[i][j].option_type)
+ {
+ case OPTION_TYPE_BOOLEAN:
+ weechat_iconv_fprintf (file, "%s = %s\n",
+ weechat_options[i][j].option_name,
+ (weechat_options[i][j].default_int) ?
+ "on" : "off");
+ break;
+ case OPTION_TYPE_INT:
+ weechat_iconv_fprintf (file, "%s = %d\n",
+ weechat_options[i][j].option_name,
+ weechat_options[i][j].default_int);
+ break;
+ case OPTION_TYPE_INT_WITH_STRING:
+ case OPTION_TYPE_COLOR:
+ weechat_iconv_fprintf (file, "%s = %s\n",
+ weechat_options[i][j].option_name,
+ weechat_options[i][j].default_string);
+ break;
+ case OPTION_TYPE_STRING:
+ weechat_iconv_fprintf (file, "%s = \"%s\"\n",
+ weechat_options[i][j].option_name,
+ weechat_options[i][j].default_string);
+ break;
+ }
+ }
+ }
+ }
+
+ /* default key bindings */
+ weechat_iconv_fprintf (file, "\n[keys]\n");
+ for (ptr_key = gui_keys; ptr_key; ptr_key = ptr_key->next_key)
+ {
+ expanded_name = gui_keyboard_get_expanded_name (ptr_key->key);
+ if (ptr_key->function)
+ {
+ function_name = gui_keyboard_function_search_by_ptr (ptr_key->function);
+ if (function_name)
+ weechat_iconv_fprintf (file, "%s = \"%s%s%s\"\n",
+ (expanded_name) ? expanded_name : ptr_key->key,
+ function_name,
+ (ptr_key->args) ? " " : "",
+ (ptr_key->args) ? ptr_key->args : "");
+ }
+ else
+ weechat_iconv_fprintf (file, "%s = \"%s\"\n",
+ (expanded_name) ? expanded_name : ptr_key->key,
+ ptr_key->command);
+ if (expanded_name)
+ free (expanded_name);
+ }
+
+ /* default aliases */
+ weechat_iconv_fprintf (file, "\n[alias]\n");
+ weechat_iconv_fprintf (file, "SAY = \"msg *\"\n");
+ weechat_iconv_fprintf (file, "BYE = \"quit\"\n");
+ weechat_iconv_fprintf (file, "EXIT = \"quit\"\n");
+ weechat_iconv_fprintf (file, "SIGNOFF = \"quit\"\n");
+ weechat_iconv_fprintf (file, "C = \"clear\"\n");
+ weechat_iconv_fprintf (file, "CL = \"clear\"\n");
+ weechat_iconv_fprintf (file, "CLOSE = \"buffer close\"\n");
+ weechat_iconv_fprintf (file, "CHAT = \"dcc chat\"\n");
+ weechat_iconv_fprintf (file, "IG = \"ignore\"\n");
+ weechat_iconv_fprintf (file, "J = \"join\"\n");
+ weechat_iconv_fprintf (file, "K = \"kick\"\n");
+ weechat_iconv_fprintf (file, "KB = \"kickban\"\n");
+ weechat_iconv_fprintf (file, "LEAVE = \"part\"\n");
+ weechat_iconv_fprintf (file, "M = \"msg\"\n");
+ weechat_iconv_fprintf (file, "MUB = \"unban *\"\n");
+ weechat_iconv_fprintf (file, "N = \"names\"\n");
+ weechat_iconv_fprintf (file, "Q = \"query\"\n");
+ weechat_iconv_fprintf (file, "T = \"topic\"\n");
+ weechat_iconv_fprintf (file, "UB = \"unban\"\n");
+ weechat_iconv_fprintf (file, "UNIG = \"unignore\"\n");
+ weechat_iconv_fprintf (file, "W = \"who\"\n");
+ weechat_iconv_fprintf (file, "WC = \"window merge\"\n");
+ weechat_iconv_fprintf (file, "WI = \"whois\"\n");
+ weechat_iconv_fprintf (file, "WW = \"whowas\"\n");
+
+ /* no ignore by default */
+
+ /* default server is freenode */
+ weechat_iconv_fprintf (file, "\n[server]\n");
+ weechat_iconv_fprintf (file, "server_name = \"freenode\"\n");
+ weechat_iconv_fprintf (file, "server_autoconnect = on\n");
+ weechat_iconv_fprintf (file, "server_autoreconnect = on\n");
+ weechat_iconv_fprintf (file, "server_autoreconnect_delay = 30\n");
+ weechat_iconv_fprintf (file, "server_address = \"irc.freenode.net\"\n");
+ weechat_iconv_fprintf (file, "server_port = 6667\n");
+ weechat_iconv_fprintf (file, "server_ipv6 = off\n");
+ weechat_iconv_fprintf (file, "server_ssl = off\n");
+ weechat_iconv_fprintf (file, "server_password = \"\"\n");
+
+ /* Get the user's name from /etc/passwd */
+ if ((my_passwd = getpwuid (geteuid ())) != NULL)
+ {
+ weechat_iconv_fprintf (file, "server_nick1 = \"%s\"\n", my_passwd->pw_name);
+ weechat_iconv_fprintf (file, "server_nick2 = \"%s1\"\n", my_passwd->pw_name);
+ weechat_iconv_fprintf (file, "server_nick3 = \"%s2\"\n", my_passwd->pw_name);
+ weechat_iconv_fprintf (file, "server_username = \"%s\"\n", my_passwd->pw_name);
+ if ((!my_passwd->pw_gecos)
+ || (my_passwd->pw_gecos[0] == '\0')
+ || (my_passwd->pw_gecos[0] == ',')
+ || (my_passwd->pw_gecos[0] == ' '))
+ weechat_iconv_fprintf (file, "server_realname = \"%s\"\n", my_passwd->pw_name);
+ else
+ {
+ realname = strdup (my_passwd->pw_gecos);
+ pos = strchr (realname, ',');
+ if (pos)
+ pos[0] = '\0';
+ weechat_iconv_fprintf (file, "server_realname = \"%s\"\n",
+ realname);
+ if (pos)
+ pos[0] = ',';
+ free (realname);
+ }
+ }
+ else
+ {
+ /* default values if /etc/passwd can't be read */
+ weechat_iconv_fprintf (stderr, "%s: %s (%s).",
+ WEECHAT_WARNING,
+ _("Unable to get user's name"),
+ strerror (errno));
+ weechat_iconv_fprintf (file, "server_nick1 = \"weechat1\"\n");
+ weechat_iconv_fprintf (file, "server_nick2 = \"weechat2\"\n");
+ weechat_iconv_fprintf (file, "server_nick3 = \"weechat3\"\n");
+ weechat_iconv_fprintf (file, "server_username = \"weechat\"\n");
+ weechat_iconv_fprintf (file, "server_realname = \"WeeChat default realname\"\n");
+ }
+
+ weechat_iconv_fprintf (file, "server_hostname = \"\"\n");
+ weechat_iconv_fprintf (file, "server_command = \"\"\n");
+ weechat_iconv_fprintf (file, "server_command_delay = 0\n");
+ weechat_iconv_fprintf (file, "server_autojoin = \"\"\n");
+ weechat_iconv_fprintf (file, "server_autorejoin = on\n");
+ weechat_iconv_fprintf (file, "server_notify_levels = \"\"\n");
+
+ fclose (file);
+ chmod (filename, 0600);
+ free (filename);
+ return 0;
+}
+
+/*
+ * config_write: write WeeChat configurtion
+ * return: 0 if ok
+ * < 0 if error
+ */
+
+int
+config_write (char *config_name)
+{
+ int filename_length;
+ char *filename, *filename2;
+ FILE *file;
+ int i, j, rc;
+ time_t current_time;
+ t_irc_server *ptr_server;
+ t_weechat_alias *ptr_alias;
+ t_irc_ignore *ptr_ignore;
+ t_gui_key *ptr_key;
+ char *expanded_name, *function_name;
+
+ if (config_name)
+ {
+ filename_length = strlen (config_name);
+ filename = strdup (config_name);
+ }
+ else
+ {
+ filename_length = strlen (weechat_home) +
+ strlen (WEECHAT_CONFIG_NAME) + 2;
+ filename =
+ (char *) malloc (filename_length * sizeof (char));
+ if (!filename)
+ return -2;
+ snprintf (filename, filename_length, "%s%s" WEECHAT_CONFIG_NAME,
+ weechat_home, DIR_SEPARATOR);
+ }
+
+ filename2 = (char *) malloc ((filename_length + 32) * sizeof (char));
+ if (!filename2)
+ {
+ free (filename);
+ return -2;
+ }
+ snprintf (filename2, filename_length + 32, "%s.weechattmp", filename);
+
+ if ((file = fopen (filename2, "w")) == NULL)
+ {
+ gui_printf (NULL, _("%s cannot create file \"%s\"\n"),
+ WEECHAT_ERROR, filename2);
+ free (filename);
+ free (filename2);
+ return -1;
+ }
+
+ weechat_log_printf (_("Saving config to disk\n"));
+
+ current_time = time (NULL);
+ weechat_iconv_fprintf (file, _("#\n# %s configuration file, created by "
+ "%s v%s on %s"),
+ PACKAGE_NAME, PACKAGE_NAME, PACKAGE_VERSION,
+ ctime (&current_time));
+ weechat_iconv_fprintf (file, _("# WARNING! Be careful when editing this file, "
+ "WeeChat writes this file when exiting.\n#\n"));
+
+ for (i = 0; i < CONFIG_NUMBER_SECTIONS; i++)
+ {
+ if ((i != CONFIG_SECTION_KEYS) && (i != CONFIG_SECTION_ALIAS)
+ && (i != CONFIG_SECTION_IGNORE) && (i != CONFIG_SECTION_SERVER))
+ {
+ weechat_iconv_fprintf (file, "\n[%s]\n", config_sections[i].section_name);
+ for (j = 0; weechat_options[i][j].option_name; j++)
+ {
+ switch (weechat_options[i][j].option_type)
+ {
+ case OPTION_TYPE_BOOLEAN:
+ weechat_iconv_fprintf (file, "%s = %s\n",
+ weechat_options[i][j].option_name,
+ (weechat_options[i][j].ptr_int &&
+ *weechat_options[i][j].ptr_int) ?
+ "on" : "off");
+ break;
+ case OPTION_TYPE_INT:
+ weechat_iconv_fprintf (file, "%s = %d\n",
+ weechat_options[i][j].option_name,
+ (weechat_options[i][j].ptr_int) ?
+ *weechat_options[i][j].ptr_int :
+ weechat_options[i][j].default_int);
+ break;
+ case OPTION_TYPE_INT_WITH_STRING:
+ weechat_iconv_fprintf (file, "%s = %s\n",
+ weechat_options[i][j].option_name,
+ (weechat_options[i][j].ptr_int) ?
+ weechat_options[i][j].array_values[*weechat_options[i][j].ptr_int] :
+ weechat_options[i][j].array_values[weechat_options[i][j].default_int]);
+ break;
+ case OPTION_TYPE_COLOR:
+ weechat_iconv_fprintf (file, "%s = %s\n",
+ weechat_options[i][j].option_name,
+ (weechat_options[i][j].ptr_int) ?
+ gui_color_get_name (*weechat_options[i][j].ptr_int) :
+ weechat_options[i][j].default_string);
+ break;
+ case OPTION_TYPE_STRING:
+ weechat_iconv_fprintf (file, "%s = \"%s\"\n",
+ weechat_options[i][j].option_name,
+ (weechat_options[i][j].ptr_string) ?
+ *weechat_options[i][j].ptr_string :
+ weechat_options[i][j].default_string);
+ break;
+ }
+ }
+ }
+ }
+
+ /* keys section */
+ weechat_iconv_fprintf (file, "\n[keys]\n");
+ for (ptr_key = gui_keys; ptr_key; ptr_key = ptr_key->next_key)
+ {
+ expanded_name = gui_keyboard_get_expanded_name (ptr_key->key);
+ if (ptr_key->function)
+ {
+ function_name = gui_keyboard_function_search_by_ptr (ptr_key->function);
+ if (function_name)
+ weechat_iconv_fprintf (file, "%s = \"%s%s%s\"\n",
+ (expanded_name) ? expanded_name : ptr_key->key,
+ function_name,
+ (ptr_key->args) ? " " : "",
+ (ptr_key->args) ? ptr_key->args : "");
+ }
+ else
+ weechat_iconv_fprintf (file, "%s = \"%s\"\n",
+ (expanded_name) ? expanded_name : ptr_key->key,
+ ptr_key->command);
+ if (expanded_name)
+ free (expanded_name);
+ }
+
+ /* alias section */
+ weechat_iconv_fprintf (file, "\n[alias]\n");
+ for (ptr_alias = weechat_alias; ptr_alias;
+ ptr_alias = ptr_alias->next_alias)
+ {
+ weechat_iconv_fprintf (file, "%s = \"%s\"\n",
+ ptr_alias->alias_name, ptr_alias->alias_command);
+ }
+
+ /* ignore section */
+ weechat_iconv_fprintf (file, "\n[ignore]\n");
+ for (ptr_ignore = irc_ignore; ptr_ignore;
+ ptr_ignore = ptr_ignore->next_ignore)
+ {
+ weechat_iconv_fprintf (file, "ignore = \"%s,%s,%s,%s\"\n",
+ ptr_ignore->mask,
+ ptr_ignore->type,
+ ptr_ignore->channel_name,
+ ptr_ignore->server_name);
+ }
+
+ /* server section */
+ for (ptr_server = irc_servers; ptr_server;
+ ptr_server = ptr_server->next_server)
+ {
+ if (!ptr_server->temp_server)
+ {
+ weechat_iconv_fprintf (file, "\n[server]\n");
+ weechat_iconv_fprintf (file, "server_name = \"%s\"\n", ptr_server->name);
+ weechat_iconv_fprintf (file, "server_autoconnect = %s\n",
+ (ptr_server->autoconnect) ? "on" : "off");
+ weechat_iconv_fprintf (file, "server_autoreconnect = %s\n",
+ (ptr_server->autoreconnect) ? "on" : "off");
+ weechat_iconv_fprintf (file, "server_autoreconnect_delay = %d\n",
+ ptr_server->autoreconnect_delay);
+ weechat_iconv_fprintf (file, "server_address = \"%s\"\n", ptr_server->address);
+ weechat_iconv_fprintf (file, "server_port = %d\n", ptr_server->port);
+ weechat_iconv_fprintf (file, "server_ipv6 = %s\n",
+ (ptr_server->ipv6) ? "on" : "off");
+ weechat_iconv_fprintf (file, "server_ssl = %s\n",
+ (ptr_server->ssl) ? "on" : "off");
+ weechat_iconv_fprintf (file, "server_password = \"%s\"\n",
+ (ptr_server->password) ? ptr_server->password : "");
+ weechat_iconv_fprintf (file, "server_nick1 = \"%s\"\n", ptr_server->nick1);
+ weechat_iconv_fprintf (file, "server_nick2 = \"%s\"\n", ptr_server->nick2);
+ weechat_iconv_fprintf (file, "server_nick3 = \"%s\"\n", ptr_server->nick3);
+ weechat_iconv_fprintf (file, "server_username = \"%s\"\n", ptr_server->username);
+ weechat_iconv_fprintf (file, "server_realname = \"%s\"\n", ptr_server->realname);
+ weechat_iconv_fprintf (file, "server_hostname = \"%s\"\n",
+ (ptr_server->hostname) ? ptr_server->hostname : "");
+ weechat_iconv_fprintf (file, "server_command = \"%s\"\n",
+ (ptr_server->command) ? ptr_server->command : "");
+ weechat_iconv_fprintf (file, "server_command_delay = %d\n", ptr_server->command_delay);
+ weechat_iconv_fprintf (file, "server_autojoin = \"%s\"\n",
+ (ptr_server->autojoin) ? ptr_server->autojoin : "");
+ weechat_iconv_fprintf (file, "server_autorejoin = %s\n",
+ (ptr_server->autorejoin) ? "on" : "off");
+ weechat_iconv_fprintf (file, "server_notify_levels = \"%s\"\n",
+ (ptr_server->notify_levels) ? ptr_server->notify_levels : "");
+ }
+ }
+
+ fclose (file);
+ chmod (filename2, 0600);
+ unlink (filename);
+ rc = rename (filename2, filename);
+ free (filename);
+ free (filename2);
+ if (rc != 0)
+ return -1;
+ return 0;
+}
diff --git a/src/core/wee-config.h b/src/core/wee-config.h
new file mode 100644
index 000000000..cac086840
--- /dev/null
+++ b/src/core/wee-config.h
@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 2003-2007 by FlashCode <flashcode@flashtux.org>
+ * See README for License detail, AUTHORS for developers list.
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef __WEECHAT_CONFIG_H
+#define __WEECHAT_CONFIG_H 1
+
+#include "../protocols/irc/irc.h"
+
+#define WEECHAT_CONFIG_NAME "weechat.rc"
+
+#define CONFIG_SECTION_NONE -1
+#define CONFIG_SECTION_LOOK 0
+#define CONFIG_SECTION_COLORS 1
+#define CONFIG_SECTION_HISTORY 2
+#define CONFIG_SECTION_LOG 3
+#define CONFIG_SECTION_IRC 4
+#define CONFIG_SECTION_DCC 5
+#define CONFIG_SECTION_PROXY 6
+#define CONFIG_SECTION_PLUGINS 7
+#define CONFIG_SECTION_KEYS 8
+#define CONFIG_SECTION_ALIAS 9
+#define CONFIG_SECTION_IGNORE 10
+#define CONFIG_SECTION_SERVER 11
+#define CONFIG_NUMBER_SECTIONS 12
+
+#define OPTION_TYPE_BOOLEAN 1 /* values: on/off */
+#define OPTION_TYPE_INT 2 /* values: from min to max */
+#define OPTION_TYPE_INT_WITH_STRING 3 /* values: one from **array_values */
+#define OPTION_TYPE_COLOR 4 /* values: a color name */
+#define OPTION_TYPE_STRING 5 /* values: any string, may be empty */
+
+#define BOOL_FALSE 0
+#define BOOL_TRUE 1
+
+#define CFG_LOOK_NICKLIST_LEFT 0
+#define CFG_LOOK_NICKLIST_RIGHT 1
+#define CFG_LOOK_NICKLIST_TOP 2
+#define CFG_LOOK_NICKLIST_BOTTOM 3
+
+#define CFG_LOOK_ALIGN_NICK_NONE 0
+#define CFG_LOOK_ALIGN_NICK_LEFT 1
+#define CFG_LOOK_ALIGN_NICK_RIGHT 2
+
+#define CFG_LOOK_HOTLIST_SORT_GROUP_TIME_ASC 0
+#define CFG_LOOK_HOTLIST_SORT_GROUP_TIME_DESC 1
+#define CFG_LOOK_HOTLIST_SORT_GROUP_NUMBER_ASC 2
+#define CFG_LOOK_HOTLIST_SORT_GROUP_NUMBER_DESC 3
+#define CFG_LOOK_HOTLIST_SORT_NUMBER_ASC 4
+#define CFG_LOOK_HOTLIST_SORT_NUMBER_DESC 5
+
+#define CFG_IRC_DISPLAY_AWAY_OFF 0
+#define CFG_IRC_DISPLAY_AWAY_LOCAL 1
+#define CFG_IRC_DISPLAY_AWAY_CHANNEL 2
+
+typedef struct t_config_section t_config_section;
+
+struct t_config_section
+{
+ int section_number;
+ char *section_name;
+};
+
+typedef struct t_config_option t_config_option;
+
+struct t_config_option
+{
+ char *option_name;
+ char *short_description;
+ char *long_description;
+ int option_type;
+ int min, max;
+ int default_int;
+ char *default_string;
+ char **array_values;
+ int *ptr_int;
+ char **ptr_string;
+ void (*handler_change)();
+};
+
+extern int cfg_look_save_on_exit;
+extern int cfg_look_set_title;
+extern int cfg_look_startup_logo;
+extern int cfg_look_startup_version;
+extern char *cfg_look_weechat_slogan;
+extern int cfg_look_one_server_buffer;
+extern int cfg_look_open_near_server;
+extern int cfg_look_scroll_amount;
+extern char *cfg_look_buffer_timestamp;
+extern int cfg_look_color_nicks_number;
+extern int cfg_look_color_actions;
+extern int cfg_look_nicklist;
+extern int cfg_look_nicklist_position;
+extern int cfg_look_nicklist_min_size;
+extern int cfg_look_nicklist_max_size;
+extern int cfg_look_nicklist_separator;
+extern int cfg_look_nickmode;
+extern int cfg_look_nickmode_empty;
+extern char *cfg_look_no_nickname;
+extern char *cfg_look_nick_prefix;
+extern char *cfg_look_nick_suffix;
+extern int cfg_look_align_nick;
+extern int cfg_look_align_other;
+extern int cfg_look_align_size;
+extern int cfg_look_align_size_max;
+extern int cfg_look_align_text_offset;
+extern char *cfg_look_nick_completor;
+extern char *cfg_look_nick_completion_ignore;
+extern int cfg_look_nick_completion_smart;
+extern int cfg_look_nick_complete_first;
+extern int cfg_look_infobar;
+extern char *cfg_look_infobar_timestamp;
+extern int cfg_look_infobar_seconds;
+extern int cfg_look_infobar_delay_highlight;
+extern int cfg_look_hotlist_names_count;
+extern int cfg_look_hotlist_names_level;
+extern int cfg_look_hotlist_names_length;
+extern int cfg_look_hotlist_sort;
+extern int cfg_look_day_change;
+extern char *cfg_look_day_change_timestamp;
+extern char *cfg_look_read_marker;
+extern char *cfg_look_input_format;
+extern int cfg_look_paste_max_lines;
+
+extern int cfg_col_real_white;
+extern int cfg_col_separator;
+extern int cfg_col_title;
+extern int cfg_col_title_more;
+extern int cfg_col_title_bg;
+extern int cfg_col_chat;
+extern int cfg_col_chat_time;
+extern int cfg_col_chat_time_sep;
+extern int cfg_col_chat_prefix1;
+extern int cfg_col_chat_prefix2;
+extern int cfg_col_chat_server;
+extern int cfg_col_chat_join;
+extern int cfg_col_chat_part;
+extern int cfg_col_chat_nick;
+extern int cfg_col_chat_host;
+extern int cfg_col_chat_channel;
+extern int cfg_col_chat_dark;
+extern int cfg_col_chat_highlight;
+extern int cfg_col_chat_bg;
+extern int cfg_col_chat_read_marker;
+extern int cfg_col_chat_read_marker_bg;
+extern int cfg_col_status;
+extern int cfg_col_status_delimiters;
+extern int cfg_col_status_channel;
+extern int cfg_col_status_data_msg;
+extern int cfg_col_status_data_private;
+extern int cfg_col_status_data_highlight;
+extern int cfg_col_status_data_other;
+extern int cfg_col_status_more;
+extern int cfg_col_status_bg;
+extern int cfg_col_infobar;
+extern int cfg_col_infobar_delimiters;
+extern int cfg_col_infobar_highlight;
+extern int cfg_col_infobar_bg;
+extern int cfg_col_input;
+extern int cfg_col_input_server;
+extern int cfg_col_input_channel;
+extern int cfg_col_input_nick;
+extern int cfg_col_input_delimiters;
+extern int cfg_col_input_text_not_found;
+extern int cfg_col_input_actions;
+extern int cfg_col_input_bg;
+extern int cfg_col_nick;
+extern int cfg_col_nick_away;
+extern int cfg_col_nick_chanowner;
+extern int cfg_col_nick_chanadmin;
+extern int cfg_col_nick_op;
+extern int cfg_col_nick_halfop;
+extern int cfg_col_nick_voice;
+extern int cfg_col_nick_user;
+extern int cfg_col_nick_more;
+extern int cfg_col_nick_sep;
+extern int cfg_col_nick_self;
+extern int cfg_col_nick_colors[GUI_COLOR_WIN_NICK_NUMBER];
+extern int cfg_col_nick_private;
+extern int cfg_col_nick_bg;
+extern int cfg_col_dcc_selected;
+extern int cfg_col_dcc_waiting;
+extern int cfg_col_dcc_connecting;
+extern int cfg_col_dcc_active;
+extern int cfg_col_dcc_done;
+extern int cfg_col_dcc_failed;
+extern int cfg_col_dcc_aborted;
+
+extern int cfg_history_max_lines;
+extern int cfg_history_max_commands;
+extern int cfg_history_display_default;
+
+extern int cfg_log_auto_server;
+extern int cfg_log_auto_channel;
+extern int cfg_log_auto_private;
+extern int cfg_log_plugin_msg;
+extern char *cfg_log_path;
+extern char *cfg_log_timestamp;
+extern int cfg_log_hide_nickserv_pwd;
+
+extern int cfg_irc_display_away;
+extern int cfg_irc_show_away_once;
+extern char *cfg_irc_default_msg_part;
+extern char *cfg_irc_default_msg_quit;
+extern int cfg_irc_notice_as_pv;
+extern int cfg_irc_away_check;
+extern int cfg_irc_away_check_max_nicks;
+extern int cfg_irc_lag_check;
+extern int cfg_irc_lag_min_show;
+extern int cfg_irc_lag_disconnect;
+extern int cfg_irc_anti_flood;
+extern int cfg_irc_fifo_pipe;
+extern char *cfg_irc_highlight;
+extern int cfg_irc_colors_receive;
+extern int cfg_irc_colors_send;
+extern int cfg_irc_send_unknown_commands;
+
+extern int cfg_dcc_auto_accept_files;
+extern int cfg_dcc_auto_accept_chats;
+extern int cfg_dcc_timeout;
+extern int cfg_dcc_blocksize;
+extern int cfg_dcc_fast_send;
+extern char *cfg_dcc_port_range;
+extern char *cfg_dcc_own_ip;
+extern char *cfg_dcc_download_path;
+extern char *cfg_dcc_upload_path;
+extern int cfg_dcc_convert_spaces;
+extern int cfg_dcc_auto_rename;
+extern int cfg_dcc_auto_resume;
+
+extern int cfg_proxy_use;
+extern int cfg_proxy_type;
+extern char *cfg_proxy_type_values[];
+extern int cfg_proxy_ipv6;
+extern char *cfg_proxy_address;
+extern int cfg_proxy_port;
+extern char *cfg_proxy_username;
+extern char *cfg_proxy_password;
+
+extern char *cfg_plugins_path;
+extern char *cfg_plugins_autoload;
+extern char *cfg_plugins_extension;
+
+extern t_config_section config_sections [CONFIG_NUMBER_SECTIONS];
+extern t_config_option * weechat_options [CONFIG_NUMBER_SECTIONS];
+
+extern char *config_get_section ();
+extern void config_change_noop ();
+extern void config_change_save_on_exit ();
+extern void config_change_title ();
+extern void config_change_buffers ();
+extern void config_change_buffer_content ();
+extern void config_change_hotlist ();
+extern void config_change_read_marker ();
+extern void config_change_charset ();
+extern void config_change_one_server_buffer ();
+extern void config_change_color ();
+extern void config_change_nicks_colors ();
+extern void config_change_away_check ();
+extern void config_change_fifo_pipe ();
+extern void config_change_notify_levels ();
+extern void config_change_log ();
+extern int config_option_set_value (t_config_option *, char *);
+extern void config_option_list_remove (char **, char *);
+extern void config_option_list_set (char **, char *, char *);
+extern void config_option_list_get_value (char **, char *, char **, int *);
+extern t_config_option *config_option_search (char *);
+extern void config_option_search_option_value (char *, t_config_option **, void **);
+extern int config_set_value (char *, char *);
+extern void *config_get_server_option_ptr (t_irc_server *, char *);
+extern int config_set_server_value (t_irc_server *, char *, char *);
+extern int config_read ();
+extern int config_create_default ();
+extern int config_write ();
+
+#endif /* weeconfig.h */
diff --git a/src/core/wee-list.c b/src/core/wee-list.c
new file mode 100644
index 000000000..3e0872eb6
--- /dev/null
+++ b/src/core/wee-list.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2003-2007 by FlashCode <flashcode@flashtux.org>
+ * See README for License detail, AUTHORS for developers list.
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/* weelist.c: sorted lists management */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "weechat.h"
+#include "weelist.h"
+#include "log.h"
+#include "util.h"
+
+
+/*
+ * weelist_get_size: get list size (number of elements)
+ */
+
+int
+weelist_get_size (t_weelist *weelist)
+{
+ t_weelist *ptr_weelist;
+ int count;
+
+ count = 0;
+
+ for (ptr_weelist = weelist; ptr_weelist; ptr_weelist = ptr_weelist->next_weelist)
+ {
+ count++;
+ }
+
+ return count;
+}
+
+/*
+ * weelist_search: search date in a list
+ */
+
+t_weelist *
+weelist_search (t_weelist *weelist, char *data)
+{
+ t_weelist *ptr_weelist;
+
+ for (ptr_weelist = weelist; ptr_weelist; ptr_weelist = ptr_weelist->next_weelist)
+ {
+ if (ascii_strcasecmp (data, ptr_weelist->data) == 0)
+ return ptr_weelist;
+ }
+ /* word not found in list */
+ return NULL;
+}
+
+/*
+ * weelist_find_pos: find position for data (keeping list sorted)
+ */
+
+t_weelist *
+weelist_find_pos (t_weelist *weelist, char *data)
+{
+ t_weelist *ptr_weelist;
+
+ for (ptr_weelist = weelist; ptr_weelist; ptr_weelist = ptr_weelist->next_weelist)
+ {
+ if (ascii_strcasecmp (data, ptr_weelist->data) < 0)
+ return ptr_weelist;
+ }
+ /* position not found, best position is at the end */
+ return NULL;
+}
+
+/*
+ * weelist_insert: insert an element to the list (at good position)
+ */
+
+void
+weelist_insert (t_weelist **weelist, t_weelist **last_weelist, t_weelist *element,
+ int position)
+{
+ t_weelist *pos_weelist;
+
+ if (*weelist)
+ {
+ /* remove element if already in list */
+ pos_weelist = weelist_search (*weelist, element->data);
+ if (pos_weelist)
+ weelist_remove (weelist, last_weelist, pos_weelist);
+ }
+
+ if (*weelist)
+ {
+ /* search position for new element, according to pos asked */
+ pos_weelist = NULL;
+ switch (position)
+ {
+ case WEELIST_POS_SORT:
+ pos_weelist = weelist_find_pos (*weelist, element->data);
+ break;
+ case WEELIST_POS_BEGINNING:
+ pos_weelist = *weelist;
+ break;
+ case WEELIST_POS_END:
+ pos_weelist = NULL;
+ break;
+ }
+
+ if (pos_weelist)
+ {
+ /* insert data into the list (before position found) */
+ element->prev_weelist = pos_weelist->prev_weelist;
+ element->next_weelist = pos_weelist;
+ if (pos_weelist->prev_weelist)
+ pos_weelist->prev_weelist->next_weelist = element;
+ else
+ *weelist = element;
+ pos_weelist->prev_weelist = element;
+ }
+ else
+ {
+ /* add data to the end */
+ element->prev_weelist = *last_weelist;
+ element->next_weelist = NULL;
+ (*last_weelist)->next_weelist = element;
+ *last_weelist = element;
+ }
+ }
+ else
+ {
+ element->prev_weelist = NULL;
+ element->next_weelist = NULL;
+ *weelist = element;
+ *last_weelist = element;
+ }
+}
+
+/*
+ * weelist_add: create new data and add it to list
+ */
+
+t_weelist *
+weelist_add (t_weelist **weelist, t_weelist **last_weelist, char *data,
+ int position)
+{
+ t_weelist *new_weelist;
+
+ if (!data || (!data[0]))
+ return NULL;
+
+ if ((new_weelist = ((t_weelist *) malloc (sizeof (t_weelist)))))
+ {
+ new_weelist->data = strdup (data);
+ weelist_insert (weelist, last_weelist, new_weelist, position);
+ return new_weelist;
+ }
+ /* failed to allocate new element */
+ return NULL;
+}
+
+/*
+ * weelist_remove: remove an element from a list
+ */
+
+void
+weelist_remove (t_weelist **weelist, t_weelist **last_weelist, t_weelist *element)
+{
+ t_weelist *new_weelist;
+
+ if (!element || !(*weelist))
+ return;
+
+ /* remove element from list */
+ if (*last_weelist == element)
+ *last_weelist = element->prev_weelist;
+ if (element->prev_weelist)
+ {
+ (element->prev_weelist)->next_weelist = element->next_weelist;
+ new_weelist = *weelist;
+ }
+ else
+ new_weelist = element->next_weelist;
+
+ if (element->next_weelist)
+ (element->next_weelist)->prev_weelist = element->prev_weelist;
+
+ /* free data */
+ if (element->data)
+ free (element->data);
+ free (element);
+ *weelist = new_weelist;
+}
+
+/*
+ * weelist_remove_all: remove all elements from a list
+ */
+
+void
+weelist_remove_all (t_weelist **weelist, t_weelist **last_weelist)
+{
+ while (*weelist)
+ {
+ weelist_remove (weelist, last_weelist, *weelist);
+ }
+}
+
+/*
+ * weelist_print_log: print weelist in log (usually for crash dump)
+ */
+
+void
+weelist_print_log (t_weelist *weelist, char *name)
+{
+ t_weelist *ptr_weelist;
+
+ for (ptr_weelist = weelist; ptr_weelist;
+ ptr_weelist = ptr_weelist->next_weelist)
+ {
+ weechat_log_printf ("[%s (addr:0x%X)]\n", name, ptr_weelist);
+ weechat_log_printf (" data . . . . . . . . . : '%s'\n", ptr_weelist->data);
+ weechat_log_printf (" prev_weelist . . . . . : 0x%X\n", ptr_weelist->prev_weelist);
+ weechat_log_printf (" next_weelist . . . . . : 0x%X\n", ptr_weelist->next_weelist);
+ }
+}
diff --git a/src/core/wee-list.h b/src/core/wee-list.h
new file mode 100644
index 000000000..4cc9ffb83
--- /dev/null
+++ b/src/core/wee-list.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2003-2007 by FlashCode <flashcode@flashtux.org>
+ * See README for License detail, AUTHORS for developers list.
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef __WEECHAT_LIST_H
+#define __WEECHAT_LIST_H 1
+
+#define WEELIST_POS_SORT 0
+#define WEELIST_POS_BEGINNING 1
+#define WEELIST_POS_END 2
+
+typedef struct t_weelist t_weelist;
+
+struct t_weelist
+{
+ char *data;
+ t_weelist *prev_weelist;
+ t_weelist *next_weelist;
+};
+
+extern int weelist_get_size (t_weelist *);
+extern t_weelist *weelist_search (t_weelist *, char *);
+extern t_weelist *weelist_add (t_weelist **, t_weelist **, char *, int);
+extern void weelist_remove (t_weelist **, t_weelist **, t_weelist *);
+extern void weelist_remove_all (t_weelist **, t_weelist **);
+extern void weelist_print_log (t_weelist *, char *);
+
+#endif /* weelist.h */
diff --git a/src/core/wee-log.c b/src/core/wee-log.c
new file mode 100644
index 000000000..2132e67a8
--- /dev/null
+++ b/src/core/wee-log.c
@@ -0,0 +1,233 @@
+/*
+ * Copyright (c) 2003-2007 by FlashCode <flashcode@flashtux.org>
+ * See README for License detail, AUTHORS for developers list.
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/* log.c: WeeChat log file */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+
+#ifdef HAVE_FLOCK
+#include <sys/file.h>
+#endif
+
+#include <sys/types.h>
+#include <time.h>
+
+#include "weechat.h"
+#include "log.h"
+#include "util.h"
+
+
+char *weechat_log_filename = NULL; /* log name (~/.weechat/weechat.log) */
+FILE *weechat_log_file = NULL; /* WeeChat log file */
+
+
+/*
+ * weechat_log_open: initialize log file
+ */
+
+int
+weechat_log_open (char *filename, char *mode)
+{
+ int filename_length;
+
+ /* exit if log already opened */
+ if (weechat_log_file)
+ return 0;
+
+ if (filename)
+ weechat_log_filename = strdup (filename);
+ else
+ {
+ filename_length = strlen (weechat_home) + 64;
+ weechat_log_filename =
+ (char *) malloc (filename_length * sizeof (char));
+ snprintf (weechat_log_filename, filename_length,
+ "%s/%s", weechat_home, WEECHAT_LOG_NAME);
+ }
+
+ weechat_log_file = fopen (weechat_log_filename, mode);
+ if (!weechat_log_file)
+ {
+ free (weechat_log_filename);
+ weechat_log_filename = NULL;
+ return 0;
+ }
+
+#ifdef HAVE_FLOCK
+ if ((flock (fileno (weechat_log_file), LOCK_EX | LOCK_NB) != 0))
+ {
+ if (errno == EWOULDBLOCK)
+ {
+ fclose (weechat_log_file);
+ weechat_log_file = NULL;
+ free (weechat_log_filename);
+ weechat_log_filename = NULL;
+ return 0;
+ }
+ }
+#endif
+
+ return 1;
+}
+
+/*
+ * weechat_log_init: initialize log file
+ */
+
+void
+weechat_log_init ()
+{
+ if (!weechat_log_open (NULL, "w"))
+ {
+ weechat_iconv_fprintf (stderr,
+ _("%s unable to create/append to log file (weechat.log)\n"
+ "If another WeeChat process is using this file, try to run WeeChat\n"
+ "with another home using \"--dir\" command line option.\n"),
+ WEECHAT_ERROR);
+ exit (1);
+ }
+}
+
+/*
+ * weechat_log_printf: write a message in WeeChat log (<weechat_home>/weechat.log)
+ */
+
+void
+weechat_log_printf (char *message, ...)
+{
+ static char buffer[4096];
+ char *ptr_buffer;
+ va_list argptr;
+ static time_t seconds;
+ struct tm *date_tmp;
+
+ if (!weechat_log_file)
+ return;
+
+ va_start (argptr, message);
+ vsnprintf (buffer, sizeof (buffer) - 1, message, argptr);
+ va_end (argptr);
+
+ /* keep only valid chars */
+ ptr_buffer = buffer;
+ while (ptr_buffer[0])
+ {
+ if ((ptr_buffer[0] != '\n')
+ && (ptr_buffer[0] != '\r')
+ && ((unsigned char)(ptr_buffer[0]) < 32))
+ ptr_buffer[0] = '.';
+ ptr_buffer++;
+ }
+
+ seconds = time (NULL);
+ date_tmp = localtime (&seconds);
+ if (date_tmp)
+ weechat_iconv_fprintf (weechat_log_file, "[%04d-%02d-%02d %02d:%02d:%02d] %s",
+ date_tmp->tm_year + 1900, date_tmp->tm_mon + 1, date_tmp->tm_mday,
+ date_tmp->tm_hour, date_tmp->tm_min, date_tmp->tm_sec,
+ buffer);
+ else
+ weechat_iconv_fprintf (weechat_log_file, "%s", buffer);
+
+ fflush (weechat_log_file);
+}
+
+/*
+ * weechat_log_close: close log file
+ */
+
+void
+weechat_log_close ()
+{
+ /* close log file */
+ if (weechat_log_file)
+ {
+#ifdef HAVE_FLOCK
+ flock (fileno (weechat_log_file), LOCK_UN);
+#endif
+ fclose (weechat_log_file);
+ weechat_log_file = NULL;
+ }
+
+ /* free filename */
+ if (weechat_log_filename)
+ {
+ free (weechat_log_filename);
+ weechat_log_filename = NULL;
+ }
+}
+
+/*
+ * weechat_log_crash_rename: rename log file when crashing
+ */
+
+int
+weechat_log_crash_rename ()
+{
+ char *old_name, *new_name;
+ int length;
+ time_t time_now;
+ struct tm *local_time;
+
+ if (!weechat_log_filename)
+ return 0;
+
+ old_name = strdup (weechat_log_filename);
+ if (!old_name)
+ return 0;
+
+ weechat_log_close ();
+
+ length = strlen (weechat_home) + 128;
+ new_name = (char *) malloc (length);
+ if (new_name)
+ {
+ time_now = time (NULL);
+ local_time = localtime (&time_now);
+ snprintf (new_name, length,
+ "%s/weechat_crash_%04d%02d%02d_%d.log",
+ weechat_home,
+ local_time->tm_year + 1900,
+ local_time->tm_mon + 1,
+ local_time->tm_mday,
+ getpid());
+ if (rename (old_name, new_name) == 0)
+ {
+ weechat_iconv_fprintf (stderr, "*** Full crash dump was saved to %s file.\n",
+ new_name);
+ weechat_log_open (new_name, "a");
+ free (old_name);
+ free (new_name);
+ return 1;
+ }
+ free (new_name);
+ }
+
+ free (old_name);
+ weechat_log_open (NULL, "a");
+ return 0;
+}
diff --git a/src/core/wee-log.h b/src/core/wee-log.h
new file mode 100644
index 000000000..4f2a9e5ce
--- /dev/null
+++ b/src/core/wee-log.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2003-2007 by FlashCode <flashcode@flashtux.org>
+ * See README for License detail, AUTHORS for developers list.
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef __WEECHAT_LOG_H
+#define __WEECHAT_LOG_H 1
+
+extern char *weechat_log_filename;
+extern FILE *weechat_log_file;
+
+extern void weechat_log_init ();
+extern void weechat_log_close ();
+extern void weechat_log_printf (char *, ...);
+extern int weechat_log_crash_rename ();
+
+#endif /* log.h */
diff --git a/src/core/wee-upgrade.c b/src/core/wee-upgrade.c
new file mode 100644
index 000000000..f74b015e5
--- /dev/null
+++ b/src/core/wee-upgrade.c
@@ -0,0 +1,1867 @@
+/*
+ * Copyright (c) 2003-2007 by FlashCode <flashcode@flashtux.org>
+ * See README for License detail, AUTHORS for developers list.
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/* session.c: save/restore session data */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+
+#ifdef HAVE_GNUTLS
+#include <gnutls/gnutls.h>
+#endif
+
+#include "weechat.h"
+#include "session.h"
+#include "hotlist.h"
+#include "log.h"
+#include "utf8.h"
+#include "util.h"
+#include "../protocols/irc/irc.h"
+#include "../gui/gui.h"
+
+
+/* current server/channel (used when loading session) */
+t_irc_server *session_current_server = NULL;
+t_irc_channel *session_current_channel = NULL;
+t_gui_buffer *session_current_buffer = NULL;
+
+long session_last_read_pos = 0;
+int session_last_read_length = 0;
+
+
+/*
+ * session_write_id: write object ID to file
+ */
+
+int
+session_write_id (FILE *file, int id)
+{
+ return (fwrite ((void *)(&id), sizeof (int), 1, file) > 0);
+}
+
+/*
+ * session_write_int: write an integer to file
+ */
+
+int
+session_write_int (FILE *file, int id, int value)
+{
+ char type;
+
+ if (id >= 0)
+ {
+ if (!session_write_id (file, id))
+ return 0;
+ }
+ type = SESSION_TYPE_INT;
+ if (fwrite ((void *)(&type), sizeof (char), 1, file) == 0)
+ return 0;
+ return (fwrite ((void *)(&value), sizeof (int), 1, file) > 0);
+}
+
+/*
+ * session_write_str: write a string to file
+ */
+
+int
+session_write_str (FILE *file, int id, char *string)
+{
+ char type;
+ int length;
+
+ if (id >= 0)
+ {
+ if (!session_write_id (file, id))
+ return 0;
+ }
+ type = SESSION_TYPE_STR;
+ if (fwrite ((void *)(&type), sizeof (char), 1, file) == 0)
+ return 0;
+ if (string && string[0])
+ {
+ length = strlen (string);
+ if (fwrite ((void *)(&length), sizeof (int), 1, file) == 0)
+ return 0;
+ return (fwrite ((void *)string, length, 1, file) > 0);
+ }
+ else
+ {
+ length = 0;
+ return (fwrite ((void *)(&length), sizeof (int), 1, file) > 0);
+ }
+}
+
+/*
+ * session_write_buf: write a buffer to file
+ */
+
+int
+session_write_buf (FILE *file, int id, void *buffer, int size)
+{
+ char type;
+
+ if (id >= 0)
+ {
+ if (!session_write_id (file, id))
+ return 0;
+ }
+ type = SESSION_TYPE_BUF;
+ if (fwrite ((void *)(&type), sizeof (char), 1, file) == 0)
+ return 0;
+ if (fwrite ((void *)(&size), sizeof (int), 1, file) == 0)
+ return 0;
+ return (fwrite (buffer, size, 1, file) > 0);
+}
+
+/*
+ * session_save_nick: save a nick into session file
+ */
+
+int
+session_save_nick (FILE *file, t_irc_nick *nick)
+{
+ int rc;
+
+ rc = 1;
+ rc = rc && (session_write_id (file, SESSION_OBJ_NICK));
+ rc = rc && (session_write_str (file, SESSION_NICK_NICK, nick->nick));
+ rc = rc && (session_write_int (file, SESSION_NICK_FLAGS, nick->flags));
+ rc = rc && (session_write_int (file, SESSION_NICK_COLOR, nick->color));
+ rc = rc && (session_write_str (file, SESSION_NICK_HOST, nick->host));
+ rc = rc && (session_write_id (file, SESSION_NICK_END));
+ return rc;
+}
+
+/*
+ * session_save_channel: save a channel into session file
+ */
+
+int
+session_save_channel (FILE *file, t_irc_channel *channel)
+{
+ int rc;
+ t_irc_nick *ptr_nick;
+
+ rc = 1;
+ rc = rc && (session_write_id (file, SESSION_OBJ_CHANNEL));
+ rc = rc && (session_write_int (file, SESSION_CHAN_TYPE, channel->type));
+ rc = rc && (session_write_str (file, SESSION_CHAN_NAME, channel->name));
+ rc = rc && (session_write_str (file, SESSION_CHAN_TOPIC, channel->topic));
+ rc = rc && (session_write_str (file, SESSION_CHAN_MODES, channel->modes));
+ rc = rc && (session_write_int (file, SESSION_CHAN_LIMIT, channel->limit));
+ rc = rc && (session_write_str (file, SESSION_CHAN_KEY, channel->key));
+ rc = rc && (session_write_int (file, SESSION_CHAN_NICKS_COUNT, channel->nicks_count));
+ rc = rc && (session_write_int (file, SESSION_CHAN_CHECKING_AWAY, channel->checking_away));
+ rc = rc && (session_write_str (file, SESSION_CHAN_AWAY_MESSAGE, channel->away_message));
+ rc = rc && (session_write_int (file, SESSION_CHAN_CYCLE, channel->cycle));
+ rc = rc && (session_write_int (file, SESSION_CHAN_CLOSE, channel->close));
+ rc = rc && (session_write_int (file, SESSION_CHAN_DISPLAY_CREATION_DATE, channel->display_creation_date));
+ rc = rc && (session_write_id (file, SESSION_CHAN_END));
+
+ if (!rc)
+ return 0;
+
+ for (ptr_nick = channel->nicks; ptr_nick;
+ ptr_nick = ptr_nick->next_nick)
+ {
+ if (!session_save_nick (file, ptr_nick))
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * session_save_servers: save all servers into session file
+ */
+
+int
+session_save_servers (FILE *file)
+{
+ int rc;
+#ifdef HAVE_GNUTLS
+ void *session_data;
+ size_t session_size;
+#endif
+ t_irc_server *ptr_server;
+ t_irc_channel *ptr_channel;
+
+ rc = 1;
+
+ for (ptr_server = irc_servers; ptr_server;
+ ptr_server = ptr_server->next_server)
+ {
+ rc = rc && (session_write_id (file, SESSION_OBJ_SERVER));
+ rc = rc && (session_write_str (file, SESSION_SERV_NAME, ptr_server->name));
+ rc = rc && (session_write_int (file, SESSION_SERV_AUTOCONNECT, ptr_server->autoconnect));
+ rc = rc && (session_write_int (file, SESSION_SERV_AUTORECONNECT, ptr_server->autoreconnect));
+ rc = rc && (session_write_int (file, SESSION_SERV_AUTORECONNECT_DELAY, ptr_server->autoreconnect_delay));
+ rc = rc && (session_write_int (file, SESSION_SERV_TEMP_SERVER, ptr_server->temp_server));
+ rc = rc && (session_write_str (file, SESSION_SERV_ADDRESS, ptr_server->address));
+ rc = rc && (session_write_int (file, SESSION_SERV_PORT, ptr_server->port));
+ rc = rc && (session_write_int (file, SESSION_SERV_IPV6, ptr_server->ipv6));
+ rc = rc && (session_write_int (file, SESSION_SERV_SSL, ptr_server->ssl));
+ rc = rc && (session_write_str (file, SESSION_SERV_PASSWORD, ptr_server->password));
+ rc = rc && (session_write_str (file, SESSION_SERV_NICK1, ptr_server->nick1));
+ rc = rc && (session_write_str (file, SESSION_SERV_NICK2, ptr_server->nick2));
+ rc = rc && (session_write_str (file, SESSION_SERV_NICK3, ptr_server->nick3));
+ rc = rc && (session_write_str (file, SESSION_SERV_USERNAME, ptr_server->username));
+ rc = rc && (session_write_str (file, SESSION_SERV_REALNAME, ptr_server->realname));
+ rc = rc && (session_write_str (file, SESSION_SERV_HOSTNAME, ptr_server->hostname));
+ rc = rc && (session_write_str (file, SESSION_SERV_COMMAND, ptr_server->command));
+ rc = rc && (session_write_int (file, SESSION_SERV_COMMAND_DELAY, ptr_server->command_delay));
+ rc = rc && (session_write_str (file, SESSION_SERV_AUTOJOIN, ptr_server->autojoin));
+ rc = rc && (session_write_int (file, SESSION_SERV_AUTOREJOIN, ptr_server->autorejoin));
+ rc = rc && (session_write_str (file, SESSION_SERV_NOTIFY_LEVELS, ptr_server->notify_levels));
+ rc = rc && (session_write_int (file, SESSION_SERV_CHILD_PID, ptr_server->child_pid));
+ rc = rc && (session_write_int (file, SESSION_SERV_CHILD_READ, ptr_server->child_read));
+ rc = rc && (session_write_int (file, SESSION_SERV_CHILD_WRITE, ptr_server->child_write));
+ rc = rc && (session_write_int (file, SESSION_SERV_SOCK, ptr_server->sock));
+ rc = rc && (session_write_int (file, SESSION_SERV_IS_CONNECTED, ptr_server->is_connected));
+ rc = rc && (session_write_int (file, SESSION_SERV_SSL_CONNECTED, ptr_server->ssl_connected));
+#ifdef HAVE_GNUTLS
+ if (ptr_server->is_connected && ptr_server->ssl_connected)
+ {
+ gnutls_session_get_data (ptr_server->gnutls_sess, NULL, &session_size);
+ if (session_size > 0)
+ {
+ session_data = malloc (session_size);
+ gnutls_session_get_data (ptr_server->gnutls_sess, session_data, &session_size);
+ rc = rc && (session_write_buf (file, SESSION_SERV_GNUTLS_SESS, &(session_data), session_size));
+ free (session_data);
+ }
+ }
+#endif
+ rc = rc && (session_write_str (file, SESSION_SERV_UNTERMINATED_MESSAGE, ptr_server->unterminated_message));
+ rc = rc && (session_write_str (file, SESSION_SERV_NICK, ptr_server->nick));
+ rc = rc && (session_write_str (file, SESSION_SERV_NICK_MODES, ptr_server->nick_modes));
+ rc = rc && (session_write_str (file, SESSION_SERV_PREFIX, ptr_server->prefix));
+ rc = rc && (session_write_buf (file, SESSION_SERV_RECONNECT_START, &(ptr_server->reconnect_start), sizeof (time_t)));
+ rc = rc && (session_write_buf (file, SESSION_SERV_COMMAND_TIME, &(ptr_server->command_time), sizeof (time_t)));
+ rc = rc && (session_write_int (file, SESSION_SERV_RECONNECT_JOIN, ptr_server->reconnect_join));
+ rc = rc && (session_write_int (file, SESSION_SERV_IS_AWAY, ptr_server->is_away));
+ rc = rc && (session_write_str (file, SESSION_SERV_AWAY_MESSAGE, ptr_server->away_message));
+ rc = rc && (session_write_buf (file, SESSION_SERV_AWAY_TIME, &(ptr_server->away_time), sizeof (time_t)));
+ rc = rc && (session_write_int (file, SESSION_SERV_LAG, ptr_server->lag));
+ rc = rc && (session_write_buf (file, SESSION_SERV_LAG_CHECK_TIME, &(ptr_server->lag_check_time), sizeof (struct timeval)));
+ rc = rc && (session_write_buf (file, SESSION_SERV_LAG_NEXT_CHECK, &(ptr_server->lag_next_check), sizeof (time_t)));
+ rc = rc && (session_write_id (file, SESSION_SERV_END));
+
+ if (!rc)
+ return 0;
+
+ for (ptr_channel = ptr_server->channels; ptr_channel;
+ ptr_channel = ptr_channel->next_channel)
+ {
+ if (!session_save_channel (file, ptr_channel))
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/*
+ * session_save_dcc: save all DCC into session file
+ */
+
+int
+session_save_dcc (FILE *file)
+{
+ int rc;
+ t_irc_dcc *ptr_dcc;
+
+ rc = 1;
+
+ for (ptr_dcc = irc_last_dcc; ptr_dcc;
+ ptr_dcc = ptr_dcc->prev_dcc)
+ {
+ rc = rc && (session_write_id (file, SESSION_OBJ_DCC));
+ rc = rc && (session_write_str (file, SESSION_DCC_SERVER, (ptr_dcc->server) ? ptr_dcc->server->name : NULL));
+ rc = rc && (session_write_str (file, SESSION_DCC_CHANNEL, (ptr_dcc->channel) ? ptr_dcc->channel->name : NULL));
+ rc = rc && (session_write_int (file, SESSION_DCC_TYPE, ptr_dcc->type));
+ rc = rc && (session_write_int (file, SESSION_DCC_STATUS, ptr_dcc->status));
+ rc = rc && (session_write_buf (file, SESSION_DCC_START_TIME, &(ptr_dcc->start_time), sizeof (time_t)));
+ rc = rc && (session_write_buf (file, SESSION_DCC_START_TRANSFER, &(ptr_dcc->start_transfer), sizeof (time_t)));
+ rc = rc && (session_write_buf (file, SESSION_DCC_ADDR, &(ptr_dcc->addr), sizeof (unsigned long)));
+ rc = rc && (session_write_int (file, SESSION_DCC_PORT, ptr_dcc->port));
+ rc = rc && (session_write_str (file, SESSION_DCC_NICK, ptr_dcc->nick));
+ rc = rc && (session_write_int (file, SESSION_DCC_SOCK, ptr_dcc->sock));
+ rc = rc && (session_write_str (file, SESSION_DCC_UNTERMINATED_MESSAGE, ptr_dcc->unterminated_message));
+ rc = rc && (session_write_int (file, SESSION_DCC_FILE, ptr_dcc->file));
+ rc = rc && (session_write_str (file, SESSION_DCC_FILENAME, ptr_dcc->filename));
+ rc = rc && (session_write_str (file, SESSION_DCC_LOCAL_FILENAME, ptr_dcc->local_filename));
+ rc = rc && (session_write_int (file, SESSION_DCC_FILENAME_SUFFIX, ptr_dcc->filename_suffix));
+ rc = rc && (session_write_buf (file, SESSION_DCC_SIZE, &(ptr_dcc->size), sizeof (unsigned long)));
+ rc = rc && (session_write_buf (file, SESSION_DCC_POS, &(ptr_dcc->pos), sizeof (unsigned long)));
+ rc = rc && (session_write_buf (file, SESSION_DCC_ACK, &(ptr_dcc->ack), sizeof (unsigned long)));
+ rc = rc && (session_write_buf (file, SESSION_DCC_START_RESUME, &(ptr_dcc->start_resume), sizeof (unsigned long)));
+ rc = rc && (session_write_buf (file, SESSION_DCC_LAST_CHECK_TIME, &(ptr_dcc->last_check_time), sizeof (time_t)));
+ rc = rc && (session_write_buf (file, SESSION_DCC_LAST_CHECK_POS, &(ptr_dcc->last_check_pos), sizeof (unsigned long)));
+ rc = rc && (session_write_buf (file, SESSION_DCC_LAST_ACTIVITY, &(ptr_dcc->last_activity), sizeof (time_t)));
+ rc = rc && (session_write_buf (file, SESSION_DCC_BYTES_PER_SEC, &(ptr_dcc->bytes_per_sec), sizeof (unsigned long)));
+ rc = rc && (session_write_buf (file, SESSION_DCC_ETA, &(ptr_dcc->eta), sizeof (unsigned long)));
+ rc = rc && (session_write_int (file, SESSION_DCC_CHILD_PID, ptr_dcc->child_pid));
+ rc = rc && (session_write_int (file, SESSION_DCC_CHILD_READ, ptr_dcc->child_read));
+ rc = rc && (session_write_int (file, SESSION_DCC_CHILD_WRITE, ptr_dcc->child_write));
+ rc = rc && (session_write_id (file, SESSION_DCC_END));
+
+ if (!rc)
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * session_save_history: save history into session file
+ * (from last to first, to restore it in good order)
+ */
+
+int
+session_save_history (FILE *file, t_history *last_history)
+{
+ int rc;
+ t_history *ptr_history;
+
+ rc = 1;
+ rc = rc && (session_write_id (file, SESSION_OBJ_HISTORY));
+ ptr_history = last_history;
+ while (ptr_history)
+ {
+ rc = rc && (session_write_str (file, SESSION_HIST_TEXT, ptr_history->text));
+ ptr_history = ptr_history->prev_history;
+ }
+ rc = rc && (session_write_id (file, SESSION_HIST_END));
+ return rc;
+}
+
+/*
+ * session_save_line: save a buffer line into session file
+ */
+
+int
+session_save_line (FILE *file, t_gui_line *line)
+{
+ int rc;
+
+ rc = 1;
+ rc = rc && (session_write_id (file, SESSION_OBJ_LINE));
+ rc = rc && (session_write_int (file, SESSION_LINE_LENGTH, line->length));
+ rc = rc && (session_write_int (file, SESSION_LINE_LENGTH_ALIGN, line->length_align));
+ rc = rc && (session_write_int (file, SESSION_LINE_LOG_WRITE, line->log_write));
+ rc = rc && (session_write_int (file, SESSION_LINE_WITH_MESSAGE, line->line_with_message));
+ rc = rc && (session_write_int (file, SESSION_LINE_WITH_HIGHLIGHT, line->line_with_highlight));
+ rc = rc && (session_write_str (file, SESSION_LINE_DATA, line->data));
+ rc = rc && (session_write_int (file, SESSION_LINE_OFS_AFTER_DATE, line->ofs_after_date));
+ rc = rc && (session_write_int (file, SESSION_LINE_OFS_START_MESSAGE, line->ofs_start_message));
+ rc = rc && (session_write_str (file, SESSION_LINE_NICK, line->nick));
+ rc = rc && (session_write_buf (file, SESSION_LINE_DATE, &(line->date), sizeof (time_t)));
+ rc = rc && (session_write_id (file, SESSION_LINE_END));
+ return rc;
+}
+
+/*
+ * session_save_buffers: save all buffers into session file
+ */
+
+int
+session_save_buffers (FILE *file)
+{
+ int rc;
+ t_gui_buffer *ptr_buffer;
+ t_gui_line *ptr_line;
+
+ rc = 1;
+
+ for (ptr_buffer = gui_buffers; ptr_buffer;
+ ptr_buffer = ptr_buffer->next_buffer)
+ {
+ rc = rc && (session_write_id (file, SESSION_OBJ_BUFFER));
+ rc = rc && (session_write_str (file, SESSION_BUFF_SERVER, GUI_SERVER(ptr_buffer) ? GUI_SERVER(ptr_buffer)->name : NULL));
+ rc = rc && (session_write_str (file, SESSION_BUFF_CHANNEL, GUI_CHANNEL(ptr_buffer) ? GUI_CHANNEL(ptr_buffer)->name : NULL));
+ rc = rc && (session_write_int (file, SESSION_BUFF_TYPE, ptr_buffer->type));
+ rc = rc && (session_write_int (file, SESSION_BUFF_ALL_SERVERS, ptr_buffer->all_servers));
+ rc = rc && (session_write_id (file, SESSION_BUFF_END));
+
+ if (!rc)
+ return 0;
+
+ for (ptr_line = ptr_buffer->lines; ptr_line;
+ ptr_line = ptr_line->next_line)
+ {
+ if (!session_save_line (file, ptr_line))
+ return 0;
+ }
+
+ if (!session_save_history (file, ptr_buffer->last_history))
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * session_save_uptime: save uptime into session file
+ */
+
+int
+session_save_uptime (FILE *file)
+{
+ int rc;
+
+ rc = 1;
+
+ rc = rc && (session_write_id (file, SESSION_OBJ_UPTIME));
+ rc = rc && (session_write_buf (file, SESSION_UPT_START_TIME, &weechat_start_time, sizeof (time_t)));
+ rc = rc && (session_write_id (file, SESSION_UPT_END));
+ return rc;
+}
+
+/*
+ * session_save_hotlist: save hotlist into session file
+ */
+
+int
+session_save_hotlist (FILE *file)
+{
+ int rc;
+ t_weechat_hotlist *ptr_hotlist;
+
+ rc = 1;
+
+ for (ptr_hotlist = weechat_hotlist; ptr_hotlist;
+ ptr_hotlist = ptr_hotlist->next_hotlist)
+ {
+ rc = rc && (session_write_id (file, SESSION_OBJ_HOTLIST));
+ rc = rc && (session_write_int (file, SESSION_HOTL_PRIORITY, ptr_hotlist->priority));
+ rc = rc && (session_write_str (file, SESSION_HOTL_SERVER, (ptr_hotlist->server) ? ptr_hotlist->server->name : NULL));
+ rc = rc && (session_write_int (file, SESSION_HOTL_BUFFER_NUMBER, ptr_hotlist->buffer->number));
+ rc = rc && (session_write_buf (file, SESSION_HOTL_CREATION_TIME, &(ptr_hotlist->creation_time), sizeof (struct timeval)));
+ rc = rc && (session_write_id (file, SESSION_HOTL_END));
+
+ if (!rc)
+ return 0;
+ }
+ return rc;
+}
+
+/*
+ * session_save: save current session
+ */
+
+int
+session_save (char *filename)
+{
+ FILE *file;
+ int rc;
+
+ if ((file = fopen (filename, "wb")) == NULL)
+ return 0;
+
+ rc = 1;
+ rc = rc && (session_write_str (file, -1, SESSION_SIGNATURE));
+ rc = rc && (session_save_servers (file));
+ rc = rc && (session_save_dcc (file));
+ rc = rc && (session_save_history (file, history_global_last));
+ rc = rc && (session_save_buffers (file));
+ rc = rc && (session_save_uptime (file));
+ rc = rc && (session_save_hotlist (file));
+
+ fclose (file);
+
+ return rc;
+}
+
+/* ========================================================================== */
+
+/*
+ * session_crash: stop WeeChat if problem during session loading
+ */
+
+void
+session_crash (FILE *file, char *message, ...)
+{
+ char buffer[4096];
+ va_list argptr;
+
+ va_start (argptr, message);
+ vsnprintf (buffer, sizeof (buffer) - 1, message, argptr);
+ va_end (argptr);
+
+ fclose (file);
+ gui_main_end ();
+ weechat_iconv_fprintf (stderr, "%s %s\n",
+ WEECHAT_ERROR, buffer);
+ weechat_iconv_fprintf (stderr,
+ _("Last operation with session file was at position %ld, "
+ "read of %d bytes\n"),
+ session_last_read_pos,
+ session_last_read_length);
+ weechat_iconv_fprintf (stderr,
+ _("Please send %s/%s, %s/%s and "
+ "above messages to WeeChat developers for support.\n"
+ "Be careful, private info may be in these files.\n"),
+ weechat_home,
+ WEECHAT_LOG_NAME,
+ weechat_home,
+ WEECHAT_SESSION_NAME);
+ exit (EXIT_FAILURE);
+}
+
+/*
+ * session_read_int: read integer from file
+ */
+
+int
+session_read_int (FILE *file, int *value)
+{
+ char type;
+
+ session_last_read_pos = ftell (file);
+ session_last_read_length = sizeof (char);
+
+ if (fread ((void *)(&type), sizeof (char), 1, file) == 0)
+ return 0;
+ if (type != SESSION_TYPE_INT)
+ {
+ session_crash (file, _("wrong type in file (expected: %d, read: %d)"),
+ SESSION_TYPE_INT, type);
+ return 0;
+ }
+
+ session_last_read_pos = ftell (file);
+ session_last_read_length = sizeof (int);
+
+ if (value)
+ return (fread ((void *)value, sizeof (int), 1, file) > 0);
+ else
+ return (fseek (file, sizeof (int), SEEK_CUR) >= 0);
+}
+
+/*
+ * session_read_str: read string from file
+ */
+
+int
+session_read_str (FILE *file, char **string)
+{
+ char type;
+ int length;
+
+ if (string && *string)
+ free (*string);
+
+ session_last_read_pos = ftell (file);
+ session_last_read_length = sizeof (char);
+
+ if (fread ((void *)(&type), sizeof (char), 1, file) == 0)
+ return 0;
+ if (type != SESSION_TYPE_STR)
+ {
+ session_crash (file, _("wrong type in file (expected: %d, read: %d)"),
+ SESSION_TYPE_STR, type);
+ return 0;
+ }
+
+ session_last_read_pos = ftell (file);
+ session_last_read_length = sizeof (int);
+
+ if (fread ((void *)(&length), sizeof (int), 1, file) == 0)
+ return 0;
+
+ if (length == 0)
+ {
+ if (string)
+ (*string) = NULL;
+ return 1;
+ }
+
+ session_last_read_pos = ftell (file);
+ session_last_read_length = length;
+
+ if (string)
+ {
+ (*string) = (char *) malloc (length + 1);
+ if (!(*string))
+ return 0;
+
+ if (fread ((void *)(*string), length, 1, file) == 0)
+ {
+ free (*string);
+ return 0;
+ }
+ (*string)[length] = '\0';
+ }
+ else
+ return (fseek (file, length, SEEK_CUR) >= 0);
+
+ return 1;
+}
+
+/*
+ * session_read_str_utf8: read string from file, then normalize UTF-8
+ */
+
+int
+session_read_str_utf8 (FILE *file, char **string)
+{
+ int rc;
+
+ rc = session_read_str (file, string);
+ if (rc && *string)
+ utf8_normalize (*string, '?');
+
+ return rc;
+}
+
+/*
+ * session_read_buf: read buffer from file
+ */
+
+int
+session_read_buf (FILE *file, void *buffer, int length_expected)
+{
+ char type;
+ int length;
+
+ session_last_read_pos = ftell (file);
+ session_last_read_length = sizeof (char);
+
+ if (fread ((void *)(&type), sizeof (char), 1, file) == 0)
+ return 0;
+ if (type != SESSION_TYPE_BUF)
+ {
+ session_crash (file, _("wrong type in file (expected: %d, read: %d)"),
+ SESSION_TYPE_BUF, type);
+ return 0;
+ }
+
+ session_last_read_pos = ftell (file);
+ session_last_read_length = sizeof (int);
+
+ if (fread ((void *)(&length), sizeof (int), 1, file) == 0)
+ return 0;
+ if ((length <= 0) || ((length_expected > 0) && (length != length_expected)))
+ {
+ session_crash (file, _("invalid length for a buffer"));
+ return 0;
+ }
+
+ session_last_read_pos = ftell (file);
+ session_last_read_length = length;
+
+ if (buffer)
+ return (fread (buffer, length, 1, file) > 0);
+ else
+ return (fseek (file, length, SEEK_CUR) >= 0);
+}
+
+/*
+ * session_read_buf_alloc: read buffer from file and allocate it in memory
+ */
+
+int
+session_read_buf_alloc (FILE *file, void **buffer, int *buffer_length)
+{
+ char type;
+
+ session_last_read_pos = ftell (file);
+ session_last_read_length = sizeof (char);
+
+ if (fread ((void *)(&type), sizeof (char), 1, file) == 0)
+ return 0;
+ if (type != SESSION_TYPE_BUF)
+ {
+ session_crash (file, _("wrong type in file (expected: %d, read: %d)"),
+ SESSION_TYPE_BUF, type);
+ return 0;
+ }
+
+ session_last_read_pos = ftell (file);
+ session_last_read_length = sizeof (int);
+
+ if (fread ((void *)(buffer_length), sizeof (int), 1, file) == 0)
+ return 0;
+ if (*buffer_length <= 0)
+ {
+ session_crash (file, _("invalid length for a buffer"));
+ return 0;
+ }
+
+ *buffer = malloc (*buffer_length);
+
+ session_last_read_pos = ftell (file);
+ session_last_read_length = *buffer_length;
+
+ return (fread (*buffer, *buffer_length, 1, file) > 0);
+}
+
+/*
+ * session_read_object: read an object in file
+ */
+
+int
+session_read_object (FILE *file, int object_id, int type, void *target, int max_buf_length)
+{
+ int object_id_read;
+ char type_read;
+
+ if (fread ((void *)(&object_id_read), sizeof (int), 1, file) == 0)
+ {
+ session_crash (file, _("object read error"));
+ return 0;
+ }
+ if (object_id_read != object_id)
+ {
+ session_crash (file, _("wrong object (expected: %d, read: %d)"),
+ object_id, object_id_read);
+ return 0;
+ }
+
+ session_last_read_pos = ftell (file);
+ session_last_read_length = sizeof (char);
+
+ if (fread ((void *)(&type_read), sizeof (char), 1, file) == 0)
+ {
+ session_crash (file, _("type read error"));
+ return 0;
+ }
+ if (type_read != type)
+ {
+ session_crash (file, _("wrong type (expected: %d, read: %d)"),
+ type, type_read);
+ return 0;
+ }
+ if (fseek (file, sizeof (char) * (-1), SEEK_CUR) < 0)
+ return 0;
+ switch (type)
+ {
+ case SESSION_TYPE_INT:
+ return session_read_int (file, (int *)target);
+ case SESSION_TYPE_STR:
+ return session_read_str (file, (char **)target);
+ case SESSION_TYPE_BUF:
+ return session_read_buf (file, target, max_buf_length);
+ }
+ return 0;
+}
+
+/*
+ * session_read_ignore_value: ignore a value from file
+ */
+
+int
+session_read_ignore_value (FILE *file)
+{
+ char type;
+
+ if (fread ((void *)(&type), sizeof (char), 1, file) == 0)
+ return 0;
+ if (fseek (file, sizeof (char) * (-1), SEEK_CUR) < 0)
+ return 0;
+ switch (type)
+ {
+ case SESSION_TYPE_INT:
+ return session_read_int (file, NULL);
+ case SESSION_TYPE_STR:
+ return session_read_str (file, NULL);
+ case SESSION_TYPE_BUF:
+ return session_read_buf (file, NULL, 0);
+ }
+ return 0;
+}
+
+/*
+ * session_read_ignore_object: ignore an object from file
+ */
+
+int
+session_read_ignore_object (FILE *file)
+{
+ int object_id;
+
+ while (1)
+ {
+ if (fread ((void *)(&object_id), sizeof (int), 1, file) == 0)
+ return 0;
+ if (feof (file))
+ return 0;
+ if (object_id == SESSION_OBJ_END)
+ return 1;
+ if (!session_read_ignore_value (file))
+ return 0;
+ }
+}
+
+/*
+ * session_load_server: load server from file
+ */
+
+int
+session_load_server (FILE *file)
+{
+ int object_id, rc;
+ char *server_name;
+#ifdef HAVE_GNUTLS
+ void *session_data;
+ size_t session_size;
+ int session_size_int;
+#endif
+
+ /* read server name */
+ server_name = NULL;
+ if (!session_read_object (file, SESSION_SERV_NAME, SESSION_TYPE_STR, &server_name, 0))
+ {
+ session_crash (file, _("server name not found"));
+ return 0;
+ }
+
+ /* use or allocate server */
+ weechat_log_printf (_("session: loading server \"%s\"\n"),
+ server_name);
+ session_current_server = irc_server_search (server_name);
+ if (session_current_server)
+ weechat_log_printf (_("server found, updating values\n"));
+ else
+ {
+ weechat_log_printf (_("server not found, creating new one\n"));
+ session_current_server = irc_server_alloc ();
+ if (!session_current_server)
+ {
+ free (server_name);
+ session_crash (file, _("can't create new server"));
+ return 0;
+ }
+ irc_server_init (session_current_server);
+ session_current_server->name = strdup (server_name);
+ }
+ free (server_name);
+
+ /* read server values */
+ rc = 1;
+ while (rc)
+ {
+ if (feof (file))
+ {
+ session_crash (file, _("unexpected end of file (reading server)"));
+ return 0;
+ }
+ if (fread ((void *)(&object_id), sizeof (int), 1, file) == 0)
+ return 0;
+ switch (object_id)
+ {
+ case SESSION_SERV_END:
+ return 1;
+ case SESSION_SERV_AUTOCONNECT:
+ rc = rc && (session_read_int (file, &(session_current_server->autoconnect)));
+ break;
+ case SESSION_SERV_AUTORECONNECT:
+ rc = rc && (session_read_int (file, &(session_current_server->autoreconnect)));
+ break;
+ case SESSION_SERV_AUTORECONNECT_DELAY:
+ rc = rc && (session_read_int (file, &(session_current_server->autoreconnect_delay)));
+ break;
+ case SESSION_SERV_TEMP_SERVER:
+ rc = rc && (session_read_int (file, &(session_current_server->temp_server)));
+ break;
+ case SESSION_SERV_ADDRESS:
+ rc = rc && (session_read_str (file, &(session_current_server->address)));
+ break;
+ case SESSION_SERV_PORT:
+ rc = rc && (session_read_int (file, &(session_current_server->port)));
+ break;
+ case SESSION_SERV_IPV6:
+ rc = rc && (session_read_int (file, &(session_current_server->ipv6)));
+ break;
+ case SESSION_SERV_SSL:
+ rc = rc && (session_read_int (file, &(session_current_server->ssl)));
+ break;
+ case SESSION_SERV_PASSWORD:
+ rc = rc && (session_read_str (file, &(session_current_server->password)));
+ break;
+ case SESSION_SERV_NICK1:
+ rc = rc && (session_read_str (file, &(session_current_server->nick1)));
+ break;
+ case SESSION_SERV_NICK2:
+ rc = rc && (session_read_str (file, &(session_current_server->nick2)));
+ break;
+ case SESSION_SERV_NICK3:
+ rc = rc && (session_read_str (file, &(session_current_server->nick3)));
+ break;
+ case SESSION_SERV_USERNAME:
+ rc = rc && (session_read_str (file, &(session_current_server->username)));
+ break;
+ case SESSION_SERV_REALNAME:
+ rc = rc && (session_read_str (file, &(session_current_server->realname)));
+ break;
+ case SESSION_SERV_HOSTNAME:
+ rc = rc && (session_read_str (file, &(session_current_server->hostname)));
+ break;
+ case SESSION_SERV_COMMAND:
+ rc = rc && (session_read_str (file, &(session_current_server->command)));
+ break;
+ case SESSION_SERV_COMMAND_DELAY:
+ rc = rc && (session_read_int (file, &(session_current_server->command_delay)));
+ break;
+ case SESSION_SERV_AUTOJOIN:
+ rc = rc && (session_read_str (file, &(session_current_server->autojoin)));
+ break;
+ case SESSION_SERV_AUTOREJOIN:
+ rc = rc && (session_read_int (file, &(session_current_server->autorejoin)));
+ break;
+ case SESSION_SERV_NOTIFY_LEVELS:
+ rc = rc && (session_read_str (file, &(session_current_server->notify_levels)));
+ break;
+ case SESSION_SERV_CHILD_PID:
+ rc = rc && (session_read_int (file, &(session_current_server->child_pid)));
+ break;
+ case SESSION_SERV_CHILD_READ:
+ rc = rc && (session_read_int (file, &(session_current_server->child_read)));
+ break;
+ case SESSION_SERV_CHILD_WRITE:
+ rc = rc && (session_read_int (file, &(session_current_server->child_write)));
+ break;
+ case SESSION_SERV_SOCK:
+ rc = rc && (session_read_int (file, &(session_current_server->sock)));
+ break;
+ case SESSION_SERV_IS_CONNECTED:
+ rc = rc && (session_read_int (file, &(session_current_server->is_connected)));
+ break;
+ case SESSION_SERV_SSL_CONNECTED:
+ rc = rc && (session_read_int (file, &(session_current_server->ssl_connected)));
+ break;
+#ifdef HAVE_GNUTLS
+ case SESSION_SERV_GNUTLS_SESS:
+ if (gnutls_init (&(session_current_server->gnutls_sess), GNUTLS_CLIENT) != 0)
+ {
+ session_crash (file, _("gnutls init error"));
+ return 0;
+ }
+ gnutls_set_default_priority (session_current_server->gnutls_sess);
+ gnutls_certificate_type_set_priority (session_current_server->gnutls_sess, gnutls_cert_type_prio);
+ gnutls_protocol_set_priority (session_current_server->gnutls_sess, gnutls_prot_prio);
+ gnutls_credentials_set (session_current_server->gnutls_sess, GNUTLS_CRD_CERTIFICATE, gnutls_xcred);
+ session_data = NULL;
+ rc = rc && (session_read_buf_alloc (file, &session_data, &session_size_int));
+ if (rc)
+ {
+ session_size = session_size_int;
+ gnutls_session_set_data (session_current_server->gnutls_sess, session_data, session_size);
+ free (session_data);
+ gnutls_transport_set_ptr (session_current_server->gnutls_sess,
+ (gnutls_transport_ptr) ((unsigned long) session_current_server->sock));
+ if (gnutls_handshake (session_current_server->gnutls_sess) < 0)
+ {
+ session_crash (file, _("gnutls handshake failed"));
+ return 0;
+ }
+ }
+ break;
+#endif
+ case SESSION_SERV_UNTERMINATED_MESSAGE:
+ rc = rc && (session_read_str (file, &(session_current_server->unterminated_message)));
+ break;
+ case SESSION_SERV_NICK:
+ rc = rc && (session_read_str (file, &(session_current_server->nick)));
+ break;
+ case SESSION_SERV_NICK_MODES:
+ rc = rc && (session_read_str (file, &(session_current_server->nick_modes)));
+ break;
+ case SESSION_SERV_PREFIX:
+ rc = rc && (session_read_str (file, &(session_current_server->prefix)));
+ break;
+ case SESSION_SERV_RECONNECT_START:
+ rc = rc && (session_read_buf (file, &(session_current_server->reconnect_start), sizeof (time_t)));
+ break;
+ case SESSION_SERV_COMMAND_TIME:
+ rc = rc && (session_read_buf (file, &(session_current_server->command_time), sizeof (time_t)));
+ break;
+ case SESSION_SERV_RECONNECT_JOIN:
+ rc = rc && (session_read_int (file, &(session_current_server->reconnect_join)));
+ break;
+ case SESSION_SERV_IS_AWAY:
+ rc = rc && (session_read_int (file, &(session_current_server->is_away)));
+ break;
+ case SESSION_SERV_AWAY_MESSAGE:
+ rc = rc && (session_read_str (file, &(session_current_server->away_message)));
+ break;
+ case SESSION_SERV_AWAY_TIME:
+ rc = rc && (session_read_buf (file, &(session_current_server->away_time), sizeof (time_t)));
+ break;
+ case SESSION_SERV_LAG:
+ rc = rc && (session_read_int (file, &(session_current_server->lag)));
+ break;
+ case SESSION_SERV_LAG_CHECK_TIME:
+ rc = rc && (session_read_buf (file, &(session_current_server->lag_check_time), sizeof (struct timeval)));
+ break;
+ case SESSION_SERV_LAG_NEXT_CHECK:
+ rc = rc && (session_read_buf (file, &(session_current_server->lag_next_check), sizeof (time_t)));
+ break;
+ case SESSION_SERV_CHARSET_DECODE_ISO__UNUSED:
+ rc = rc && (session_read_ignore_value (file));
+ break;
+ case SESSION_SERV_CHARSET_DECODE_UTF__UNUSED:
+ rc = rc && (session_read_ignore_value (file));
+ break;
+ case SESSION_SERV_CHARSET_ENCODE__UNUSED:
+ rc = rc && (session_read_ignore_value (file));
+ break;
+ default:
+ weechat_log_printf (_("session: warning: ignoring value from "
+ "server (object id: %d)\n"),
+ object_id);
+ rc = rc && (session_read_ignore_value (file));
+ break;
+ }
+ }
+ return 0;
+}
+
+/*
+ * session_load_channel: load channel from file
+ */
+
+int
+session_load_channel (FILE *file)
+{
+ int object_id, rc, channel_type;
+ char *channel_name;
+
+ /* check if server is allocated for this channel */
+ if (!session_current_server)
+ {
+ session_crash (file, _("channel found without server"));
+ return 0;
+ }
+
+ /* read channel type */
+ if (!session_read_object (file, SESSION_CHAN_TYPE, SESSION_TYPE_INT, &channel_type, 0))
+ {
+ session_crash (file, _("channel type not found"));
+ return 0;
+ }
+
+ /* read channel name */
+ channel_name = NULL;
+ if (!session_read_object (file, SESSION_CHAN_NAME, SESSION_TYPE_STR, &channel_name, 0))
+ {
+ session_crash (file, _("channel name not found"));
+ return 0;
+ }
+
+ /* allocate channel */
+ weechat_log_printf (_("session: loading channel \"%s\"\n"),
+ channel_name);
+ session_current_channel = irc_channel_new (session_current_server,
+ channel_type,
+ channel_name);
+ free (channel_name);
+ if (!session_current_channel)
+ {
+ session_crash (file, _("can't create new channel"));
+ return 0;
+ }
+
+ /* read channel values */
+ rc = 1;
+ while (rc)
+ {
+ if (feof (file))
+ {
+ session_crash (file, _("unexpected end of file (reading channel)"));
+ return 0;
+ }
+ if (fread ((void *)(&object_id), sizeof (int), 1, file) == 0)
+ return 0;
+ switch (object_id)
+ {
+ case SESSION_CHAN_END:
+ return 1;
+ case SESSION_CHAN_TOPIC:
+ rc = rc && (session_read_str_utf8 (file, &(session_current_channel->topic)));
+ break;
+ case SESSION_CHAN_MODES:
+ rc = rc && (session_read_str (file, (char **)(&(session_current_channel->modes))));
+ break;
+ case SESSION_CHAN_LIMIT:
+ rc = rc && (session_read_int (file, &(session_current_channel->limit)));
+ break;
+ case SESSION_CHAN_KEY:
+ rc = rc && (session_read_str (file, &(session_current_channel->key)));
+ break;
+ case SESSION_CHAN_NICKS_COUNT:
+ rc = rc && (session_read_int (file, &(session_current_channel->nicks_count)));
+ /* will be incremented when adding nicks */
+ session_current_channel->nicks_count = 0;
+ break;
+ case SESSION_CHAN_CHECKING_AWAY:
+ rc = rc && (session_read_int (file, &(session_current_channel->checking_away)));
+ break;
+ case SESSION_CHAN_AWAY_MESSAGE:
+ rc = rc && (session_read_str (file, &(session_current_channel->away_message)));
+ break;
+ case SESSION_CHAN_CYCLE:
+ rc = rc && (session_read_int (file, &(session_current_channel->cycle)));
+ break;
+ case SESSION_CHAN_CLOSE:
+ rc = rc && (session_read_int (file, &(session_current_channel->close)));
+ break;
+ case SESSION_CHAN_DISPLAY_CREATION_DATE:
+ rc = rc && (session_read_int (file, &(session_current_channel->display_creation_date)));
+ break;
+ default:
+ weechat_log_printf (_("session: warning: ignoring value from "
+ "channel (object id: %d)\n"),
+ object_id);
+ rc = rc && (session_read_ignore_value (file));
+ break;
+ }
+ }
+ return 0;
+}
+
+/*
+ * session_load_nick: load nick from file
+ */
+
+int
+session_load_nick (FILE *file)
+{
+ int rc, object_id;
+ char *nick_name;
+ t_irc_nick *nick;
+
+ /* check if channel is allocated for this nick */
+ if (!session_current_channel)
+ {
+ session_crash (file, _("nick found without channel"));
+ return 0;
+ }
+
+ /* read nick name */
+ nick_name = NULL;
+ if (!session_read_object (file, SESSION_NICK_NICK, SESSION_TYPE_STR, &nick_name, 0))
+ {
+ session_crash (file, _("nick name not found"));
+ return 0;
+ }
+
+ /* allocate nick */
+ nick = irc_nick_new (session_current_server, session_current_channel,
+ nick_name, 0, 0, 0, 0, 0, 0, 0);
+ free (nick_name);
+ if (!nick)
+ {
+ session_crash (file, _("can't create new nick"));
+ return 0;
+ }
+
+ /* read nick values */
+ rc = 1;
+ while (rc)
+ {
+ if (feof (file))
+ {
+ session_crash (file, _("unexpected end of file (reading nick)"));
+ return 0;
+ }
+ if (fread ((void *)(&object_id), sizeof (int), 1, file) == 0)
+ return 0;
+ switch (object_id)
+ {
+ case SESSION_NICK_END:
+ return 1;
+ case SESSION_NICK_FLAGS:
+ rc = rc && (session_read_int (file, &(nick->flags)));
+ break;
+ case SESSION_NICK_COLOR:
+ rc = rc && (session_read_int (file, &(nick->color)));
+ break;
+ case SESSION_NICK_HOST:
+ rc = rc && (session_read_str (file, &(nick->host)));
+ break;
+ default:
+ weechat_log_printf (_("session: warning: ignoring value from "
+ "nick (object id: %d)\n"),
+ object_id);
+ rc = rc && (session_read_ignore_value (file));
+ break;
+ }
+ }
+ return 0;
+}
+
+/*
+ * session_load_dcc: load DCC from file
+ */
+
+int
+session_load_dcc (FILE *file)
+{
+ int object_id, rc;
+ t_irc_dcc *dcc;
+ char *string;
+ t_irc_server *ptr_server;
+ t_irc_channel *ptr_channel;
+
+ /* allocate DCC */
+ dcc = irc_dcc_alloc ();
+ if (!dcc)
+ {
+ session_crash (file, _("can't create new DCC"));
+ return 0;
+ }
+
+ weechat_log_printf (_("session: loading DCC\n"));
+
+ /* read DCC values */
+ ptr_server = NULL;
+ ptr_channel = NULL;
+ rc = 1;
+ while (rc)
+ {
+ if (feof (file))
+ {
+ session_crash (file, _("unexpected end of file (reading DCC)"));
+ return 0;
+ }
+ if (fread ((void *)(&object_id), sizeof (int), 1, file) == 0)
+ return 0;
+ switch (object_id)
+ {
+ case SESSION_DCC_END:
+ return 1;
+ case SESSION_DCC_SERVER:
+ string = NULL;
+ rc = rc && (session_read_str (file, &string));
+ if (!rc)
+ return 0;
+ if (string && string[0])
+ {
+ ptr_server = irc_server_search (string);
+ if (!ptr_server)
+ {
+ session_crash (file, _("server not found for DCC"));
+ return 0;
+ }
+ dcc->server = ptr_server;
+ }
+ break;
+ case SESSION_DCC_CHANNEL:
+ if (!ptr_server)
+ {
+ session_crash (file, _("DCC with channel but without server"));
+ return 0;
+ }
+ string = NULL;
+ rc = rc && (session_read_str (file, &string));
+ if (!rc)
+ return 0;
+ if (string && string[0])
+ {
+ ptr_channel = irc_channel_search_any (ptr_server, string);
+ if (!ptr_channel)
+ {
+ session_crash (file, _("channel not found for DCC"));
+ return 0;
+ }
+ dcc->channel = ptr_channel;
+ ptr_channel->dcc_chat = dcc;
+ }
+ break;
+ case SESSION_DCC_TYPE:
+ rc = rc && (session_read_int (file, &(dcc->type)));
+ break;
+ case SESSION_DCC_STATUS:
+ rc = rc && (session_read_int (file, &(dcc->status)));
+ break;
+ case SESSION_DCC_START_TIME:
+ rc = rc && (session_read_buf (file, &(dcc->start_time), sizeof (time_t)));
+ break;
+ case SESSION_DCC_START_TRANSFER:
+ rc = rc && (session_read_buf (file, &(dcc->start_transfer), sizeof (time_t)));
+ break;
+ case SESSION_DCC_ADDR:
+ rc = rc && (session_read_buf (file, &(dcc->addr), sizeof (unsigned long)));
+ break;
+ case SESSION_DCC_PORT:
+ rc = rc && (session_read_int (file, &(dcc->port)));
+ break;
+ case SESSION_DCC_NICK:
+ rc = rc && (session_read_str (file, &(dcc->nick)));
+ break;
+ case SESSION_DCC_SOCK:
+ rc = rc && (session_read_int (file, &(dcc->sock)));
+ break;
+ case SESSION_DCC_UNTERMINATED_MESSAGE:
+ rc = rc && (session_read_str (file, &(dcc->unterminated_message)));
+ break;
+ case SESSION_DCC_FILE:
+ rc = rc && (session_read_int (file, &(dcc->file)));
+ break;
+ case SESSION_DCC_FILENAME:
+ rc = rc && (session_read_str (file, &(dcc->filename)));
+ break;
+ case SESSION_DCC_LOCAL_FILENAME:
+ rc = rc && (session_read_str (file, &(dcc->local_filename)));
+ break;
+ case SESSION_DCC_FILENAME_SUFFIX:
+ rc = rc && (session_read_int (file, &(dcc->filename_suffix)));
+ break;
+ case SESSION_DCC_SIZE:
+ rc = rc && (session_read_buf (file, &(dcc->size), sizeof (unsigned long)));
+ break;
+ case SESSION_DCC_POS:
+ rc = rc && (session_read_buf (file, &(dcc->pos), sizeof (unsigned long)));
+ break;
+ case SESSION_DCC_ACK:
+ rc = rc && (session_read_buf (file, &(dcc->ack), sizeof (unsigned long)));
+ break;
+ case SESSION_DCC_START_RESUME:
+ rc = rc && (session_read_buf (file, &(dcc->start_resume), sizeof (unsigned long)));
+ break;
+ case SESSION_DCC_LAST_CHECK_TIME:
+ rc = rc && (session_read_buf (file, &(dcc->last_check_time), sizeof (time_t)));
+ break;
+ case SESSION_DCC_LAST_CHECK_POS:
+ rc = rc && (session_read_buf (file, &(dcc->last_check_pos), sizeof (unsigned long)));
+ break;
+ case SESSION_DCC_LAST_ACTIVITY:
+ rc = rc && (session_read_buf (file, &(dcc->last_activity), sizeof (time_t)));
+ break;
+ case SESSION_DCC_BYTES_PER_SEC:
+ rc = rc && (session_read_buf (file, &(dcc->bytes_per_sec), sizeof (unsigned long)));
+ break;
+ case SESSION_DCC_ETA:
+ rc = rc && (session_read_buf (file, &(dcc->eta), sizeof (unsigned long)));
+ break;
+ case SESSION_DCC_CHILD_PID:
+ rc = rc && (session_read_int (file, &(dcc->child_pid)));
+ break;
+ case SESSION_DCC_CHILD_READ:
+ rc = rc && (session_read_int (file, &(dcc->child_read)));
+ break;
+ case SESSION_DCC_CHILD_WRITE:
+ rc = rc && (session_read_int (file, &(dcc->child_write)));
+ break;
+ default:
+ weechat_log_printf (_("session: warning: ignoring value from "
+ "DCC (object id: %d)\n"),
+ object_id);
+ rc = rc && (session_read_ignore_value (file));
+ break;
+ }
+ }
+ return 0;
+}
+
+/*
+ * session_load_history: load history from file (global or for a buffer)
+ */
+
+int
+session_load_history (FILE *file)
+{
+ int object_id, rc;
+ char *text;
+
+ if (session_current_buffer)
+ weechat_log_printf (_("session: loading buffer history\n"));
+ else
+ weechat_log_printf (_("session: loading global history\n"));
+
+ /* read history values */
+ rc = 1;
+ while (rc)
+ {
+ if (feof (file))
+ {
+ session_crash (file, _("unexpected end of file (reading history)"));
+ return 0;
+ }
+ if (fread ((void *)(&object_id), sizeof (int), 1, file) == 0)
+ return 0;
+ switch (object_id)
+ {
+ case SESSION_HIST_END:
+ return 1;
+ case SESSION_HIST_TEXT:
+ text = NULL;
+ if (!session_read_str_utf8 (file, &text))
+ return 0;
+ if (session_current_buffer)
+ history_buffer_add (session_current_buffer, text);
+ else
+ history_global_add (text);
+ free (text);
+ break;
+ default:
+ weechat_log_printf (_("session: warning: ignoring value from "
+ "history (object id: %d)\n"),
+ object_id);
+ rc = rc && (session_read_ignore_value (file));
+ break;
+ }
+ }
+ return 0;
+}
+
+/*
+ * session_load_buffer: load buffer from file
+ */
+
+int
+session_load_buffer (FILE *file)
+{
+ int object_id, rc;
+ char *server_name, *channel_name;
+ int buffer_type;
+ t_irc_server *ptr_server;
+ t_irc_channel *ptr_channel;
+
+ /* read server name */
+ server_name = NULL;
+ if (!session_read_object (file, SESSION_BUFF_SERVER, SESSION_TYPE_STR, &server_name, 0))
+ {
+ session_crash (file, _("server name not found for buffer"));
+ return 0;
+ }
+
+ /* read channel name */
+ channel_name = NULL;
+ if (!session_read_object (file, SESSION_BUFF_CHANNEL, SESSION_TYPE_STR, &channel_name, 0))
+ {
+ session_crash (file, _("channel name not found for buffer"));
+ return 0;
+ }
+
+ /* read buffer type */
+ if (!session_read_object (file, SESSION_BUFF_TYPE, SESSION_TYPE_INT, &buffer_type, 0))
+ {
+ session_crash (file, _("buffer type not found"));
+ return 0;
+ }
+
+ /* allocate buffer */
+ weechat_log_printf (_("session: loading buffer (server: %s, channel: %s, type: %d)\n"),
+ (server_name) ? server_name : "-",
+ (channel_name) ? channel_name : "-",
+ buffer_type);
+ ptr_server = NULL;
+ ptr_channel = NULL;
+ if (server_name)
+ {
+ ptr_server = irc_server_search (server_name);
+ if (!ptr_server)
+ {
+ session_crash (file, _("server not found for buffer"));
+ return 0;
+ }
+ }
+
+ if (channel_name)
+ {
+ ptr_channel = irc_channel_search_any_without_buffer (ptr_server, channel_name);
+ if (!ptr_channel)
+ {
+ session_crash (file, _("channel not found for buffer"));
+ return 0;
+ }
+ }
+
+ session_current_buffer = gui_buffer_new (gui_windows, ptr_server,
+ ptr_channel, buffer_type, 1);
+ if (!session_current_buffer)
+ {
+ session_crash (file, _("can't create new buffer"));
+ return 0;
+ }
+
+ free (server_name);
+ free (channel_name);
+
+ /* read buffer values */
+ rc = 1;
+ while (rc)
+ {
+ if (feof (file))
+ {
+ session_crash (file, _("unexpected end of file (reading buffer)"));
+ return 0;
+ }
+ if (fread ((void *)(&object_id), sizeof (int), 1, file) == 0)
+ return 0;
+ switch (object_id)
+ {
+ case SESSION_BUFF_END:
+ return 1;
+ case SESSION_BUFF_ALL_SERVERS:
+ rc = rc && (session_read_int (file, &(session_current_buffer->all_servers)));
+ break;
+ default:
+ weechat_log_printf (_("session: warning: ignoring value from "
+ "buffer (object id: %d)\n"),
+ object_id);
+ rc = rc && (session_read_ignore_value (file));
+ break;
+ }
+ }
+ return 0;
+}
+
+/*
+ * session_load_line: load buffer line from file
+ */
+
+int
+session_load_line (FILE *file)
+{
+ int object_id, rc;
+ t_gui_line *line;
+
+ /* check if buffer is allocated for this line */
+ if (!session_current_buffer)
+ {
+ session_crash (file, _("line found without buffer"));
+ return 0;
+ }
+
+ /* allocate line */
+ line = gui_buffer_line_new (session_current_buffer, time (NULL));
+ if (!line)
+ {
+ session_crash (file, _("can't create new line"));
+ return 0;
+ }
+
+ /* read line values */
+ rc = 1;
+ while (rc)
+ {
+ if (feof (file))
+ {
+ session_crash (file, _("unexpected end of file (reading line)"));
+ return 0;
+ }
+ if (fread ((void *)(&object_id), sizeof (int), 1, file) == 0)
+ return 0;
+ switch (object_id)
+ {
+ case SESSION_LINE_END:
+ return 1;
+ case SESSION_LINE_LENGTH:
+ rc = rc && (session_read_int (file, &(line->length)));
+ break;
+ case SESSION_LINE_LENGTH_ALIGN:
+ rc = rc && (session_read_int (file, &(line->length_align)));
+ break;
+ case SESSION_LINE_LOG_WRITE:
+ rc = rc && (session_read_int (file, &(line->log_write)));
+ break;
+ case SESSION_LINE_WITH_MESSAGE:
+ rc = rc && (session_read_int (file, &(line->line_with_message)));
+ break;
+ case SESSION_LINE_WITH_HIGHLIGHT:
+ rc = rc && (session_read_int (file, &(line->line_with_highlight)));
+ break;
+ case SESSION_LINE_DATA:
+ rc = rc && (session_read_str_utf8 (file, &(line->data)));
+ break;
+ case SESSION_LINE_OFS_AFTER_DATE:
+ rc = rc && (session_read_int (file, &(line->ofs_after_date)));
+ break;
+ case SESSION_LINE_OFS_START_MESSAGE:
+ rc = rc && (session_read_int (file, &(line->ofs_start_message)));
+ break;
+ case SESSION_LINE_NICK:
+ rc = rc && (session_read_str (file, &(line->nick)));
+ break;
+ case SESSION_LINE_DATE:
+ rc = rc && (session_read_buf (file, &(line->date), sizeof (time_t)));
+ break;
+ default:
+ weechat_log_printf (_("session: warning: ignoring value from "
+ "line (object id: %d)\n"),
+ object_id);
+ rc = rc && (session_read_ignore_value (file));
+ break;
+ }
+ }
+ return 0;
+}
+
+/*
+ * session_load_uptime: load uptime from file
+ */
+
+int
+session_load_uptime (FILE *file)
+{
+ int object_id, rc;
+
+ /* read uptime values */
+ rc = 1;
+ while (rc)
+ {
+ if (feof (file))
+ {
+ session_crash (file, _("unexpected end of file (reading uptime)"));
+ return 0;
+ }
+ if (fread ((void *)(&object_id), sizeof (int), 1, file) == 0)
+ return 0;
+ switch (object_id)
+ {
+ case SESSION_UPT_END:
+ return 1;
+ case SESSION_UPT_START_TIME:
+ rc = rc && (session_read_buf (file, &weechat_start_time, sizeof (time_t)));
+ break;
+ default:
+ weechat_log_printf (_("session: warning: ignoring value from "
+ "uptime (object id: %d)\n"),
+ object_id);
+ rc = rc && (session_read_ignore_value (file));
+ break;
+ }
+ }
+ return 0;
+}
+
+/*
+ * session_load_hotlist: load hotlist from file
+ */
+
+int
+session_load_hotlist (FILE *file)
+{
+ int object_id, rc;
+ int priority;
+ struct timeval creation_time;
+ char *server_name;
+ t_irc_server *ptr_server;
+ int buffer_number;
+ t_gui_buffer *ptr_buffer;
+
+ priority = 0;
+ creation_time.tv_sec = 0;
+ creation_time.tv_usec = 0;
+ ptr_server = NULL;
+ ptr_buffer = NULL;
+
+ /* read hotlist values */
+ rc = 1;
+ while (rc)
+ {
+ if (feof (file))
+ {
+ session_crash (file, _("unexpected end of file (reading hotlist)"));
+ return 0;
+ }
+ if (fread ((void *)(&object_id), sizeof (int), 1, file) == 0)
+ return 0;
+ switch (object_id)
+ {
+ case SESSION_HOTL_END:
+ hotlist_add (priority, &creation_time, ptr_server, ptr_buffer, 1);
+ return 1;
+ case SESSION_HOTL_PRIORITY:
+ rc = rc && (session_read_int (file, &priority));
+ break;
+ case SESSION_HOTL_SERVER:
+ server_name = NULL;
+ if (!session_read_str (file, &server_name))
+ return 0;
+ ptr_server = irc_server_search (server_name);
+ free (server_name);
+ break;
+ case SESSION_HOTL_BUFFER_NUMBER:
+ rc = rc && (session_read_int (file, &buffer_number));
+ ptr_buffer = gui_buffer_search_by_number (buffer_number);
+ break;
+ case SESSION_HOTL_CREATION_TIME:
+ rc = rc && (session_read_buf (file, &creation_time, sizeof (struct timeval)));
+ break;
+ default:
+ weechat_log_printf (_("session: warning: ignoring value from "
+ "history (object id: %d)\n"),
+ object_id);
+ rc = rc && (session_read_ignore_value (file));
+ break;
+ }
+ }
+ return 0;
+}
+
+/*
+ * session_load: load session from file
+ */
+
+int
+session_load (char *filename)
+{
+ FILE *file;
+ char *signature;
+ int object_id;
+ t_irc_server *ptr_server;
+
+ session_current_server = NULL;
+ session_current_channel = NULL;
+ session_current_buffer = NULL;
+
+ session_last_read_pos = -1;
+ session_last_read_length = -1;
+
+ if ((file = fopen (filename, "rb")) == NULL)
+ {
+ session_crash (file, _("session file not found"));
+ return 0;
+ }
+
+ signature = NULL;
+ if (!session_read_str (file, &signature))
+ {
+ session_crash (file, _("signature not found"));
+ return 0;
+ }
+ if (!signature || (strcmp (signature, SESSION_SIGNATURE) != 0))
+ {
+ session_crash (file, _("bad session signature"));
+ return 0;
+ }
+ free (signature);
+
+ while (!feof (file))
+ {
+ if (fread ((void *)(&object_id), sizeof (int), 1, file) == 0)
+ {
+ if (feof (file))
+ break;
+ session_crash (file, _("object id not found"));
+ return 0;
+ }
+ switch (object_id)
+ {
+ case SESSION_OBJ_SERVER:
+ if (!session_load_server (file))
+ {
+ session_crash (file, _("failed to load server"));
+ return 0;
+ }
+ break;
+ case SESSION_OBJ_CHANNEL:
+ if (!session_load_channel (file))
+ {
+ session_crash (file, _("failed to load channel"));
+ return 0;
+ }
+ break;
+ case SESSION_OBJ_NICK:
+ if (!session_load_nick (file))
+ {
+ session_crash (file, _("failed to load nick"));
+ return 0;
+ }
+ break;
+ case SESSION_OBJ_DCC:
+ if (!session_load_dcc (file))
+ {
+ session_crash (file, _("failed to load DCC"));
+ return 0;
+ }
+ break;
+ case SESSION_OBJ_HISTORY:
+ if (!session_load_history (file))
+ {
+ session_crash (file, _("failed to load history"));
+ return 0;
+ }
+ break;
+ case SESSION_OBJ_BUFFER:
+ if (!session_load_buffer (file))
+ {
+ session_crash (file, _("failed to load buffer"));
+ return 0;
+ }
+ break;
+ case SESSION_OBJ_LINE:
+ if (!session_load_line (file))
+ {
+ session_crash (file, _("failed to load line"));
+ return 0;
+ }
+ break;
+ case SESSION_OBJ_UPTIME:
+ if (!session_load_uptime (file))
+ {
+ session_crash (file, _("failed to load uptime"));
+ return 0;
+ }
+ break;
+ case SESSION_OBJ_HOTLIST:
+ if (!session_load_hotlist (file))
+ {
+ session_crash (file, _("failed to load hotlist"));
+ return 0;
+ }
+ break;
+ default:
+ weechat_log_printf (_("ignoring object (id: %d)\n"),
+ object_id);
+ if (!session_read_ignore_object (file))
+ {
+ session_crash (file, _("failed to ignore object (id: %d)"),
+ object_id);
+ return 0;
+ }
+ }
+ }
+
+ /* assign a buffer to all connected servers */
+ for (ptr_server = irc_servers; ptr_server;
+ ptr_server = ptr_server->next_server)
+ {
+ if ((ptr_server->is_connected) && (!ptr_server->buffer))
+ ptr_server->buffer = gui_buffers;
+ }
+
+ gui_window_switch_to_buffer (gui_windows, gui_buffers);
+ gui_window_redraw_buffer (gui_current_window->buffer);
+
+ fclose (file);
+
+ if (unlink (filename) < 0)
+ {
+ irc_display_prefix (NULL, gui_current_window->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (gui_current_window->buffer,
+ _("%s can't delete session file (%s)\n"),
+ WEECHAT_ERROR, filename);
+ }
+
+ irc_display_prefix (NULL, gui_current_window->buffer, GUI_PREFIX_INFO);
+ gui_printf_nolog (gui_current_window->buffer,
+ _("Upgrade completed successfully\n"));
+
+ return 1;
+}
diff --git a/src/core/wee-upgrade.h b/src/core/wee-upgrade.h
new file mode 100644
index 000000000..7728220f3
--- /dev/null
+++ b/src/core/wee-upgrade.h
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 2003-2007 by FlashCode <flashcode@flashtux.org>
+ * See README for License detail, AUTHORS for developers list.
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef __WEECHAT_SESSION_H
+#define __WEECHAT_SESSION_H 1
+
+#define WEECHAT_SESSION_NAME "weechat_session.bin"
+
+#define SESSION_SIGNATURE "== WeeChat Upgrade file v1.0 - binary, do not edit! =="
+
+/* For developers: please add new values ONLY AT THE END of enums */
+
+enum t_session_type
+{
+ SESSION_TYPE_INT = 0,
+ SESSION_TYPE_STR,
+ SESSION_TYPE_BUF
+};
+
+enum t_session_object
+{
+ SESSION_OBJ_END = 0,
+ SESSION_OBJ_SERVER,
+ SESSION_OBJ_CHANNEL,
+ SESSION_OBJ_NICK,
+ SESSION_OBJ_DCC,
+ SESSION_OBJ_HISTORY,
+ SESSION_OBJ_BUFFER,
+ SESSION_OBJ_LINE,
+ SESSION_OBJ_UPTIME,
+ SESSION_OBJ_HOTLIST
+};
+
+enum t_session_server
+{
+ SESSION_SERV_END = 0,
+ SESSION_SERV_NAME,
+ SESSION_SERV_AUTOCONNECT,
+ SESSION_SERV_AUTORECONNECT,
+ SESSION_SERV_AUTORECONNECT_DELAY,
+ SESSION_SERV_TEMP_SERVER,
+ SESSION_SERV_ADDRESS,
+ SESSION_SERV_PORT,
+ SESSION_SERV_IPV6,
+ SESSION_SERV_SSL,
+ SESSION_SERV_PASSWORD,
+ SESSION_SERV_NICK1,
+ SESSION_SERV_NICK2,
+ SESSION_SERV_NICK3,
+ SESSION_SERV_USERNAME,
+ SESSION_SERV_REALNAME,
+ SESSION_SERV_COMMAND,
+ SESSION_SERV_COMMAND_DELAY,
+ SESSION_SERV_AUTOJOIN,
+ SESSION_SERV_AUTOREJOIN,
+ SESSION_SERV_NOTIFY_LEVELS,
+ SESSION_SERV_CHILD_PID,
+ SESSION_SERV_CHILD_READ,
+ SESSION_SERV_CHILD_WRITE,
+ SESSION_SERV_SOCK,
+ SESSION_SERV_IS_CONNECTED,
+ SESSION_SERV_SSL_CONNECTED,
+ SESSION_SERV_GNUTLS_SESS,
+ SESSION_SERV_UNTERMINATED_MESSAGE,
+ SESSION_SERV_NICK,
+ SESSION_SERV_RECONNECT_START,
+ SESSION_SERV_RECONNECT_JOIN,
+ SESSION_SERV_IS_AWAY,
+ SESSION_SERV_AWAY_TIME,
+ SESSION_SERV_LAG,
+ SESSION_SERV_LAG_CHECK_TIME,
+ SESSION_SERV_LAG_NEXT_CHECK,
+ SESSION_SERV_CHARSET_DECODE_ISO__UNUSED,
+ SESSION_SERV_CHARSET_DECODE_UTF__UNUSED,
+ SESSION_SERV_CHARSET_ENCODE__UNUSED,
+ SESSION_SERV_HOSTNAME,
+ SESSION_SERV_NICK_MODES,
+ SESSION_SERV_AWAY_MESSAGE,
+ SESSION_SERV_PREFIX,
+ SESSION_SERV_COMMAND_TIME
+};
+
+enum t_session_channel
+{
+ SESSION_CHAN_END = 0,
+ SESSION_CHAN_TYPE,
+ SESSION_CHAN_NAME,
+ SESSION_CHAN_TOPIC,
+ SESSION_CHAN_MODES,
+ SESSION_CHAN_LIMIT,
+ SESSION_CHAN_KEY,
+ SESSION_CHAN_NICKS_COUNT,
+ SESSION_CHAN_CHECKING_AWAY,
+ SESSION_CHAN_AWAY_MESSAGE,
+ SESSION_CHAN_CYCLE,
+ SESSION_CHAN_CLOSE,
+ SESSION_CHAN_DISPLAY_CREATION_DATE
+};
+
+enum t_session_nick
+{
+ SESSION_NICK_END = 0,
+ SESSION_NICK_NICK,
+ SESSION_NICK_FLAGS,
+ SESSION_NICK_COLOR,
+ SESSION_NICK_HOST
+};
+
+enum t_session_dcc
+{
+ SESSION_DCC_END = 0,
+ SESSION_DCC_SERVER,
+ SESSION_DCC_CHANNEL,
+ SESSION_DCC_TYPE,
+ SESSION_DCC_STATUS,
+ SESSION_DCC_START_TIME,
+ SESSION_DCC_START_TRANSFER,
+ SESSION_DCC_ADDR,
+ SESSION_DCC_PORT,
+ SESSION_DCC_NICK,
+ SESSION_DCC_SOCK,
+ SESSION_DCC_UNTERMINATED_MESSAGE,
+ SESSION_DCC_FILE,
+ SESSION_DCC_FILENAME,
+ SESSION_DCC_LOCAL_FILENAME,
+ SESSION_DCC_FILENAME_SUFFIX,
+ SESSION_DCC_SIZE,
+ SESSION_DCC_POS,
+ SESSION_DCC_ACK,
+ SESSION_DCC_START_RESUME,
+ SESSION_DCC_LAST_CHECK_TIME,
+ SESSION_DCC_LAST_CHECK_POS,
+ SESSION_DCC_LAST_ACTIVITY,
+ SESSION_DCC_BYTES_PER_SEC,
+ SESSION_DCC_ETA,
+ SESSION_DCC_CHILD_PID,
+ SESSION_DCC_CHILD_READ,
+ SESSION_DCC_CHILD_WRITE
+};
+
+enum t_session_history
+{
+ SESSION_HIST_END = 0,
+ SESSION_HIST_TEXT
+};
+
+enum t_session_buffer
+{
+ SESSION_BUFF_END = 0,
+ SESSION_BUFF_SERVER,
+ SESSION_BUFF_CHANNEL,
+ SESSION_BUFF_TYPE,
+ SESSION_BUFF_ALL_SERVERS
+};
+
+enum t_session_line
+{
+ SESSION_LINE_END = 0,
+ SESSION_LINE_LENGTH,
+ SESSION_LINE_LENGTH_ALIGN,
+ SESSION_LINE_LOG_WRITE,
+ SESSION_LINE_WITH_MESSAGE,
+ SESSION_LINE_WITH_HIGHLIGHT,
+ SESSION_LINE_DATA,
+ SESSION_LINE_OFS_AFTER_DATE,
+ SESSION_LINE_OFS_START_MESSAGE,
+ SESSION_LINE_NICK,
+ SESSION_LINE_DATE
+};
+
+enum t_session_uptime
+{
+ SESSION_UPT_END = 0,
+ SESSION_UPT_START_TIME
+};
+
+enum t_session_hotlist
+{
+ SESSION_HOTL_END = 0,
+ SESSION_HOTL_PRIORITY,
+ SESSION_HOTL_SERVER,
+ SESSION_HOTL_BUFFER_NUMBER,
+ SESSION_HOTL_CREATION_TIME
+};
+
+int session_save (char *filename);
+int session_load (char *filename);
+
+#endif /* session.h */
diff --git a/src/core/wee-utf8.c b/src/core/wee-utf8.c
new file mode 100644
index 000000000..176fee797
--- /dev/null
+++ b/src/core/wee-utf8.c
@@ -0,0 +1,426 @@
+/*
+ * Copyright (c) 2003-2007 by FlashCode <flashcode@flashtux.org>
+ * See README for License detail, AUTHORS for developers list.
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/* utf8.c: UTF-8 string functions for WeeChat */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "weechat.h"
+#include "utf8.h"
+#include "util.h"
+#include "weeconfig.h"
+
+
+int local_utf8 = 0;
+
+/*
+ * utf8_init: initializes UTF-8 in WeeChat
+ */
+
+void
+utf8_init ()
+{
+ local_utf8 = (ascii_strcasecmp (local_charset, "UTF-8") == 0);
+}
+
+/*
+ * utf8_has_8bits: return 1 if string has 8-bits chars, 0 if only 7-bits chars
+ */
+
+int
+utf8_has_8bits (char *string)
+{
+ while (string && string[0])
+ {
+ if (string[0] & 0x80)
+ return 1;
+ string++;
+ }
+ return 0;
+}
+
+/*
+ * utf8_is_valid: return 1 if UTF-8 string is valid, 0 otherwise
+ * if error is not NULL, it's set with first non valid UTF-8
+ * char in string, if any
+ */
+
+int
+utf8_is_valid (char *string, char **error)
+{
+ while (string && string[0])
+ {
+ /* UTF-8, 2 bytes, should be: 110vvvvv 10vvvvvv */
+ if (((unsigned char)(string[0]) & 0xE0) == 0xC0)
+ {
+ if (!string[1] || (((unsigned char)(string[1]) & 0xC0) != 0x80))
+ {
+ if (error)
+ *error = string;
+ return 0;
+ }
+ string += 2;
+ }
+ /* UTF-8, 3 bytes, should be: 1110vvvv 10vvvvvv 10vvvvvv */
+ else if (((unsigned char)(string[0]) & 0xF0) == 0xE0)
+ {
+ if (!string[1] || !string[2]
+ || (((unsigned char)(string[1]) & 0xC0) != 0x80)
+ || (((unsigned char)(string[2]) & 0xC0) != 0x80))
+ {
+ if (error)
+ *error = string;
+ return 0;
+ }
+ string += 3;
+ }
+ /* UTF-8, 4 bytes, should be: 11110vvv 10vvvvvv 10vvvvvv 10vvvvvv */
+ else if (((unsigned char)(string[0]) & 0xF8) == 0xF0)
+ {
+ if (!string[1] || !string[2] || !string[3]
+ || (((unsigned char)(string[1]) & 0xC0) != 0x80)
+ || (((unsigned char)(string[2]) & 0xC0) != 0x80)
+ || (((unsigned char)(string[3]) & 0xC0) != 0x80))
+ {
+ if (error)
+ *error = string;
+ return 0;
+ }
+ string += 4;
+ }
+ /* UTF-8, 1 byte, should be: 0vvvvvvv */
+ else if ((unsigned char)(string[0]) >= 0x80)
+ {
+ if (error)
+ *error = string;
+ return 0;
+ }
+ else
+ string++;
+ }
+ if (error)
+ *error = NULL;
+ return 1;
+}
+
+/*
+ * utf8_normalize: normalize UTF-8 string: remove non UTF-8 chars and
+ * replace them by a char
+ */
+
+void
+utf8_normalize (char *string, char replacement)
+{
+ char *error;
+
+ while (string && string[0])
+ {
+ if (utf8_is_valid (string, &error))
+ return;
+ error[0] = replacement;
+ string = error + 1;
+ }
+}
+
+/*
+ * utf8_prev_char: return previous UTF-8 char in a string
+ */
+
+char *
+utf8_prev_char (char *string_start, char *string)
+{
+ if (!string || (string <= string_start))
+ return NULL;
+
+ string--;
+
+ if (((unsigned char)(string[0]) & 0xC0) == 0x80)
+ {
+ /* UTF-8, at least 2 bytes */
+ string--;
+ if (string < string_start)
+ return string + 1;
+ if (((unsigned char)(string[0]) & 0xC0) == 0x80)
+ {
+ /* UTF-8, at least 3 bytes */
+ string--;
+ if (string < string_start)
+ return string + 1;
+ if (((unsigned char)(string[0]) & 0xC0) == 0x80)
+ {
+ /* UTF-8, 4 bytes */
+ string--;
+ if (string < string_start)
+ return string + 1;
+ return string;
+ }
+ else
+ return string;
+ }
+ else
+ return string;
+ }
+ return string;
+}
+
+/*
+ * utf8_next_char: return next UTF-8 char in a string
+ */
+
+char *
+utf8_next_char (char *string)
+{
+ if (!string)
+ return NULL;
+
+ /* UTF-8, 2 bytes: 110vvvvv 10vvvvvv */
+ if (((unsigned char)(string[0]) & 0xE0) == 0xC0)
+ {
+ if (!string[1])
+ return string + 1;
+ return string + 2;
+ }
+ /* UTF-8, 3 bytes: 1110vvvv 10vvvvvv 10vvvvvv */
+ else if (((unsigned char)(string[0]) & 0xF0) == 0xE0)
+ {
+ if (!string[1])
+ return string + 1;
+ if (!string[2])
+ return string + 2;
+ return string + 3;
+ }
+ /* UTF-8, 4 bytes: 11110vvv 10vvvvvv 10vvvvvv 10vvvvvv */
+ else if (((unsigned char)(string[0]) & 0xF8) == 0xF0)
+ {
+ if (!string[1])
+ return string + 1;
+ if (!string[2])
+ return string + 2;
+ if (!string[3])
+ return string + 3;
+ return string + 4;
+ }
+ /* UTF-8, 1 byte: 0vvvvvvv */
+ return string + 1;
+}
+
+/*
+ * utf8_char_size: return UTF-8 char size
+ */
+
+int
+utf8_char_size (char *string)
+{
+ if (!string)
+ return 0;
+
+ return utf8_next_char (string) - string;
+}
+
+/*
+ * utf8_strlen: return length of an UTF-8 string (<= strlen(string))
+ */
+
+int
+utf8_strlen (char *string)
+{
+ int length;
+
+ if (!string)
+ return 0;
+
+ length = 0;
+ while (string && string[0])
+ {
+ string = utf8_next_char (string);
+ length++;
+ }
+ return length;
+}
+
+/*
+ * utf8_strnlen: return length of an UTF-8 string, for N bytes
+ */
+
+int
+utf8_strnlen (char *string, int bytes)
+{
+ char *start;
+ int length;
+
+ if (!string)
+ return 0;
+
+ start = string;
+ length = 0;
+ while (string && string[0] && (string - start < bytes))
+ {
+ string = utf8_next_char (string);
+ length++;
+ }
+ return length;
+}
+
+/*
+ * utf8_width_screen: return number of chars needed on screen to display UTF-8 string
+ */
+
+int
+utf8_width_screen (char *string)
+{
+ int length, num_char;
+ wchar_t *wstring;
+
+ if (!string)
+ return 0;
+
+ if (!local_utf8)
+ return utf8_strlen (string);
+
+ num_char = mbstowcs (NULL, string, 0) + 1;
+ wstring = (wchar_t *) malloc ((num_char + 1) * sizeof (wchar_t));
+ if (!wstring)
+ return utf8_strlen (string);
+
+ if (mbstowcs (wstring, string, num_char) == (size_t)(-1))
+ {
+ free (wstring);
+ return utf8_strlen (string);
+ }
+
+ length = wcswidth (wstring, num_char);
+ free (wstring);
+ return length;
+}
+
+/*
+ * utf8_add_offset: moves forward N chars in an UTF-8 string
+ */
+
+char *
+utf8_add_offset (char *string, int offset)
+{
+ int count;
+
+ if (!string)
+ return string;
+
+ count = 0;
+ while (string && string[0] && (count < offset))
+ {
+ string = utf8_next_char (string);
+ count++;
+ }
+ return string;
+}
+
+/*
+ * utf8_real_pos: get real position in UTF-8
+ * for example: ("aébc", 2) returns 3
+ */
+
+int
+utf8_real_pos (char *string, int pos)
+{
+ int count, real_pos;
+ char *next_char;
+
+ if (!string)
+ return pos;
+
+ count = 0;
+ real_pos = 0;
+ while (string && string[0] && (count < pos))
+ {
+ next_char = utf8_next_char (string);
+ real_pos += (next_char - string);
+ string = next_char;
+ count++;
+ }
+ return real_pos;
+}
+
+/*
+ * utf8_pos: get position in UTF-8
+ * for example: ("aébc", 3) returns 2
+ */
+
+int
+utf8_pos (char *string, int real_pos)
+{
+ int count;
+ char *limit;
+
+ if (!string || !local_charset)
+ return real_pos;
+
+ count = 0;
+ limit = string + real_pos;
+ while (string && string[0] && (string < limit))
+ {
+ string = utf8_next_char (string);
+ count++;
+ }
+ return count;
+}
+
+/*
+ * utf8_get_wc: get wide char from string (first char)
+ */
+
+wint_t
+utf8_get_wc (char *string)
+{
+ int char_size;
+ wint_t result;
+
+ if (!string || !string[0])
+ return WEOF;
+
+ char_size = utf8_char_size (string);
+ switch (char_size)
+ {
+ case 1:
+ result = (wint_t)string[0];
+ break;
+ case 2:
+ result = ((wint_t)((unsigned char)string[0])) << 8
+ | ((wint_t)((unsigned char)string[1]));
+ break;
+ case 3:
+ result = ((wint_t)((unsigned char)string[0])) << 16
+ | ((wint_t)((unsigned char)string[1])) << 8
+ | ((wint_t)((unsigned char)string[2]));
+ break;
+ case 4:
+ result = ((wint_t)((unsigned char)string[0])) << 24
+ | ((wint_t)((unsigned char)string[1])) << 16
+ | ((wint_t)((unsigned char)string[2])) << 8
+ | ((wint_t)((unsigned char)string[3]));
+ break;
+ default:
+ result = WEOF;
+ }
+ return result;
+}
diff --git a/src/core/wee-utf8.h b/src/core/wee-utf8.h
new file mode 100644
index 000000000..caf7b7b10
--- /dev/null
+++ b/src/core/wee-utf8.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2003-2007 by FlashCode <flashcode@flashtux.org>
+ * See README for License detail, AUTHORS for developers list.
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef __WEECHAT_UTF8_H
+#define __WEECHAT_UTF8_H 1
+
+#ifndef __USE_XOPEN
+#define __USE_XOPEN
+#endif
+
+#if defined(__OpenBSD__)
+#include <utf8/wchar.h>
+#else
+#include <wchar.h>
+#endif
+
+extern int local_utf8;
+
+extern void utf8_init ();
+extern int utf8_has_8bits (char *);
+extern int utf8_is_valid (char *, char **);
+extern void utf8_normalize (char *, char);
+extern char *utf8_prev_char (char *, char *);
+extern char *utf8_next_char (char *);
+extern int utf8_char_size (char *);
+extern int utf8_strlen (char *);
+extern int utf8_strnlen (char *, int);
+extern int utf8_width_screen (char *);
+extern char *utf8_add_offset (char *, int);
+extern int utf8_real_pos (char *, int);
+extern int utf8_pos (char *, int);
+extern wint_t utf8_get_wc (char *);
+
+#endif /* utf8.h */
diff --git a/src/core/wee-util.c b/src/core/wee-util.c
new file mode 100644
index 000000000..4fe9395c5
--- /dev/null
+++ b/src/core/wee-util.c
@@ -0,0 +1,730 @@
+/*
+ * Copyright (c) 2003-2007 by FlashCode <flashcode@flashtux.org>
+ * See README for License detail, AUTHORS for developers list.
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/* util.c: some useful functions for WeeChat */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+
+#ifdef HAVE_ICONV
+#include <iconv.h>
+#endif
+
+#ifndef ICONV_CONST
+ #ifdef ICONV_2ARG_IS_CONST
+ #define ICONV_CONST const
+ #else
+ #define ICONV_CONST
+ #endif
+#endif
+
+#include "weechat.h"
+#include "utf8.h"
+#include "weeconfig.h"
+
+
+/*
+ * strndup: define strndup function if not existing (FreeBSD and maybe other)
+ */
+
+#ifndef HAVE_STRNDUP
+char *
+strndup (char *string, int length)
+{
+ char *result;
+
+ if ((int)strlen (string) < length)
+ return strdup (string);
+
+ result = (char *)malloc (length + 1);
+ if (!result)
+ return NULL;
+
+ memcpy (result, string, length);
+ result[length] = '\0';
+
+ return result;
+}
+#endif
+
+/*
+ * ascii_tolower: locale independant string conversion to lower case
+ */
+
+void
+ascii_tolower (char *string)
+{
+ while (string && string[0])
+ {
+ if ((string[0] >= 'A') && (string[0] <= 'Z'))
+ string[0] += ('a' - 'A');
+ string++;
+ }
+}
+
+/*
+ * ascii_toupper: locale independant string conversion to upper case
+ */
+
+void
+ascii_toupper (char *string)
+{
+ while (string && string[0])
+ {
+ if ((string[0] >= 'a') && (string[0] <= 'z'))
+ string[0] -= ('a' - 'A');
+ string++;
+ }
+}
+
+/*
+ * ascii_strcasecmp: locale and case independent string comparison
+ */
+
+int
+ascii_strcasecmp (char *string1, char *string2)
+{
+ int c1, c2;
+
+ if (!string1 || !string2)
+ return (string1) ? 1 : ((string2) ? -1 : 0);
+
+ while (string1[0] && string2[0])
+ {
+ c1 = (int)((unsigned char) string1[0]);
+ c2 = (int)((unsigned char) string2[0]);
+
+ if ((c1 >= 'A') && (c1 <= 'Z'))
+ c1 += ('a' - 'A');
+
+ if ((c2 >= 'A') && (c2 <= 'Z'))
+ c2 += ('a' - 'A');
+
+ if ((c1 - c2) != 0)
+ return c1 - c2;
+
+ string1++;
+ string2++;
+ }
+
+ return (string1[0]) ? 1 : ((string2[0]) ? -1 : 0);
+}
+
+/*
+ * ascii_strncasecmp: locale and case independent string comparison
+ * with max length
+ */
+
+int
+ascii_strncasecmp (char *string1, char *string2, int max)
+{
+ int c1, c2, count;
+
+ if (!string1 || !string2)
+ return (string1) ? 1 : ((string2) ? -1 : 0);
+
+ count = 0;
+ while ((count < max) && string1[0] && string2[0])
+ {
+ c1 = (int)((unsigned char) string1[0]);
+ c2 = (int)((unsigned char) string2[0]);
+
+ if ((c1 >= 'A') && (c1 <= 'Z'))
+ c1 += ('a' - 'A');
+
+ if ((c2 >= 'A') && (c2 <= 'Z'))
+ c2 += ('a' - 'A');
+
+ if ((c1 - c2) != 0)
+ return c1 - c2;
+
+ string1++;
+ string2++;
+ count++;
+ }
+
+ if (count >= max)
+ return 0;
+ else
+ return (string1[0]) ? 1 : ((string2[0]) ? -1 : 0);
+}
+
+/*
+ * ascii_strcasestr: locale and case independent string search
+ */
+
+char *
+ascii_strcasestr (char *string, char *search)
+{
+ int length_search;
+
+ length_search = strlen (search);
+
+ if (!string || !search || (length_search == 0))
+ return NULL;
+
+ while (string[0])
+ {
+ if (ascii_strncasecmp (string, search, length_search) == 0)
+ return string;
+
+ string++;
+ }
+
+ return NULL;
+}
+
+/*
+ * weechat_iconv: convert string to another charset
+ */
+
+char *
+weechat_iconv (int from_utf8, char *from_code, char *to_code, char *string)
+{
+ char *outbuf;
+
+#ifdef HAVE_ICONV
+ iconv_t cd;
+ char *inbuf, *ptr_inbuf, *ptr_outbuf, *next_char;
+ char *ptr_inbuf_shift;
+ int done;
+ size_t err, inbytesleft, outbytesleft;
+
+ if (from_code && from_code[0] && to_code && to_code[0]
+ && (ascii_strcasecmp(from_code, to_code) != 0))
+ {
+ cd = iconv_open (to_code, from_code);
+ if (cd == (iconv_t)(-1))
+ outbuf = strdup (string);
+ else
+ {
+ inbuf = strdup (string);
+ ptr_inbuf = inbuf;
+ inbytesleft = strlen (inbuf);
+ outbytesleft = inbytesleft * 4;
+ outbuf = (char *) malloc (outbytesleft + 2);
+ ptr_outbuf = outbuf;
+ ptr_inbuf_shift = NULL;
+ done = 0;
+ while (!done)
+ {
+ err = iconv (cd, (ICONV_CONST char **)(&ptr_inbuf), &inbytesleft,
+ &ptr_outbuf, &outbytesleft);
+ if (err == (size_t)(-1))
+ {
+ switch (errno)
+ {
+ case EINVAL:
+ done = 1;
+ break;
+ case E2BIG:
+ done = 1;
+ break;
+ case EILSEQ:
+ if (from_utf8)
+ {
+ next_char = utf8_next_char (ptr_inbuf);
+ if (next_char)
+ {
+ inbytesleft -= next_char - ptr_inbuf;
+ ptr_inbuf = next_char;
+ }
+ else
+ {
+ inbytesleft--;
+ ptr_inbuf++;
+ }
+ }
+ else
+ {
+ ptr_inbuf++;
+ inbytesleft--;
+ }
+ ptr_outbuf[0] = '?';
+ ptr_outbuf++;
+ outbytesleft--;
+ break;
+ }
+ }
+ else
+ {
+ if (!ptr_inbuf_shift)
+ {
+ ptr_inbuf_shift = ptr_inbuf;
+ ptr_inbuf = NULL;
+ inbytesleft = 0;
+ }
+ else
+ done = 1;
+ }
+ }
+ if (ptr_inbuf_shift)
+ ptr_inbuf = ptr_inbuf_shift;
+ ptr_outbuf[0] = '\0';
+ free (inbuf);
+ iconv_close (cd);
+ }
+ }
+ else
+ outbuf = strdup (string);
+#else
+ /* make C compiler happy */
+ (void) from_utf8;
+ (void) from_code;
+ (void) to_code;
+ outbuf = strdup (string);
+#endif /* HAVE_ICONV */
+
+ return outbuf;
+}
+
+/*
+ * weechat_iconv_to_internal: convert user string (input, script, ..) to
+ * WeeChat internal storage charset
+ */
+
+char *
+weechat_iconv_to_internal (char *charset, char *string)
+{
+ char *input, *output;
+
+ input = strdup (string);
+
+ /* optimize for UTF-8: if charset is NULL => we use term charset =>
+ if ths charset is already UTF-8, then no iconv needed */
+ if (local_utf8 && (!charset || !charset[0]))
+ return input;
+
+ if (input)
+ {
+ if (utf8_has_8bits (input) && utf8_is_valid (input, NULL))
+ return input;
+
+ output = weechat_iconv (0,
+ (charset && charset[0]) ?
+ charset : local_charset,
+ WEECHAT_INTERNAL_CHARSET,
+ input);
+ utf8_normalize (output, '?');
+ free (input);
+ return output;
+ }
+ return NULL;
+}
+
+/*
+ * weechat_iconv_from_internal: convert internal string to terminal charset,
+ * for display
+ */
+
+char *
+weechat_iconv_from_internal (char *charset, char *string)
+{
+ char *input, *output;
+
+ input = strdup (string);
+
+ /* optimize for UTF-8: if charset is NULL => we use term charset =>
+ if ths charset is already UTF-8, then no iconv needed */
+ if (local_utf8 && (!charset || !charset[0]))
+ return input;
+
+ if (input)
+ {
+ utf8_normalize (input, '?');
+ output = weechat_iconv (1,
+ WEECHAT_INTERNAL_CHARSET,
+ (charset && charset[0]) ?
+ charset : local_charset,
+ input);
+ free (input);
+ return output;
+ }
+ return NULL;
+}
+
+/*
+ * weechat_iconv_fprintf: encode to terminal charset, then call fprintf on a file
+ */
+
+void
+weechat_iconv_fprintf (FILE *file, char *data, ...)
+{
+ va_list argptr;
+ static char buf[4096];
+ char *buf2;
+
+ va_start (argptr, data);
+ vsnprintf (buf, sizeof (buf) - 1, data, argptr);
+ va_end (argptr);
+
+ buf2 = weechat_iconv_from_internal (NULL, buf);
+ fprintf (file, "%s", (buf2) ? buf2 : buf);
+ if (buf2)
+ free (buf2);
+}
+
+/*
+ * weechat_strreplace: replace a string by new one in a string
+ * note: returned value has to be free() after use
+ */
+
+char *
+weechat_strreplace (char *string, char *search, char *replace)
+{
+ char *pos, *new_string;
+ int length1, length2, length_new, count;
+
+ if (!string || !search || !replace)
+ return NULL;
+
+ length1 = strlen (search);
+ length2 = strlen (replace);
+
+ /* count number of strings to replace */
+ count = 0;
+ pos = string;
+ while (pos && pos[0] && (pos = strstr (pos, search)))
+ {
+ count++;
+ pos += length1;
+ }
+
+ /* easy: no string to replace! */
+ if (count == 0)
+ return strdup (string);
+
+ /* compute needed memory for new string */
+ length_new = strlen (string) - (count * length1) + (count * length2) + 1;
+
+ /* allocate new string */
+ new_string = (char *)malloc (length_new * sizeof (char));
+ if (!new_string)
+ return strdup (string);
+
+ /* replace all occurences */
+ new_string[0] = '\0';
+ while (string && string[0])
+ {
+ pos = strstr (string, search);
+ if (pos)
+ {
+ strncat (new_string, string, pos - string);
+ strcat (new_string, replace);
+ pos += length1;
+ }
+ else
+ strcat (new_string, string);
+ string = pos;
+ }
+ return new_string;
+}
+
+/*
+ * weechat_convert_hex_chars: convert hex chars (\x??) to value
+ */
+
+char *
+weechat_convert_hex_chars (char *string)
+{
+ char *output, hex_str[8], *error;
+ int pos_output;
+ long number;
+
+ output = (char *)malloc (strlen (string) + 1);
+ if (output)
+ {
+ pos_output = 0;
+ while (string && string[0])
+ {
+ if (string[0] == '\\')
+ {
+ string++;
+ switch (string[0])
+ {
+ case '\\':
+ output[pos_output++] = '\\';
+ string++;
+ break;
+ case 'x':
+ case 'X':
+ if (isxdigit (string[1])
+ && isxdigit (string[2]))
+ {
+ snprintf (hex_str, sizeof (hex_str),
+ "0x%c%c", string[1], string[2]);
+ number = strtol (hex_str, &error, 16);
+ if ((error) && (error[0] == '\0'))
+ {
+ output[pos_output++] = number;
+ string += 3;
+ }
+ else
+ {
+ output[pos_output++] = '\\';
+ output[pos_output++] = string[0];
+ string++;
+ }
+ }
+ else
+ {
+ output[pos_output++] = string[0];
+ string++;
+ }
+ break;
+ default:
+ output[pos_output++] = '\\';
+ output[pos_output++] = string[0];
+ string++;
+ break;
+ }
+ }
+ else
+ {
+ output[pos_output++] = string[0];
+ string++;
+ }
+ }
+ output[pos_output] = '\0';
+ }
+
+ return output;
+}
+
+/*
+ * get_timeval_diff: calculates difference between two times (return in milliseconds)
+ */
+
+long
+get_timeval_diff (struct timeval *tv1, struct timeval *tv2)
+{
+ long diff_sec, diff_usec;
+
+ diff_sec = tv2->tv_sec - tv1->tv_sec;
+ diff_usec = tv2->tv_usec - tv1->tv_usec;
+
+ if (diff_usec < 0)
+ {
+ diff_usec += 1000000;
+ diff_sec--;
+ }
+ return ((diff_usec / 1000) + (diff_sec * 1000));
+}
+
+/*
+ * explode_string: explode a string according to separators
+ */
+
+char **
+explode_string (char *string, char *separators, int num_items_max,
+ int *num_items)
+{
+ int i, n_items;
+ char **array;
+ char *ptr, *ptr1, *ptr2;
+
+ if (num_items != NULL)
+ *num_items = 0;
+
+ if (!string || !string[0])
+ return NULL;
+
+ /* calculate number of items */
+ ptr = string;
+ i = 1;
+ while ((ptr = strpbrk (ptr, separators)))
+ {
+ while (strchr (separators, ptr[0]) != NULL)
+ ptr++;
+ i++;
+ }
+ n_items = i;
+
+ if ((num_items_max != 0) && (n_items > num_items_max))
+ n_items = num_items_max;
+
+ array =
+ (char **) malloc ((n_items + 1) * sizeof (char *));
+
+ ptr1 = string;
+ ptr2 = string;
+
+ for (i = 0; i < n_items; i++)
+ {
+ while (strchr (separators, ptr1[0]) != NULL)
+ ptr1++;
+ if (i == (n_items - 1) || (ptr2 = strpbrk (ptr1, separators)) == NULL)
+ if ((ptr2 = strchr (ptr1, '\r')) == NULL)
+ if ((ptr2 = strchr (ptr1, '\n')) == NULL)
+ ptr2 = strchr (ptr1, '\0');
+
+ if ((ptr1 == NULL) || (ptr2 == NULL))
+ {
+ array[i] = NULL;
+ }
+ else
+ {
+ if (ptr2 - ptr1 > 0)
+ {
+ array[i] =
+ (char *) malloc ((ptr2 - ptr1 + 1) * sizeof (char));
+ array[i] = strncpy (array[i], ptr1, ptr2 - ptr1);
+ array[i][ptr2 - ptr1] = '\0';
+ ptr1 = ++ptr2;
+ }
+ else
+ {
+ array[i] = NULL;
+ }
+ }
+ }
+
+ array[i] = NULL;
+ if (num_items != NULL)
+ *num_items = i;
+
+ return array;
+}
+
+/*
+ * free_exploded_string: free an exploded string
+ */
+
+void
+free_exploded_string (char **exploded_string)
+{
+ int i;
+
+ if (exploded_string)
+ {
+ for (i = 0; exploded_string[i]; i++)
+ free (exploded_string[i]);
+ free (exploded_string);
+ }
+}
+
+/*
+ * split_multi_command: split a list of commands separated by 'sep'
+ * and ecscaped with '\'
+ * - empty commands are removed
+ * - spaces on the left of each commands are stripped
+ * Result must be freed with free_multi_command
+ */
+
+char **
+split_multi_command (char *command, char sep)
+{
+ int nb_substr, arr_idx, str_idx, type;
+ char **array;
+ char *buffer, *ptr, *p;
+
+ if (command == NULL)
+ return NULL;
+
+ nb_substr = 1;
+ ptr = command;
+ while ( (p = strchr(ptr, sep)) != NULL)
+ {
+ nb_substr++;
+ ptr = ++p;
+ }
+
+ array = (char **) malloc ((nb_substr + 1) * sizeof(char *));
+ if (!array)
+ return NULL;
+
+ buffer = (char *) malloc ( (strlen(command) + 1) * sizeof (char));
+ if (!buffer)
+ {
+ free (array);
+ return NULL;
+ }
+
+ ptr = command;
+ str_idx = 0;
+ arr_idx = 0;
+ while(*ptr != '\0')
+ {
+ type = 0;
+ if (*ptr == ';')
+ {
+ if (ptr == command)
+ type = 1;
+ else if ( *(ptr-1) != '\\')
+ type = 1;
+ else if ( *(ptr-1) == '\\')
+ type = 2;
+ }
+ if (type == 1)
+ {
+ buffer[str_idx] = '\0';
+ str_idx = -1;
+ p = buffer;
+ /* strip white spaces a the begining of the line */
+ while (*p == ' ') p++;
+ if (p && p[0])
+ array[arr_idx++] = strdup (p);
+ }
+ else if (type == 2)
+ buffer[--str_idx] = *ptr;
+ else
+ buffer[str_idx] = *ptr;
+ str_idx++;
+ ptr++;
+ }
+
+ buffer[str_idx] = '\0';
+ p = buffer;
+ while (*p == ' ') p++;
+ if (p && p[0])
+ array[arr_idx++] = strdup (p);
+
+ array[arr_idx] = NULL;
+
+ free (buffer);
+
+ array = (char **) realloc (array, (arr_idx + 1) * sizeof(char *));
+
+ return array;
+}
+
+/*
+ * free_multi_command : free a list of commands splitted
+ * with split_multi_command
+ */
+
+void
+free_multi_command (char **commands)
+{
+ int i;
+
+ if (commands)
+ {
+ for (i = 0; commands[i]; i++)
+ free (commands[i]);
+ free (commands);
+ }
+}
diff --git a/src/core/wee-util.h b/src/core/wee-util.h
new file mode 100644
index 000000000..e3ec09e38
--- /dev/null
+++ b/src/core/wee-util.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2003-2007 by FlashCode <flashcode@flashtux.org>
+ * See README for License detail, AUTHORS for developers list.
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef __WEECHAT_UTIL_H
+#define __WEECHAT_UTIL_H 1
+
+#ifndef HAVE_STRNDUP
+extern char *strndup (char *, int);
+#endif
+extern void ascii_tolower (char *);
+extern void ascii_toupper (char *);
+extern int ascii_strcasecmp (char *, char *);
+extern int ascii_strncasecmp (char *, char *, int);
+extern char *ascii_strcasestr (char *, char *);
+extern char *weechat_iconv (char *, char *, char *);
+extern char *weechat_iconv_to_internal (char *, char *);
+extern char *weechat_iconv_from_internal (char *, char *);
+extern void weechat_iconv_fprintf (FILE *, char *, ...);
+extern char *weechat_strreplace (char *, char *, char *);
+extern char *weechat_convert_hex_chars (char *);
+extern long get_timeval_diff (struct timeval *, struct timeval *);
+extern char **explode_string (char *, char *, int, int *);
+extern void free_exploded_string (char **);
+
+#endif /* util.h */
diff --git a/src/core/weechat.c b/src/core/weechat.c
new file mode 100644
index 000000000..60fc100e1
--- /dev/null
+++ b/src/core/weechat.c
@@ -0,0 +1,884 @@
+/* ############################################################################
+ * ### ___ __ ______________ _____ ###
+ * ### __ | / /___________ ____/__ /_______ __ /_ ###
+ * ### __ | /| / /_ _ \ _ \ / __ __ \ __ `/ __/ ###
+ * ### __ |/ |/ / / __/ __/ /___ _ / / / /_/ // /_ ###
+ * ### ____/|__/ \___/\___/\____/ /_/ /_/\__,_/ \__/ ###
+ * ### ###
+ * ### WeeChat - Wee Enhanced Environment for Chat ###
+ * ### Fast & light environment for Chat ###
+ * ### ###
+ * ### By FlashCode <flashcode@flashtux.org> ###
+ * ### ###
+ * ### http://weechat.flashtux.org ###
+ * ### ###
+ * ############################################################################
+ *
+ * Copyright (c) 2003-2007 by FlashCode <flashcode@flashtux.org>
+ * See README for License detail, AUTHORS for developers list.
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/* weechat.c: core functions for WeeChat */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <signal.h>
+
+#ifdef HAVE_GNUTLS
+#include <gnutls/gnutls.h>
+#endif
+
+#ifdef HAVE_LANGINFO_CODESET
+#include <langinfo.h>
+#endif
+
+#include "weechat.h"
+#include "alias.h"
+#include "backtrace.h"
+#include "command.h"
+#include "fifo.h"
+#include "hotlist.h"
+#include "log.h"
+#include "session.h"
+#include "utf8.h"
+#include "util.h"
+#include "weeconfig.h"
+#include "../protocols/irc/irc.h"
+#include "../gui/gui.h"
+
+#ifdef PLUGINS
+#include "../plugins/plugins.h"
+#endif
+
+
+char *weechat_argv0 = NULL; /* WeeChat binary file name (argv[0]) */
+char *weechat_session = NULL; /* WeeChat session file (for /upgrade cmd) */
+time_t weechat_start_time; /* WeeChat start time (used by /uptime cmd) */
+int quit_weechat; /* = 1 if quit request from user... why ? :'( */
+int sigsegv = 0; /* SIGSEGV received? */
+char *weechat_home = NULL; /* WeeChat home dir. (default: ~/.weechat) */
+
+char *local_charset = NULL; /* local charset, for ex.: ISO-8859-1, UTF-8 */
+
+int server_cmd_line; /* at least 1 server on WeeChat command line */
+int auto_connect; /* enabled by default (cmd option to disable) */
+int auto_load_plugins; /* enabled by default (cmd option to disable) */
+
+#ifdef HAVE_GNUTLS
+gnutls_certificate_credentials gnutls_xcred; /* gnutls client credentials */
+#endif
+
+
+/*
+ * weechat_display_usage: display WeeChat usage
+ */
+
+void
+weechat_display_usage (char *exec_name)
+{
+ weechat_iconv_fprintf (stdout, "\n");
+ weechat_iconv_fprintf (stdout,
+ _("%s (c) Copyright 2003-2007, compiled on %s %s\n"
+ "Developed by FlashCode <flashcode@flashtux.org> - %s"),
+ PACKAGE_STRING, __DATE__, __TIME__, WEECHAT_WEBSITE);
+ weechat_iconv_fprintf (stdout, "\n\n");
+ weechat_iconv_fprintf (stdout,
+ _("Usage: %s [options ...]\n" \
+ " or: %s [irc[6][s]://[nickname[:password]@]irc.example.org[:port][/channel][,channel[...]]"),
+ exec_name, exec_name);
+ weechat_iconv_fprintf (stdout, "\n\n");
+ weechat_iconv_fprintf (stdout,
+ _(" -a, --no-connect disable auto-connect to servers at startup\n"
+ " -c, --config display config file options\n"
+ " -d, --dir <path> set WeeChat home directory (default: ~/.weechat)\n"
+ " -f, --key-functions display WeeChat internal functions for keys\n"
+ " -h, --help this help\n"
+ " -i, --irc-commands display IRC commands\n"
+ " -k, --keys display WeeChat default keys\n"
+ " -l, --license display WeeChat license\n"
+ " -p, --no-plugin don't load any plugin at startup\n"
+ " -v, --version display WeeChat version\n"
+ " -w, --weechat-commands display WeeChat commands\n"));
+ weechat_iconv_fprintf(stdout, "\n");
+}
+
+/*
+ * weechat_display_config_options: display config options
+ */
+
+void
+weechat_display_config_options ()
+{
+ int i, j, k;
+
+ weechat_iconv_fprintf (stdout,
+ _("WeeChat configuration options (<weechat_home>/weechat.rc):\n\n"));
+ for (i = 0; i < CONFIG_NUMBER_SECTIONS; i++)
+ {
+ if (weechat_options[i])
+ {
+ j = 0;
+ while (weechat_options[i][j].option_name)
+ {
+ weechat_iconv_fprintf (stdout,
+ "* %s:\n",
+ weechat_options[i][j].option_name);
+ switch (weechat_options[i][j].option_type)
+ {
+ case OPTION_TYPE_BOOLEAN:
+ weechat_iconv_fprintf (stdout, _(" . type: boolean\n"));
+ weechat_iconv_fprintf (stdout, _(" . values: 'on' or 'off'\n"));
+ weechat_iconv_fprintf (stdout, _(" . default value: '%s'\n"),
+ (weechat_options[i][j].default_int == BOOL_TRUE) ?
+ "on" : "off");
+ break;
+ case OPTION_TYPE_INT:
+ weechat_iconv_fprintf (stdout, _(" . type: integer\n"));
+ weechat_iconv_fprintf (stdout, _(" . values: between %d and %d\n"),
+ weechat_options[i][j].min,
+ weechat_options[i][j].max);
+ weechat_iconv_fprintf (stdout, _(" . default value: %d\n"),
+ weechat_options[i][j].default_int);
+ break;
+ case OPTION_TYPE_INT_WITH_STRING:
+ weechat_iconv_fprintf (stdout, _(" . type: string\n"));
+ weechat_iconv_fprintf (stdout, _(" . values: "));
+ k = 0;
+ while (weechat_options[i][j].array_values[k])
+ {
+ weechat_iconv_fprintf (stdout, "'%s'",
+ weechat_options[i][j].array_values[k]);
+ if (weechat_options[i][j].array_values[k + 1])
+ weechat_iconv_fprintf (stdout, ", ");
+ k++;
+ }
+ weechat_iconv_fprintf (stdout, "\n");
+ weechat_iconv_fprintf (stdout, _(" . default value: '%s'\n"),
+ (weechat_options[i][j].default_string) ?
+ weechat_options[i][j].default_string : _("empty"));
+ break;
+ case OPTION_TYPE_COLOR:
+ weechat_iconv_fprintf (stdout, _(" . type: color\n"));
+ weechat_iconv_fprintf (stdout, _(" . values: Curses or Gtk color\n"));
+ weechat_iconv_fprintf (stdout, _(" . default value: '%s'\n"),
+ (weechat_options[i][j].default_string) ?
+ weechat_options[i][j].default_string : _("empty"));
+ break;
+ case OPTION_TYPE_STRING:
+ switch (weechat_options[i][j].max)
+ {
+ case 0:
+ weechat_iconv_fprintf (stdout, _(" . type: string\n"));
+ weechat_iconv_fprintf (stdout, _(" . values: any string\n"));
+ break;
+ case 1:
+ weechat_iconv_fprintf (stdout, _(" . type: char\n"));
+ weechat_iconv_fprintf (stdout, _(" . values: any char\n"));
+ break;
+ default:
+ weechat_iconv_fprintf (stdout, _(" . type: string\n"));
+ weechat_iconv_fprintf (stdout, _(" . values: any string (limit: %d chars)\n"),
+ weechat_options[i][j].max);
+ break;
+ }
+ weechat_iconv_fprintf (stdout, _(" . default value: '%s'\n"),
+ (weechat_options[i][j].default_string) ?
+ weechat_options[i][j].default_string : _("empty"));
+ break;
+ }
+ weechat_iconv_fprintf (stdout, _(" . description: %s\n"),
+ _(weechat_options[i][j].long_description));
+ weechat_iconv_fprintf (stdout, "\n");
+ j++;
+ }
+ }
+ }
+}
+
+/*
+ * weechat_display_commands: display WeeChat and/or IRC commands
+ */
+
+void
+weechat_display_commands (int weechat_cmd, int irc_cmd)
+{
+ int i;
+
+ if (weechat_cmd)
+ {
+ weechat_iconv_fprintf (stdout,
+ _("%s internal commands:\n"), PACKAGE_NAME);
+ weechat_iconv_fprintf (stdout, "\n");
+ for (i = 0; weechat_commands[i].command_name; i++)
+ {
+ weechat_iconv_fprintf (stdout, "* %s", weechat_commands[i].command_name);
+ if (weechat_commands[i].arguments &&
+ weechat_commands[i].arguments[0])
+ weechat_iconv_fprintf (stdout, " %s\n\n", _(weechat_commands[i].arguments));
+ else
+ weechat_iconv_fprintf (stdout, "\n\n");
+ weechat_iconv_fprintf (stdout, "%s\n\n", _(weechat_commands[i].command_description));
+ if (weechat_commands[i].arguments_description &&
+ weechat_commands[i].arguments_description[0])
+ weechat_iconv_fprintf (stdout, "%s\n\n",
+ _(weechat_commands[i].arguments_description));
+ }
+ }
+
+ if (irc_cmd)
+ {
+ weechat_iconv_fprintf (stdout, _("IRC commands:\n"));
+ weechat_iconv_fprintf (stdout, "\n");
+ for (i = 0; irc_commands[i].command_name; i++)
+ {
+ if (irc_commands[i].cmd_function_args ||
+ irc_commands[i].cmd_function_1arg)
+ {
+ weechat_iconv_fprintf (stdout, "* %s", irc_commands[i].command_name);
+ if (irc_commands[i].arguments &&
+ irc_commands[i].arguments[0])
+ weechat_iconv_fprintf (stdout, " %s\n\n", _(irc_commands[i].arguments));
+ else
+ weechat_iconv_fprintf (stdout, "\n\n");
+ weechat_iconv_fprintf (stdout, "%s\n\n", _(irc_commands[i].command_description));
+ if (irc_commands[i].arguments_description &&
+ irc_commands[i].arguments_description[0])
+ weechat_iconv_fprintf (stdout, "%s\n\n",
+ _(irc_commands[i].arguments_description));
+ }
+ }
+ }
+}
+
+/*
+ * weechat_display_key_functions: display WeeChat key functions
+ */
+
+void
+weechat_display_key_functions ()
+{
+ int i;
+
+ weechat_iconv_fprintf (stdout, _("Internal key functions:\n"));
+ weechat_iconv_fprintf (stdout, "\n");
+ i = 0;
+ while (gui_key_functions[i].function_name)
+ {
+ weechat_iconv_fprintf (stdout,
+ "* %s: %s\n",
+ gui_key_functions[i].function_name,
+ _(gui_key_functions[i].description));
+ i++;
+ }
+}
+
+/*
+ * weechat_display_keys: display WeeChat default keys
+ */
+
+void
+weechat_display_keys ()
+{
+ t_gui_key *ptr_key;
+ char *expanded_name;
+
+ weechat_iconv_fprintf (stdout,
+ _("%s default keys:\n"), PACKAGE_NAME);
+ weechat_iconv_fprintf (stdout, "\n");
+ for (ptr_key = gui_keys; ptr_key; ptr_key = ptr_key->next_key)
+ {
+ expanded_name = gui_keyboard_get_expanded_name (ptr_key->key);
+ weechat_iconv_fprintf (stdout,
+ "* %s => %s\n",
+ (expanded_name) ? expanded_name : ptr_key->key,
+ (ptr_key->function) ? gui_keyboard_function_search_by_ptr (ptr_key->function) : ptr_key->command);
+ if (expanded_name)
+ free (expanded_name);
+ }
+}
+
+/*
+ * weechat_parse_args: parse command line args
+ */
+
+void
+weechat_parse_args (int argc, char *argv[])
+{
+ int i;
+ t_irc_server server_tmp;
+
+ weechat_argv0 = strdup (argv[0]);
+ weechat_session = NULL;
+ weechat_home = NULL;
+ server_cmd_line = 0;
+ auto_connect = 1;
+ auto_load_plugins = 1;
+
+ for (i = 1; i < argc; i++)
+ {
+ if ((strcmp (argv[i], "-a") == 0)
+ || (strcmp (argv[i], "--no-connect") == 0))
+ auto_connect = 0;
+ else if ((strcmp (argv[i], "-c") == 0)
+ || (strcmp (argv[i], "--config") == 0))
+ {
+ weechat_display_config_options ();
+ weechat_shutdown (EXIT_SUCCESS, 0);
+ }
+ else if ((strcmp (argv[i], "-d") == 0)
+ || (strcmp (argv[i], "--dir") == 0))
+ {
+ if (i + 1 < argc)
+ weechat_home = strdup (argv[++i]);
+ else
+ {
+ weechat_iconv_fprintf (stderr,
+ _("%s missing argument for --dir option\n"),
+ WEECHAT_ERROR);
+ weechat_shutdown (EXIT_FAILURE, 0);
+ }
+ }
+ else if ((strcmp (argv[i], "-f") == 0)
+ || (strcmp (argv[i], "--key-functions") == 0))
+ {
+ weechat_display_key_functions ();
+ weechat_shutdown (EXIT_SUCCESS, 0);
+ }
+ else if ((strcmp (argv[i], "-h") == 0)
+ || (strcmp (argv[i], "--help") == 0))
+ {
+ weechat_display_usage (argv[0]);
+ weechat_shutdown (EXIT_SUCCESS, 0);
+ }
+ else if ((strcmp (argv[i], "-i") == 0)
+ || (strcmp (argv[i], "--irc-commands") == 0))
+ {
+ weechat_display_commands (0, 1);
+ weechat_shutdown (EXIT_SUCCESS, 0);
+ }
+ else if ((strcmp (argv[i], "-k") == 0)
+ || (strcmp (argv[i], "--keys") == 0))
+ {
+ weechat_display_keys ();
+ weechat_shutdown (EXIT_SUCCESS, 0);
+ }
+ else if ((strcmp (argv[i], "-l") == 0)
+ || (strcmp (argv[i], "--license") == 0))
+ {
+ weechat_iconv_fprintf (stdout, "\n%s%s", WEE_LICENSE);
+ weechat_shutdown (EXIT_SUCCESS, 0);
+ }
+ else if ((strcmp (argv[i], "-p") == 0)
+ || (strcmp (argv[i], "--no-plugin") == 0))
+ auto_load_plugins = 0;
+ else if (strcmp (argv[i], "--session") == 0)
+ {
+ if (i + 1 < argc)
+ weechat_session = strdup (argv[++i]);
+ else
+ {
+ weechat_iconv_fprintf (stderr,
+ _("%s missing argument for --session option\n"),
+ WEECHAT_ERROR);
+ weechat_shutdown (EXIT_FAILURE, 0);
+ }
+ }
+ else if ((strcmp (argv[i], "-v") == 0)
+ || (strcmp (argv[i], "--version") == 0))
+ {
+ weechat_iconv_fprintf (stdout, PACKAGE_VERSION "\n");
+ weechat_shutdown (EXIT_SUCCESS, 0);
+ }
+ else if ((strcmp (argv[i], "-w") == 0)
+ || (strcmp (argv[i], "--weechat-commands") == 0))
+ {
+ weechat_display_commands (1, 0);
+ weechat_shutdown (EXIT_SUCCESS, 0);
+ }
+ else if ((ascii_strncasecmp (argv[i], "irc", 3) == 0))
+ {
+ if (irc_server_init_with_url (argv[i], &server_tmp) < 0)
+ {
+ weechat_iconv_fprintf (stderr,
+ _("%s invalid syntax for IRC server ('%s'), ignored\n"),
+ WEECHAT_WARNING, argv[i]);
+ }
+ else
+ {
+ if (!irc_server_new (server_tmp.name, server_tmp.autoconnect,
+ server_tmp.autoreconnect,
+ server_tmp.autoreconnect_delay,
+ 1, server_tmp.address, server_tmp.port,
+ server_tmp.ipv6, server_tmp.ssl,
+ server_tmp.password, server_tmp.nick1,
+ server_tmp.nick2, server_tmp.nick3,
+ NULL, NULL, NULL, NULL, 0,
+ server_tmp.autojoin, 1, NULL))
+ weechat_iconv_fprintf (stderr,
+ _("%s unable to create server ('%s'), ignored\n"),
+ WEECHAT_WARNING, argv[i]);
+ irc_server_destroy (&server_tmp);
+ server_cmd_line = 1;
+ }
+ }
+ else
+ {
+ weechat_iconv_fprintf (stderr,
+ _("%s unknown parameter '%s', ignored\n"),
+ WEECHAT_WARNING, argv[i]);
+ }
+ }
+}
+
+/*
+ * weechat_create_dir: create a directory
+ * return: 1 if ok (or directory already exists)
+ * 0 if error
+ */
+
+int
+weechat_create_dir (char *directory, int permissions)
+{
+ if (mkdir (directory, 0755) < 0)
+ {
+ /* exit if error (except if directory already exists) */
+ if (errno != EEXIST)
+ {
+ weechat_iconv_fprintf (stderr, _("%s cannot create directory \"%s\"\n"),
+ WEECHAT_ERROR, directory);
+ return 0;
+ }
+ return 1;
+ }
+ if ((permissions != 0) && (strcmp (directory, getenv ("HOME")) != 0))
+ chmod (directory, permissions);
+ return 1;
+}
+
+/*
+ * weechat_create_home_dirs: create WeeChat directories
+ */
+
+void
+weechat_create_home_dirs ()
+{
+ char *ptr_home;
+ int dir_length;
+ struct stat statinfo;
+
+ if (!weechat_home)
+ {
+ ptr_home = getenv ("HOME");
+ if (!ptr_home)
+ {
+ weechat_iconv_fprintf (stderr, _("%s unable to get HOME directory\n"),
+ WEECHAT_ERROR);
+ weechat_shutdown (EXIT_FAILURE, 0);
+ }
+ dir_length = strlen (ptr_home) + 10;
+ weechat_home =
+ (char *) malloc (dir_length * sizeof (char));
+ if (!weechat_home)
+ {
+ weechat_iconv_fprintf (stderr, _("%s not enough memory for home directory\n"),
+ WEECHAT_ERROR);
+ weechat_shutdown (EXIT_FAILURE, 0);
+ }
+ snprintf (weechat_home, dir_length, "%s%s.weechat", ptr_home,
+ DIR_SEPARATOR);
+ }
+
+ /* if home already exists, it has to be a directory */
+ if (stat (weechat_home, &statinfo) == 0)
+ {
+ if (!S_ISDIR (statinfo.st_mode))
+ {
+ weechat_iconv_fprintf (stderr, _("%s home (%s) is not a directory\n"),
+ WEECHAT_ERROR, weechat_home);
+ weechat_shutdown (EXIT_FAILURE, 0);
+ }
+ }
+
+ /* create home directory; error is fatal */
+ if (!weechat_create_dir (weechat_home, 0))
+ {
+ weechat_iconv_fprintf (stderr, _("%s unable to create \"%s\" directory\n"),
+ WEECHAT_ERROR, weechat_home);
+ weechat_shutdown (EXIT_FAILURE, 0);
+ }
+}
+
+/*
+ * weechat_create_config_dirs: create config directories (read from config file)
+ */
+
+void
+weechat_create_config_dirs ()
+{
+ char *dir1, *dir2;
+
+ /* create logs directory" */
+ dir1 = weechat_strreplace (cfg_log_path, "~", getenv ("HOME"));
+ dir2 = weechat_strreplace (dir1, "%h", weechat_home);
+ (void) weechat_create_dir (dir2, 0700);
+ if (dir1)
+ free (dir1);
+ if (dir2)
+ free (dir2);
+
+ /* create DCC download directory */
+ dir1 = weechat_strreplace (cfg_dcc_download_path, "~", getenv ("HOME"));
+ dir2 = weechat_strreplace (dir1, "%h", weechat_home);
+ (void) weechat_create_dir (dir2, 0700);
+ if (dir1)
+ free (dir1);
+ if (dir2)
+ free (dir2);
+}
+
+/*
+ * weechat_init_vars: initialize some variables
+ */
+
+void
+weechat_init_vars ()
+{
+ /* start time, used by /uptime command */
+ weechat_start_time = time (NULL);
+
+ /* init gnutls */
+#ifdef HAVE_GNUTLS
+ gnutls_global_init ();
+ gnutls_certificate_allocate_credentials (&gnutls_xcred);
+ gnutls_certificate_set_x509_trust_file (gnutls_xcred, "ca.pem", GNUTLS_X509_FMT_PEM);
+#endif
+}
+
+/*
+ * weechat_config_read: read WeeChat config file
+ */
+
+void
+weechat_config_read ()
+{
+ switch (config_read ())
+ {
+ case 0: /* read ok */
+ break;
+ case -1: /* config file not found */
+ if (config_create_default () < 0)
+ exit (EXIT_FAILURE);
+ if (config_read () != 0)
+ exit (EXIT_FAILURE);
+ break;
+ default: /* other error (fatal) */
+ irc_server_free_all ();
+ exit (EXIT_FAILURE);
+ }
+}
+
+/*
+ * weechat_welcome_message: display WeeChat welcome message - yeah!
+ */
+
+void
+weechat_welcome_message ()
+{
+ if (cfg_look_startup_logo)
+ {
+ gui_printf (NULL,
+ "%s ___ __ ______________ _____ \n"
+ "%s __ | / /___________ ____/__ /_______ __ /_\n"
+ "%s __ | /| / /_ _ \\ _ \\ / __ __ \\ __ `/ __/\n"
+ "%s __ |/ |/ / / __/ __/ /___ _ / / / /_/ // /_ \n"
+ "%s ____/|__/ \\___/\\___/\\____/ /_/ /_/\\__,_/ \\__/ \n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK));
+ }
+ if (cfg_look_weechat_slogan && cfg_look_weechat_slogan[0])
+ {
+ gui_printf (NULL, _("%sWelcome to %s%s%s, %s\n"),
+ (cfg_look_startup_logo) ? " " : "",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ PACKAGE_NAME,
+ GUI_NO_COLOR,
+ cfg_look_weechat_slogan);
+ }
+ if (cfg_look_startup_version)
+ {
+ gui_printf (NULL, "%s%s%s%s, %s %s %s\n",
+ (cfg_look_startup_logo) ? " " : "",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ PACKAGE_STRING,
+ GUI_NO_COLOR,
+ _("compiled on"), __DATE__, __TIME__);
+ }
+ if (cfg_look_startup_logo ||
+ (cfg_look_weechat_slogan && cfg_look_weechat_slogan[0]) ||
+ cfg_look_startup_version)
+ gui_printf (NULL,
+ "%s-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK));
+
+ weechat_log_printf ("%s (%s %s %s)\n",
+ PACKAGE_STRING, _("compiled on"), __DATE__, __TIME__);
+}
+
+/*
+ * weechat_shutdown: shutdown WeeChat
+ */
+
+void
+weechat_shutdown (int return_code, int crash)
+{
+ if (weechat_argv0)
+ free (weechat_argv0);
+ fifo_remove ();
+ if (weechat_home)
+ free (weechat_home);
+ weechat_log_close ();
+ if (local_charset)
+ free (local_charset);
+ alias_free_all ();
+
+#ifdef HAVE_GNUTLS
+ gnutls_certificate_free_credentials (gnutls_xcred);
+ gnutls_global_deinit();
+#endif
+
+ if (crash)
+ abort();
+ else
+ exit (return_code);
+}
+
+/*
+ * weechat_dump: write dump to WeeChat log file
+ */
+
+void
+weechat_dump (int crash)
+{
+ t_irc_server *ptr_server;
+ t_irc_channel *ptr_channel;
+ t_irc_nick *ptr_nick;
+ t_gui_window *ptr_window;
+ t_gui_buffer *ptr_buffer;
+#ifdef PLUGINS
+ t_weechat_plugin *ptr_plugin;
+#endif
+
+ /* prevent reentrance */
+ if (sigsegv)
+ exit (EXIT_FAILURE);
+
+ if (crash)
+ {
+ sigsegv = 1;
+ weechat_log_printf ("Very bad, WeeChat is crashing (SIGSEGV received)...\n");
+ }
+
+ weechat_log_printf ("\n");
+ if (crash)
+ {
+ weechat_log_printf ("****** WeeChat CRASH DUMP ******\n");
+ weechat_log_printf ("****** Please send this file to WeeChat developers ******\n");
+ weechat_log_printf ("****** and explain when this crash happened ******\n");
+ }
+ else
+ {
+ weechat_log_printf ("****** WeeChat dump request ******\n");
+ }
+
+ for (ptr_server = irc_servers; ptr_server; ptr_server = ptr_server->next_server)
+ {
+ weechat_log_printf ("\n");
+ irc_server_print_log (ptr_server);
+
+ for (ptr_channel = ptr_server->channels; ptr_channel;
+ ptr_channel = ptr_channel->next_channel)
+ {
+ weechat_log_printf ("\n");
+ irc_channel_print_log (ptr_channel);
+
+ for (ptr_nick = ptr_channel->nicks; ptr_nick;
+ ptr_nick = ptr_nick->next_nick)
+ {
+ weechat_log_printf ("\n");
+ irc_nick_print_log (ptr_nick);
+ }
+
+ }
+ }
+
+ irc_dcc_print_log ();
+
+ gui_panel_print_log ();
+
+ weechat_log_printf ("\n");
+ weechat_log_printf ("[windows/buffers]\n");
+ weechat_log_printf (" => windows:\n");
+ for (ptr_window = gui_windows; ptr_window; ptr_window = ptr_window->next_window)
+ {
+ weechat_log_printf (" 0x%X\n", ptr_window);
+ }
+ weechat_log_printf (" => buffers:\n");
+ for (ptr_buffer = gui_buffers; ptr_buffer; ptr_buffer = ptr_buffer->next_buffer)
+ {
+ weechat_log_printf (" 0x%X\n", ptr_buffer);
+ }
+ weechat_log_printf (" => current window = 0x%X\n", gui_current_window);
+
+ for (ptr_window = gui_windows; ptr_window; ptr_window = ptr_window->next_window)
+ {
+ weechat_log_printf ("\n");
+ gui_window_print_log (ptr_window);
+ }
+
+ for (ptr_buffer = gui_buffers; ptr_buffer;
+ ptr_buffer = ptr_buffer->next_buffer)
+ {
+ weechat_log_printf ("\n");
+ gui_buffer_print_log (ptr_buffer);
+ }
+
+ weechat_log_printf ("\n");
+ irc_ignore_print_log ();
+
+ weechat_log_printf ("\n");
+ hotlist_print_log ();
+
+#ifdef PLUGINS
+ for (ptr_plugin = weechat_plugins; ptr_plugin;
+ ptr_plugin = ptr_plugin->next_plugin)
+ {
+ weechat_log_printf ("\n");
+ plugin_print_log (ptr_plugin);
+ }
+#endif
+
+ weechat_log_printf ("\n");
+ weechat_log_printf ("****** End of dump ******\n");
+ weechat_log_printf ("\n");
+}
+
+/*
+ * weechat_sigsegv: SIGSEGV handler: save crash log to <weechat_home>/weechat.log and exit
+ */
+
+void
+weechat_sigsegv ()
+{
+ weechat_dump (1);
+ irc_dcc_end ();
+ irc_server_free_all ();
+ gui_main_end ();
+
+ weechat_iconv_fprintf (stderr, "\n");
+ weechat_iconv_fprintf (stderr, "*** Very bad! WeeChat is crashing (SIGSEGV received)\n");
+ if (!weechat_log_crash_rename ())
+ weechat_iconv_fprintf (stderr,
+ "*** Full crash dump was saved to %s/weechat.log file.\n",
+ weechat_home);
+ weechat_iconv_fprintf (stderr, "***\n");
+ weechat_iconv_fprintf (stderr, "*** Please help WeeChat developers to fix this bug:\n");
+ weechat_iconv_fprintf (stderr, "*** 1. If you have a core file, please run: gdb weechat-curses core\n");
+ weechat_iconv_fprintf (stderr, "*** then issue \"bt\" command and send result to developers\n");
+ weechat_iconv_fprintf (stderr, "*** To enable core files with bash shell: ulimit -c 10000\n");
+ weechat_iconv_fprintf (stderr, "*** 2. Otherwise send backtrace (below) and weechat.log\n");
+ weechat_iconv_fprintf (stderr, "*** (be careful, private info may be in this file since\n");
+ weechat_iconv_fprintf (stderr, "*** part of chats are displayed, so remove lines if needed)\n\n");
+
+ weechat_backtrace ();
+
+ /* shutdown with error code */
+ weechat_shutdown (EXIT_FAILURE, 1);
+}
+
+/*
+ * main: WeeChat startup
+ */
+
+int
+main (int argc, char *argv[])
+{
+ setlocale (LC_ALL, ""); /* initialize gettext */
+#ifdef ENABLE_NLS
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ bind_textdomain_codeset (PACKAGE, "UTF-8");
+ textdomain (PACKAGE);
+#endif
+
+#ifdef HAVE_LANGINFO_CODESET
+ local_charset = strdup (nl_langinfo (CODESET));
+#else
+ local_charset = strdup ("");
+#endif
+ utf8_init ();
+
+ signal (SIGINT, SIG_IGN); /* ignore SIGINT signal */
+ signal (SIGQUIT, SIG_IGN); /* ignore SIGQUIT signal */
+ signal (SIGPIPE, SIG_IGN); /* ignore SIGPIPE signal */
+ signal (SIGSEGV, weechat_sigsegv); /* crash dump when SIGSEGV received */
+ gui_main_pre_init (&argc, &argv); /* pre-initiliaze interface */
+ weechat_init_vars (); /* initialize some variables */
+ gui_keyboard_init (); /* init keyb. (default key bindings)*/
+ weechat_parse_args (argc, argv); /* parse command line args */
+ weechat_create_home_dirs (); /* create WeeChat directories */
+ weechat_log_init (); /* init log file */
+ command_index_build (); /* build cmd index for completion */
+ weechat_config_read (); /* read configuration */
+ weechat_create_config_dirs (); /* create config directories */
+ gui_main_init (); /* init WeeChat interface */
+ fifo_create (); /* FIFO pipe for remote control */
+ if (weechat_session)
+ session_load (weechat_session); /* load previous session if asked */
+ weechat_welcome_message (); /* display WeeChat welcome message */
+#ifdef PLUGINS
+ plugin_init (auto_load_plugins); /* init plugin interface(s) */
+#endif
+
+ irc_server_auto_connect (auto_connect, /* auto-connect to servers */
+ server_cmd_line);
+
+ gui_main_loop (); /* WeeChat main loop */
+
+#ifdef PLUGINS
+ plugin_end (); /* end plugin interface(s) */
+#endif
+ irc_server_disconnect_all (); /* disconnect from all servers */
+ if (cfg_look_save_on_exit)
+ (void) config_write (NULL); /* save config file */
+ command_index_free (); /* free commands index */
+ irc_dcc_end (); /* remove all DCC */
+ irc_server_free_all (); /* free all servers */
+ gui_main_end (); /* shut down WeeChat GUI */
+ weechat_shutdown (EXIT_SUCCESS, 0); /* quit WeeChat (oh no, why?) */
+
+ return EXIT_SUCCESS; /* make C compiler happy */
+}
diff --git a/src/core/weechat.h b/src/core/weechat.h
new file mode 100644
index 000000000..34e95a50e
--- /dev/null
+++ b/src/core/weechat.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2003-2007 by FlashCode <flashcode@flashtux.org>
+ * See README for License detail, AUTHORS for developers list.
+ *
+ * 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 3 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, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef __WEECHAT_H
+#define __WEECHAT_H 1
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <sys/time.h>
+
+#ifdef HAVE_GNUTLS
+#include <gnutls/gnutls.h>
+#endif
+
+#include <locale.h>
+
+#if defined(ENABLE_NLS) && !defined(_)
+ #ifdef HAVE_LIBINTL_H
+ #include <libintl.h>
+ #else
+ #include "../../intl/libintl.h"
+ #endif
+ #define _(string) gettext(string)
+ #define NG_(single,plural,number) ngettext(single,plural,number)
+ #ifdef gettext_noop
+ #define N_(string) gettext_noop(string)
+ #else
+ #define N_(string) (string)
+ #endif
+#endif
+#if !defined(_)
+ #define _(string) (string)
+ #define NG_(single,plural,number) (plural)
+ #define N_(string) (string)
+#endif
+
+
+#define WEECHAT_COPYRIGHT_DATE "(c) 2003-2007"
+#define WEECHAT_WEBSITE "http://weechat.flashtux.org"
+
+#define WEECHAT_ERROR _("WeeChat Error:")
+#define WEECHAT_WARNING _("WeeChat Warning:")
+
+/* log file */
+
+#define WEECHAT_LOG_NAME "weechat.log"
+
+/* license */
+
+#define WEE_LICENSE \
+ PACKAGE_STRING " (c) Copyright 2003-2007, compiled on " __DATE__ " " __TIME__ \
+ "\nDeveloped by FlashCode <flashcode@flashtux.org> - " WEECHAT_WEBSITE "\n\n" \
+ "This program is free software; you can redistribute it and/or modify\n" \
+ "it under the terms of the GNU General Public License as published by\n" \
+ "the Free Software Foundation; either version 3 of the License, or\n" \
+ "(at your option) any later version.\n" \
+ "\n", \
+ \
+ "This program is distributed in the hope that it will be useful,\n" \
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" \
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" \
+ "GNU General Public License for more details.\n" \
+ "\n" \
+ "You should have received a copy of the GNU General Public License\n" \
+ "along with this program. If not, see <http://www.gnu.org/licenses/>.\n\n"
+
+/* directory separator, depending on OS */
+
+#ifdef _WIN32
+ #define DIR_SEPARATOR "\\"
+ #define DIR_SEPARATOR_CHAR '\\'
+#else
+ #define DIR_SEPARATOR "/"
+ #define DIR_SEPARATOR_CHAR '/'
+#endif
+
+/* some systems (like GNU/Hurd) doesn't define PATH_MAX */
+
+#ifndef PATH_MAX
+ #define PATH_MAX 4096
+#endif
+
+/* internal charset */
+
+#define WEECHAT_INTERNAL_CHARSET "UTF-8"
+
+/* global variables and functions */
+
+extern char *weechat_argv0;
+extern time_t weechat_start_time;
+extern int quit_weechat;
+extern char *weechat_home;
+extern char *local_charset;
+
+#ifdef HAVE_GNUTLS
+extern gnutls_certificate_credentials gnutls_xcred;
+#endif
+
+extern void weechat_dump (int);
+extern void weechat_shutdown (int, int);
+
+#endif /* weechat.h */