summaryrefslogtreecommitdiff
path: root/src/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/irc/CMakeLists.txt25
-rw-r--r--src/plugins/irc/Makefile.am31
-rw-r--r--src/plugins/irc/irc-channel.c469
-rw-r--r--src/plugins/irc/irc-commands.c514
-rw-r--r--src/plugins/irc/irc-dcc.c1939
-rw-r--r--src/plugins/irc/irc-display.c487
-rw-r--r--src/plugins/irc/irc-ignore.c440
-rw-r--r--src/plugins/irc/irc-mode.c316
-rw-r--r--src/plugins/irc/irc-nick.c454
-rw-r--r--src/plugins/irc/irc-recv.c5058
-rw-r--r--src/plugins/irc/irc-send.c2281
-rw-r--r--src/plugins/irc/irc-server.c2415
-rw-r--r--src/plugins/irc/irc.h613
13 files changed, 15042 insertions, 0 deletions
diff --git a/src/plugins/irc/CMakeLists.txt b/src/plugins/irc/CMakeLists.txt
new file mode 100644
index 000000000..1942e6ceb
--- /dev/null
+++ b/src/plugins/irc/CMakeLists.txt
@@ -0,0 +1,25 @@
+# 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_IRC_SRC irc.h irc-commands.c irc-send.c irc-recv.c irc-server.c
+irc-channel.c irc-nick.c irc-mode.c irc-dcc.c irc-ignore.c irc-display.c)
+
+CHECK_INCLUDE_FILES("regex.h" HAVE_REGEX_H)
+CHECK_FUNCTION_EXISTS(regexec HAVE_REGEXEC)
+CHECK_FUNCTION_EXISTS(uname HAVE_UNAME)
+
+INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR})
+ADD_LIBRARY(weechat_irc STATIC ${LIB_IRC_SRC})
diff --git a/src/plugins/irc/Makefile.am b/src/plugins/irc/Makefile.am
new file mode 100644
index 000000000..2670aca85
--- /dev/null
+++ b/src/plugins/irc/Makefile.am
@@ -0,0 +1,31 @@
+# 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_irc.a
+
+lib_weechat_irc_a_SOURCES = irc.h \
+ irc-commands.c \
+ irc-send.c \
+ irc-recv.c \
+ irc-server.c \
+ irc-channel.c \
+ irc-nick.c \
+ irc-mode.c \
+ irc-dcc.c \
+ irc-ignore.c \
+ irc-display.c
diff --git a/src/plugins/irc/irc-channel.c b/src/plugins/irc/irc-channel.c
new file mode 100644
index 000000000..ab5dfa63d
--- /dev/null
+++ b/src/plugins/irc/irc-channel.c
@@ -0,0 +1,469 @@
+/*
+ * 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/>.
+ */
+
+/* irc-channel.c: manages a chat (channel or private chat) */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "../../common/weechat.h"
+#include "irc.h"
+#include "../../common/log.h"
+#include "../../common/utf8.h"
+#include "../../common/util.h"
+#include "../../common/weeconfig.h"
+#include "../../gui/gui.h"
+
+
+/*
+ * irc_channel_new: allocate a new channel for a server and add it to the
+ * server queue
+ */
+
+t_irc_channel *
+irc_channel_new (t_irc_server *server, int channel_type, char *channel_name)
+{
+ t_irc_channel *new_channel;
+
+ /* alloc memory for new channel */
+ if ((new_channel = (t_irc_channel *) malloc (sizeof (t_irc_channel))) == NULL)
+ {
+ fprintf (stderr, _("%s cannot allocate new channel"), WEECHAT_ERROR);
+ return NULL;
+ }
+
+ /* initialize new channel */
+ new_channel->type = channel_type;
+ new_channel->dcc_chat = NULL;
+ new_channel->name = strdup (channel_name);
+ new_channel->topic = NULL;
+ new_channel->modes = NULL;
+ new_channel->limit = 0;
+ new_channel->key = NULL;
+ new_channel->nicks_count = 0;
+ new_channel->checking_away = 0;
+ new_channel->away_message = NULL;
+ new_channel->cycle = 0;
+ new_channel->close = 0;
+ new_channel->display_creation_date = 0;
+ new_channel->nick_completion_reset = 0;
+ new_channel->nicks = NULL;
+ new_channel->last_nick = NULL;
+ new_channel->buffer = NULL;
+ new_channel->nicks_speaking = NULL;
+ new_channel->last_nick_speaking = NULL;
+
+ /* add new channel to queue */
+ new_channel->prev_channel = server->last_channel;
+ new_channel->next_channel = NULL;
+ if (server->channels)
+ server->last_channel->next_channel = new_channel;
+ else
+ server->channels = new_channel;
+ server->last_channel = new_channel;
+
+ /* all is ok, return address of new channel */
+ return new_channel;
+}
+
+/*
+ * irc_channel_free: free a channel and remove it from channels queue
+ */
+
+void
+irc_channel_free (t_irc_server *server, t_irc_channel *channel)
+{
+ t_irc_channel *new_channels;
+
+ if (!server || !channel)
+ return;
+
+ /* close DCC CHAT */
+ if (channel->dcc_chat)
+ {
+ ((t_irc_dcc *)(channel->dcc_chat))->channel = NULL;
+ if (!IRC_DCC_ENDED(((t_irc_dcc *)(channel->dcc_chat))->status))
+ {
+ irc_dcc_close ((t_irc_dcc *)(channel->dcc_chat), IRC_DCC_ABORTED);
+ irc_dcc_redraw (1);
+ }
+ }
+
+ /* remove channel from queue */
+ if (server->last_channel == channel)
+ server->last_channel = channel->prev_channel;
+ if (channel->prev_channel)
+ {
+ (channel->prev_channel)->next_channel = channel->next_channel;
+ new_channels = server->channels;
+ }
+ else
+ new_channels = channel->next_channel;
+
+ if (channel->next_channel)
+ (channel->next_channel)->prev_channel = channel->prev_channel;
+
+ /* free data */
+ if (channel->name)
+ free (channel->name);
+ if (channel->topic)
+ free (channel->topic);
+ if (channel->modes)
+ free (channel->modes);
+ if (channel->key)
+ free (channel->key);
+ irc_nick_free_all (channel);
+ if (channel->away_message)
+ free (channel->away_message);
+ if (channel->nicks_speaking)
+ weelist_remove_all (&(channel->nicks_speaking),
+ &(channel->last_nick_speaking));
+ free (channel);
+ server->channels = new_channels;
+}
+
+/*
+ * irc_channel_free_all: free all allocated channels
+ */
+
+void
+irc_channel_free_all (t_irc_server *server)
+{
+ /* remove all channels for the server */
+ while (server->channels)
+ irc_channel_free (server, server->channels);
+}
+
+/*
+ * irc_channel_search: returns pointer on a channel with name
+ * WARNING: DCC chat channels are not returned by this function
+ */
+
+t_irc_channel *
+irc_channel_search (t_irc_server *server, char *channel_name)
+{
+ t_irc_channel *ptr_channel;
+
+ if (!server || !channel_name)
+ return NULL;
+
+ for (ptr_channel = server->channels; ptr_channel;
+ ptr_channel = ptr_channel->next_channel)
+ {
+ if ((ptr_channel->type != IRC_CHANNEL_TYPE_DCC_CHAT)
+ && (ascii_strcasecmp (ptr_channel->name, channel_name) == 0))
+ return ptr_channel;
+ }
+ return NULL;
+}
+
+/*
+ * irc_channel_search_any: returns pointer on a channel with name
+ */
+
+t_irc_channel *
+irc_channel_search_any (t_irc_server *server, char *channel_name)
+{
+ t_irc_channel *ptr_channel;
+
+ if (!server || !channel_name)
+ return NULL;
+
+ for (ptr_channel = server->channels; ptr_channel;
+ ptr_channel = ptr_channel->next_channel)
+ {
+ if (ascii_strcasecmp (ptr_channel->name, channel_name) == 0)
+ return ptr_channel;
+ }
+ return NULL;
+}
+
+/*
+ * irc_channel_search_any_without_buffer: returns pointer on a channel with name
+ * looks only for channels without buffer
+ */
+
+t_irc_channel *
+irc_channel_search_any_without_buffer (t_irc_server *server, char *channel_name)
+{
+ t_irc_channel *ptr_channel;
+
+ if (!server || !channel_name)
+ return NULL;
+
+ for (ptr_channel = server->channels; ptr_channel;
+ ptr_channel = ptr_channel->next_channel)
+ {
+ if (!ptr_channel->buffer
+ && (ascii_strcasecmp (ptr_channel->name, channel_name) == 0))
+ return ptr_channel;
+ }
+ return NULL;
+}
+
+/*
+ * irc_channel_search_dcc: returns pointer on a DCC chat channel with name
+ */
+
+t_irc_channel *
+irc_channel_search_dcc (t_irc_server *server, char *channel_name)
+{
+ t_irc_channel *ptr_channel;
+
+ if (!server || !channel_name)
+ return NULL;
+
+ for (ptr_channel = server->channels; ptr_channel;
+ ptr_channel = ptr_channel->next_channel)
+ {
+ if ((ptr_channel->type == IRC_CHANNEL_TYPE_DCC_CHAT)
+ && (ascii_strcasecmp (ptr_channel->name, channel_name) == 0))
+ return ptr_channel;
+ }
+ return NULL;
+}
+
+/*
+ * irc_channel_is_channel: returns 1 if string is channel
+ */
+
+int
+irc_channel_is_channel (char *string)
+{
+ char first_char[2];
+
+ if (!string)
+ return 0;
+
+ first_char[0] = string[0];
+ first_char[1] = '\0';
+ return (strpbrk (first_char, IRC_CHANNEL_PREFIX)) ? 1 : 0;
+}
+
+/*
+ * irc_channel_remove_away: remove away for all nicks on a channel
+ */
+
+void
+irc_channel_remove_away (t_irc_channel *channel)
+{
+ t_irc_nick *ptr_nick;
+
+ if (channel->type == IRC_CHANNEL_TYPE_CHANNEL)
+ {
+ for (ptr_nick = channel->nicks; ptr_nick; ptr_nick = ptr_nick->next_nick)
+ {
+ IRC_NICK_SET_FLAG(ptr_nick, 0, IRC_NICK_AWAY);
+ }
+ gui_nicklist_draw (channel->buffer, 0, 0);
+ }
+}
+
+/*
+ * irc_channel_check_away: check for away on a channel
+ */
+
+void
+irc_channel_check_away (t_irc_server *server, t_irc_channel *channel, int force)
+{
+ if (channel->type == IRC_CHANNEL_TYPE_CHANNEL)
+ {
+ if (force || (cfg_irc_away_check_max_nicks == 0) ||
+ (channel->nicks_count <= cfg_irc_away_check_max_nicks))
+ {
+ channel->checking_away++;
+ irc_server_sendf (server, "WHO %s", channel->name);
+ }
+ else
+ irc_channel_remove_away (channel);
+ }
+}
+
+/*
+ * irc_channel_set_away: set/unset away status for a channel
+ */
+
+void
+irc_channel_set_away (t_irc_channel *channel, char *nick, int is_away)
+{
+ t_irc_nick *ptr_nick;
+
+ if (channel->type == IRC_CHANNEL_TYPE_CHANNEL)
+ {
+ ptr_nick = irc_nick_search (channel, nick);
+ if (ptr_nick)
+ irc_nick_set_away (channel, ptr_nick, is_away);
+ }
+}
+
+/*
+ * irc_channel_create_dcc: create DCC CHAT channel
+ */
+
+int
+irc_channel_create_dcc (t_irc_dcc *ptr_dcc)
+{
+ t_irc_channel *ptr_channel;
+
+ ptr_channel = irc_channel_search_dcc (ptr_dcc->server, ptr_dcc->nick);
+ if (!ptr_channel)
+ {
+ ptr_channel = irc_channel_new (ptr_dcc->server,
+ IRC_CHANNEL_TYPE_DCC_CHAT,
+ ptr_dcc->nick);
+ if (!ptr_channel)
+ return 0;
+ gui_buffer_new (gui_current_window, ptr_dcc->server, ptr_channel,
+ GUI_BUFFER_TYPE_STANDARD, 0);
+ }
+
+ if (ptr_channel->dcc_chat &&
+ (!IRC_DCC_ENDED(((t_irc_dcc *)(ptr_channel->dcc_chat))->status)))
+ return 0;
+
+ ptr_channel->dcc_chat = ptr_dcc;
+ ptr_dcc->channel = ptr_channel;
+ gui_window_redraw_buffer (ptr_channel->buffer);
+ return 1;
+}
+
+/*
+ * irc_channel_get_notify_level: get channel notify level
+ */
+
+int
+irc_channel_get_notify_level (t_irc_server *server, t_irc_channel *channel)
+{
+ char *name, *pos, *pos2;
+ int server_default_notify, notify;
+
+ if ((!server) || (!channel))
+ return GUI_NOTIFY_LEVEL_DEFAULT;
+
+ if ((!server->notify_levels) || (!server->notify_levels[0]))
+ return GUI_NOTIFY_LEVEL_DEFAULT;
+
+ server_default_notify = irc_server_get_default_notify_level (server);
+ if ((channel->type != IRC_CHANNEL_TYPE_CHANNEL)
+ && (server_default_notify == 1))
+ server_default_notify = 2;
+
+ name = (char *) malloc (strlen (channel->name) + 2);
+ strcpy (name, channel->name);
+ strcat (name, ":");
+ pos = strstr (server->notify_levels, name);
+ free (name);
+ if (!pos)
+ return server_default_notify;
+
+ pos2 = pos + strlen (channel->name);
+ if (pos2[0] != ':')
+ return server_default_notify;
+ pos2++;
+ if (!pos2[0])
+ return server_default_notify;
+
+ notify = (int)(pos2[0] - '0');
+ if ((notify >= GUI_NOTIFY_LEVEL_MIN) && (notify <= GUI_NOTIFY_LEVEL_MAX))
+ return notify;
+
+ return server_default_notify;
+}
+
+/*
+ * irc_channel_set_notify_level: set channel notify level
+ */
+
+void
+irc_channel_set_notify_level (t_irc_server *server, t_irc_channel *channel,
+ int notify)
+{
+ char level_string[2];
+
+ if ((!server) || (!channel))
+ return;
+
+ level_string[0] = notify + '0';
+ level_string[1] = '\0';
+ config_option_list_set (&(server->notify_levels), channel->name, level_string);
+}
+
+/*
+ * irc_channel_add_nick_speaking: add a nick speaking on a channel
+ */
+
+void
+irc_channel_add_nick_speaking (t_irc_channel *channel, char *nick)
+{
+ int size, to_remove, i;
+
+ weelist_add (&(channel->nicks_speaking), &(channel->last_nick_speaking),
+ nick, WEELIST_POS_END);
+
+ size = weelist_get_size (channel->nicks_speaking);
+ if (size > IRC_CHANNEL_NICKS_SPEAKING_LIMIT)
+ {
+ to_remove = size - IRC_CHANNEL_NICKS_SPEAKING_LIMIT;
+ for (i = 0; i < to_remove; i++)
+ {
+ weelist_remove (&(channel->nicks_speaking),
+ &(channel->last_nick_speaking),
+ channel->nicks_speaking);
+ }
+ }
+}
+
+/*
+ * irc_channel_print_log: print channel infos in log (usually for crash dump)
+ */
+
+void
+irc_channel_print_log (t_irc_channel *channel)
+{
+ weechat_log_printf ("=> channel %s (addr:0x%X)]\n", channel->name, channel);
+ weechat_log_printf (" type . . . . . . . . : %d\n", channel->type);
+ weechat_log_printf (" dcc_chat . . . . . . : 0x%X\n", channel->dcc_chat);
+ weechat_log_printf (" topic. . . . . . . . : '%s'\n", channel->topic);
+ weechat_log_printf (" modes. . . . . . . . : '%s'\n", channel->modes);
+ weechat_log_printf (" limit. . . . . . . . : %d\n", channel->limit);
+ weechat_log_printf (" key. . . . . . . . . : '%s'\n", channel->key);
+ weechat_log_printf (" checking_away. . . . : %d\n", channel->checking_away);
+ weechat_log_printf (" away_message . . . . : '%s'\n", channel->away_message);
+ weechat_log_printf (" cycle. . . . . . . . : %d\n", channel->cycle);
+ weechat_log_printf (" close. . . . . . . . : %d\n", channel->close);
+ weechat_log_printf (" display_creation_date: %d\n", channel->close);
+ weechat_log_printf (" nicks. . . . . . . . : 0x%X\n", channel->nicks);
+ weechat_log_printf (" last_nick. . . . . . : 0x%X\n", channel->last_nick);
+ weechat_log_printf (" buffer . . . . . . . : 0x%X\n", channel->buffer);
+ weechat_log_printf (" nicks_speaking . . . : 0x%X\n", channel->nicks_speaking);
+ weechat_log_printf (" last_nick_speaking . : 0x%X\n", channel->last_nick_speaking);
+ weechat_log_printf (" prev_channel . . . . : 0x%X\n", channel->prev_channel);
+ weechat_log_printf (" next_channel . . . . : 0x%X\n", channel->next_channel);
+ if (channel->nicks_speaking)
+ {
+ weechat_log_printf ("\n");
+ weelist_print_log (channel->nicks_speaking,
+ "channel nick speaking element");
+ }
+}
diff --git a/src/plugins/irc/irc-commands.c b/src/plugins/irc/irc-commands.c
new file mode 100644
index 000000000..762008dd8
--- /dev/null
+++ b/src/plugins/irc/irc-commands.c
@@ -0,0 +1,514 @@
+/*
+ * 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/>.
+ */
+
+/* irc-commands.c: implementation of IRC commands, according to
+ RFC 1459,2810,2811,2812 */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "../../common/weechat.h"
+#include "irc.h"
+#include "../../common/command.h"
+
+
+t_irc_command irc_commands[] =
+{ { "admin", N_("find information about the administrator of the server"),
+ N_("[target]"),
+ N_("target: server"),
+ NULL, 0, 1, 0, 1, NULL, irc_send_cmd_admin, NULL },
+ { "ame", N_("send a CTCP action to all channels of all connected servers"),
+ N_("message"),
+ N_("message: message to send"),
+ "", 1, MAX_ARGS, 1, 1, NULL, irc_send_cmd_ame, NULL },
+ { "amsg", N_("send message to all channels of all connected servers"),
+ N_("text"),
+ N_("text: text to send"),
+ "", 1, MAX_ARGS, 1, 1, NULL, irc_send_cmd_amsg, NULL },
+ { "away", N_("toggle away status"),
+ N_("[-all] [message]"),
+ N_(" -all: toggle away status on all connected servers\n"
+ "message: message for away (if no message is given, away status is removed)"),
+ "-all", 0, MAX_ARGS, 1, 0, NULL, irc_send_cmd_away, NULL },
+ { "ban", N_("bans nicks or hosts"),
+ N_("[channel] [nickname [nickname ...]]"),
+ N_(" channel: channel for ban\n"
+ "nickname: user or host to ban"),
+ "%N", 0, MAX_ARGS, 0, 1, NULL, irc_send_cmd_ban, NULL },
+ { "ctcp", N_("send a CTCP message (Client-To-Client Protocol)"),
+ N_("receiver type [arguments]"),
+ N_(" receiver: nick or channel to send CTCP to\n"
+ " type: CTCP type (examples: \"version\", \"ping\", ..)\n"
+ "arguments: arguments for CTCP"),
+ "%c|%n action|ping|version", 2, MAX_ARGS, 1, 1, NULL, irc_send_cmd_ctcp, NULL },
+ { "cycle", N_("leave and rejoin a channel"),
+ N_("[channel[,channel]] [part_message]"),
+ N_(" channel: channel name for cycle\n"
+ "part_message: part message (displayed to other users)"),
+ "%p", 0, MAX_ARGS, 0, 1, NULL, irc_send_cmd_cycle, NULL },
+ { "dehalfop", N_("removes half channel operator status from nickname(s)"),
+ N_("[nickname [nickname]]"), "",
+ "", 0, MAX_ARGS, 0, 1, irc_send_cmd_dehalfop, NULL, NULL },
+ { "deop", N_("removes channel operator status from nickname(s)"),
+ N_("[nickname [nickname]]"), "",
+ "", 0, MAX_ARGS, 0, 1, irc_send_cmd_deop, NULL, NULL },
+ { "devoice", N_("removes voice from nickname(s)"),
+ N_("[nickname [nickname]]"), "",
+ "", 0, MAX_ARGS, 0, 1, irc_send_cmd_devoice, NULL, NULL },
+ { "die", N_("shutdown the server"), "", "",
+ NULL, 0, 0, 0, 1, NULL, irc_send_cmd_die, NULL },
+ { "error", N_("error received from IRC server"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_error },
+ { "halfop", N_("gives half channel operator status to nickname(s)"),
+ N_("[nickname [nickname]]"), "",
+ "", 0, MAX_ARGS, 0, 1, irc_send_cmd_halfop, NULL, NULL },
+ { "info", N_("get information describing the server"),
+ N_("[target]"),
+ N_("target: server name"),
+ NULL, 0, 1, 0, 1, NULL, irc_send_cmd_info, NULL },
+ { "invite", N_("invite a nick on a channel"),
+ N_("nickname channel"),
+ N_("nickname: nick to invite\n"
+ " channel: channel to invite"),
+ "%n %c", 1, 2, 0, 1, irc_send_cmd_invite, NULL, irc_recv_cmd_invite },
+ { "ison", N_("check if a nickname is currently on IRC"),
+ N_("nickname [nickname ...]"),
+ N_("nickname: nickname"),
+ "", 1, MAX_ARGS, 0, 1, NULL, irc_send_cmd_ison, NULL },
+ { "join", N_("join a channel"),
+ N_("channel[,channel] [key[,key]]"),
+ N_("channel: channel name to join\n"
+ " key: key to join the channel"),
+ "%C", 1, MAX_ARGS, 0, 1, NULL, irc_send_cmd_join, irc_recv_cmd_join },
+ { "kick", N_("forcibly remove a user from a channel"),
+ N_("[channel] nickname [comment]"),
+ N_(" channel: channel where user is\n"
+ "nickname: nickname to kick\n"
+ " comment: comment for kick"),
+ "%n %-", 1, MAX_ARGS, 0, 1, NULL, irc_send_cmd_kick, irc_recv_cmd_kick },
+ { "kickban", N_("kicks and bans a nick from a channel"),
+ N_("[channel] nickname [comment]"),
+ N_(" channel: channel where user is\n"
+ "nickname: nickname to kick and ban\n"
+ " comment: comment for kick"),
+ "%n %-", 1, MAX_ARGS, 0, 1, NULL, irc_send_cmd_kickban, NULL },
+ { "kill", N_("close client-server connection"),
+ N_("nickname comment"),
+ N_("nickname: nickname\n"
+ " comment: comment for kill"),
+ "%n %-", 2, MAX_ARGS, 0, 1, NULL, irc_send_cmd_kill, irc_recv_cmd_kill },
+ { "links", N_("list all servernames which are known by the server answering the query"),
+ N_("[[server] server_mask]"),
+ N_(" server: this server should answer the query\n"
+ "server_mask: list of servers must match this mask"),
+ NULL, 0, 2, 0, 1, NULL, irc_send_cmd_links, NULL },
+ { "list", N_("list channels and their topic"),
+ N_("[channel[,channel] [server]]"),
+ N_("channel: channel to list (a regexp is allowed)\nserver: server name"),
+ NULL, 0, MAX_ARGS, 0, 1, NULL, irc_send_cmd_list, NULL },
+ { "lusers", N_("get statistics about the size of the IRC network"),
+ N_("[mask [target]]"),
+ N_(" mask: servers matching the mask only\n"
+ "target: server for forwarding request"),
+ NULL, 0, 2, 0, 1, NULL, irc_send_cmd_lusers, NULL },
+ { "me", N_("send a CTCP action to the current channel"),
+ N_("message"),
+ N_("message: message to send"),
+ "", 0, MAX_ARGS, 1, 1, NULL, irc_send_cmd_me, NULL },
+ { "mode", N_("change channel or user mode"),
+ N_("{ channel {[+|-]|o|p|s|i|t|n|b|v} [limit] [user] [ban mask] } | "
+ "{ nickname {[+|-]|i|w|s|o} }"),
+ N_("channel modes:\n"
+ " channel: channel name to modify\n"
+ " o: give/take channel operator privileges\n"
+ " p: private channel flag\n"
+ " s: secret channel flag\n"
+ " i: invite-only channel flag\n"
+ " t: topic settable by channel operator only flag\n"
+ " n: no messages to channel from clients on the outside\n"
+ " m: moderated channel\n"
+ " l: set the user limit to channel\n"
+ " b: set a ban mask to keep users out\n"
+ " e: set exception mask\n"
+ " v: give/take the ability to speak on a moderated channel\n"
+ " k: set a channel key (password)\n"
+ "user modes:\n"
+ " nickname: nickname to modify\n"
+ " i: mark a user as invisible\n"
+ " s: mark a user for receive server notices\n"
+ " w: user receives wallops\n"
+ " o: operator flag"),
+ "%c|%m", 1, MAX_ARGS, 0, 1, NULL, irc_send_cmd_mode, irc_recv_cmd_mode },
+ { "motd", N_("get the \"Message Of The Day\""),
+ N_("[target]"),
+ N_("target: server name"),
+ NULL, 0, 1, 0, 1, NULL, irc_send_cmd_motd, NULL },
+ { "msg", N_("send message to a nick or channel"),
+ N_("receiver[,receiver] text"),
+ N_("receiver: nick or channel (may be mask, '*' = current channel)\n"
+ "text: text to send"),
+ "", 2, MAX_ARGS, 1, 1, NULL, irc_send_cmd_msg, NULL },
+ { "names", N_("list nicknames on channels"),
+ N_("[channel[,channel]]"),
+ N_("channel: channel name"),
+ NULL, 0, 1, 0, 1, NULL, irc_send_cmd_names, NULL },
+ { "nick", N_("change current nickname"),
+ N_("[-all] nickname"),
+ N_(" -all: set new nickname for all connected servers\n"
+ "nickname: new nickname"),
+ "-all", 1, 2, 0, 0, irc_send_cmd_nick, NULL, irc_recv_cmd_nick },
+ { "notice", N_("send notice message to user"),
+ N_("nickname text"),
+ N_("nickname: user to send notice to\n"
+ " text: text to send"),
+ "%n %-", 2, MAX_ARGS, 1, 1, NULL, irc_send_cmd_notice, irc_recv_cmd_notice },
+ { "op", N_("gives channel operator status to nickname(s)"),
+ N_("nickname [nickname]"), "",
+ "", 1, MAX_ARGS, 0, 1, irc_send_cmd_op, NULL, NULL },
+ { "oper", N_("get operator privileges"),
+ N_("user password"),
+ N_("user/password: used to get privileges on current IRC server"),
+ NULL, 2, 2, 0, 1, NULL, irc_send_cmd_oper, NULL },
+ { "part", N_("leave a channel"),
+ N_("[channel[,channel]] [part_message]"),
+ N_(" channel: channel name to leave\n"
+ "part_message: part message (displayed to other users)"),
+ "%p", 0, MAX_ARGS, 0, 1, NULL, irc_send_cmd_part, irc_recv_cmd_part },
+ { "ping", N_("ping server"),
+ N_("server1 [server2]"),
+ N_("server1: server to ping\nserver2: forward ping to this server"),
+ NULL, 1, 2, 0, 1, NULL, irc_send_cmd_ping, irc_recv_cmd_ping },
+ { "pong", N_("answer to a ping message"),
+ N_("daemon [daemon2]"),
+ N_(" daemon: daemon who has responded to Ping message\n"
+ "daemon2: forward message to this daemon"),
+ NULL, 1, 2, 0, 1, NULL, irc_send_cmd_pong, irc_recv_cmd_pong },
+ { "privmsg", N_("message received"), "", "",
+ "", 0, 0, 1, 1, NULL, NULL, irc_recv_cmd_privmsg },
+ { "query", N_("send a private message to a nick"),
+ N_("nickname [text]"),
+ N_("nickname: nickname for private conversation\n"
+ " text: text to send"),
+ "%n %-", 1, MAX_ARGS, 1, 1, NULL, irc_send_cmd_query, NULL },
+ { "quit", N_("close all connections and quit"),
+ N_("[quit_message]"),
+ N_("quit_message: quit message (displayed to other users)"),
+ "%q", 0, MAX_ARGS, 1, 0, NULL, irc_send_cmd_quit, irc_recv_cmd_quit },
+ { "quote", N_("send raw data to server without parsing"),
+ N_("data"),
+ N_("data: raw data to send"),
+ "", 1, MAX_ARGS, 1, 0, NULL, irc_send_cmd_quote, NULL },
+ { "rehash", N_("tell the server to reload its config file"), "", "",
+ NULL, 0, 0, 0, 1, NULL, irc_send_cmd_rehash, NULL },
+ { "restart", N_("tell the server to restart itself"), "", "",
+ NULL, 0, 0, 0, 1, NULL, irc_send_cmd_restart, NULL },
+ { "service", N_("register a new service"),
+ N_("nickname reserved distribution type reserved info"),
+ N_("distribution: visibility of service\n"
+ " type: reserved for future usage"),
+ NULL, 6, 6, 0, 1, NULL, irc_send_cmd_service, NULL },
+ { "servlist", N_("list services currently connected to the network"),
+ N_("[mask [type]]"),
+ N_("mask: list only services matching this mask\n"
+ "type: list only services of this type"),
+ NULL, 0, 2, 0, 1, NULL, irc_send_cmd_servlist, NULL },
+ { "squery", N_("deliver a message to a service"),
+ N_("service text"),
+ N_("service: name of service\ntext: text to send"),
+ NULL, 2, MAX_ARGS, 1, 1, NULL, irc_send_cmd_squery, NULL },
+ { "squit", N_("disconnect server links"),
+ N_("server comment"),
+ N_( "server: server name\n"
+ "comment: comment for quit"),
+ NULL, 2, 2, 1, 1, NULL, irc_send_cmd_squit, NULL },
+ { "stats", N_("query statistics about server"),
+ N_("[query [server]]"),
+ N_(" query: c/h/i/k/l/m/o/y/u (see RFC1459)\n"
+ "server: server name"),
+ NULL, 0, 2, 0, 1, NULL, irc_send_cmd_stats, NULL },
+ { "summon", N_("give users who are on a host running an IRC server a message "
+ "asking them to please join IRC"),
+ N_("user [target [channel]]"),
+ N_(" user: username\ntarget: server name\n"
+ "channel: channel name"),
+ NULL, 1, 3, 0, 1, NULL, irc_send_cmd_summon, NULL },
+ { "time", N_("query local time from server"),
+ N_("[target]"),
+ N_("target: query time from specified server"),
+ NULL, 0, 1, 0, 1, NULL, irc_send_cmd_time, NULL },
+ { "topic", N_("get/set channel topic"),
+ N_("[channel] [topic]"),
+ N_("channel: channel name\ntopic: new topic for channel "
+ "(if topic is \"-delete\" then topic is deleted)"),
+ "%t|-delete %-", 0, MAX_ARGS, 1, 1, NULL, irc_send_cmd_topic, irc_recv_cmd_topic },
+ { "trace", N_("find the route to specific server"),
+ N_("[target]"),
+ N_("target: server"),
+ NULL, 0, 1, 0, 1, NULL, irc_send_cmd_trace, NULL },
+ { "unban", N_("unbans nicks or hosts"),
+ N_("[channel] nickname [nickname ...]"),
+ N_(" channel: channel for unban\n"
+ "nickname: user or host to unban"),
+ "", 1, MAX_ARGS, 0, 1, NULL, irc_send_cmd_unban, NULL },
+ { "userhost", N_("return a list of information about nicknames"),
+ N_("nickname [nickname ...]"),
+ N_("nickname: nickname"),
+ "%n", 1, MAX_ARGS, 0, 1, NULL, irc_send_cmd_userhost, NULL },
+ { "users", N_("list of users logged into the server"),
+ N_("[target]"),
+ N_("target: server"),
+ NULL, 0, 1, 0, 1, NULL, irc_send_cmd_users, NULL },
+ { "version", N_("gives the version info of nick or server (current or specified)"),
+ N_("[server | nickname]"),
+ N_(" server: server name\n"
+ "nickname: nickname"),
+ NULL, 0, 1, 0, 1, NULL, irc_send_cmd_version, NULL },
+ { "voice", N_("gives voice to nickname(s)"),
+ N_("[nickname [nickname]]"), "",
+ "", 0, MAX_ARGS, 0, 1, irc_send_cmd_voice, NULL, NULL },
+ { "wallops", N_("send a message to all currently connected users who have "
+ "set the 'w' user mode for themselves"),
+ N_("text"),
+ N_("text to send"),
+ NULL, 1, MAX_ARGS, 1, 1, NULL, irc_send_cmd_wallops, irc_recv_cmd_wallops },
+ { "who", N_("generate a query which returns a list of information"),
+ N_("[mask [\"o\"]]"),
+ N_("mask: only information which match this mask\n"
+ " o: only operators are returned according to the mask supplied"),
+ "%C", 0, 2, 0, 1, NULL, irc_send_cmd_who, NULL },
+ { "whois", N_("query information about user(s)"),
+ N_("[server] nickname[,nickname]"),
+ N_(" server: server name\n"
+ "nickname: nickname (may be a mask)"),
+ "", 1, MAX_ARGS, 0, 1, NULL, irc_send_cmd_whois, NULL },
+ { "whowas", N_("ask for information about a nickname which no longer exists"),
+ N_("nickname [,nickname [,nickname ...]] [count [target]]"),
+ N_("nickname: nickname to search\n"
+ " count: number of replies to return (full search if negative number)\n"
+ " target: reply should match this mask"),
+ "", 1, MAX_ARGS, 0, 1, NULL, irc_send_cmd_whowas, NULL },
+ { "001", N_("a server message"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_001 },
+ { "005", N_("a server message"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_005 },
+ { "221", N_("user mode string"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_221 },
+ { "301", N_("away message"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_301 },
+ { "302", N_("userhost"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_302 },
+ { "303", N_("ison"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_303 },
+ { "305", N_("unaway"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_305 },
+ { "306", N_("now away"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_306 },
+ { "307", N_("whois (registered nick)"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_whois_nick_msg },
+ { "310", N_("whois (help mode)"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_310 },
+ { "311", N_("whois (user)"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_311 },
+ { "312", N_("whois (server)"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_312 },
+ { "313", N_("whois (operator)"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_whois_nick_msg },
+ { "314", N_("whowas"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_314 },
+ { "315", N_("end of /who list"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_315 },
+ { "317", N_("whois (idle)"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_317 },
+ { "318", N_("whois (end)"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_whois_nick_msg },
+ { "319", N_("whois (channels)"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_319 },
+ { "320", N_("whois (identified user)"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_whois_nick_msg },
+ { "321", N_("/list start"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_321 },
+ { "322", N_("channel (for /list)"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_322 },
+ { "323", N_("/list end"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_323 },
+ { "324", N_("channel mode"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_324 },
+ { "326", N_("whois (has oper privs)"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_whois_nick_msg },
+ { "327", N_("whois (host)"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_327 },
+ { "329", N_("channel creation date"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_329 },
+ { "331", N_("no topic for channel"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_331 },
+ { "332", N_("topic of channel"),
+ N_("channel :topic"),
+ N_("channel: name of channel\n"
+ " topic: topic of the channel"),
+ NULL, 2, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_332 },
+ { "333", N_("infos about topic (nick and date changed)"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_333 },
+ { "338", N_("whois (host)"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_338 },
+ { "341", N_("inviting"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_341 },
+ { "344", N_("channel reop"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_344 },
+ { "345", N_("end of channel reop list"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_345 },
+ { "348", N_("channel exception list"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_348 },
+ { "349", N_("end of channel exception list"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_349 },
+ { "351", N_("server version"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_351 },
+ { "352", N_("who"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_352 },
+ { "353", N_("list of nicks on channel"),
+ N_("channel :[[@|+]nick ...]"),
+ N_("channel: name of channel\n"
+ " nick: nick on the channel"),
+ NULL, 2, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_353 },
+ { "366", N_("end of /names list"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_366 },
+ { "367", N_("banlist"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_367 },
+ { "368", N_("end of banlist"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_368 },
+ { "378", N_("whois (connecting from)"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_whois_nick_msg },
+ { "379", N_("whois (using modes)"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_whois_nick_msg },
+ { "401", N_("no such nick/channel"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "402", N_("no such server"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "403", N_("no such channel"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "404", N_("cannot send to channel"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "405", N_("too many channels"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "406", N_("was no such nick"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "407", N_("was no such nick"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "409", N_("no origin"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "410", N_("no services"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "411", N_("no recipient"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "412", N_("no text to send"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "413", N_("no toplevel"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "414", N_("wilcard in toplevel domain"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "421", N_("unknown command"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "422", N_("MOTD is missing"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "423", N_("no administrative info"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "424", N_("file error"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "431", N_("no nickname given"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "432", N_("erroneous nickname"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_432 },
+ { "433", N_("nickname already in use"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_433 },
+ { "436", N_("nickname collision"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "437", N_("resource unavailable"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "438", N_("not authorized to change nickname"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_438 },
+ { "441", N_("user not in channel"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "442", N_("not on channel"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "443", N_("user already on channel"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "444", N_("user not logged in"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "445", N_("summon has been disabled"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "446", N_("users has been disabled"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "451", N_("you are not registered"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "461", N_("not enough parameters"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "462", N_("you may not register"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "463", N_("your host isn't among the privileged"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "464", N_("password incorrect"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "465", N_("you are banned from this server"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "467", N_("channel key already set"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "470", N_("forwarding to another channel"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "471", N_("channel is already full"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "472", N_("unknown mode char to me"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "473", N_("cannot join channel (invite only)"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "474", N_("cannot join channel (banned from channel)"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "475", N_("cannot join channel (bad channel key)"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "476", N_("bad channel mask"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "477", N_("channel doesn't support modes"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "481", N_("you're not an IRC operator"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "482", N_("you're not channel operator"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "483", N_("you can't kill a server!"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "484", N_("your connection is restricted!"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "485", N_("user is immune from kick/deop"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "487", N_("network split"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "491", N_("no O-lines for your host"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "501", N_("unknown mode flag"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "502", N_("can't change mode for other users"), "", "",
+ NULL, 0, 0, MAX_ARGS, 1, NULL, NULL, irc_recv_cmd_error },
+ { "671", N_("whois (secure connection)"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_671 },
+ { "973", N_("whois (secure connection)"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_server_mode_reason },
+ { "974", N_("whois (secure connection)"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_server_mode_reason },
+ { "975", N_("whois (secure connection)"), "", "",
+ NULL, 0, 0, 0, 1, NULL, NULL, irc_recv_cmd_server_mode_reason },
+ { NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 1, NULL, NULL, NULL }
+};
diff --git a/src/plugins/irc/irc-dcc.c b/src/plugins/irc/irc-dcc.c
new file mode 100644
index 000000000..6580b7110
--- /dev/null
+++ b/src/plugins/irc/irc-dcc.c
@@ -0,0 +1,1939 @@
+/*
+ * 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/>.
+ */
+
+/* irc-dcc.c: Direct Client-to-Client (DCC) communication (files & chat) */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <time.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include "../../common/weechat.h"
+#include "irc.h"
+#include "../../common/log.h"
+#include "../../common/hotlist.h"
+#include "../../common/util.h"
+#include "../../common/weeconfig.h"
+#include "../../gui/gui.h"
+
+
+t_irc_dcc *irc_dcc_list = NULL; /* DCC files & chat list */
+t_irc_dcc *irc_last_dcc = NULL; /* last DCC in list */
+char *irc_dcc_status_string[] = /* strings for DCC status */
+{ N_("Waiting"), N_("Connecting"), N_("Active"), N_("Done"), N_("Failed"),
+ N_("Aborted") };
+
+
+/*
+ * irc_dcc_redraw: redraw DCC buffer (and add to hotlist)
+ */
+
+void
+irc_dcc_redraw (int highlight)
+{
+ t_gui_buffer *ptr_buffer;
+
+ ptr_buffer = gui_buffer_get_dcc (gui_current_window);
+ gui_window_redraw_buffer (ptr_buffer);
+ if (highlight && gui_add_hotlist && (ptr_buffer->num_displayed == 0))
+ {
+ hotlist_add (highlight, NULL, NULL, ptr_buffer, 0);
+ gui_status_draw (gui_current_window->buffer, 0);
+ }
+}
+
+/*
+ * irc_dcc_search: search a DCC
+ */
+
+t_irc_dcc *
+irc_dcc_search (t_irc_server *server, int type, int status, int port)
+{
+ t_irc_dcc *ptr_dcc;
+
+ for (ptr_dcc = irc_dcc_list; ptr_dcc; ptr_dcc = ptr_dcc->next_dcc)
+ {
+ if ((ptr_dcc->server == server)
+ && (ptr_dcc->type == type)
+ && (ptr_dcc->status = status)
+ && (ptr_dcc->port == port))
+ return ptr_dcc;
+ }
+
+ /* DCC not found */
+ return NULL;
+}
+
+/*
+ * irc_dcc_port_in_use: return 1 if a port is in used
+ * (by an active or connecting DCC)
+ */
+
+int
+irc_dcc_port_in_use (int port)
+{
+ t_irc_dcc *ptr_dcc;
+
+ /* skip any currently used ports */
+ for (ptr_dcc = irc_dcc_list; ptr_dcc; ptr_dcc = ptr_dcc->next_dcc)
+ {
+ if ((ptr_dcc->port == port) && (!IRC_DCC_ENDED(ptr_dcc->status)))
+ return 1;
+ }
+
+ /* port not in use */
+ return 0;
+}
+
+/*
+ * irc_dcc_file_is_resumable: check if a file can be used for resuming a download
+ */
+
+int
+irc_dcc_file_is_resumable (t_irc_dcc *ptr_dcc, char *filename)
+{
+ struct stat st;
+
+ if (!cfg_dcc_auto_resume)
+ return 0;
+
+ if (access (filename, W_OK) == 0)
+ {
+ if (stat (filename, &st) != -1)
+ {
+ if ((unsigned long) st.st_size < ptr_dcc->size)
+ {
+ ptr_dcc->start_resume = (unsigned long) st.st_size;
+ ptr_dcc->pos = st.st_size;
+ ptr_dcc->last_check_pos = st.st_size;
+ return 1;
+ }
+ }
+ }
+
+ /* not resumable */
+ return 0;
+}
+
+/*
+ * irc_dcc_find_filename: find local filename for a DCC
+ * if type if file/recv, add a suffix (like .1) if needed
+ * if download is resumable, set "start_resume" to good value
+ */
+
+void
+irc_dcc_find_filename (t_irc_dcc *ptr_dcc)
+{
+ char *dir1, *dir2, *filename2;
+
+ if (!IRC_DCC_IS_FILE(ptr_dcc->type))
+ return;
+
+ dir1 = weechat_strreplace (cfg_dcc_download_path, "~", getenv ("HOME"));
+ if (!dir1)
+ return;
+ dir2 = weechat_strreplace (dir1, "%h", weechat_home);
+ if (!dir2)
+ {
+ free (dir1);
+ return;
+ }
+
+ ptr_dcc->local_filename = (char *) malloc (strlen (dir2) +
+ strlen (ptr_dcc->nick) +
+ strlen (ptr_dcc->filename) + 4);
+ if (!ptr_dcc->local_filename)
+ return;
+
+ strcpy (ptr_dcc->local_filename, dir2);
+ if (ptr_dcc->local_filename[strlen (ptr_dcc->local_filename) - 1] != DIR_SEPARATOR_CHAR)
+ strcat (ptr_dcc->local_filename, DIR_SEPARATOR);
+ strcat (ptr_dcc->local_filename, ptr_dcc->nick);
+ strcat (ptr_dcc->local_filename, ".");
+ strcat (ptr_dcc->local_filename, ptr_dcc->filename);
+
+ if (dir1)
+ free (dir1);
+ if (dir2 )
+ free (dir2);
+
+ /* file already exists? */
+ if (access (ptr_dcc->local_filename, F_OK) == 0)
+ {
+ if (irc_dcc_file_is_resumable (ptr_dcc, ptr_dcc->local_filename))
+ return;
+
+ /* if auto rename is not set, then abort DCC */
+ if (!cfg_dcc_auto_rename)
+ {
+ irc_dcc_close (ptr_dcc, IRC_DCC_FAILED);
+ irc_dcc_redraw (HOTLIST_MSG);
+ return;
+ }
+
+ filename2 = (char *) malloc (strlen (ptr_dcc->local_filename) + 16);
+ if (!filename2)
+ {
+ irc_dcc_close (ptr_dcc, IRC_DCC_FAILED);
+ irc_dcc_redraw (HOTLIST_MSG);
+ return;
+ }
+ ptr_dcc->filename_suffix = 0;
+ do
+ {
+ ptr_dcc->filename_suffix++;
+ sprintf (filename2, "%s.%d",
+ ptr_dcc->local_filename,
+ ptr_dcc->filename_suffix);
+ if (access (filename2, F_OK) == 0)
+ {
+ if (irc_dcc_file_is_resumable (ptr_dcc, filename2))
+ break;
+ }
+ else
+ break;
+ }
+ while (1);
+
+ free (ptr_dcc->local_filename);
+ ptr_dcc->local_filename = strdup (filename2);
+ free (filename2);
+ }
+}
+
+/*
+ * irc_dcc_calculate_speed: calculate DCC speed (for files only)
+ */
+
+void
+irc_dcc_calculate_speed (t_irc_dcc *ptr_dcc, int ended)
+{
+ time_t local_time, elapsed;
+ unsigned long bytes_per_sec_total;
+
+ local_time = time (NULL);
+ if (ended || local_time > ptr_dcc->last_check_time)
+ {
+ if (ended)
+ {
+ /* calculate bytes per second (global) */
+ elapsed = local_time - ptr_dcc->start_transfer;
+ if (elapsed == 0)
+ elapsed = 1;
+ ptr_dcc->bytes_per_sec = (ptr_dcc->pos - ptr_dcc->start_resume) / elapsed;
+ ptr_dcc->eta = 0;
+ }
+ else
+ {
+ /* calculate ETA */
+ elapsed = local_time - ptr_dcc->start_transfer;
+ if (elapsed == 0)
+ elapsed = 1;
+ bytes_per_sec_total = (ptr_dcc->pos - ptr_dcc->start_resume) / elapsed;
+ if (bytes_per_sec_total == 0)
+ bytes_per_sec_total = 1;
+ ptr_dcc->eta = (ptr_dcc->size - ptr_dcc->pos) / bytes_per_sec_total;
+
+ /* calculate bytes per second (since last check time) */
+ elapsed = local_time - ptr_dcc->last_check_time;
+ if (elapsed == 0)
+ elapsed = 1;
+ ptr_dcc->bytes_per_sec = (ptr_dcc->pos - ptr_dcc->last_check_pos) / elapsed;
+ }
+ ptr_dcc->last_check_time = local_time;
+ ptr_dcc->last_check_pos = ptr_dcc->pos;
+ }
+}
+
+/*
+ * irc_dcc_connect_to_sender: connect to sender
+ */
+
+int
+irc_dcc_connect_to_sender (t_irc_dcc *ptr_dcc)
+{
+ struct sockaddr_in addr;
+ struct hostent *hostent;
+ char *ip4;
+ int ret;
+
+ if (cfg_proxy_use)
+ {
+ memset (&addr, 0, sizeof (addr));
+ addr.sin_addr.s_addr = htonl (ptr_dcc->addr);
+ ip4 = inet_ntoa(addr.sin_addr);
+
+ memset (&addr, 0, sizeof (addr));
+ addr.sin_port = htons (cfg_proxy_port);
+ addr.sin_family = AF_INET;
+ if ((hostent = gethostbyname (cfg_proxy_address)) == NULL)
+ return 0;
+ memcpy(&(addr.sin_addr),*(hostent->h_addr_list), sizeof(struct in_addr));
+ ret = connect (ptr_dcc->sock, (struct sockaddr *) &addr, sizeof (addr));
+ if ((ret == -1) && (errno != EINPROGRESS))
+ return 0;
+ if (irc_server_pass_proxy (ptr_dcc->sock, ip4, ptr_dcc->port,
+ ptr_dcc->server->username) == -1)
+ return 0;
+ }
+ else
+ {
+ memset (&addr, 0, sizeof (addr));
+ addr.sin_port = htons (ptr_dcc->port);
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = htonl (ptr_dcc->addr);
+ ret = connect (ptr_dcc->sock, (struct sockaddr *) &addr, sizeof (addr));
+ if ((ret == -1) && (errno != EINPROGRESS))
+ return 0;
+ }
+ return 1;
+}
+
+/*
+ * irc_dcc_connect: connect to another host
+ */
+
+int
+irc_dcc_connect (t_irc_dcc *ptr_dcc)
+{
+ if (ptr_dcc->type == IRC_DCC_CHAT_SEND)
+ ptr_dcc->status = IRC_DCC_WAITING;
+ else
+ ptr_dcc->status = IRC_DCC_CONNECTING;
+
+ if (ptr_dcc->sock < 0)
+ {
+ ptr_dcc->sock = socket (AF_INET, SOCK_STREAM, 0);
+ if (ptr_dcc->sock < 0)
+ return 0;
+ }
+
+ /* for chat or file sending, listen to socket for a connection */
+ if (IRC_DCC_IS_SEND(ptr_dcc->type))
+ {
+ if (fcntl (ptr_dcc->sock, F_SETFL, O_NONBLOCK) == -1)
+ return 0;
+ if (listen (ptr_dcc->sock, 1) == -1)
+ return 0;
+ if (fcntl (ptr_dcc->sock, F_SETFL, 0) == -1)
+ return 0;
+ }
+
+ /* for chat receiving, connect to listening host */
+ if (ptr_dcc->type == IRC_DCC_CHAT_RECV)
+ {
+ if (fcntl (ptr_dcc->sock, F_SETFL, O_NONBLOCK) == -1)
+ return 0;
+ irc_dcc_connect_to_sender (ptr_dcc);
+ }
+
+ /* for file receiving, connection is made in child process (blocking) socket */
+
+ return 1;
+}
+
+/*
+ * irc_dcc_free: free DCC struct and remove it from list
+ */
+
+void
+irc_dcc_free (t_irc_dcc *ptr_dcc)
+{
+ t_irc_dcc *new_dcc_list;
+
+ if (!ptr_dcc)
+ return;
+
+ /* DCC CHAT with channel => remove channel
+ (to prevent channel from becoming standard pv) */
+ if (ptr_dcc->channel)
+ {
+ /* check if channel is used for another active DCC CHAT */
+ if (!ptr_dcc->channel->dcc_chat
+ || (IRC_DCC_ENDED(((t_irc_dcc *)(ptr_dcc->channel->dcc_chat))->status)))
+ {
+ gui_buffer_free (ptr_dcc->channel->buffer, 1);
+ if (ptr_dcc->channel)
+ irc_channel_free (ptr_dcc->server, ptr_dcc->channel);
+ }
+ }
+
+ /* remove DCC from list */
+ if (irc_last_dcc == ptr_dcc)
+ irc_last_dcc = ptr_dcc->prev_dcc;
+ if (ptr_dcc->prev_dcc)
+ {
+ (ptr_dcc->prev_dcc)->next_dcc = ptr_dcc->next_dcc;
+ new_dcc_list = irc_dcc_list;
+ }
+ else
+ new_dcc_list = ptr_dcc->next_dcc;
+ if (ptr_dcc->next_dcc)
+ (ptr_dcc->next_dcc)->prev_dcc = ptr_dcc->prev_dcc;
+
+ /* free data */
+ if (ptr_dcc->nick)
+ free (ptr_dcc->nick);
+ if (ptr_dcc->unterminated_message)
+ free (ptr_dcc->unterminated_message);
+ if (ptr_dcc->filename)
+ free (ptr_dcc->filename);
+
+ free (ptr_dcc);
+ irc_dcc_list = new_dcc_list;
+}
+
+/*
+ * irc_dcc_file_child_kill: kill child process and close pipe
+ */
+
+void
+irc_dcc_file_child_kill (t_irc_dcc *ptr_dcc)
+{
+ /* kill process */
+ if (ptr_dcc->child_pid > 0)
+ {
+ kill (ptr_dcc->child_pid, SIGKILL);
+ waitpid (ptr_dcc->child_pid, NULL, 0);
+ ptr_dcc->child_pid = 0;
+ }
+
+ /* close pipe used with child */
+ if (ptr_dcc->child_read != -1)
+ {
+ close (ptr_dcc->child_read);
+ ptr_dcc->child_read = -1;
+ }
+ if (ptr_dcc->child_write != -1)
+ {
+ close (ptr_dcc->child_write);
+ ptr_dcc->child_write = -1;
+ }
+}
+
+/*
+ * irc_dcc_close: close a DCC connection
+ */
+
+void
+irc_dcc_close (t_irc_dcc *ptr_dcc, int status)
+{
+ t_gui_buffer *ptr_buffer;
+ struct stat st;
+
+ ptr_dcc->status = status;
+
+ if ((status == IRC_DCC_DONE) || (status == IRC_DCC_ABORTED) || (status == IRC_DCC_FAILED))
+ {
+ if (IRC_DCC_IS_FILE(ptr_dcc->type))
+ {
+ irc_display_prefix (ptr_dcc->server, ptr_dcc->server->buffer,
+ GUI_PREFIX_INFO);
+ gui_printf (ptr_dcc->server->buffer,
+ _("DCC: file %s%s%s"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ ptr_dcc->filename,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT));
+ if (ptr_dcc->local_filename)
+ gui_printf (ptr_dcc->server->buffer,
+ _(" (local filename: %s%s%s)"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ ptr_dcc->local_filename,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT));
+ if (ptr_dcc->type == IRC_DCC_FILE_SEND)
+ gui_printf (ptr_dcc->server->buffer, _(" sent to "));
+ else
+ gui_printf (ptr_dcc->server->buffer, _(" received from "));
+ gui_printf (ptr_dcc->server->buffer, "%s%s%s: %s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ ptr_dcc->nick,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ (status == IRC_DCC_DONE) ? _("OK") : _("FAILED"));
+ irc_dcc_file_child_kill (ptr_dcc);
+ }
+ }
+ if (status == IRC_DCC_ABORTED)
+ {
+ if (IRC_DCC_IS_CHAT(ptr_dcc->type))
+ {
+ if (ptr_dcc->channel)
+ ptr_buffer = ptr_dcc->channel->buffer;
+ else
+ ptr_buffer = ptr_dcc->server->buffer;
+ irc_display_prefix (ptr_dcc->server, ptr_buffer, GUI_PREFIX_INFO);
+ gui_printf (ptr_buffer,
+ _("DCC chat closed with %s%s %s(%s%d.%d.%d.%d%s)\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ ptr_dcc->nick,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_HOST),
+ ptr_dcc->addr >> 24,
+ (ptr_dcc->addr >> 16) & 0xff,
+ (ptr_dcc->addr >> 8) & 0xff,
+ ptr_dcc->addr & 0xff,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK));
+ }
+ }
+
+ /* remove empty file if received file failed and nothing was transfered */
+ if (((status == IRC_DCC_FAILED) || (status == IRC_DCC_ABORTED))
+ && IRC_DCC_IS_FILE(ptr_dcc->type)
+ && IRC_DCC_IS_RECV(ptr_dcc->type)
+ && ptr_dcc->local_filename
+ && ptr_dcc->pos == 0)
+ {
+ /* erase file only if really empty on disk */
+ if (stat (ptr_dcc->local_filename, &st) != -1)
+ {
+ if ((unsigned long) st.st_size == 0)
+ unlink (ptr_dcc->local_filename);
+ }
+ }
+
+ if (IRC_DCC_IS_FILE(ptr_dcc->type))
+ irc_dcc_calculate_speed (ptr_dcc, 1);
+
+ if (ptr_dcc->sock >= 0)
+ {
+ close (ptr_dcc->sock);
+ ptr_dcc->sock = -1;
+ }
+ if (ptr_dcc->file >= 0)
+ {
+ close (ptr_dcc->file);
+ ptr_dcc->file = -1;
+ }
+}
+
+/*
+ * irc_dcc_channel_for_chat: create channel for DCC chat
+ */
+
+void
+irc_dcc_channel_for_chat (t_irc_dcc *ptr_dcc)
+{
+ if (!irc_channel_create_dcc (ptr_dcc))
+ {
+ irc_display_prefix (ptr_dcc->server, ptr_dcc->server->buffer,
+ GUI_PREFIX_ERROR);
+ gui_printf (ptr_dcc->server->buffer,
+ _("%s can't associate DCC chat with private buffer "
+ "(maybe private buffer has already DCC CHAT?)\n"),
+ WEECHAT_ERROR);
+ irc_dcc_close (ptr_dcc, IRC_DCC_FAILED);
+ irc_dcc_redraw (HOTLIST_MSG);
+ return;
+ }
+
+ irc_display_prefix (ptr_dcc->server, ptr_dcc->channel->buffer,
+ GUI_PREFIX_INFO);
+ gui_printf_type (ptr_dcc->channel->buffer, GUI_MSG_TYPE_MSG,
+ _("Connected to %s%s %s(%s%d.%d.%d.%d%s)%s via DCC chat\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ ptr_dcc->nick,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_HOST),
+ ptr_dcc->addr >> 24,
+ (ptr_dcc->addr >> 16) & 0xff,
+ (ptr_dcc->addr >> 8) & 0xff,
+ ptr_dcc->addr & 0xff,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT));
+}
+
+/*
+ * irc_dcc_chat_remove_channel: remove a buffer for DCC chat
+ */
+
+void
+irc_dcc_chat_remove_channel (t_irc_channel *channel)
+{
+ t_irc_dcc *ptr_dcc;
+
+ if (!channel)
+ return;
+
+ for (ptr_dcc = irc_dcc_list; ptr_dcc; ptr_dcc = ptr_dcc->next_dcc)
+ {
+ if (ptr_dcc->channel == channel)
+ ptr_dcc->channel = NULL;
+ }
+}
+
+/*
+ * irc_dcc_recv_connect_init: connect to sender and init file or chat
+ */
+
+void
+irc_dcc_recv_connect_init (t_irc_dcc *ptr_dcc)
+{
+ if (!irc_dcc_connect (ptr_dcc))
+ {
+ irc_dcc_close (ptr_dcc, IRC_DCC_FAILED);
+ irc_dcc_redraw (HOTLIST_MSG);
+ }
+ else
+ {
+ /* DCC file => launch child process */
+ if (IRC_DCC_IS_FILE(ptr_dcc->type))
+ {
+ ptr_dcc->status = IRC_DCC_CONNECTING;
+ irc_dcc_file_recv_fork (ptr_dcc);
+ }
+ else
+ {
+ /* DCC CHAT => associate DCC with channel */
+ ptr_dcc->status = IRC_DCC_ACTIVE;
+ irc_dcc_channel_for_chat (ptr_dcc);
+ }
+ }
+ irc_dcc_redraw (HOTLIST_MSG);
+}
+
+/*
+ * irc_dcc_accept: accepts a DCC file or chat request
+ */
+
+void
+irc_dcc_accept (t_irc_dcc *ptr_dcc)
+{
+ if (IRC_DCC_IS_FILE(ptr_dcc->type) && (ptr_dcc->start_resume > 0))
+ {
+ ptr_dcc->status = IRC_DCC_CONNECTING;
+ irc_server_sendf (ptr_dcc->server,
+ (strchr (ptr_dcc->filename, ' ')) ?
+ "PRIVMSG %s :\01DCC RESUME \"%s\" %d %u\01\n" :
+ "PRIVMSG %s :\01DCC RESUME %s %d %u\01",
+ ptr_dcc->nick, ptr_dcc->filename,
+ ptr_dcc->port, ptr_dcc->start_resume);
+ irc_dcc_redraw (HOTLIST_MSG);
+ }
+ else
+ irc_dcc_recv_connect_init (ptr_dcc);
+}
+
+/*
+ * irc_dcc_accept_resume: accepts a resume and inform the receiver
+ */
+
+void
+irc_dcc_accept_resume (t_irc_server *server, char *filename, int port,
+ unsigned long pos_start)
+{
+ t_irc_dcc *ptr_dcc;
+
+ ptr_dcc = irc_dcc_search (server, IRC_DCC_FILE_SEND, IRC_DCC_CONNECTING, port);
+ if (ptr_dcc)
+ {
+ ptr_dcc->pos = pos_start;
+ ptr_dcc->ack = pos_start;
+ ptr_dcc->start_resume = pos_start;
+ ptr_dcc->last_check_pos = pos_start;
+ irc_server_sendf (ptr_dcc->server,
+ (strchr (ptr_dcc->filename, ' ')) ?
+ "PRIVMSG %s :\01DCC ACCEPT \"%s\" %d %u\01\n" :
+ "PRIVMSG %s :\01DCC ACCEPT %s %d %u\01",
+ ptr_dcc->nick, ptr_dcc->filename,
+ ptr_dcc->port, ptr_dcc->start_resume);
+
+ irc_display_prefix (ptr_dcc->server, ptr_dcc->server->buffer,
+ GUI_PREFIX_INFO);
+ gui_printf (ptr_dcc->server->buffer,
+ _("DCC: file %s%s%s resumed at position %u\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ ptr_dcc->filename,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ ptr_dcc->start_resume);
+ irc_dcc_redraw (HOTLIST_MSG);
+ }
+ else
+ gui_printf (server->buffer,
+ _("%s can't resume file \"%s\" (port: %d, start position: %u): DCC not found or ended\n"),
+ WEECHAT_ERROR, filename, port, pos_start);
+}
+
+/*
+ * irc_dcc_start_resume: called when "DCC ACCEPT" is received (resume accepted by sender)
+ */
+
+void
+irc_dcc_start_resume (t_irc_server *server, char *filename, int port,
+ unsigned long pos_start)
+{
+ t_irc_dcc *ptr_dcc;
+
+ ptr_dcc = irc_dcc_search (server, IRC_DCC_FILE_RECV, IRC_DCC_CONNECTING, port);
+ if (ptr_dcc)
+ {
+ ptr_dcc->pos = pos_start;
+ ptr_dcc->ack = pos_start;
+ ptr_dcc->start_resume = pos_start;
+ ptr_dcc->last_check_pos = pos_start;
+ irc_dcc_recv_connect_init (ptr_dcc);
+ }
+ else
+ gui_printf (server->buffer,
+ _("%s can't resume file \"%s\" (port: %d, start position: %u): DCC not found or ended\n"),
+ WEECHAT_ERROR, filename, port, pos_start);
+}
+
+/*
+ * irc_dcc_alloc: allocate a new DCC file
+ */
+
+t_irc_dcc *
+irc_dcc_alloc ()
+{
+ t_irc_dcc *new_dcc;
+
+ /* create new DCC struct */
+ if ((new_dcc = (t_irc_dcc *) malloc (sizeof (t_irc_dcc))) == NULL)
+ return NULL;
+
+ /* default values */
+ new_dcc->server = NULL;
+ new_dcc->channel = NULL;
+ new_dcc->type = 0;
+ new_dcc->status = 0;
+ new_dcc->start_time = 0;
+ new_dcc->start_transfer = 0;
+ new_dcc->addr = 0;
+ new_dcc->port = 0;
+ new_dcc->nick = NULL;
+ new_dcc->sock = -1;
+ new_dcc->child_pid = 0;
+ new_dcc->child_read = -1;
+ new_dcc->child_write = -1;
+ new_dcc->unterminated_message = NULL;
+ new_dcc->fast_send = cfg_dcc_fast_send;
+ new_dcc->file = -1;
+ new_dcc->filename = NULL;
+ new_dcc->local_filename = NULL;
+ new_dcc->filename_suffix = -1;
+ new_dcc->blocksize = cfg_dcc_blocksize;
+ new_dcc->size = 0;
+ new_dcc->pos = 0;
+ new_dcc->ack = 0;
+ new_dcc->start_resume = 0;
+ new_dcc->last_check_time = 0;
+ new_dcc->last_check_pos = 0;
+ new_dcc->last_activity = 0;
+ new_dcc->bytes_per_sec = 0;
+ new_dcc->eta = 0;
+
+ new_dcc->prev_dcc = NULL;
+ new_dcc->next_dcc = irc_dcc_list;
+ if (irc_dcc_list)
+ irc_dcc_list->prev_dcc = new_dcc;
+ else
+ irc_last_dcc = new_dcc;
+ irc_dcc_list = new_dcc;
+
+ return new_dcc;
+}
+
+/*
+ * irc_dcc_add: add a DCC file to queue
+ */
+
+t_irc_dcc *
+irc_dcc_add (t_irc_server *server, int type, unsigned long addr, int port, char *nick,
+ int sock, char *filename, char *local_filename, unsigned long size)
+{
+ t_irc_dcc *new_dcc;
+
+ new_dcc = irc_dcc_alloc ();
+ if (!new_dcc)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf (server->buffer,
+ _("%s not enough memory for new DCC\n"),
+ WEECHAT_ERROR);
+ return NULL;
+ }
+
+ /* initialize new DCC */
+ new_dcc->server = server;
+ new_dcc->channel = NULL;
+ new_dcc->type = type;
+ new_dcc->status = IRC_DCC_WAITING;
+ new_dcc->start_time = time (NULL);
+ new_dcc->start_transfer = time (NULL);
+ new_dcc->addr = addr;
+ new_dcc->port = port;
+ new_dcc->nick = strdup (nick);
+ new_dcc->sock = sock;
+ new_dcc->unterminated_message = NULL;
+ new_dcc->file = -1;
+ if (IRC_DCC_IS_CHAT(type))
+ new_dcc->filename = strdup (_("DCC chat"));
+ else
+ new_dcc->filename = (filename) ? strdup (filename) : NULL;
+ new_dcc->local_filename = NULL;
+ new_dcc->filename_suffix = -1;
+ new_dcc->size = size;
+ new_dcc->pos = 0;
+ new_dcc->ack = 0;
+ new_dcc->start_resume = 0;
+ new_dcc->last_check_time = time (NULL);
+ new_dcc->last_check_pos = 0;
+ new_dcc->last_activity = time (NULL);
+ new_dcc->bytes_per_sec = 0;
+ new_dcc->eta = 0;
+ if (local_filename)
+ new_dcc->local_filename = strdup (local_filename);
+ else
+ irc_dcc_find_filename (new_dcc);
+
+ gui_current_window->dcc_first = NULL;
+ gui_current_window->dcc_selected = NULL;
+
+ /* write info message on server buffer */
+ if (type == IRC_DCC_FILE_RECV)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_INFO);
+ gui_printf (server->buffer,
+ _("Incoming DCC file from %s%s%s (%s%d.%d.%d.%d%s)%s: %s%s%s, %s%lu%s bytes\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ nick,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_HOST),
+ addr >> 24,
+ (addr >> 16) & 0xff,
+ (addr >> 8) & 0xff,
+ addr & 0xff,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ filename,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ size,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT));
+ irc_dcc_redraw (HOTLIST_MSG);
+ }
+ if (type == IRC_DCC_FILE_SEND)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_INFO);
+ gui_printf (server->buffer,
+ _("Sending DCC file to %s%s%s: %s%s%s "
+ "(local filename: %s%s%s), %s%lu%s bytes\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ nick,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ filename,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ local_filename,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ size,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT));
+ irc_dcc_redraw (HOTLIST_MSG);
+ }
+ if (type == IRC_DCC_CHAT_RECV)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_INFO);
+ gui_printf (server->buffer,
+ _("Incoming DCC chat request from %s%s%s "
+ "(%s%d.%d.%d.%d%s)\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ nick,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_HOST),
+ addr >> 24,
+ (addr >> 16) & 0xff,
+ (addr >> 8) & 0xff,
+ addr & 0xff,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK));
+ irc_dcc_redraw (HOTLIST_MSG);
+ }
+ if (type == IRC_DCC_CHAT_SEND)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_INFO);
+ gui_printf (server->buffer,
+ _("Sending DCC chat request to %s%s\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ nick);
+ irc_dcc_redraw (HOTLIST_MSG);
+ }
+
+ if (IRC_DCC_IS_FILE(type) && (!new_dcc->local_filename))
+ {
+ irc_dcc_close (new_dcc, IRC_DCC_FAILED);
+ irc_dcc_redraw (HOTLIST_MSG);
+ return NULL;
+ }
+
+ if (IRC_DCC_IS_FILE(type) && (new_dcc->start_resume > 0))
+ {
+ irc_display_prefix (new_dcc->server, new_dcc->server->buffer,
+ GUI_PREFIX_INFO);
+ gui_printf (new_dcc->server->buffer,
+ _("DCC: file %s%s%s (local filename: %s%s%s) "
+ "will be resumed at position %u\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ new_dcc->filename,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ new_dcc->local_filename,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ new_dcc->start_resume);
+ irc_dcc_redraw (HOTLIST_MSG);
+ }
+
+ /* connect if needed and redraw DCC buffer */
+ if (IRC_DCC_IS_SEND(type))
+ {
+ if (!irc_dcc_connect (new_dcc))
+ {
+ irc_dcc_close (new_dcc, IRC_DCC_FAILED);
+ irc_dcc_redraw (HOTLIST_MSG);
+ return NULL;
+ }
+ }
+
+ if ( ( (type == IRC_DCC_CHAT_RECV) && (cfg_dcc_auto_accept_chats) )
+ || ( (type == IRC_DCC_FILE_RECV) && (cfg_dcc_auto_accept_files) ) )
+ irc_dcc_accept (new_dcc);
+ else
+ irc_dcc_redraw (HOTLIST_PRIVATE);
+ gui_status_draw (gui_current_window->buffer, 0);
+
+ return new_dcc;
+}
+
+/*
+ * irc_dcc_send_request: send DCC request (file or chat)
+ */
+
+void
+irc_dcc_send_request (t_irc_server *server, int type, char *nick, char *filename)
+{
+ char *dir1, *dir2, *filename2, *short_filename, *pos;
+ int spaces, args, port_start, port_end;
+ struct stat st;
+ int sock, port;
+ struct hostent *host;
+ struct in_addr tmpaddr;
+ struct sockaddr_in addr;
+ socklen_t length;
+ unsigned long local_addr;
+ t_irc_dcc *ptr_dcc;
+
+ filename2 = NULL;
+ short_filename = NULL;
+ spaces = 0;
+
+ if (type == IRC_DCC_FILE_SEND)
+ {
+ /* add home if filename not beginning with '/' or '~' (not for Win32) */
+#ifdef _WIN32
+ filename2 = strdup (filename);
+#else
+ if (filename[0] == '/')
+ filename2 = strdup (filename);
+ else if (filename[0] == '~')
+ filename2 = weechat_strreplace (filename, "~", getenv ("HOME"));
+ else
+ {
+ dir1 = weechat_strreplace (cfg_dcc_upload_path, "~", getenv ("HOME"));
+ if (!dir1)
+ return;
+ dir2 = weechat_strreplace (dir1, "%h", weechat_home);
+ if (!dir2)
+ {
+ free (dir1);
+ return;
+ }
+ filename2 = (char *) malloc (strlen (dir2) +
+ strlen (filename) + 4);
+ if (!filename2)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf (server->buffer,
+ _("%s not enough memory for DCC SEND\n"),
+ WEECHAT_ERROR);
+ return;
+ }
+ strcpy (filename2, dir2);
+ if (filename2[strlen (filename2) - 1] != DIR_SEPARATOR_CHAR)
+ strcat (filename2, DIR_SEPARATOR);
+ strcat (filename2, filename);
+ if (dir1)
+ free (dir1);
+ if (dir2)
+ free (dir2);
+ }
+#endif
+
+ /* check if file exists */
+ if (stat (filename2, &st) == -1)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf (server->buffer,
+ _("%s cannot access file \"%s\"\n"),
+ WEECHAT_ERROR, filename2);
+ if (filename2)
+ free (filename2);
+ return;
+ }
+ }
+
+ /* get local IP address */
+
+ /* look up the IP address from dcc_own_ip, if set */
+ local_addr = 0;
+ if (cfg_dcc_own_ip && cfg_dcc_own_ip[0])
+ {
+ host = gethostbyname (cfg_dcc_own_ip);
+ if (host)
+ {
+ memcpy (&tmpaddr, host->h_addr_list[0], sizeof(struct in_addr));
+ local_addr = ntohl (tmpaddr.s_addr);
+ }
+ else
+ gui_printf (server->buffer,
+ _("%s could not find address for '%s'. Falling back to local IP.\n"),
+ WEECHAT_WARNING, cfg_dcc_own_ip);
+ }
+
+ /* use the local interface, from the server socket */
+ memset (&addr, 0, sizeof (struct sockaddr_in));
+ length = sizeof (addr);
+ getsockname (server->sock, (struct sockaddr *) &addr, &length);
+ addr.sin_family = AF_INET;
+
+ /* fallback to the local IP address on the interface, if required */
+ if (local_addr == 0)
+ local_addr = ntohl (addr.sin_addr.s_addr);
+
+ /* open socket for DCC */
+ sock = socket (AF_INET, SOCK_STREAM, 0);
+ if (sock < 0)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf (server->buffer,
+ _("%s cannot create socket for DCC\n"),
+ WEECHAT_ERROR);
+ if (filename2)
+ free (filename2);
+ return;
+ }
+
+ /* look for port */
+
+ port = 0;
+
+ if (cfg_dcc_port_range && cfg_dcc_port_range[0])
+ {
+ /* find a free port in the specified range */
+ args = sscanf (cfg_dcc_port_range, "%d-%d", &port_start, &port_end);
+ if (args > 0)
+ {
+ port = port_start;
+ if (args == 1)
+ port_end = port_start;
+
+ /* loop through the entire allowed port range */
+ while (port <= port_end)
+ {
+ if (!irc_dcc_port_in_use (port))
+ {
+ /* attempt to bind to the free port */
+ addr.sin_port = htons (port);
+ if (bind (sock, (struct sockaddr *) &addr, sizeof (addr)) == 0)
+ break;
+ }
+ port++;
+ }
+
+ if (port > port_end)
+ port = -1;
+ }
+ }
+
+ if (port == 0)
+ {
+ /* find port automatically */
+ addr.sin_port = 0;
+ if (bind (sock, (struct sockaddr *) &addr, sizeof (addr)) == 0)
+ {
+ length = sizeof (addr);
+ getsockname (sock, (struct sockaddr *) &addr, &length);
+ port = ntohs (addr.sin_port);
+ }
+ else
+ port = -1;
+ }
+
+ if (port == -1)
+ {
+ /* Could not find any port to bind */
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf (server->buffer,
+ _("%s cannot find available port for DCC\n"),
+ WEECHAT_ERROR);
+ close (sock);
+ if (filename2)
+ free (filename2);
+ return;
+ }
+
+ if (type == IRC_DCC_FILE_SEND)
+ {
+ /* extract short filename (without path) */
+ pos = strrchr (filename2, DIR_SEPARATOR_CHAR);
+ if (pos)
+ short_filename = strdup (pos + 1);
+ else
+ short_filename = strdup (filename2);
+
+ /* convert spaces to underscore if asked and needed */
+ pos = short_filename;
+ spaces = 0;
+ while (pos[0])
+ {
+ if (pos[0] == ' ')
+ {
+ if (cfg_dcc_convert_spaces)
+ pos[0] = '_';
+ else
+ spaces = 1;
+ }
+ pos++;
+ }
+ }
+
+ /* add DCC entry and listen to socket */
+ if (type == IRC_DCC_CHAT_SEND)
+ ptr_dcc = irc_dcc_add (server, IRC_DCC_CHAT_SEND, local_addr, port, nick, sock,
+ NULL, NULL, 0);
+ else
+ ptr_dcc = irc_dcc_add (server, IRC_DCC_FILE_SEND, local_addr, port, nick, sock,
+ short_filename, filename2, st.st_size);
+ if (!ptr_dcc)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf (server->buffer,
+ _("%s cannot send DCC\n"),
+ WEECHAT_ERROR);
+ close (sock);
+ if (short_filename)
+ free (short_filename);
+ if (filename2)
+ free (filename2);
+ return;
+ }
+
+ /* send DCC request to nick */
+ if (type == IRC_DCC_CHAT_SEND)
+ irc_server_sendf (server,
+ "PRIVMSG %s :\01DCC CHAT chat %lu %d\01",
+ nick, local_addr, port);
+ else
+ irc_server_sendf (server,
+ (spaces) ?
+ "PRIVMSG %s :\01DCC SEND \"%s\" %lu %d %u\01\n" :
+ "PRIVMSG %s :\01DCC SEND %s %lu %d %u\01",
+ nick, short_filename, local_addr, port,
+ (unsigned long) st.st_size);
+
+ if (short_filename)
+ free (short_filename);
+ if (filename2)
+ free (filename2);
+}
+
+/*
+ * irc_dcc_chat_send: send data to remote host via DCC CHAT
+ */
+
+int
+irc_dcc_chat_send (t_irc_dcc *ptr_dcc, char *buffer, int size_buf)
+{
+ if (!ptr_dcc)
+ return -1;
+
+ return send (ptr_dcc->sock, buffer, size_buf, 0);
+}
+
+/*
+ * irc_dcc_chat_sendf: send formatted data to remote host via DCC CHAT
+ */
+
+void
+irc_dcc_chat_sendf (t_irc_dcc *ptr_dcc, char *fmt, ...)
+{
+ va_list args;
+ static char buffer[4096];
+ int size_buf;
+
+ if (!ptr_dcc || (ptr_dcc->sock < 0))
+ return;
+
+ va_start (args, fmt);
+ size_buf = vsnprintf (buffer, sizeof (buffer) - 1, fmt, args);
+ va_end (args);
+
+ if ((size_buf == 0) || (strcmp (buffer, "\r\n") == 0))
+ return;
+
+ buffer[sizeof (buffer) - 1] = '\0';
+ if ((size_buf < 0) || (size_buf > (int) (sizeof (buffer) - 1)))
+ size_buf = strlen (buffer);
+#ifdef DEBUG
+ buffer[size_buf - 2] = '\0';
+ gui_printf (ptr_dcc->server->buffer, "[DEBUG] Sending to remote host (DCC CHAT) >>> %s\n", buffer);
+ buffer[size_buf - 2] = '\r';
+#endif
+ if (irc_dcc_chat_send (ptr_dcc, buffer, strlen (buffer)) <= 0)
+ {
+ irc_display_prefix (ptr_dcc->server, ptr_dcc->server->buffer,
+ GUI_PREFIX_ERROR);
+ gui_printf (ptr_dcc->server->buffer,
+ _("%s error sending data to \"%s\" via DCC CHAT\n"),
+ WEECHAT_ERROR, ptr_dcc->nick);
+ irc_dcc_close (ptr_dcc, IRC_DCC_FAILED);
+ }
+}
+
+/*
+ * irc_dcc_chat_recv: receive data from DCC CHAT host
+ */
+
+void
+irc_dcc_chat_recv (t_irc_dcc *ptr_dcc)
+{
+ fd_set read_fd;
+ static struct timeval timeout;
+ static char buffer[4096 + 2];
+ char *buf2, *pos, *ptr_buf, *next_ptr_buf;
+ int num_read;
+
+ FD_ZERO (&read_fd);
+ FD_SET (ptr_dcc->sock, &read_fd);
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+
+ /* something to read on socket? */
+ if (select (FD_SETSIZE, &read_fd, NULL, NULL, &timeout) <= 0)
+ return;
+
+ if (!FD_ISSET (ptr_dcc->sock, &read_fd))
+ return;
+
+ /* there's something to read on socket! */
+ num_read = recv (ptr_dcc->sock, buffer, sizeof (buffer) - 2, 0);
+ if (num_read > 0)
+ {
+ buffer[num_read] = '\0';
+
+ buf2 = NULL;
+ ptr_buf = buffer;
+ if (ptr_dcc->unterminated_message)
+ {
+ buf2 = (char *) malloc (strlen (ptr_dcc->unterminated_message) +
+ strlen (buffer) + 1);
+ if (buf2)
+ {
+ strcpy (buf2, ptr_dcc->unterminated_message);
+ strcat (buf2, buffer);
+ }
+ ptr_buf = buf2;
+ free (ptr_dcc->unterminated_message);
+ ptr_dcc->unterminated_message = NULL;
+ }
+
+ while (ptr_buf && ptr_buf[0])
+ {
+ next_ptr_buf = NULL;
+ pos = strstr (ptr_buf, "\r\n");
+ if (pos)
+ {
+ pos[0] = '\0';
+ next_ptr_buf = pos + 2;
+ }
+ else
+ {
+ pos = strstr (ptr_buf, "\n");
+ if (pos)
+ {
+ pos[0] = '\0';
+ next_ptr_buf = pos + 1;
+ }
+ else
+ {
+ ptr_dcc->unterminated_message = strdup (ptr_buf);
+ ptr_buf = NULL;
+ next_ptr_buf = NULL;
+ }
+ }
+
+ if (ptr_buf)
+ {
+ if (irc_recv_is_highlight (ptr_buf, ptr_dcc->server->nick))
+ {
+ irc_display_nick (ptr_dcc->channel->buffer, NULL, ptr_dcc->nick,
+ GUI_MSG_TYPE_NICK | GUI_MSG_TYPE_HIGHLIGHT, 1,
+ GUI_COLOR_WIN_CHAT_HIGHLIGHT, 0);
+ if ((cfg_look_infobar_delay_highlight > 0)
+ && (ptr_dcc->channel->buffer != gui_current_window->buffer))
+ {
+ gui_infobar_printf (cfg_look_infobar_delay_highlight,
+ GUI_COLOR_WIN_INFOBAR_HIGHLIGHT,
+ _("Private %s> %s"),
+ ptr_dcc->nick, ptr_buf);
+ }
+ }
+ else
+ irc_display_nick (ptr_dcc->channel->buffer, NULL, ptr_dcc->nick,
+ GUI_MSG_TYPE_NICK, 1, GUI_COLOR_WIN_NICK_PRIVATE, 0);
+ gui_printf_type (ptr_dcc->channel->buffer, GUI_MSG_TYPE_MSG,
+ "%s%s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ ptr_buf);
+ }
+
+ ptr_buf = next_ptr_buf;
+ }
+
+ if (buf2)
+ free (buf2);
+ }
+ else
+ {
+ irc_dcc_close (ptr_dcc, IRC_DCC_ABORTED);
+ irc_dcc_redraw (HOTLIST_MSG);
+ }
+}
+
+/*
+ * irc_dcc_file_create_pipe: create pipe for communication with child process
+ * return 1 if ok, 0 if error
+ */
+
+int
+irc_dcc_file_create_pipe (t_irc_dcc *ptr_dcc)
+{
+ int child_pipe[2];
+
+ if (pipe (child_pipe) < 0)
+ {
+ irc_display_prefix (ptr_dcc->server, ptr_dcc->server->buffer,
+ GUI_PREFIX_ERROR);
+ gui_printf (ptr_dcc->server->buffer,
+ _("%s DCC: unable to create pipe\n"),
+ WEECHAT_ERROR);
+ irc_dcc_close (ptr_dcc, IRC_DCC_FAILED);
+ irc_dcc_redraw (HOTLIST_MSG);
+ return 0;
+ }
+
+ ptr_dcc->child_read = child_pipe[0];
+ ptr_dcc->child_write = child_pipe[1];
+ return 1;
+}
+
+/*
+ * irc_dcc_file_write_pipe: write data into pipe
+ */
+
+void
+irc_dcc_file_write_pipe (t_irc_dcc *ptr_dcc, int status, int error)
+{
+ char buffer[1 + 1 + 12 + 1]; /* status + error + pos + \0 */
+
+ snprintf (buffer, sizeof (buffer), "%c%c%012lu",
+ status + '0', error + '0', ptr_dcc->pos);
+ write (ptr_dcc->child_write, buffer, sizeof (buffer));
+}
+
+/*
+ * irc_dcc_file_send_child: child process for sending file
+ */
+
+void
+irc_dcc_file_send_child (t_irc_dcc *ptr_dcc)
+{
+ int num_read, num_sent;
+ static char buffer[IRC_DCC_MAX_BLOCKSIZE];
+ uint32_t ack;
+ time_t last_sent, new_time;
+
+ last_sent = time (NULL);
+ while (1)
+ {
+ /* read DCC ACK (sent by receiver) */
+ if (ptr_dcc->pos > ptr_dcc->ack)
+ {
+ /* we should receive ACK for packets sent previously */
+ while (1)
+ {
+ num_read = recv (ptr_dcc->sock, (char *) &ack, 4, MSG_PEEK);
+ if ((num_read < 1) &&
+ ((num_read != -1) || (errno != EAGAIN)))
+ {
+ irc_dcc_file_write_pipe (ptr_dcc, IRC_DCC_FAILED, IRC_DCC_ERROR_SEND_BLOCK);
+ return;
+ }
+ if (num_read == 4)
+ {
+ recv (ptr_dcc->sock, (char *) &ack, 4, 0);
+ ptr_dcc->ack = ntohl (ack);
+
+ /* DCC send ok? */
+ if ((ptr_dcc->pos >= ptr_dcc->size)
+ && (ptr_dcc->ack >= ptr_dcc->size))
+ {
+ irc_dcc_file_write_pipe (ptr_dcc, IRC_DCC_DONE, IRC_DCC_NO_ERROR);
+ return;
+ }
+ }
+ else
+ break;
+ }
+ }
+
+ /* send a block to receiver */
+ if ((ptr_dcc->pos < ptr_dcc->size) &&
+ (ptr_dcc->fast_send || (ptr_dcc->pos <= ptr_dcc->ack)))
+ {
+ lseek (ptr_dcc->file, ptr_dcc->pos, SEEK_SET);
+ num_read = read (ptr_dcc->file, buffer, ptr_dcc->blocksize);
+ if (num_read < 1)
+ {
+ irc_dcc_file_write_pipe (ptr_dcc, IRC_DCC_FAILED, IRC_DCC_ERROR_READ_LOCAL);
+ return;
+ }
+ num_sent = send (ptr_dcc->sock, buffer, num_read, 0);
+ if (num_sent < 0)
+ {
+ /* socket is temporarily not available (receiver can't receive
+ amount of data we sent ?!) */
+ if (errno == EAGAIN)
+ usleep (1000);
+ else
+ {
+ irc_dcc_file_write_pipe (ptr_dcc, IRC_DCC_FAILED, IRC_DCC_ERROR_SEND_BLOCK);
+ return;
+ }
+ }
+ if (num_sent > 0)
+ {
+ ptr_dcc->pos += (unsigned long) num_sent;
+ new_time = time (NULL);
+ if (last_sent != new_time)
+ {
+ last_sent = new_time;
+ irc_dcc_file_write_pipe (ptr_dcc, IRC_DCC_ACTIVE, IRC_DCC_NO_ERROR);
+ }
+ }
+ }
+ else
+ usleep (1000);
+ }
+}
+
+/*
+ * irc_dcc_file_recv_child: child process for receiving file
+ */
+
+void
+irc_dcc_file_recv_child (t_irc_dcc *ptr_dcc)
+{
+ int num_read;
+ static char buffer[IRC_DCC_MAX_BLOCKSIZE];
+ uint32_t pos;
+ time_t last_sent, new_time;
+
+ /* first connect to sender (blocking) */
+ if (!irc_dcc_connect_to_sender (ptr_dcc))
+ {
+ irc_dcc_file_write_pipe (ptr_dcc, IRC_DCC_FAILED, IRC_DCC_ERROR_CONNECT_SENDER);
+ return;
+ }
+
+ /* connection is ok, change DCC status (inform parent process) */
+ irc_dcc_file_write_pipe (ptr_dcc, IRC_DCC_ACTIVE, IRC_DCC_NO_ERROR);
+
+ last_sent = time (NULL);
+ while (1)
+ {
+ num_read = recv (ptr_dcc->sock, buffer, sizeof (buffer), 0);
+ if (num_read == -1)
+ {
+ /* socket is temporarily not available (sender is not fast ?!) */
+ if (errno == EAGAIN)
+ usleep (1000);
+ else
+ {
+ irc_dcc_file_write_pipe (ptr_dcc, IRC_DCC_FAILED, IRC_DCC_ERROR_RECV_BLOCK);
+ return;
+ }
+ }
+ else
+ {
+ if (num_read == 0)
+ {
+ irc_dcc_file_write_pipe (ptr_dcc, IRC_DCC_FAILED, IRC_DCC_ERROR_RECV_BLOCK);
+ return;
+ }
+
+ if (write (ptr_dcc->file, buffer, num_read) == -1)
+ {
+ irc_dcc_file_write_pipe (ptr_dcc, IRC_DCC_FAILED, IRC_DCC_ERROR_WRITE_LOCAL);
+ return;
+ }
+
+ ptr_dcc->pos += (unsigned long) num_read;
+ pos = htonl (ptr_dcc->pos);
+
+ /* we don't check return code, not a problem if an ACK send failed */
+ send (ptr_dcc->sock, (char *) &pos, 4, 0);
+
+ /* file received ok? */
+ if (ptr_dcc->pos >= ptr_dcc->size)
+ {
+ irc_dcc_file_write_pipe (ptr_dcc, IRC_DCC_DONE, IRC_DCC_NO_ERROR);
+ return;
+ }
+
+ new_time = time (NULL);
+ if (last_sent != new_time)
+ {
+ last_sent = new_time;
+ irc_dcc_file_write_pipe (ptr_dcc, IRC_DCC_ACTIVE, IRC_DCC_NO_ERROR);
+ }
+ }
+ }
+}
+
+/*
+ * irc_dcc_file_child_read: read data from child via pipe
+ */
+
+void
+irc_dcc_file_child_read (t_irc_dcc *ptr_dcc)
+{
+ fd_set read_fd;
+ static struct timeval timeout;
+ char bufpipe[1 + 1 + 12 + 1];
+ int num_read;
+ char *error;
+
+ FD_ZERO (&read_fd);
+ FD_SET (ptr_dcc->child_read, &read_fd);
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+
+ /* something to read on child pipe? */
+ if (select (FD_SETSIZE, &read_fd, NULL, NULL, &timeout) <= 0)
+ return;
+
+ if (!FD_ISSET (ptr_dcc->child_read, &read_fd))
+ return;
+
+ /* there's something to read in pipe! */
+ num_read = read (ptr_dcc->child_read, bufpipe, sizeof (bufpipe));
+ if (num_read > 0)
+ {
+ error = NULL;
+ ptr_dcc->pos = strtol (bufpipe + 2, &error, 10);
+ ptr_dcc->last_activity = time (NULL);
+ irc_dcc_calculate_speed (ptr_dcc, 0);
+
+ /* read error code */
+ switch (bufpipe[1] - '0')
+ {
+ /* errors for sender */
+ case IRC_DCC_ERROR_READ_LOCAL:
+ irc_display_prefix (ptr_dcc->server, ptr_dcc->server->buffer,
+ GUI_PREFIX_ERROR);
+ gui_printf (ptr_dcc->server->buffer,
+ _("%s DCC: unable to read local file\n"),
+ WEECHAT_ERROR);
+ break;
+ case IRC_DCC_ERROR_SEND_BLOCK:
+ irc_display_prefix (ptr_dcc->server, ptr_dcc->server->buffer,
+ GUI_PREFIX_ERROR);
+ gui_printf (ptr_dcc->server->buffer,
+ _("%s DCC: unable to send block to receiver\n"),
+ WEECHAT_ERROR);
+ break;
+ case IRC_DCC_ERROR_READ_ACK:
+ irc_display_prefix (ptr_dcc->server, ptr_dcc->server->buffer,
+ GUI_PREFIX_ERROR);
+ gui_printf (ptr_dcc->server->buffer,
+ _("%s DCC: unable to read ACK from receiver\n"),
+ WEECHAT_ERROR);
+ break;
+ /* errors for receiver */
+ case IRC_DCC_ERROR_CONNECT_SENDER:
+ irc_display_prefix (ptr_dcc->server, ptr_dcc->server->buffer,
+ GUI_PREFIX_ERROR);
+ gui_printf (ptr_dcc->server->buffer,
+ _("%s DCC: unable to connect to sender\n"),
+ WEECHAT_ERROR);
+ break;
+ case IRC_DCC_ERROR_RECV_BLOCK:
+ irc_display_prefix (ptr_dcc->server, ptr_dcc->server->buffer,
+ GUI_PREFIX_ERROR);
+ gui_printf (ptr_dcc->server->buffer,
+ _("%s DCC: unable to receive block from sender\n"),
+ WEECHAT_ERROR);
+ break;
+ case IRC_DCC_ERROR_WRITE_LOCAL:
+ irc_display_prefix (ptr_dcc->server, ptr_dcc->server->buffer,
+ GUI_PREFIX_ERROR);
+ gui_printf (ptr_dcc->server->buffer,
+ _("%s DCC: unable to write local file\n"),
+ WEECHAT_ERROR);
+ break;
+ }
+
+ /* read new DCC status */
+ switch (bufpipe[0] - '0')
+ {
+ case IRC_DCC_ACTIVE:
+ if (ptr_dcc->status == IRC_DCC_CONNECTING)
+ {
+ /* connection was successful by child, init transfert times */
+ ptr_dcc->status = IRC_DCC_ACTIVE;
+ ptr_dcc->start_transfer = time (NULL);
+ ptr_dcc->last_check_time = time (NULL);
+ irc_dcc_redraw (HOTLIST_MSG);
+ }
+ else
+ irc_dcc_redraw (HOTLIST_LOW);
+ break;
+ case IRC_DCC_DONE:
+ irc_dcc_close (ptr_dcc, IRC_DCC_DONE);
+ irc_dcc_redraw (HOTLIST_MSG);
+ break;
+ case IRC_DCC_FAILED:
+ irc_dcc_close (ptr_dcc, IRC_DCC_FAILED);
+ irc_dcc_redraw (HOTLIST_MSG);
+ break;
+ }
+ }
+}
+
+/*
+ * irc_dcc_file_send_fork: fork process for sending file
+ */
+
+void
+irc_dcc_file_send_fork (t_irc_dcc *ptr_dcc)
+{
+ pid_t pid;
+
+ if (!irc_dcc_file_create_pipe (ptr_dcc))
+ return;
+
+ ptr_dcc->file = open (ptr_dcc->local_filename, O_RDONLY | O_NONBLOCK, 0644);
+
+ switch (pid = fork ())
+ {
+ /* fork failed */
+ case -1:
+ irc_display_prefix (ptr_dcc->server, ptr_dcc->server->buffer,
+ GUI_PREFIX_ERROR);
+ gui_printf (ptr_dcc->server->buffer,
+ _("%s DCC: unable to fork\n"),
+ WEECHAT_ERROR);
+ irc_dcc_close (ptr_dcc, IRC_DCC_FAILED);
+ irc_dcc_redraw (HOTLIST_MSG);
+ return;
+ /* child process */
+ case 0:
+ setuid (getuid ());
+ irc_dcc_file_send_child (ptr_dcc);
+ _exit (EXIT_SUCCESS);
+ }
+
+ /* parent process */
+ ptr_dcc->child_pid = pid;
+}
+
+/*
+ * irc_dcc_file_recv_fork: fork process for receiving file
+ */
+
+void
+irc_dcc_file_recv_fork (t_irc_dcc *ptr_dcc)
+{
+ pid_t pid;
+
+ if (!irc_dcc_file_create_pipe (ptr_dcc))
+ return;
+
+ if (ptr_dcc->start_resume > 0)
+ ptr_dcc->file = open (ptr_dcc->local_filename,
+ O_APPEND | O_WRONLY | O_NONBLOCK);
+ else
+ ptr_dcc->file = open (ptr_dcc->local_filename,
+ O_CREAT | O_TRUNC | O_WRONLY | O_NONBLOCK,
+ 0644);
+
+ switch (pid = fork ())
+ {
+ /* fork failed */
+ case -1:
+ irc_display_prefix (ptr_dcc->server, ptr_dcc->server->buffer,
+ GUI_PREFIX_ERROR);
+ gui_printf (ptr_dcc->server->buffer,
+ _("%s DCC: unable to fork\n"),
+ WEECHAT_ERROR);
+ irc_dcc_close (ptr_dcc, IRC_DCC_FAILED);
+ irc_dcc_redraw (HOTLIST_MSG);
+ return;
+ /* child process */
+ case 0:
+ setuid (getuid ());
+ irc_dcc_file_recv_child (ptr_dcc);
+ _exit (EXIT_SUCCESS);
+ }
+
+ /* parent process */
+ ptr_dcc->child_pid = pid;
+}
+
+/*
+ * irc_dcc_handle: receive/send data for all active DCC
+ */
+
+void
+irc_dcc_handle ()
+{
+ t_irc_dcc *ptr_dcc;
+ fd_set read_fd;
+ static struct timeval timeout;
+ int sock;
+ struct sockaddr_in addr;
+ socklen_t length;
+
+ for (ptr_dcc = irc_dcc_list; ptr_dcc; ptr_dcc = ptr_dcc->next_dcc)
+ {
+ /* check DCC timeout */
+ if (IRC_DCC_IS_FILE(ptr_dcc->type) && !IRC_DCC_ENDED(ptr_dcc->status))
+ {
+ if ((cfg_dcc_timeout != 0) && (time (NULL) > ptr_dcc->last_activity + cfg_dcc_timeout))
+ {
+ irc_display_prefix (ptr_dcc->server, ptr_dcc->server->buffer,
+ GUI_PREFIX_ERROR);
+ gui_printf (ptr_dcc->server->buffer,
+ _("%s DCC: timeout\n"),
+ WEECHAT_ERROR);
+ irc_dcc_close (ptr_dcc, IRC_DCC_FAILED);
+ irc_dcc_redraw (HOTLIST_MSG);
+ continue;
+ }
+ }
+
+ if (ptr_dcc->status == IRC_DCC_CONNECTING)
+ {
+ if (ptr_dcc->type == IRC_DCC_FILE_SEND)
+ {
+ FD_ZERO (&read_fd);
+ FD_SET (ptr_dcc->sock, &read_fd);
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+
+ /* something to read on socket? */
+ if (select (FD_SETSIZE, &read_fd, NULL, NULL, &timeout) > 0)
+ {
+ if (FD_ISSET (ptr_dcc->sock, &read_fd))
+ {
+ ptr_dcc->last_activity = time (NULL);
+ length = sizeof (addr);
+ sock = accept (ptr_dcc->sock, (struct sockaddr *) &addr, &length);
+ close (ptr_dcc->sock);
+ ptr_dcc->sock = -1;
+ if (sock < 0)
+ {
+ irc_display_prefix (ptr_dcc->server, ptr_dcc->server->buffer,
+ GUI_PREFIX_ERROR);
+ gui_printf (ptr_dcc->server->buffer,
+ _("%s DCC: unable to create socket for sending file\n"),
+ WEECHAT_ERROR);
+ irc_dcc_close (ptr_dcc, IRC_DCC_FAILED);
+ irc_dcc_redraw (HOTLIST_MSG);
+ continue;
+ }
+ ptr_dcc->sock = sock;
+ if (fcntl (ptr_dcc->sock, F_SETFL, O_NONBLOCK) == -1)
+ {
+ irc_display_prefix (ptr_dcc->server, ptr_dcc->server->buffer,
+ GUI_PREFIX_ERROR);
+ gui_printf (ptr_dcc->server->buffer,
+ _("%s DCC: unable to set 'nonblock' option for socket\n"),
+ WEECHAT_ERROR);
+ irc_dcc_close (ptr_dcc, IRC_DCC_FAILED);
+ irc_dcc_redraw (HOTLIST_MSG);
+ continue;
+ }
+ ptr_dcc->addr = ntohl (addr.sin_addr.s_addr);
+ ptr_dcc->status = IRC_DCC_ACTIVE;
+ ptr_dcc->start_transfer = time (NULL);
+ irc_dcc_redraw (HOTLIST_MSG);
+ irc_dcc_file_send_fork (ptr_dcc);
+ }
+ }
+ }
+ if (ptr_dcc->type == IRC_DCC_FILE_RECV)
+ {
+ if (ptr_dcc->child_read != -1)
+ irc_dcc_file_child_read (ptr_dcc);
+ }
+ }
+
+ if (ptr_dcc->status == IRC_DCC_WAITING)
+ {
+ if (ptr_dcc->type == IRC_DCC_CHAT_SEND)
+ {
+ FD_ZERO (&read_fd);
+ FD_SET (ptr_dcc->sock, &read_fd);
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+
+ /* something to read on socket? */
+ if (select (FD_SETSIZE, &read_fd, NULL, NULL, &timeout) > 0)
+ {
+ if (FD_ISSET (ptr_dcc->sock, &read_fd))
+ {
+ length = sizeof (addr);
+ sock = accept (ptr_dcc->sock, (struct sockaddr *) &addr, &length);
+ close (ptr_dcc->sock);
+ ptr_dcc->sock = -1;
+ if (sock < 0)
+ {
+ irc_dcc_close (ptr_dcc, IRC_DCC_FAILED);
+ irc_dcc_redraw (HOTLIST_MSG);
+ continue;
+ }
+ ptr_dcc->sock = sock;
+ if (fcntl (ptr_dcc->sock, F_SETFL, O_NONBLOCK) == -1)
+ {
+ irc_dcc_close (ptr_dcc, IRC_DCC_FAILED);
+ irc_dcc_redraw (HOTLIST_MSG);
+ continue;
+ }
+ ptr_dcc->addr = ntohl (addr.sin_addr.s_addr);
+ ptr_dcc->status = IRC_DCC_ACTIVE;
+ irc_dcc_redraw (HOTLIST_MSG);
+ irc_dcc_channel_for_chat (ptr_dcc);
+ }
+ }
+ }
+ }
+
+ if (ptr_dcc->status == IRC_DCC_ACTIVE)
+ {
+ if (IRC_DCC_IS_CHAT(ptr_dcc->type))
+ irc_dcc_chat_recv (ptr_dcc);
+ else
+ irc_dcc_file_child_read (ptr_dcc);
+ }
+ }
+}
+
+/*
+ * irc_dcc_end: close all opened sockets (called when WeeChat is exiting)
+ */
+
+void
+irc_dcc_end ()
+{
+ t_irc_dcc *ptr_dcc;
+
+ for (ptr_dcc = irc_dcc_list; ptr_dcc; ptr_dcc = ptr_dcc->next_dcc)
+ {
+ if (ptr_dcc->sock >= 0)
+ {
+ if (ptr_dcc->status == IRC_DCC_ACTIVE)
+ weechat_log_printf (_("Aborting active DCC: \"%s\" from %s\n"),
+ ptr_dcc->filename, ptr_dcc->nick);
+ irc_dcc_close (ptr_dcc, IRC_DCC_FAILED);
+ }
+ }
+}
+
+/*
+ * irc_dcc_print_log: print DCC infos in log (usually for crash dump)
+ */
+
+void
+irc_dcc_print_log ()
+{
+ t_irc_dcc *ptr_dcc;
+
+ for (ptr_dcc = irc_dcc_list; ptr_dcc; ptr_dcc = ptr_dcc->next_dcc)
+ {
+ weechat_log_printf ("\n");
+ weechat_log_printf ("[DCC (addr:0x%X)]\n", ptr_dcc);
+ weechat_log_printf (" server. . . . . . . : 0x%X\n", ptr_dcc->server);
+ weechat_log_printf (" channel . . . . . . : 0x%X\n", ptr_dcc->channel);
+ weechat_log_printf (" type. . . . . . . . : %d\n", ptr_dcc->type);
+ weechat_log_printf (" status. . . . . . . : %d\n", ptr_dcc->status);
+ weechat_log_printf (" start_time. . . . . : %ld\n", ptr_dcc->start_time);
+ weechat_log_printf (" start_transfer. . . : %ld\n", ptr_dcc->start_transfer);
+ weechat_log_printf (" addr. . . . . . . . : %lu\n", ptr_dcc->addr);
+ weechat_log_printf (" port. . . . . . . . : %d\n", ptr_dcc->port);
+ weechat_log_printf (" nick. . . . . . . . : '%s'\n", ptr_dcc->nick);
+ weechat_log_printf (" sock. . . . . . . . : %d\n", ptr_dcc->sock);
+ weechat_log_printf (" child_pid . . . . . : %d\n", ptr_dcc->child_pid);
+ weechat_log_printf (" child_read. . . . . : %d\n", ptr_dcc->child_read);
+ weechat_log_printf (" child_write . . . . : %d\n", ptr_dcc->child_write);
+ weechat_log_printf (" unterminated_message: '%s'\n", ptr_dcc->unterminated_message);
+ weechat_log_printf (" fast_send . . . . . : %d\n", ptr_dcc->fast_send);
+ weechat_log_printf (" file. . . . . . . . : %d\n", ptr_dcc->file);
+ weechat_log_printf (" filename. . . . . . : '%s'\n", ptr_dcc->filename);
+ weechat_log_printf (" local_filename. . . : '%s'\n", ptr_dcc->local_filename);
+ weechat_log_printf (" filename_suffix . . : %d\n", ptr_dcc->filename_suffix);
+ weechat_log_printf (" blocksize . . . . . : %d\n", ptr_dcc->blocksize);
+ weechat_log_printf (" size. . . . . . . . : %lu\n", ptr_dcc->size);
+ weechat_log_printf (" pos . . . . . . . . : %lu\n", ptr_dcc->pos);
+ weechat_log_printf (" ack . . . . . . . . : %lu\n", ptr_dcc->ack);
+ weechat_log_printf (" start_resume. . . . : %lu\n", ptr_dcc->start_resume);
+ weechat_log_printf (" last_check_time . . : %ld\n", ptr_dcc->last_check_time);
+ weechat_log_printf (" last_check_pos. . . : %lu\n", ptr_dcc->last_check_pos);
+ weechat_log_printf (" last_activity . . . : %ld\n", ptr_dcc->last_activity);
+ weechat_log_printf (" bytes_per_sec . . . : %lu\n", ptr_dcc->bytes_per_sec);
+ weechat_log_printf (" eta . . . . . . . . : %lu\n", ptr_dcc->eta);
+ weechat_log_printf (" prev_dcc. . . . . . : 0x%X\n", ptr_dcc->prev_dcc);
+ weechat_log_printf (" next_dcc. . . . . . : 0x%X\n", ptr_dcc->next_dcc);
+ }
+}
diff --git a/src/plugins/irc/irc-display.c b/src/plugins/irc/irc-display.c
new file mode 100644
index 000000000..f1112eaa8
--- /dev/null
+++ b/src/plugins/irc/irc-display.c
@@ -0,0 +1,487 @@
+/*
+ * 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/>.
+ */
+
+/* irc-display.c: display functions for IRC */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "../../common/weechat.h"
+#include "irc.h"
+#include "../../common/utf8.h"
+#include "../../common/weeconfig.h"
+#include "../../gui/gui.h"
+
+
+/*
+ * irc_display_hide_password: hide IRC password(s) in a string
+ */
+
+void
+irc_display_hide_password (char *string, int look_for_nickserv)
+{
+ char *pos_nickserv, *pos, *pos_pwd;
+
+ pos = string;
+ while (1)
+ {
+ if (look_for_nickserv)
+ {
+ pos_nickserv = strstr (pos, "nickserv ");
+ if (!pos_nickserv)
+ return;
+ pos = pos_nickserv + 9;
+ while (pos[0] == ' ')
+ pos++;
+ if ((strncmp (pos, "identify ", 9) == 0)
+ || (strncmp (pos, "register ", 9) == 0))
+ pos_pwd = pos + 9;
+ else
+ pos_pwd = NULL;
+ }
+ else
+ {
+ pos_pwd = strstr (pos, "identify ");
+ if (!pos_pwd)
+ pos_pwd = strstr (pos, "register ");
+ if (!pos_pwd)
+ return;
+ pos_pwd += 9;
+ }
+
+ if (pos_pwd)
+ {
+ while (pos_pwd[0] == ' ')
+ pos_pwd++;
+
+ while (pos_pwd[0] && (pos_pwd[0] != ';') && (pos_pwd[0] != ' ')
+ && (pos_pwd[0] != '"'))
+ {
+ pos_pwd[0] = '*';
+ pos_pwd++;
+ }
+ pos = pos_pwd;
+ }
+ }
+}
+
+/*
+ * irc_display_prefix: display a prefix for action/info/error msg
+ * prefix must be 3 chars length
+ */
+
+void
+irc_display_prefix (t_irc_server *server, t_gui_buffer *buffer, char *prefix)
+{
+ int type;
+ char format[32];
+
+ type = GUI_MSG_TYPE_INFO | GUI_MSG_TYPE_PREFIX;
+
+ if (!cfg_log_plugin_msg && (strcmp (prefix, GUI_PREFIX_PLUGIN) == 0))
+ type |= GUI_MSG_TYPE_NOLOG;
+
+ if (buffer)
+ {
+ if (cfg_look_align_other
+ && (GUI_BUFFER_IS_CHANNEL(buffer) || GUI_BUFFER_IS_PRIVATE(buffer)))
+ {
+ snprintf (format, 32, "%%-%ds", cfg_look_align_size - 2);
+ gui_printf_type (buffer, GUI_MSG_TYPE_NICK, format, " ");
+ }
+ }
+
+ if (prefix[0] == prefix[2])
+ {
+ gui_printf_type (buffer, type, "%s%c%s%c%s%c ",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_PREFIX1),
+ prefix[0],
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_PREFIX2),
+ prefix[1],
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_PREFIX1),
+ prefix[2]);
+ }
+ else
+ {
+ if (strcmp (prefix, GUI_PREFIX_JOIN) == 0)
+ gui_printf_type (buffer, type, "%s%s ",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_JOIN), prefix);
+ else if (strcmp (prefix, GUI_PREFIX_PART) == 0)
+ gui_printf_type (buffer, type, "%s%s ",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_PART), prefix);
+ else
+ gui_printf_type (buffer, type, "%s%s ",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_PREFIX1), prefix);
+ }
+ if (server && (server->buffer == buffer) && buffer->all_servers)
+ {
+ gui_printf_type (buffer, type, "%s[%s%s%s] ",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_SERVER), server->name,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK));
+ }
+ gui_printf_type (buffer, type, GUI_NO_COLOR);
+}
+
+/*
+ * irc_display_nick: display nick in chat window
+ */
+
+void
+irc_display_nick (t_gui_buffer *buffer, t_irc_nick *nick, char *nickname,
+ int type, int display_around, int force_color, int no_nickmode)
+{
+ char format[32], *ptr_nickname;
+ int max_align, i, nickname_length, external_nick, length, spaces;
+ int disable_prefix_suffix;
+
+ max_align = (cfg_look_align_size_max >= cfg_look_align_size) ?
+ cfg_look_align_size_max : cfg_look_align_size;
+
+ ptr_nickname = strdup ((nick) ? nick->nick : nickname);
+ if (!ptr_nickname)
+ return;
+ nickname_length = utf8_width_screen (ptr_nickname);
+ external_nick = (!nick && !GUI_BUFFER_IS_PRIVATE(buffer));
+ disable_prefix_suffix = ((cfg_look_align_nick != CFG_LOOK_ALIGN_NICK_NONE)
+ && ((int)strlen (cfg_look_nick_prefix) +
+ (int)strlen (cfg_look_nick_suffix) > max_align - 4));
+
+ /* calculate length to display, to truncate it if too long */
+ length = nickname_length;
+ if (!disable_prefix_suffix && cfg_look_nick_prefix)
+ length += strlen (cfg_look_nick_prefix);
+ if (external_nick)
+ length += 2;
+ if (nick && cfg_look_nickmode)
+ {
+ if (nick->flags & (IRC_NICK_CHANOWNER | IRC_NICK_CHANADMIN |
+ IRC_NICK_CHANADMIN2 | IRC_NICK_OP | IRC_NICK_HALFOP |
+ IRC_NICK_VOICE | IRC_NICK_CHANUSER))
+ length += 1;
+ else if (cfg_look_nickmode_empty && !no_nickmode)
+ length += 1;
+ }
+ if (!disable_prefix_suffix && cfg_look_nick_suffix)
+ length += strlen (cfg_look_nick_suffix);
+
+ /* calculate number of spaces to insert before or after nick */
+ spaces = 0;
+ if (cfg_look_align_nick != CFG_LOOK_ALIGN_NICK_NONE)
+ {
+ if (length > max_align)
+ spaces = max_align - length;
+ else if (length > cfg_look_align_size)
+ spaces = 0;
+ else
+ spaces = cfg_look_align_size - length;
+ }
+
+ /* display prefix */
+ if (display_around && !disable_prefix_suffix
+ && cfg_look_nick_prefix && cfg_look_nick_prefix[0])
+ gui_printf_type (buffer, type, "%s%s",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ cfg_look_nick_prefix);
+
+ /* display spaces before nick, if needed */
+ if (display_around
+ && (cfg_look_align_nick == CFG_LOOK_ALIGN_NICK_RIGHT)
+ && (spaces > 0))
+ {
+ snprintf (format, 32, "%%-%ds", spaces);
+ gui_printf_type (buffer, type, format, " ");
+ }
+
+ /* display nick mode */
+ if (nick && cfg_look_nickmode)
+ {
+ if (nick->flags & IRC_NICK_CHANOWNER)
+ gui_printf_type (buffer, type, "%s~",
+ GUI_COLOR(GUI_COLOR_WIN_NICK_OP));
+ else if (nick->flags & IRC_NICK_CHANADMIN)
+ gui_printf_type (buffer, type, "%s&",
+ GUI_COLOR(GUI_COLOR_WIN_NICK_OP));
+ else if (nick->flags & IRC_NICK_CHANADMIN2)
+ gui_printf_type (buffer, type, "%s!",
+ GUI_COLOR(GUI_COLOR_WIN_NICK_OP));
+ else if (nick->flags & IRC_NICK_OP)
+ gui_printf_type (buffer, type, "%s@",
+ GUI_COLOR(GUI_COLOR_WIN_NICK_OP));
+ else if (nick->flags & IRC_NICK_HALFOP)
+ gui_printf_type (buffer, type, "%s%%",
+ GUI_COLOR(GUI_COLOR_WIN_NICK_HALFOP));
+ else if (nick->flags & IRC_NICK_VOICE)
+ gui_printf_type (buffer, type, "%s+",
+ GUI_COLOR(GUI_COLOR_WIN_NICK_VOICE));
+ else if (nick->flags & IRC_NICK_CHANUSER)
+ gui_printf_type (buffer, type, "%s-",
+ GUI_COLOR(GUI_COLOR_WIN_NICK_CHANUSER));
+ else if (cfg_look_nickmode_empty && !no_nickmode)
+ gui_printf_type (buffer, type, "%s ",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT));
+ }
+
+ /* display nick */
+ if (external_nick)
+ gui_printf_type (buffer, type, "%s%s",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ "(");
+ if (display_around && (spaces < 0))
+ {
+ i = nickname_length + spaces - 1;
+ if (i < 3)
+ {
+ if (nickname_length < 3)
+ i = nickname_length;
+ else
+ i = 3;
+ }
+ ptr_nickname[i] = '\0';
+ }
+ if (display_around)
+ gui_printf_type_nick (buffer, type,
+ (nick) ? nick->nick : nickname,
+ "%s%s",
+ (force_color >= 0) ?
+ GUI_COLOR(force_color) :
+ GUI_COLOR((nick) ? nick->color : GUI_COLOR_WIN_CHAT),
+ ptr_nickname);
+ else
+ gui_printf_type (buffer, type,
+ "%s%s",
+ (force_color >= 0) ?
+ GUI_COLOR(force_color) :
+ GUI_COLOR((nick) ? nick->color : GUI_COLOR_WIN_CHAT),
+ ptr_nickname);
+ if (display_around && (spaces < 0))
+ gui_printf_type (buffer, type, "%s+",
+ GUI_COLOR(GUI_COLOR_WIN_NICK_MORE));
+ if (external_nick)
+ gui_printf_type (buffer, type, "%s%s",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ ")");
+
+ /* display spaces after nick, if needed */
+ if (display_around
+ && (cfg_look_align_nick == CFG_LOOK_ALIGN_NICK_LEFT)
+ && (spaces > 0))
+ {
+ snprintf (format, 32, "%%-%ds", spaces);
+ gui_printf_type (buffer, type, format, " ");
+ }
+
+ /* display suffix */
+ if (display_around && !disable_prefix_suffix
+ && cfg_look_nick_suffix && cfg_look_nick_suffix[0])
+ gui_printf_type (buffer, type, "%s%s",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ cfg_look_nick_suffix);
+
+ gui_printf_type (buffer, type, "%s%s",
+ GUI_NO_COLOR,
+ (display_around) ? " " : "");
+ free (ptr_nickname);
+}
+
+/*
+ * irc_display_away: display away on all channels of all servers
+ */
+
+void
+irc_display_away (t_irc_server *server, char *string1, char *string2)
+{
+ t_irc_channel *ptr_channel;
+ char format[32];
+
+ for (ptr_channel = server->channels; ptr_channel;
+ ptr_channel = ptr_channel->next_channel)
+ {
+ if (ptr_channel->type == IRC_CHANNEL_TYPE_CHANNEL)
+ {
+ if (cfg_look_align_other)
+ {
+ snprintf (format, 32, "%%-%ds", cfg_look_align_size + 1);
+ gui_printf_type (ptr_channel->buffer, GUI_MSG_TYPE_NICK,
+ format, " ");
+ }
+ gui_printf_nolog (ptr_channel->buffer,
+ "%s[%s%s%s %s: %s%s]\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ server->nick,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ string1,
+ string2,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK));
+ }
+ }
+}
+
+/*
+ * irc_display_mode: display IRC message for mode change
+ */
+
+void
+irc_display_mode (t_irc_server *server, t_gui_buffer *buffer,
+ char *channel_name, char *nick_name, char set_flag,
+ char *symbol, char *nick_host, char *message, char *param)
+{
+ irc_display_prefix (server, buffer, GUI_PREFIX_INFO);
+ gui_printf (buffer, "%s[%s%s%s/%s%c%s%s] %s%s",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ (channel_name) ?
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL) :
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ (channel_name) ? channel_name : nick_name,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ set_flag,
+ symbol,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ nick_host);
+ if (param)
+ gui_printf (buffer, " %s%s %s%s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ message,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ param);
+ else
+ gui_printf (buffer, " %s%s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ message);
+}
+
+/*
+ * irc_display_server: display server description
+ */
+
+void
+irc_display_server (t_irc_server *server, int with_detail)
+{
+ char *string;
+ int num_channels, num_pv;
+
+ if (with_detail)
+ {
+ gui_printf (NULL, "\n");
+ gui_printf (NULL, _("%sServer: %s%s %s[%s%s%s]\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_SERVER),
+ server->name,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ (server->is_connected) ?
+ _("connected") : _("not connected"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK));
+
+ gui_printf (NULL, " server_autoconnect . . . . : %s%s\n",
+ (server->autoconnect) ? _("on") : _("off"),
+ (server->temp_server) ?
+ _(" (temporary server, will not be saved)") : "");
+ gui_printf (NULL, " server_autoreconnect . . . : %s\n",
+ (server->autoreconnect) ? _("on") : _("off"));
+ gui_printf (NULL, " server_autoreconnect_delay : %d %s\n",
+ server->autoreconnect_delay,
+ _("seconds"));
+ gui_printf (NULL, " server_address . . . . . . : %s\n",
+ server->address);
+ gui_printf (NULL, " server_port . . . . . . . : %d\n",
+ server->port);
+ gui_printf (NULL, " server_ipv6 . . . . . . . : %s\n",
+ (server->ipv6) ? _("on") : _("off"));
+ gui_printf (NULL, " server_ssl . . . . . . . . : %s\n",
+ (server->ssl) ? _("on") : _("off"));
+ gui_printf (NULL, " server_password . . . . . : %s\n",
+ (server->password && server->password[0]) ?
+ _("(hidden)") : "");
+ gui_printf (NULL, " server_nick1/2/3 . . . . . : %s %s/ %s%s %s/ %s%s\n",
+ server->nick1,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ server->nick2,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ server->nick3);
+ gui_printf (NULL, " server_username . . . . . : %s\n",
+ server->username);
+ gui_printf (NULL, " server_realname . . . . . : %s\n",
+ server->realname);
+ gui_printf (NULL, " server_hostname . . . . . : %s\n",
+ (server->hostname) ? server->hostname : "");
+ if (server->command && server->command[0])
+ string = strdup (server->command);
+ else
+ string = NULL;
+ if (string)
+ {
+ if (cfg_log_hide_nickserv_pwd)
+ irc_display_hide_password (string, 1);
+ gui_printf (NULL, " server_command . . . . . . : %s\n",
+ string);
+ free (string);
+ }
+ else
+ gui_printf (NULL, " server_command . . . . . . : %s\n",
+ (server->command && server->command[0]) ?
+ server->command : "");
+ gui_printf (NULL, " server_command_delay . . . : %d %s\n",
+ server->command_delay,
+ _("seconds"));
+ gui_printf (NULL, " server_autojoin . . . . . : %s\n",
+ (server->autojoin && server->autojoin[0]) ?
+ server->autojoin : "");
+ gui_printf (NULL, " server_notify_levels . . . : %s\n",
+ (server->notify_levels && server->notify_levels[0]) ?
+ server->notify_levels : "");
+ }
+ else
+ {
+ gui_printf (NULL, " %s %s%s ",
+ (server->is_connected) ? "*" : " ",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_SERVER),
+ server->name);
+ gui_printf (NULL, "%s[%s%s",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ (server->is_connected) ?
+ _("connected") : _("not connected"));
+ if (server->is_connected)
+ {
+ num_channels = irc_server_get_channel_count (server);
+ num_pv = irc_server_get_pv_count (server);
+ gui_printf (NULL, ", ");
+ gui_printf (NULL, NG_("%d channel", "%d channels", num_channels),
+ num_channels);
+ gui_printf (NULL, ", ");
+ gui_printf (NULL, _("%d pv"), num_pv);
+ }
+ gui_printf (NULL, "%s]%s%s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ (server->temp_server) ? _(" (temporary)") : "");
+ }
+}
diff --git a/src/plugins/irc/irc-ignore.c b/src/plugins/irc/irc-ignore.c
new file mode 100644
index 000000000..c7e8b509d
--- /dev/null
+++ b/src/plugins/irc/irc-ignore.c
@@ -0,0 +1,440 @@
+/*
+ * 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/>.
+ */
+
+/* irc-ignore.c: manages IRC ignore list */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "../../common/weechat.h"
+#include "irc.h"
+#include "../../common/command.h"
+#include "../../common/log.h"
+#include "../../common/util.h"
+
+
+t_irc_ignore *irc_ignore = NULL;
+t_irc_ignore *last_irc_ignore = NULL;
+
+
+/*
+ * irc_ignore_check_mask: return 1 is mask1 and mask2 are the same host
+ * anyone or both strings may have user and/or host after
+ */
+
+int
+irc_ignore_check_mask (char *mask1, char *mask2)
+{
+ char *m1, *m2, *pos;
+ int match;
+
+ if (!mask1 || !mask1[0] || !mask2 || !mask2[0])
+ return 0;
+
+ m1 = strdup (mask1);
+ m2 = strdup (mask2);
+
+ pos = strchr (m1, '!');
+ if (!pos)
+ {
+ /* remove '!' from m2 */
+ pos = strchr (m2, '!');
+ if (pos)
+ pos[0] = '\0';
+ }
+ pos = strchr (m2, '!');
+ if (!pos)
+ {
+ /* remove '!' from m1 */
+ pos = strchr (m1, '!');
+ if (pos)
+ pos[0] = '\0';
+ }
+
+ /* TODO: use regexp to match both masks */
+ match = ascii_strcasecmp (m1, m2);
+
+ free (m1);
+ free (m2);
+
+ return (match == 0);
+}
+
+/*
+ * irc_ignore_match: check if pointed ignore matches with arguments
+ */
+
+int
+irc_ignore_match (t_irc_ignore *ptr_ignore, char *mask, char *type,
+ char *channel_name, char *server_name)
+{
+ /* check mask */
+ if ((strcmp (mask, "*") != 0) && (strcmp (ptr_ignore->mask, "*") != 0)
+ && (!irc_ignore_check_mask (ptr_ignore->mask, mask)))
+ return 0;
+
+ /* mask is matching, go on with type */
+ if ((strcmp (type, "*") != 0) && (strcmp (ptr_ignore->type, "*") != 0)
+ && (ascii_strcasecmp (ptr_ignore->type, type) != 0))
+ return 0;
+
+ /* mask and type matching, go on with server */
+ if (server_name && server_name[0])
+ {
+ if ((strcmp (server_name, "*") != 0) && (strcmp (ptr_ignore->server_name, "*") != 0)
+ && (ascii_strcasecmp (ptr_ignore->server_name, server_name) != 0))
+ return 0;
+ }
+ else
+ {
+ if (strcmp (ptr_ignore->server_name, "*") != 0)
+ return 0;
+ }
+
+ /* mask, type and server matching, go on with channel */
+ if (channel_name && channel_name[0])
+ {
+ if ((strcmp (channel_name, "*") != 0) && (strcmp (ptr_ignore->channel_name, "*") != 0)
+ && (ascii_strcasecmp (ptr_ignore->channel_name, channel_name) != 0))
+ return 0;
+ }
+ else
+ {
+ if (strcmp (ptr_ignore->channel_name, "*") != 0)
+ return 0;
+ }
+
+ /* all is matching => we find a ignore! */
+ return 1;
+}
+
+/*
+ * irc_ignore_check: check if an ignore is set for arguments
+ * return 1 if at least one ignore exists (message should NOT be displayed)
+ * 0 if no ignore found (message will be displayed)
+ */
+
+int
+irc_ignore_check (char *mask, char *type, char *channel_name, char *server_name)
+{
+ t_irc_ignore *ptr_ignore;
+
+ if (!mask || !mask[0] || !type || !type[0])
+ return 0;
+
+ for (ptr_ignore = irc_ignore; ptr_ignore;
+ ptr_ignore = ptr_ignore->next_ignore)
+ {
+ if (irc_ignore_match (ptr_ignore, mask, type, channel_name, server_name))
+ return 1;
+ }
+
+ /* no ignore found */
+ return 0;
+}
+
+/*
+ * irc_ignore_search: search for an ignore
+ */
+
+t_irc_ignore *
+irc_ignore_search (char *mask, char *type, char *channel_name, char *server_name)
+{
+ t_irc_ignore *ptr_ignore;
+
+ for (ptr_ignore = irc_ignore; ptr_ignore;
+ ptr_ignore = ptr_ignore->next_ignore)
+ {
+ if ((ascii_strcasecmp (ptr_ignore->mask, mask) == 0)
+ && (ascii_strcasecmp (ptr_ignore->type, type) == 0)
+ && (ascii_strcasecmp (ptr_ignore->channel_name, channel_name) == 0)
+ && (ascii_strcasecmp (ptr_ignore->server_name, server_name) == 0))
+ return ptr_ignore;
+ }
+
+ /* ignore not found */
+ return NULL;
+}
+
+/*
+ * irc_ignore_add: add an ignore in list
+ */
+
+t_irc_ignore *
+irc_ignore_add (char *mask, char *type, char *channel_name, char *server_name)
+{
+ int type_index;
+ t_irc_command *command_ptr;
+ t_irc_ignore *new_ignore;
+
+ if (!mask || !mask[0] || !type || !type[0] || !channel_name || !channel_name[0]
+ || !server_name || !server_name[0])
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s too few arguments for ignore\n"),
+ WEECHAT_ERROR);
+ return NULL;
+ }
+
+#ifdef DEBUG
+ weechat_log_printf ("Adding ignore: mask:'%s', type:'%s', channel:'%s', "
+ "server:'%s'\n",
+ mask, type, channel_name, server_name);
+#endif
+
+ type_index = -1;
+ command_ptr = NULL;
+
+ if ((strcmp (mask, "*") == 0) && (strcmp (type, "*") == 0))
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s mask or type/command should be non generic value for ignore\n"),
+ WEECHAT_ERROR);
+ return NULL;
+ }
+
+ if (irc_ignore_search (mask, type, channel_name, server_name))
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s ignore already exists\n"),
+ WEECHAT_ERROR);
+ return NULL;
+ }
+
+ /* create new ignore */
+ new_ignore = (t_irc_ignore *) malloc (sizeof (t_irc_ignore));
+ if (new_ignore)
+ {
+ new_ignore->mask = strdup (mask);
+ new_ignore->type = strdup (type);
+ new_ignore->server_name = strdup (server_name);
+ new_ignore->channel_name = strdup (channel_name);
+
+ /* add new ignore to queue */
+ new_ignore->prev_ignore = last_irc_ignore;
+ new_ignore->next_ignore = NULL;
+ if (irc_ignore)
+ last_irc_ignore->next_ignore = new_ignore;
+ else
+ irc_ignore = new_ignore;
+ last_irc_ignore = new_ignore;
+ }
+ else
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf (NULL,
+ _("%s not enough memory to create ignore\n"),
+ WEECHAT_ERROR);
+ return NULL;
+ }
+
+ return new_ignore;
+}
+
+/*
+ * irc_ignore_add_from_config: add an ignore to list, read from config file
+ * (comma serparated values)
+ */
+
+t_irc_ignore *
+irc_ignore_add_from_config (char *string)
+{
+ t_irc_ignore *new_ignore;
+ char *string2;
+ char *pos_mask, *pos_type, *pos_channel, *pos_server;
+
+ if (!string || !string[0])
+ return NULL;
+
+ new_ignore = NULL;
+ string2 = strdup (string);
+
+ pos_mask = string2;
+ pos_type = strchr (pos_mask, ',');
+ if (pos_type)
+ {
+ pos_type[0] = '\0';
+ pos_type++;
+ pos_channel = strchr (pos_type, ',');
+ if (pos_channel)
+ {
+ pos_channel[0] = '\0';
+ pos_channel++;
+ pos_server = strchr (pos_channel, ',');
+ if (pos_server)
+ {
+ pos_server[0] = '\0';
+ pos_server++;
+ new_ignore = irc_ignore_add (pos_mask, pos_type, pos_channel, pos_server);
+ }
+ }
+ }
+
+ free (string2);
+ return new_ignore;
+}
+
+/*
+ * irc_ignore_free: free an ignore
+ */
+
+void
+irc_ignore_free (t_irc_ignore *ptr_ignore)
+{
+ t_irc_ignore *new_irc_ignore;
+
+ /* free data */
+ if (ptr_ignore->mask)
+ free (ptr_ignore->mask);
+ if (ptr_ignore->type)
+ free (ptr_ignore->type);
+ if (ptr_ignore->channel_name)
+ free (ptr_ignore->channel_name);
+ if (ptr_ignore->server_name)
+ free (ptr_ignore->server_name);
+
+ /* remove ignore from queue */
+ if (last_irc_ignore == ptr_ignore)
+ last_irc_ignore = ptr_ignore->prev_ignore;
+ if (ptr_ignore->prev_ignore)
+ {
+ (ptr_ignore->prev_ignore)->next_ignore = ptr_ignore->next_ignore;
+ new_irc_ignore = irc_ignore;
+ }
+ else
+ new_irc_ignore = ptr_ignore->next_ignore;
+
+ if (ptr_ignore->next_ignore)
+ (ptr_ignore->next_ignore)->prev_ignore = ptr_ignore->prev_ignore;
+
+ free (ptr_ignore);
+ irc_ignore = new_irc_ignore;
+}
+
+/*
+ * irc_ignore_free_all: free all ignores
+ */
+
+void
+irc_ignore_free_all ()
+{
+ while (irc_ignore)
+ irc_ignore_free (irc_ignore);
+}
+
+/*
+ * irc_ignore_search_free: search and free ignore(s)
+ * return: number of ignore found and deleted
+ * 0 if no ignore found
+ */
+
+int
+irc_ignore_search_free (char *mask, char *type,
+ char *channel_name, char *server_name)
+{
+ int found;
+ t_irc_ignore *ptr_ignore, *next_ignore;
+
+ found = 0;
+ ptr_ignore = irc_ignore;
+ while (ptr_ignore)
+ {
+ if (irc_ignore_match (ptr_ignore, mask, type, channel_name, server_name))
+ {
+ found++;
+ if (found == 1)
+ gui_printf (NULL, "\n");
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_INFO);
+ weechat_cmd_ignore_display (_("Removing ignore:"), ptr_ignore);
+ next_ignore = ptr_ignore->next_ignore;
+ irc_ignore_free (ptr_ignore);
+ ptr_ignore = next_ignore;
+ }
+ else
+ ptr_ignore = ptr_ignore->next_ignore;
+ }
+
+ return found;
+}
+
+/*
+ * irc_ignore_search_free_by_number: search and free ignore(s) by number
+ * return: 1 if ignore found and deleted
+ * 0 if ignore not found
+ */
+
+int
+irc_ignore_search_free_by_number (int number)
+{
+ int i;
+ t_irc_ignore *ptr_ignore;
+
+ if (number < 1)
+ return 0;
+
+ i = 0;
+ for (ptr_ignore = irc_ignore; ptr_ignore;
+ ptr_ignore = ptr_ignore->next_ignore)
+ {
+ i++;
+ if (i == number)
+ {
+ gui_printf (NULL, "\n");
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_INFO);
+ weechat_cmd_ignore_display (_("Removing ignore:"), ptr_ignore);
+ irc_ignore_free (ptr_ignore);
+ return 1;
+ }
+ }
+
+ /* ignore number not found */
+ return 0;
+}
+
+/*
+ * irc_ignore_print_log: print ignore list in log (usually for crash dump)
+ */
+
+void
+irc_ignore_print_log ()
+{
+ t_irc_ignore *ptr_ignore;
+
+ weechat_log_printf ("[ignore list]\n");
+
+ for (ptr_ignore = irc_ignore; ptr_ignore;
+ ptr_ignore = ptr_ignore->next_ignore)
+ {
+ weechat_log_printf ("\n");
+ weechat_log_printf (" -> ignore at 0x%X:\n", ptr_ignore);
+ weechat_log_printf (" mask. . . . . . . : %s\n", ptr_ignore->mask);
+ weechat_log_printf (" type. . . . . . . : %s\n", ptr_ignore->type);
+ weechat_log_printf (" channel_name. . . : %s\n", ptr_ignore->channel_name);
+ weechat_log_printf (" server_name . . . : %s\n", ptr_ignore->server_name);
+ weechat_log_printf (" prev_ignore . . . : 0x%X\n", ptr_ignore->prev_ignore);
+ weechat_log_printf (" next_ignore . . . : 0x%X\n", ptr_ignore->next_ignore);
+ }
+}
diff --git a/src/plugins/irc/irc-mode.c b/src/plugins/irc/irc-mode.c
new file mode 100644
index 000000000..766b91b5d
--- /dev/null
+++ b/src/plugins/irc/irc-mode.c
@@ -0,0 +1,316 @@
+/*
+ * 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/>.
+ */
+
+/* irc-mode.c: IRC channel/user modes management */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "../../common/weechat.h"
+#include "irc.h"
+#include "../../common/util.h"
+#include "../../gui/gui.h"
+
+
+/*
+ * irc_mode_channel_set_nick: set a mode for a nick on a channel
+ */
+
+void
+irc_mode_channel_set_nick (t_irc_channel *channel, char *nick,
+ char set_flag, int flag)
+{
+ t_irc_nick *ptr_nick;
+
+ if (nick)
+ {
+ ptr_nick = irc_nick_search (channel, nick);
+ if (ptr_nick)
+ {
+ IRC_NICK_SET_FLAG(ptr_nick, (set_flag == '+'), flag);
+ irc_nick_resort (channel, ptr_nick);
+ gui_nicklist_draw (channel->buffer, 1, 1);
+ }
+ }
+}
+
+/*
+ * irc_mode_channel_get_flag: search for flag before current position
+ */
+
+char
+irc_mode_channel_get_flag (char *str, char *pos)
+{
+ char set_flag;
+
+ set_flag = '+';
+ pos--;
+ while (pos >= str)
+ {
+ if (pos[0] == '-')
+ return '-';
+ if (pos[0] == '+')
+ return '+';
+ pos--;
+ }
+ return set_flag;
+}
+
+/*
+ * irc_mode_channel_set: set channel modes
+ */
+
+void
+irc_mode_channel_set (t_irc_server *server, t_irc_channel *channel,
+ char *modes)
+{
+ char *pos_args, set_flag, **argv, *pos, *ptr_arg;
+ int argc, current_arg;
+
+ argc = 0;
+ argv = NULL;
+ current_arg = 0;
+ pos_args = strchr (modes, ' ');
+ if (pos_args)
+ {
+ pos_args[0] = '\0';
+ pos_args++;
+ while (pos_args[0] == ' ')
+ pos_args++;
+ argv = explode_string (pos_args, " ", 0, &argc);
+ if (argc > 0)
+ current_arg = argc - 1;
+ }
+
+ if (modes && modes[0])
+ {
+ set_flag = '+';
+ pos = modes + strlen (modes) - 1;
+ while (pos >= modes)
+ {
+ switch (pos[0])
+ {
+ case ':':
+ case ' ':
+ case '+':
+ case '-':
+ break;
+ default:
+ set_flag = irc_mode_channel_get_flag (modes, pos);
+ switch (pos[0])
+ {
+ case 'a': /* channel admin (unrealircd specific flag) */
+ ptr_arg = ((argc > 0) && (current_arg >= 0)) ?
+ argv[current_arg--] : NULL;
+ if (irc_mode_nick_prefix_allowed (server, '~'))
+ irc_mode_channel_set_nick (channel, ptr_arg,
+ set_flag, IRC_NICK_CHANADMIN);
+ break;
+ case 'b': /* ban (ignored) */
+ ptr_arg = ((argc > 0) && (current_arg >= 0)) ?
+ argv[current_arg--] : NULL;
+ break;
+ case 'h': /* half-op */
+ ptr_arg = ((argc > 0) && (current_arg >= 0)) ?
+ argv[current_arg--] : NULL;
+ if (irc_mode_nick_prefix_allowed (server, '%'))
+ irc_mode_channel_set_nick (channel, ptr_arg,
+ set_flag, IRC_NICK_HALFOP);
+ break;
+ case 'k': /* channel key */
+ if (channel->key)
+ {
+ free (channel->key);
+ channel->key = NULL;
+ }
+ if (set_flag == '+')
+ {
+ ptr_arg = ((argc > 0) && (current_arg >= 0)) ?
+ argv[current_arg--] : NULL;
+ if (ptr_arg)
+ channel->key = strdup (ptr_arg);
+ }
+ break;
+ case 'l': /* channel limit */
+ if (set_flag == '-')
+ channel->limit = 0;
+ if (set_flag == '+')
+ {
+ ptr_arg = ((argc > 0) && (current_arg >= 0)) ?
+ argv[current_arg--] : NULL;
+ if (ptr_arg)
+ channel->limit = atoi (ptr_arg);
+ }
+ break;
+ case 'o': /* op */
+ ptr_arg = ((argc > 0) && (current_arg >= 0)) ?
+ argv[current_arg--] : NULL;
+ if (irc_mode_nick_prefix_allowed (server, '@'))
+ irc_mode_channel_set_nick (channel, ptr_arg,
+ set_flag, IRC_NICK_OP);
+ break;
+ case 'q': /* channel owner (unrealircd specific flag) */
+ ptr_arg = ((argc > 0) && (current_arg >= 0)) ?
+ argv[current_arg--] : NULL;
+ if (irc_mode_nick_prefix_allowed (server, '~'))
+ irc_mode_channel_set_nick (channel, ptr_arg,
+ set_flag, IRC_NICK_CHANOWNER);
+ break;
+ case 'u': /* channel user */
+ ptr_arg = ((argc > 0) && (current_arg >= 0)) ?
+ argv[current_arg--] : NULL;
+ if (irc_mode_nick_prefix_allowed (server, '-'))
+ irc_mode_channel_set_nick (channel, ptr_arg,
+ set_flag, IRC_NICK_CHANUSER);
+ break;
+ case 'v': /* voice */
+ ptr_arg = ((argc > 0) && (current_arg >= 0)) ?
+ argv[current_arg--] : NULL;
+ if (irc_mode_nick_prefix_allowed (server, '+'))
+ irc_mode_channel_set_nick (channel, ptr_arg,
+ set_flag, IRC_NICK_VOICE);
+ break;
+ }
+ break;
+ }
+ pos--;
+ }
+ }
+
+ if (argv)
+ free_exploded_string (argv);
+}
+
+/*
+ * irc_mode_user_add: add a user mode
+ */
+
+void
+irc_mode_user_add (t_irc_server *server, char mode)
+{
+ char str_mode[2];
+
+ str_mode[0] = mode;
+ str_mode[1] = '\0';
+
+ if (server->nick_modes)
+ {
+ if (!strchr (server->nick_modes, mode))
+ {
+ server->nick_modes = (char *) realloc (server->nick_modes,
+ strlen (server->nick_modes) + 1 + 1);
+ strcat (server->nick_modes, str_mode);
+ gui_status_draw (gui_current_window->buffer, 1);
+ gui_input_draw (gui_current_window->buffer, 1);
+ }
+ }
+ else
+ {
+ server->nick_modes = (char *) malloc (2);
+ strcpy (server->nick_modes, str_mode);
+ gui_status_draw (gui_current_window->buffer, 1);
+ gui_input_draw (gui_current_window->buffer, 1);
+ }
+}
+
+/*
+ * irc_mode_user_remove: remove a user mode
+ */
+
+void
+irc_mode_user_remove (t_irc_server *server, char mode)
+{
+ char *pos;
+ int new_size;
+
+ if (server->nick_modes)
+ {
+ pos = strchr (server->nick_modes, mode);
+ if (pos)
+ {
+ new_size = strlen (server->nick_modes);
+ memmove (pos, pos + 1, strlen (pos + 1) + 1);
+ server->nick_modes = (char *) realloc (server->nick_modes,
+ new_size);
+ gui_status_draw (gui_current_window->buffer, 1);
+ gui_input_draw (gui_current_window->buffer, 1);
+ }
+ }
+}
+
+/*
+ * irc_mode_user_set: set user modes
+ */
+
+void
+irc_mode_user_set (t_irc_server *server, char *modes)
+{
+ char set_flag;
+
+ set_flag = '+';
+ while (modes && modes[0])
+ {
+ switch (modes[0])
+ {
+ case ':':
+ case ' ':
+ break;
+ case '+':
+ set_flag = '+';
+ break;
+ case '-':
+ set_flag = '-';
+ break;
+ default:
+ if (set_flag == '+')
+ irc_mode_user_add (server, modes[0]);
+ else
+ irc_mode_user_remove (server, modes[0]);
+ break;
+ }
+ modes++;
+ }
+}
+
+/*
+ * irc_mode_nick_prefix_allowed: return <> 0 if nick prefix is allowed by server
+ * for example :
+ * IRC: 005 (...) PREFIX=(ov)@+
+ * => allowed prefixes: @+
+ */
+
+int
+irc_mode_nick_prefix_allowed (t_irc_server *server, char prefix)
+{
+ char str[2];
+
+ /* if server did not send any prefix info, then use default prefixes */
+ if (!server->prefix)
+ {
+ str[0] = prefix;
+ str[1] = '\0';
+ return (strpbrk (str, IRC_DEFAULT_PREFIXES_LIST)) ? 1 : 0;
+ }
+
+ return (strchr (server->prefix, prefix) != NULL);
+}
diff --git a/src/plugins/irc/irc-nick.c b/src/plugins/irc/irc-nick.c
new file mode 100644
index 000000000..27e5378a8
--- /dev/null
+++ b/src/plugins/irc/irc-nick.c
@@ -0,0 +1,454 @@
+/*
+ * 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/>.
+ */
+
+/* irc-nick.c: manages nick list for channels */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include "../../common/weechat.h"
+#include "irc.h"
+#include "../../common/log.h"
+#include "../../common/utf8.h"
+#include "../../common/util.h"
+#include "../../common/weeconfig.h"
+
+
+/*
+ * irc_nick_find_color: find a color for a nick (according to nick letters)
+ */
+
+int
+irc_nick_find_color (t_irc_nick *nick)
+{
+ int i, color;
+
+ color = 0;
+ for (i = strlen (nick->nick) - 1; i >= 0; i--)
+ {
+ color += (int)(nick->nick[i]);
+ }
+ color = (color % cfg_look_color_nicks_number);
+
+ return GUI_COLOR_WIN_NICK_1 + color;
+}
+
+/*
+ * irc_nick_score_for_sort: return score for sorting nick, according to privileges
+ */
+
+int
+irc_nick_score_for_sort (t_irc_nick *nick)
+{
+ if (nick->flags & IRC_NICK_CHANOWNER)
+ return -128;
+ if (nick->flags & IRC_NICK_CHANADMIN)
+ return -64;
+ if (nick->flags & IRC_NICK_CHANADMIN2)
+ return -32;
+ if (nick->flags & IRC_NICK_OP)
+ return -16;
+ if (nick->flags & IRC_NICK_HALFOP)
+ return -8;
+ if (nick->flags & IRC_NICK_VOICE)
+ return -4;
+ if (nick->flags & IRC_NICK_CHANUSER)
+ return -2;
+ return 0;
+}
+
+/*
+ * irc_nick_compare: compare two nicks
+ * return: -1 is nick1 < nick2
+ * 0 if nick1 = nick2
+ * +1 if nick1 > nick2
+ * status sort: operator > voice > normal nick
+ */
+
+int
+irc_nick_compare (t_irc_nick *nick1, t_irc_nick *nick2)
+{
+ int score1, score2, comp;
+
+ score1 = irc_nick_score_for_sort (nick1);
+ score2 = irc_nick_score_for_sort (nick2);
+
+ comp = ascii_strcasecmp (nick1->nick, nick2->nick);
+ if (comp > 0)
+ score1++;
+ if (comp < 0)
+ score2++;
+
+ /* nick1 > nick2 */
+ if (score1 > score2)
+ return 1;
+ /* nick1 < nick2 */
+ if (score1 < score2)
+ return -1;
+ /* nick1 == nick2 */
+ return 0;
+}
+
+/*
+ * irc_nick_find_pos: find position for a nick (for sorting nick list)
+ */
+
+t_irc_nick *
+irc_nick_find_pos (t_irc_channel *channel, t_irc_nick *nick)
+{
+ t_irc_nick *ptr_nick;
+
+ for (ptr_nick = channel->nicks; ptr_nick; ptr_nick = ptr_nick->next_nick)
+ {
+ if (irc_nick_compare (nick, ptr_nick) < 0)
+ return ptr_nick;
+ }
+ return NULL;
+}
+
+/*
+ * irc_nick_insert_sorted: insert nick into sorted list
+ */
+
+void
+irc_nick_insert_sorted (t_irc_channel *channel, t_irc_nick *nick)
+{
+ t_irc_nick *pos_nick;
+
+ if (channel->nicks)
+ {
+ pos_nick = irc_nick_find_pos (channel, nick);
+
+ if (pos_nick)
+ {
+ /* insert nick into the list (before nick found) */
+ nick->prev_nick = pos_nick->prev_nick;
+ nick->next_nick = pos_nick;
+ if (pos_nick->prev_nick)
+ pos_nick->prev_nick->next_nick = nick;
+ else
+ channel->nicks = nick;
+ pos_nick->prev_nick = nick;
+ }
+ else
+ {
+ /* add nick to the end */
+ nick->prev_nick = channel->last_nick;
+ nick->next_nick = NULL;
+ channel->last_nick->next_nick = nick;
+ channel->last_nick = nick;
+ }
+ }
+ else
+ {
+ nick->prev_nick = NULL;
+ nick->next_nick = NULL;
+ channel->nicks = nick;
+ channel->last_nick = nick;
+ }
+}
+
+/*
+ * irc_nick_resort: resort nick in the list
+ */
+
+void
+irc_nick_resort (t_irc_channel *channel, t_irc_nick *nick)
+{
+ /* temporarly remove nick from list */
+ if (nick == channel->nicks)
+ channel->nicks = nick->next_nick;
+ else
+ nick->prev_nick->next_nick = nick->next_nick;
+ if (nick->next_nick)
+ nick->next_nick->prev_nick = nick->prev_nick;
+ if (nick == channel->last_nick)
+ channel->last_nick = nick->prev_nick;
+
+ /* insert again nick into sorted list */
+ irc_nick_insert_sorted (channel, nick);
+}
+
+/*
+ * irc_nick_new: allocate a new nick for a channel and add it to the nick list
+ */
+
+t_irc_nick *
+irc_nick_new (t_irc_server *server, t_irc_channel *channel, char *nick_name,
+ int is_chanowner, int is_chanadmin, int is_chanadmin2, int is_op,
+ int is_halfop, int has_voice, int is_chanuser)
+{
+ t_irc_nick *new_nick;
+
+ /* nick already exists on this channel? */
+ if ((new_nick = irc_nick_search (channel, nick_name)))
+ {
+ /* update nick */
+ IRC_NICK_SET_FLAG(new_nick, is_chanowner, IRC_NICK_CHANOWNER);
+ IRC_NICK_SET_FLAG(new_nick, is_chanadmin, IRC_NICK_CHANADMIN);
+ IRC_NICK_SET_FLAG(new_nick, is_chanadmin2, IRC_NICK_CHANADMIN2);
+ IRC_NICK_SET_FLAG(new_nick, is_op, IRC_NICK_OP);
+ IRC_NICK_SET_FLAG(new_nick, is_halfop, IRC_NICK_HALFOP);
+ IRC_NICK_SET_FLAG(new_nick, has_voice, IRC_NICK_VOICE);
+ IRC_NICK_SET_FLAG(new_nick, is_chanuser, IRC_NICK_CHANUSER);
+ irc_nick_resort (channel, new_nick);
+ return new_nick;
+ }
+
+ /* alloc memory for new nick */
+ if ((new_nick = (t_irc_nick *) malloc (sizeof (t_irc_nick))) == NULL)
+ return NULL;
+
+ /* initialize new nick */
+ new_nick->nick = strdup (nick_name);
+ new_nick->host = NULL;
+ new_nick->flags = 0;
+ IRC_NICK_SET_FLAG(new_nick, is_chanowner, IRC_NICK_CHANOWNER);
+ IRC_NICK_SET_FLAG(new_nick, is_chanadmin, IRC_NICK_CHANADMIN);
+ IRC_NICK_SET_FLAG(new_nick, is_chanadmin2, IRC_NICK_CHANADMIN2);
+ IRC_NICK_SET_FLAG(new_nick, is_op, IRC_NICK_OP);
+ IRC_NICK_SET_FLAG(new_nick, is_halfop, IRC_NICK_HALFOP);
+ IRC_NICK_SET_FLAG(new_nick, has_voice, IRC_NICK_VOICE);
+ IRC_NICK_SET_FLAG(new_nick, is_chanuser, IRC_NICK_CHANUSER);
+ if (ascii_strcasecmp (new_nick->nick, server->nick) == 0)
+ new_nick->color = GUI_COLOR_WIN_NICK_SELF;
+ else
+ new_nick->color = irc_nick_find_color (new_nick);
+
+ irc_nick_insert_sorted (channel, new_nick);
+
+ channel->nicks_count++;
+
+ channel->nick_completion_reset = 1;
+
+ /* all is ok, return address of new nick */
+ return new_nick;
+}
+
+/*
+ * irc_nick_change: change nickname and move it if necessary (list is sorted)
+ */
+
+void
+irc_nick_change (t_irc_channel *channel, t_irc_nick *nick, char *new_nick)
+{
+ int nick_is_me;
+ t_weelist *ptr_weelist;
+
+ nick_is_me = (strcmp (nick->nick, GUI_SERVER(channel->buffer)->nick) == 0) ? 1 : 0;
+
+ if (!nick_is_me && channel->nicks_speaking)
+ {
+ ptr_weelist = weelist_search (channel->nicks_speaking, nick->nick);
+ if (ptr_weelist && ptr_weelist->data)
+ {
+ free (ptr_weelist->data);
+ ptr_weelist->data = strdup (new_nick);
+ }
+ }
+
+ /* change nickname */
+ if (nick->nick)
+ free (nick->nick);
+ nick->nick = strdup (new_nick);
+ if (nick_is_me)
+ nick->color = GUI_COLOR_WIN_NICK_SELF;
+ else
+ nick->color = irc_nick_find_color (nick);
+
+ /* insert again nick into sorted list */
+ irc_nick_resort (channel, nick);
+}
+
+/*
+ * irc_nick_free: free a nick and remove it from nicks queue
+ */
+
+void
+irc_nick_free (t_irc_channel *channel, t_irc_nick *nick)
+{
+ t_irc_nick *new_nicks;
+
+ if (!channel || !nick)
+ return;
+
+ /* remove nick from queue */
+ if (channel->last_nick == nick)
+ channel->last_nick = nick->prev_nick;
+ if (nick->prev_nick)
+ {
+ (nick->prev_nick)->next_nick = nick->next_nick;
+ new_nicks = channel->nicks;
+ }
+ else
+ new_nicks = nick->next_nick;
+
+ if (nick->next_nick)
+ (nick->next_nick)->prev_nick = nick->prev_nick;
+
+ channel->nicks_count--;
+
+ /* free data */
+ if (nick->nick)
+ free (nick->nick);
+ if (nick->host)
+ free (nick->host);
+ free (nick);
+ channel->nicks = new_nicks;
+
+ channel->nick_completion_reset = 1;
+}
+
+/*
+ * irc_nick_free_all: free all allocated nicks for a channel
+ */
+
+void
+irc_nick_free_all (t_irc_channel *channel)
+{
+ if (!channel)
+ return;
+
+ /* remove all nicks for the channel */
+ while (channel->nicks)
+ irc_nick_free (channel, channel->nicks);
+
+ /* sould be zero, but prevent any bug :D */
+ channel->nicks_count = 0;
+}
+
+/*
+ * irc_nick_search: returns pointer on a nick
+ */
+
+t_irc_nick *
+irc_nick_search (t_irc_channel *channel, char *nickname)
+{
+ t_irc_nick *ptr_nick;
+
+ if (!nickname)
+ return NULL;
+
+ for (ptr_nick = channel->nicks; ptr_nick;
+ ptr_nick = ptr_nick->next_nick)
+ {
+ if (ascii_strcasecmp (ptr_nick->nick, nickname) == 0)
+ return ptr_nick;
+ }
+ return NULL;
+}
+
+/*
+ * irc_nick_count: returns number of nicks (total, op, halfop, voice) on a channel
+ */
+
+void
+irc_nick_count (t_irc_channel *channel, int *total, int *count_op,
+ int *count_halfop, int *count_voice, int *count_normal)
+{
+ t_irc_nick *ptr_nick;
+
+ (*total) = 0;
+ (*count_op) = 0;
+ (*count_halfop) = 0;
+ (*count_voice) = 0;
+ (*count_normal) = 0;
+ for (ptr_nick = channel->nicks; ptr_nick;
+ ptr_nick = ptr_nick->next_nick)
+ {
+ (*total)++;
+ if ((ptr_nick->flags & IRC_NICK_CHANOWNER) ||
+ (ptr_nick->flags & IRC_NICK_CHANADMIN) ||
+ (ptr_nick->flags & IRC_NICK_CHANADMIN2) ||
+ (ptr_nick->flags & IRC_NICK_OP))
+ (*count_op)++;
+ else
+ {
+ if (ptr_nick->flags & IRC_NICK_HALFOP)
+ (*count_halfop)++;
+ else
+ {
+ if (ptr_nick->flags & IRC_NICK_VOICE)
+ (*count_voice)++;
+ else
+ (*count_normal)++;
+ }
+ }
+ }
+}
+
+/*
+ * irc_nick_get_max_length: returns longer nickname on a channel
+ */
+
+int
+irc_nick_get_max_length (t_irc_channel *channel)
+{
+ int length, max_length;
+ t_irc_nick *ptr_nick;
+
+ max_length = 0;
+ for (ptr_nick = channel->nicks; ptr_nick; ptr_nick = ptr_nick->next_nick)
+ {
+ length = utf8_width_screen (ptr_nick->nick);
+ if (length > max_length)
+ max_length = length;
+ }
+ return max_length;
+}
+
+/*
+ * irc_nick_set_away: set/unset away status for a channel
+ */
+
+void
+irc_nick_set_away (t_irc_channel *channel, t_irc_nick *nick, int is_away)
+{
+ if ((cfg_irc_away_check > 0)
+ && ((cfg_irc_away_check_max_nicks == 0) ||
+ (channel->nicks_count <= cfg_irc_away_check_max_nicks)))
+ {
+ if (((is_away) && (!(nick->flags & IRC_NICK_AWAY))) ||
+ ((!is_away) && (nick->flags & IRC_NICK_AWAY)))
+ {
+ IRC_NICK_SET_FLAG(nick, is_away, IRC_NICK_AWAY);
+ gui_nicklist_draw (channel->buffer, 0, 0);
+ }
+ }
+}
+
+/*
+ * irc_nick_print_log: print nick infos in log (usually for crash dump)
+ */
+
+void
+irc_nick_print_log (t_irc_nick *nick)
+{
+ weechat_log_printf ("=> nick %s (addr:0x%X)]\n", nick->nick, nick);
+ weechat_log_printf (" host . . . . . : %s\n", nick->host);
+ weechat_log_printf (" flags. . . . . : %d\n", nick->flags);
+ weechat_log_printf (" color. . . . . : %d\n", nick->color);
+ weechat_log_printf (" prev_nick. . . : 0x%X\n", nick->prev_nick);
+ weechat_log_printf (" next_nick. . . : 0x%X\n", nick->next_nick);
+}
diff --git a/src/plugins/irc/irc-recv.c b/src/plugins/irc/irc-recv.c
new file mode 100644
index 000000000..4e0d195ad
--- /dev/null
+++ b/src/plugins/irc/irc-recv.c
@@ -0,0 +1,5058 @@
+/*
+ * 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/>.
+ */
+
+/* irc-recv.c: implementation of IRC commands (server to client),
+ according to RFC 1459,2810,2811,2812 */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <wctype.h>
+#include <sys/time.h>
+#include <time.h>
+#include <sys/utsname.h>
+#include <regex.h>
+
+#include "../../common/weechat.h"
+#include "irc.h"
+#include "../../common/alias.h"
+#include "../../common/command.h"
+#include "../../common/hotlist.h"
+#include "../../common/utf8.h"
+#include "../../common/util.h"
+#include "../../common/weeconfig.h"
+#include "../../gui/gui.h"
+
+#ifdef PLUGINS
+#include "../../plugins/plugins.h"
+#endif
+
+
+char *irc_last_command_received = NULL;
+int command_ignored, command_force_highlight;
+
+
+/*
+ * irc_recv_is_word_char: return 1 if given character is a "word character"
+ */
+
+int
+irc_recv_is_word_char (char *str)
+{
+ wint_t c = utf8_get_wc (str);
+
+ if (c == WEOF)
+ return 0;
+
+ if (iswalnum (c))
+ return 1;
+
+ switch (c)
+ {
+ case '-':
+ case '_':
+ case '|':
+ return 1;
+ }
+
+ /* not a 'word char' */
+ return 0;
+}
+
+/*
+ * irc_recv_command_is_numeric: return 1 if given string is 100% numeric
+ */
+
+int
+irc_recv_command_is_numeric (char *str)
+{
+ while (str && str[0])
+ {
+ if (!isdigit (str[0]))
+ return 0;
+ str++;
+ }
+ return 1;
+}
+
+/*
+ * irc_recv_is_highlight: return 1 if given message contains highlight (with given nick
+ * or at least one of string in "irc_higlight" setting)
+ */
+
+int
+irc_recv_is_highlight (char *message, char *nick)
+{
+ char *msg, *highlight, *match, *match_pre, *match_post, *msg_pos, *pos, *pos_end;
+ int end, length, startswith, endswith, wildcard_start, wildcard_end;
+
+ /* empty message ? */
+ if (!message || !message[0])
+ return 0;
+
+ /* highlight asked by a plugin */
+ if (command_force_highlight)
+ return 1;
+
+ /* highlight by nickname */
+ match = strstr (message, nick);
+ if (match)
+ {
+ match_pre = utf8_prev_char (message, match);
+ if (!match_pre)
+ match_pre = match - 1;
+ match_post = match + strlen(nick);
+ startswith = ((match == message) || (!irc_recv_is_word_char (match_pre)));
+ endswith = ((!match_post[0]) || (!irc_recv_is_word_char (match_post)));
+ if (startswith && endswith)
+ return 1;
+ }
+
+ /* no highlight by nickname and "irc_highlight" is empty */
+ if (!cfg_irc_highlight || !cfg_irc_highlight[0])
+ return 0;
+
+ /* convert both strings to lower case */
+ if ((msg = strdup (message)) == NULL)
+ return 0;
+ if ((highlight = strdup (cfg_irc_highlight)) == NULL)
+ {
+ free (msg);
+ return 0;
+ }
+ pos = msg;
+ while (pos[0])
+ {
+ pos[0] = tolower (pos[0]);
+ pos++;
+ }
+ pos = highlight;
+ while (pos[0])
+ {
+ pos[0] = tolower (pos[0]);
+ pos++;
+ }
+
+ /* look in "irc_highlight" for highlight */
+ pos = highlight;
+ end = 0;
+ while (!end)
+ {
+ pos_end = strchr (pos, ',');
+ if (!pos_end)
+ {
+ pos_end = strchr (pos, '\0');
+ end = 1;
+ }
+ /* error parsing string! */
+ if (!pos_end)
+ {
+ free (msg);
+ free (highlight);
+ return 0;
+ }
+
+ length = pos_end - pos;
+ pos_end[0] = '\0';
+ if (length > 0)
+ {
+ if ((wildcard_start = (pos[0] == '*')))
+ {
+ pos++;
+ length--;
+ }
+ if ((wildcard_end = (*(pos_end - 1) == '*')))
+ {
+ *(pos_end - 1) = '\0';
+ length--;
+ }
+ }
+
+ if (length > 0)
+ {
+ msg_pos = msg;
+ /* highlight found! */
+ while ((match = strstr (msg_pos, pos)) != NULL)
+ {
+ match_pre = match - 1;
+ match_pre = utf8_prev_char (msg, match);
+ if (!match_pre)
+ match_pre = match - 1;
+ match_post = match + length;
+ startswith = ((match == msg) || (!irc_recv_is_word_char (match_pre)));
+ endswith = ((!match_post[0]) || (!irc_recv_is_word_char (match_post)));
+ if ((wildcard_start && wildcard_end) ||
+ (!wildcard_start && !wildcard_end &&
+ startswith && endswith) ||
+ (wildcard_start && endswith) ||
+ (wildcard_end && startswith))
+ {
+ free (msg);
+ free (highlight);
+ return 1;
+ }
+ msg_pos = match_post;
+ }
+ }
+
+ if (!end)
+ pos = pos_end + 1;
+ }
+
+ /* no highlight found with "irc_highlight" list */
+ free (msg);
+ free (highlight);
+ return 0;
+}
+
+/*
+ * irc_recv_command: executes action when receiving IRC command
+ * returns: 0 = all ok, command executed
+ * -1 = command failed
+ * -2 = no command to execute
+ * -3 = command not found
+ */
+
+int
+irc_recv_command (t_irc_server *server, char *entire_line,
+ char *host, char *command, char *arguments)
+{
+ int i, cmd_found, return_code;
+ char *pos, *nick;
+ char *dup_entire_line, *dup_host, *dup_arguments;
+ t_irc_recv_func *cmd_recv_func;
+ char *cmd_name;
+
+ if (!command)
+ return -2;
+
+ /* look for IRC command */
+ cmd_found = -1;
+ for (i = 0; irc_commands[i].command_name; i++)
+ {
+ if (ascii_strcasecmp (irc_commands[i].command_name, command) == 0)
+ {
+ cmd_found = i;
+ break;
+ }
+ }
+
+ /* command not found */
+ if (cmd_found < 0)
+ {
+ /* for numeric commands, we use default recv function (irc_recv_server_msg) */
+ if (irc_recv_command_is_numeric (command))
+ {
+ cmd_name = command;
+ cmd_recv_func = irc_recv_cmd_server_msg;
+ }
+ else
+ return -3;
+ }
+ else
+ {
+ cmd_name = irc_commands[cmd_found].command_name;
+ cmd_recv_func = irc_commands[cmd_found].recv_function;
+ }
+
+ if (cmd_recv_func != NULL)
+ {
+ dup_entire_line = (entire_line) ? strdup (entire_line) : NULL;
+ dup_host = (host) ? strdup (host) : NULL;
+ dup_arguments = (arguments) ? strdup (arguments) : NULL;
+
+ command_ignored = irc_ignore_check (dup_host,
+ cmd_name,
+ NULL,
+ server->name);
+ command_force_highlight = 0;
+#ifdef PLUGINS
+ return_code = plugin_msg_handler_exec (server->name,
+ cmd_name,
+ dup_entire_line);
+ /* plugin handler choosed to discard message for WeeChat,
+ so we ignore this message in standard handler */
+ if (return_code & PLUGIN_RC_OK_IGNORE_WEECHAT)
+ command_ignored = 1;
+ /* plugin asked for highlight ? */
+ if (return_code & PLUGIN_RC_OK_WITH_HIGHLIGHT)
+ command_force_highlight = 1;
+#endif
+ pos = (dup_host) ? strchr (dup_host, '!') : NULL;
+ if (pos)
+ pos[0] = '\0';
+ nick = (dup_host) ? strdup (dup_host) : NULL;
+ if (pos)
+ pos[0] = '!';
+ irc_last_command_received = strdup (dup_entire_line);
+ return_code = (int) (cmd_recv_func) (server, dup_host, nick,
+ dup_arguments);
+ if (irc_last_command_received)
+ free (irc_last_command_received);
+ if (nick)
+ free (nick);
+ if (dup_entire_line)
+ free (dup_entire_line);
+ if (dup_host)
+ free (dup_host);
+ if (dup_arguments)
+ free (dup_arguments);
+ return return_code;
+ }
+
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_error: error received from server
+ */
+
+int
+irc_recv_cmd_error (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos;
+ int first;
+ t_gui_buffer *ptr_buffer;
+ t_irc_channel *ptr_channel;
+
+ /* make C compiler happy */
+ (void) host;
+ (void) nick;
+
+ first = 1;
+ ptr_buffer = server->buffer;
+
+ while (arguments && arguments[0])
+ {
+ while (arguments[0] == ' ')
+ arguments++;
+
+ if (arguments[0] == ':')
+ {
+ arguments++;
+ if (first)
+ irc_display_prefix (server, ptr_buffer, GUI_PREFIX_ERROR);
+ gui_printf (ptr_buffer, "%s%s%s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ (first) ? "" : ": ",
+ arguments);
+ if (strncmp (arguments, "Closing Link", 12) == 0)
+ irc_server_disconnect (server, 1);
+ arguments = NULL;
+ }
+ else
+ {
+ pos = strchr (arguments, ' ');
+ if (pos)
+ pos[0] = '\0';
+ if (strcasecmp (arguments, server->nick) != 0)
+ {
+ if (first)
+ {
+ ptr_channel = irc_channel_search (server, arguments);
+ if (ptr_channel)
+ ptr_buffer = ptr_channel->buffer;
+ irc_display_prefix (server, ptr_buffer, GUI_PREFIX_ERROR);
+ }
+ gui_printf (ptr_buffer, "%s%s%s",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ (first) ? "" : " ",
+ arguments);
+ first = 0;
+ }
+ if (pos)
+ arguments = pos + 1;
+ else
+ arguments = NULL;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_invite: 'invite' message received
+ */
+
+int
+irc_recv_cmd_invite (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos_channel;
+
+ pos_channel = strchr (arguments, ' ');
+ if (pos_channel)
+ {
+ pos_channel[0] = '\0';
+ pos_channel++;
+ while (pos_channel[0] == ' ')
+ pos_channel++;
+ if (pos_channel[0] == ':')
+ pos_channel++;
+
+ command_ignored |= irc_ignore_check (host, "invite", pos_channel, server->name);
+
+ if (!command_ignored)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_SERVER);
+ gui_printf (server->buffer, _("You have been invited to %s%s%s by %s%s\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ pos_channel,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ nick);
+ if (gui_add_hotlist
+ && ((server->buffer->num_displayed == 0) || (gui_buffer_is_scrolled (server->buffer))))
+ {
+ hotlist_add (HOTLIST_HIGHLIGHT, NULL, server, server->buffer, 0);
+ gui_status_draw (gui_current_window->buffer, 1);
+ }
+ }
+ }
+ else
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s channel \"%s\" not found for \"%s\" command\n"),
+ WEECHAT_ERROR, "", "invite");
+ return -1;
+ }
+ return 0;
+}
+
+
+/*
+ * irc_recv_cmd_join: 'join' message received
+ */
+
+int
+irc_recv_cmd_join (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ t_irc_channel *ptr_channel;
+ t_irc_nick *ptr_nick;
+ char *pos;
+
+ /* no host => we can't identify sender of message! */
+ if (!host)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s \"%s\" command received without host\n"),
+ WEECHAT_ERROR, "join");
+ return -1;
+ }
+
+ if (arguments[0] == ':')
+ arguments++;
+
+ command_ignored |= irc_ignore_check (host, "join", arguments, server->name);
+
+ ptr_channel = irc_channel_search (server, arguments);
+ if (!ptr_channel)
+ {
+ ptr_channel = irc_channel_new (server, IRC_CHANNEL_TYPE_CHANNEL, arguments);
+ if (!ptr_channel)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot create new channel \"%s\"\n"),
+ WEECHAT_ERROR, arguments);
+ return -1;
+ }
+ gui_buffer_new (gui_current_window, server, ptr_channel,
+ GUI_BUFFER_TYPE_STANDARD, 1);
+ }
+
+ pos = strchr (host, '!');
+ if (!command_ignored)
+ {
+ irc_display_prefix (server, ptr_channel->buffer, GUI_PREFIX_JOIN);
+ gui_printf (ptr_channel->buffer,
+ _("%s%s %s(%s%s%s)%s has joined %s%s\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ nick,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_HOST),
+ (pos) ? pos + 1 : host,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ arguments);
+ }
+
+ /* remove topic and display channel creation date if joining new channel */
+ if (!ptr_channel->nicks)
+ {
+ if (ptr_channel->topic)
+ {
+ free (ptr_channel->topic);
+ ptr_channel->topic = NULL;
+ gui_chat_draw_title (ptr_channel->buffer, 1);
+ }
+ ptr_channel->display_creation_date = 1;
+ }
+
+ /* add nick in channel */
+ ptr_nick = irc_nick_new (server, ptr_channel, nick, 0, 0, 0, 0, 0, 0, 0);
+ if (ptr_nick)
+ ptr_nick->host = strdup ((pos) ? pos + 1 : host);
+
+ /* redraw nicklist and status bar */
+ gui_nicklist_draw (ptr_channel->buffer, 1, 1);
+ gui_status_draw (ptr_channel->buffer, 1);
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_kick: 'kick' message received
+ */
+
+int
+irc_recv_cmd_kick (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos_nick, *pos_comment;
+ t_irc_channel *ptr_channel;
+ t_irc_nick *ptr_nick;
+
+ pos_nick = strchr (arguments, ' ');
+ if (pos_nick)
+ {
+ pos_nick[0] = '\0';
+ pos_nick++;
+ while (pos_nick[0] == ' ')
+ pos_nick++;
+
+ pos_comment = strchr (pos_nick, ' ');
+ if (pos_comment)
+ {
+ pos_comment[0] = '\0';
+ pos_comment++;
+ while (pos_comment[0] == ' ')
+ pos_comment++;
+ if (pos_comment[0] == ':')
+ pos_comment++;
+ }
+
+ command_ignored |= irc_ignore_check (host, "kick", arguments, server->name);
+
+ ptr_channel = irc_channel_search (server, arguments);
+ if (!ptr_channel)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s channel \"%s\" not found for \"%s\" command\n"),
+ WEECHAT_ERROR, arguments, "kick");
+ return -1;
+ }
+
+ if (!command_ignored)
+ {
+ irc_display_prefix (server, ptr_channel->buffer, GUI_PREFIX_PART);
+ gui_printf (ptr_channel->buffer, _("%s%s%s has kicked %s%s%s from %s%s"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ nick,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ pos_nick,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ arguments);
+ if (pos_comment)
+ gui_printf (ptr_channel->buffer, " %s(%s%s%s)\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ pos_comment,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK));
+ else
+ gui_printf (ptr_channel->buffer, "\n");
+ }
+ }
+ else
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s nick \"%s\" not found for \"%s\" command\n"),
+ WEECHAT_ERROR, "", "kick");
+ return -1;
+ }
+ if (strcmp (pos_nick, server->nick) == 0)
+ {
+ /* my nick was kicked => free all nicks, channel is not active any more */
+ irc_nick_free_all (ptr_channel);
+ gui_nicklist_draw (ptr_channel->buffer, 1, 1);
+ gui_status_draw (ptr_channel->buffer, 1);
+ if (server->autorejoin)
+ irc_send_cmd_join (server, NULL, ptr_channel->name);
+ }
+ {
+ /* someone was kicked from channel (but not me) => remove only this nick */
+ ptr_nick = irc_nick_search (ptr_channel, pos_nick);
+ if (ptr_nick)
+ {
+ irc_nick_free (ptr_channel, ptr_nick);
+ gui_nicklist_draw (ptr_channel->buffer, 1, 1);
+ gui_status_draw (ptr_channel->buffer, 1);
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_kill: 'kill' message received
+ */
+
+int
+irc_recv_cmd_kill (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos_host2, *pos_comment;
+ t_irc_channel *ptr_channel;
+
+ pos_host2 = strchr (arguments, ' ');
+ if (pos_host2)
+ {
+ pos_host2[0] = '\0';
+ pos_host2++;
+ while (pos_host2[0] == ' ')
+ pos_host2++;
+
+ if (pos_host2[0] == ':')
+ pos_comment = pos_host2 + 1;
+ else
+ {
+ pos_comment = strchr (pos_host2, ' ');
+ if (pos_comment)
+ {
+ pos_comment[0] = '\0';
+ pos_comment++;
+ while (pos_comment[0] == ' ')
+ pos_comment++;
+ if (pos_comment[0] == ':')
+ pos_comment++;
+ }
+ }
+
+ for (ptr_channel = server->channels; ptr_channel;
+ ptr_channel = ptr_channel->next_channel)
+ {
+ if (!command_ignored
+ && !irc_ignore_check (host, "kill", ptr_channel->name, server->name))
+ {
+ irc_display_prefix (server, ptr_channel->buffer, GUI_PREFIX_PART);
+ gui_printf (ptr_channel->buffer, _("%s%s%s has killed %s%s%s from server"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ nick,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ arguments,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT));
+ if (pos_comment)
+ gui_printf (ptr_channel->buffer, " %s(%s%s%s)\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ pos_comment,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK));
+ else
+ gui_printf (ptr_channel->buffer, "\n");
+ }
+ }
+ }
+ else
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s host not found for \"%s\" command\n"),
+ WEECHAT_ERROR, "kill");
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_mode: 'mode' message received
+ */
+
+int
+irc_recv_cmd_mode (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos_modes, *pos;
+ t_irc_channel *ptr_channel;
+
+ /* no host => we can't identify sender of message! */
+ if (!host)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s \"%s\" command received without host\n"),
+ WEECHAT_ERROR, "mode");
+ return -1;
+ }
+
+ pos_modes = strchr (arguments, ' ');
+ if (!pos_modes)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s \"%s\" command received without channel or nickname\n"),
+ WEECHAT_ERROR, "mode");
+ return -1;
+ }
+ pos_modes[0] = '\0';
+ pos_modes++;
+ while (pos_modes[0] == ' ')
+ pos_modes++;
+ if (pos_modes[0] == ':')
+ pos_modes++;
+
+ /* remove spaces after modes */
+ pos = pos_modes + strlen (pos_modes) - 1;
+ while ((pos >= pos_modes) && (pos[0] == ' '))
+ {
+ pos[0] = '\0';
+ pos--;
+ }
+
+ if (irc_channel_is_channel (arguments))
+ {
+ ptr_channel = irc_channel_search (server, arguments);
+ if (ptr_channel)
+ {
+ command_ignored |= irc_ignore_check (host, "mode",
+ ptr_channel->name, server->name);
+ if (!command_ignored)
+ {
+ irc_display_prefix (server, ptr_channel->buffer, GUI_PREFIX_INFO);
+ gui_printf (ptr_channel->buffer,
+ _("Mode %s%s %s[%s%s%s]%s by %s%s\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ ptr_channel->name,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ pos_modes,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ nick);
+ }
+ irc_mode_channel_set (server, ptr_channel, pos_modes);
+ irc_server_sendf (server, "MODE %s", ptr_channel->name);
+ }
+ else
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s channel \"%s\" not found for \"%s\" command\n"),
+ WEECHAT_ERROR, arguments, "mode");
+ return -1;
+ }
+ }
+ else
+ {
+ if (!command_ignored)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_INFO);
+ gui_printf (server->buffer,
+ _("User mode %s[%s%s%s]%s by %s%s\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ pos_modes,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ nick);
+ }
+ irc_mode_user_set (server, pos_modes);
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_nick: 'nick' message received
+ */
+
+int
+irc_recv_cmd_nick (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ t_irc_channel *ptr_channel;
+ t_irc_nick *ptr_nick;
+ int nick_is_me;
+ t_gui_window *ptr_win;
+ t_gui_buffer *ptr_buffer;
+
+ /* no host => we can't identify sender of message! */
+ if (!host)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s \"%s\" command received without host\n"),
+ WEECHAT_ERROR, "nick");
+ return -1;
+ }
+
+ if (arguments[0] == ':')
+ arguments++;
+
+ /* change nickname in any opened private window */
+ for (ptr_buffer = gui_buffers; ptr_buffer;
+ ptr_buffer = ptr_buffer->next_buffer)
+ {
+ if ((GUI_SERVER(ptr_buffer) == server) && GUI_BUFFER_IS_PRIVATE(ptr_buffer))
+ {
+ if ((GUI_CHANNEL(ptr_buffer)->name)
+ && (ascii_strcasecmp (nick, GUI_CHANNEL(ptr_buffer)->name) == 0))
+ {
+ ptr_channel = irc_channel_search_any (server, arguments);
+ if (!ptr_channel)
+ {
+ free (GUI_CHANNEL(ptr_buffer)->name);
+ GUI_CHANNEL(ptr_buffer)->name = strdup (arguments);
+ }
+ }
+ }
+ }
+
+ for (ptr_channel = server->channels; ptr_channel;
+ ptr_channel = ptr_channel->next_channel)
+ {
+ ptr_nick = irc_nick_search (ptr_channel, nick);
+ if (ptr_nick)
+ {
+ nick_is_me = (strcmp (ptr_nick->nick, server->nick) == 0) ? 1 : 0;
+ if (nick_is_me)
+ gui_add_hotlist = 0;
+ irc_nick_change (ptr_channel, ptr_nick, arguments);
+ if (!command_ignored
+ && !irc_ignore_check (host, "nick", ptr_channel->name, server->name))
+ {
+ irc_display_prefix (server, ptr_channel->buffer, GUI_PREFIX_INFO);
+ if (nick_is_me)
+ gui_printf (ptr_channel->buffer, _("You are now known as %s%s\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ arguments);
+ else
+ gui_printf (ptr_channel->buffer, _("%s%s%s is now known as %s%s\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ nick,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ arguments);
+ }
+ gui_nicklist_draw (ptr_channel->buffer, 1, 1);
+ gui_add_hotlist = 1;
+ }
+ }
+
+ if (strcmp (server->nick, nick) == 0)
+ {
+ free (server->nick);
+ server->nick = strdup (arguments);
+ gui_status_draw (gui_current_window->buffer, 1);
+ for (ptr_win = gui_windows; ptr_win; ptr_win = ptr_win->next_window)
+ {
+ if (ptr_win->buffer->server == server)
+ gui_input_draw (ptr_win->buffer, 1);
+ }
+ }
+ else
+ {
+ gui_status_draw (gui_current_window->buffer, 1);
+ gui_input_draw (gui_current_window->buffer, 1);
+ }
+
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_notice: 'notice' message received
+ */
+
+int
+irc_recv_cmd_notice (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *host2, *pos, *pos2, *pos_usec;
+ struct timeval tv;
+ long sec1, usec1, sec2, usec2, difftime;
+ t_irc_channel *ptr_channel;
+ int highlight;
+
+ host2 = NULL;
+ if (host)
+ {
+ pos = strchr (host, '!');
+ if (pos)
+ host2 = pos + 1;
+ }
+
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ if (pos[0] == ':')
+ pos++;
+ }
+ else
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s nickname not found for \"%s\" command\n"),
+ WEECHAT_ERROR, "notice");
+ return -1;
+ }
+
+ if (!command_ignored)
+ {
+ if (strncmp (pos, "\01VERSION", 8) == 0)
+ {
+ pos += 9;
+ pos2 = strchr (pos, '\01');
+ if (pos2)
+ pos2[0] = '\0';
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_SERVER);
+ gui_printf (server->buffer, _("CTCP %sVERSION%s reply from %s%s%s: %s\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ nick,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ pos);
+ }
+ else
+ {
+ if (strncmp (pos, "\01PING", 5) == 0)
+ {
+ pos += 5;
+ while (pos[0] == ' ')
+ pos++;
+ pos_usec = strchr (pos, ' ');
+ if (pos_usec)
+ {
+ pos_usec[0] = '\0';
+ pos_usec++;
+ pos2 = strchr (pos_usec, '\01');
+ if (pos2)
+ {
+ pos2[0] = '\0';
+
+ gettimeofday (&tv, NULL);
+ sec1 = atol (pos);
+ usec1 = atol (pos_usec);
+ sec2 = tv.tv_sec;
+ usec2 = tv.tv_usec;
+
+ difftime = ((sec2 * 1000000) + usec2) - ((sec1 * 1000000) + usec1);
+
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_SERVER);
+ gui_printf (server->buffer, _("CTCP %sPING%s reply from %s%s%s: %ld.%ld seconds\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ nick,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ difftime / 1000000,
+ (difftime % 1000000) / 1000);
+ }
+ }
+ }
+ else
+ {
+ if (nick && nick[0] && cfg_irc_notice_as_pv)
+ {
+ ptr_channel = irc_channel_search (server, nick);
+ if (!ptr_channel)
+ {
+ ptr_channel = irc_channel_new (server, IRC_CHANNEL_TYPE_PRIVATE, nick);
+ if (!ptr_channel)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot create new private window \"%s\"\n"),
+ WEECHAT_ERROR, nick);
+ return -1;
+ }
+ gui_buffer_new (gui_current_window, server, ptr_channel,
+ GUI_BUFFER_TYPE_STANDARD, 0);
+ }
+ if (!ptr_channel->topic)
+ {
+ ptr_channel->topic = strdup ((host2) ? host2 : "");
+ gui_chat_draw_title (ptr_channel->buffer, 1);
+ }
+
+ gui_printf_type (ptr_channel->buffer, GUI_MSG_TYPE_NICK,
+ "%s<",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK));
+ if (irc_recv_is_highlight (pos, server->nick))
+ {
+ gui_printf_type (ptr_channel->buffer,
+ GUI_MSG_TYPE_NICK | GUI_MSG_TYPE_HIGHLIGHT,
+ "%s%s",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_HIGHLIGHT),
+ nick);
+ if ( (cfg_look_infobar_delay_highlight > 0)
+ && (ptr_channel->buffer != gui_current_window->buffer) )
+ gui_infobar_printf (cfg_look_infobar_delay_highlight,
+ GUI_COLOR_WIN_INFOBAR_HIGHLIGHT,
+ _("Private %s> %s"),
+ nick, pos);
+ highlight = 1;
+ }
+ else
+ {
+ gui_printf_type (ptr_channel->buffer, GUI_MSG_TYPE_NICK,
+ "%s%s",
+ GUI_COLOR(GUI_COLOR_WIN_NICK_PRIVATE),
+ nick);
+ highlight = 0;
+ }
+ gui_printf_type (ptr_channel->buffer, GUI_MSG_TYPE_NICK,
+ "%s> ",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK));
+ gui_printf_type (ptr_channel->buffer, GUI_MSG_TYPE_MSG,
+ "%s%s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ pos);
+#ifdef PLUGINS
+ if (highlight)
+ (void) plugin_msg_handler_exec (server->name,
+ "weechat_highlight",
+ irc_last_command_received);
+#endif
+ }
+ else
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_SERVER);
+ if (host)
+ {
+ gui_printf (server->buffer, "%s%s",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK), nick);
+ if (host2)
+ gui_printf (server->buffer, " %s(%s%s%s)",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_HOST),
+ host2,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK));
+ gui_printf (server->buffer, "%s: ",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT));
+ }
+ gui_printf (server->buffer, "%s%s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ pos);
+ if ((nick) && (ascii_strcasecmp (nick, "nickserv") != 0) &&
+ (ascii_strcasecmp (nick, "chanserv") != 0) &&
+ (ascii_strcasecmp (nick, "memoserv") != 0))
+ {
+ if (gui_add_hotlist
+ && ((server->buffer->num_displayed == 0) || (gui_buffer_is_scrolled (server->buffer))))
+ {
+ hotlist_add (HOTLIST_PRIVATE, NULL, server, server->buffer, 0);
+ gui_status_draw (gui_current_window->buffer, 1);
+ }
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_part: 'part' message received
+ */
+
+int
+irc_recv_cmd_part (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos, *pos_args, *join_string;
+ int join_length;
+ t_irc_channel *ptr_channel;
+ t_irc_nick *ptr_nick;
+
+ /* no host => we can't identify sender of message! */
+ if (!host || !arguments)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s \"%s\" command received without host or channel\n"),
+ WEECHAT_ERROR, "part");
+ return -1;
+ }
+
+ if (arguments[0] == ':')
+ arguments++;
+
+ pos_args = strchr (arguments, ' ');
+ if (pos_args)
+ {
+ pos_args[0] = '\0';
+ pos_args++;
+ while (pos_args[0] == ' ')
+ pos_args++;
+ if (pos_args[0] == ':')
+ pos_args++;
+ }
+
+ ptr_channel = irc_channel_search (server, arguments);
+ if (ptr_channel)
+ {
+ command_ignored |= irc_ignore_check (host, "part", ptr_channel->name, server->name);
+ ptr_nick = irc_nick_search (ptr_channel, nick);
+ if (ptr_nick)
+ {
+ /* display part message */
+ if (!command_ignored)
+ {
+ pos = strchr (host, '!');
+ irc_display_prefix (server, ptr_channel->buffer, GUI_PREFIX_PART);
+ gui_printf (ptr_channel->buffer, _("%s%s %s(%s%s%s)%s has left %s%s"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ nick,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_HOST),
+ (pos) ? pos + 1 : "",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ ptr_channel->name);
+ if (pos_args && pos_args[0])
+ gui_printf (ptr_channel->buffer, " %s(%s%s%s)\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ pos_args,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK));
+ else
+ gui_printf (ptr_channel->buffer, "\n");
+ }
+
+ /* part request was issued by local client ? */
+ if (strcmp (ptr_nick->nick, server->nick) == 0)
+ {
+ irc_nick_free_all (ptr_channel);
+
+ /* cycling ? => rejoin channel immediately */
+ if (ptr_channel->cycle)
+ {
+ ptr_channel->cycle = 0;
+ if (ptr_channel->key)
+ {
+ join_length = strlen (ptr_channel->name) + 1 +
+ strlen (ptr_channel->key) + 1;
+ join_string = (char *)malloc (join_length);
+ if (join_string)
+ {
+ snprintf (join_string, join_length, "%s %s",
+ ptr_channel->name,
+ ptr_channel->key);
+ irc_send_cmd_join(server, ptr_channel, join_string);
+ free (join_string);
+ }
+ else
+ irc_send_cmd_join(server, ptr_channel, ptr_channel->name);
+ }
+ else
+ irc_send_cmd_join(server, ptr_channel, ptr_channel->name);
+ }
+ if (ptr_channel->close)
+ {
+ gui_buffer_free (ptr_channel->buffer, 1);
+ irc_channel_free (server, ptr_channel);
+ ptr_channel = NULL;
+ }
+ }
+ else
+ irc_nick_free (ptr_channel, ptr_nick);
+
+ if (ptr_channel)
+ {
+ gui_nicklist_draw (ptr_channel->buffer, 1, 1);
+ gui_status_draw (ptr_channel->buffer, 1);
+ }
+ gui_input_draw (gui_current_window->buffer, 1);
+ }
+ }
+ else
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s channel \"%s\" not found for \"%s\" command\n"),
+ WEECHAT_ERROR, arguments, "part");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_ping: 'ping' command received
+ */
+
+int
+irc_recv_cmd_ping (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos;
+
+ /* make C compiler happy */
+ (void) host;
+ (void) nick;
+
+ if (arguments[0] == ':')
+ arguments++;
+
+ pos = strrchr (arguments, ' ');
+ if (pos)
+ pos[0] = '\0';
+
+ irc_server_sendf (server, "PONG :%s", arguments);
+
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_pong: 'pong' command received
+ */
+
+int
+irc_recv_cmd_pong (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ struct timeval tv;
+ int old_lag;
+
+ /* make C compiler happy */
+ (void) host;
+ (void) nick;
+ (void) arguments;
+
+ if (server->lag_check_time.tv_sec != 0)
+ {
+ /* calculate lag (time diff with lag check) */
+ old_lag = server->lag;
+ gettimeofday (&tv, NULL);
+ server->lag = (int) get_timeval_diff (&(server->lag_check_time), &tv);
+ if (old_lag != server->lag)
+ gui_status_draw (gui_current_window->buffer, 1);
+
+ /* schedule next lag check */
+ server->lag_check_time.tv_sec = 0;
+ server->lag_check_time.tv_usec = 0;
+ server->lag_next_check = time (NULL) + cfg_irc_lag_check;
+ }
+ return 0;
+}
+
+/*
+ * irc_cmd_reply_version: send version in reply to "CTCP VERSION" request
+ */
+
+void
+irc_cmd_reply_version (t_irc_server *server, t_irc_channel *channel,
+ char *host, char *nick, char *message)
+{
+ char *pos;
+ struct utsname *buf;
+ t_gui_buffer *ptr_buffer;
+
+ ptr_buffer = (channel) ? channel->buffer : server->buffer;
+
+ command_ignored |= irc_ignore_check (host, "ctcp", NULL, server->name);
+ if (!command_ignored)
+ {
+ pos = strchr (message, ' ');
+ if (pos)
+ {
+ while (pos[0] == ' ')
+ pos++;
+ if (pos[0] == '\01')
+ pos = NULL;
+ else if (!pos[0])
+ pos = NULL;
+ }
+
+ buf = (struct utsname *) malloc (sizeof (struct utsname));
+ if (buf && (uname (buf) >= 0))
+ {
+ irc_server_sendf (server,
+ "NOTICE %s :%sVERSION %s v%s"
+ " compiled on %s, running "
+ "%s %s / %s%s",
+ nick, "\01", PACKAGE_NAME, PACKAGE_VERSION, __DATE__,
+ &buf->sysname,
+ &buf->release, &buf->machine, "\01");
+ free (buf);
+ }
+ else
+ irc_server_sendf (server,
+ "NOTICE %s :%sVERSION %s v%s"
+ " compiled on %s%s",
+ nick, "\01", PACKAGE_NAME, PACKAGE_VERSION, __DATE__,
+ "\01");
+ irc_display_prefix (server, ptr_buffer, GUI_PREFIX_SERVER);
+ gui_printf (ptr_buffer,
+ _("CTCP %sVERSION%s received from %s%s"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ nick);
+ if (pos)
+ gui_printf (ptr_buffer, "%s: %s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ pos);
+ else
+ gui_printf (ptr_buffer, "\n");
+#ifdef PLUGINS
+ (void) plugin_msg_handler_exec (server->name,
+ "weechat_ctcp",
+ irc_last_command_received);
+#endif
+ }
+}
+
+/*
+ * irc_recv_cmd_privmsg: 'privmsg' command received
+ */
+
+int
+irc_recv_cmd_privmsg (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos, *pos2, *host2;
+ char *pos_file, *pos_addr, *pos_port, *pos_size, *pos_start_resume; /* for DCC */
+ t_irc_channel *ptr_channel;
+ t_irc_nick *ptr_nick;
+ int highlight;
+
+ /* no host => we can't identify sender of message! */
+ if (!host)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s \"%s\" command received without host\n"),
+ WEECHAT_ERROR, "privmsg");
+ return -1;
+ }
+
+ pos = strchr (host, '!');
+ if (pos)
+ host2 = pos + 1;
+ else
+ host2 = host;
+
+ /* receiver is a channel ? */
+ if (irc_channel_is_channel (arguments))
+ {
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ if (pos[0] == ':')
+ pos++;
+
+ ptr_channel = irc_channel_search (server, arguments);
+ if (ptr_channel)
+ {
+ if (strncmp (pos, "\01ACTION ", 8) == 0)
+ {
+ command_ignored |= irc_ignore_check (host, "action", ptr_channel->name, server->name);
+ pos += 8;
+ pos2 = strchr (pos, '\01');
+ if (pos2)
+ pos2[0] = '\0';
+ if (!command_ignored)
+ {
+ irc_display_prefix (server, ptr_channel->buffer, GUI_PREFIX_ACTION_ME);
+ if (irc_recv_is_highlight (pos, server->nick))
+ {
+ gui_printf_type (ptr_channel->buffer,
+ GUI_MSG_TYPE_MSG | GUI_MSG_TYPE_HIGHLIGHT,
+ "%s%s",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_HIGHLIGHT),
+ nick);
+ if ( (cfg_look_infobar)
+ && (cfg_look_infobar_delay_highlight > 0)
+ && (ptr_channel->buffer != gui_current_window->buffer) )
+ gui_infobar_printf (cfg_look_infobar_delay_highlight,
+ GUI_COLOR_WIN_INFOBAR_HIGHLIGHT,
+ _("Channel %s: * %s %s"),
+ ptr_channel->name, nick, pos);
+ gui_printf (ptr_channel->buffer, " %s%s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT), pos);
+#ifdef PLUGINS
+ (void) plugin_msg_handler_exec (server->name,
+ "weechat_highlight",
+ irc_last_command_received);
+#endif
+ }
+ else
+ {
+ gui_printf_type (ptr_channel->buffer, GUI_MSG_TYPE_MSG,
+ "%s%s",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ nick);
+ gui_printf (ptr_channel->buffer, " %s%s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT), pos);
+ }
+ irc_channel_add_nick_speaking (ptr_channel, nick);
+ }
+ return 0;
+ }
+ if (strncmp (pos, "\01SOUND ", 7) == 0)
+ {
+ command_ignored |= irc_ignore_check (host, "ctcp", ptr_channel->name, server->name);
+ pos += 7;
+ pos2 = strchr (pos, '\01');
+ if (pos2)
+ pos2[0] = '\0';
+ if (!command_ignored)
+ {
+ irc_display_prefix (server, ptr_channel->buffer, GUI_PREFIX_SERVER);
+ gui_printf (ptr_channel->buffer,
+ _("Received a CTCP %sSOUND%s \"%s\" from %s%s\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ pos,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ nick);
+ }
+ return 0;
+ }
+ if (strncmp (pos, "\01PING", 5) == 0)
+ {
+ command_ignored |= irc_ignore_check (host, "ctcp", ptr_channel->name, server->name);
+ pos += 5;
+ while (pos[0] == ' ')
+ pos++;
+ pos2 = strchr (pos, '\01');
+ if (pos2)
+ pos2[0] = '\0';
+ else
+ pos = NULL;
+ if (pos && !pos[0])
+ pos = NULL;
+ if (pos)
+ irc_server_sendf (server, "NOTICE %s :\01PING %s\01",
+ nick, pos);
+ else
+ irc_server_sendf (server, "NOTICE %s :\01PING\01",
+ nick);
+ irc_display_prefix (server, ptr_channel->buffer, GUI_PREFIX_SERVER);
+ gui_printf (ptr_channel->buffer,
+ _("CTCP %sPING%s received from %s%s\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ nick);
+ return 0;
+ }
+ if (strncmp (pos, "\01VERSION", 8) == 0)
+ {
+ irc_cmd_reply_version (server, ptr_channel, host, nick, pos);
+ return 0;
+ }
+
+ /* unknown CTCP ? */
+ pos2 = strchr (pos + 1, '\01');
+ if ((pos[0] == '\01') && pos2 && (pos2[1] == '\0'))
+ {
+ command_ignored |= irc_ignore_check (host, "ctcp", ptr_channel->name, server->name);
+ pos++;
+ pos2[0] = '\0';
+ pos2 = strchr (pos, ' ');
+ if (pos2)
+ {
+ pos2[0] = '\0';
+ pos2++;
+ while (pos2[0] == ' ')
+ pos2++;
+ if (!pos2[0])
+ pos2 = NULL;
+ }
+ if (!command_ignored)
+ {
+ irc_display_prefix (server, ptr_channel->buffer, GUI_PREFIX_SERVER);
+ gui_printf (ptr_channel->buffer,
+ _("Unknown CTCP %s%s%s received from %s%s"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ pos,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ nick);
+ if (pos2)
+ gui_printf (ptr_channel->buffer, "%s: %s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ pos2);
+ else
+ gui_printf (ptr_channel->buffer, "\n");
+ }
+ return 0;
+ }
+
+ /* other message */
+ command_ignored |= irc_ignore_check (host, "privmsg", ptr_channel->name, server->name);
+ if (!command_ignored)
+ {
+ ptr_nick = irc_nick_search (ptr_channel, nick);
+ if (irc_recv_is_highlight (pos, server->nick))
+ {
+ irc_display_nick (ptr_channel->buffer, ptr_nick,
+ (ptr_nick) ? NULL : nick,
+ GUI_MSG_TYPE_NICK | GUI_MSG_TYPE_HIGHLIGHT,
+ 1, GUI_COLOR_WIN_CHAT_HIGHLIGHT, 0);
+ if ( (cfg_look_infobar)
+ && (cfg_look_infobar_delay_highlight > 0)
+ && (ptr_channel->buffer != gui_current_window->buffer) )
+ gui_infobar_printf (cfg_look_infobar_delay_highlight,
+ GUI_COLOR_WIN_INFOBAR_HIGHLIGHT,
+ _("Channel %s: %s> %s"),
+ ptr_channel->name, nick, pos);
+ gui_printf_type (ptr_channel->buffer, GUI_MSG_TYPE_MSG,
+ "%s\n", pos);
+#ifdef PLUGINS
+ (void) plugin_msg_handler_exec (server->name,
+ "weechat_highlight",
+ irc_last_command_received);
+#endif
+ }
+ else
+ {
+ irc_display_nick (ptr_channel->buffer, ptr_nick,
+ (ptr_nick) ? NULL : nick,
+ GUI_MSG_TYPE_NICK, 1, -1, 0);
+ gui_printf_type (ptr_channel->buffer, GUI_MSG_TYPE_MSG,
+ "%s\n", pos);
+ }
+ irc_channel_add_nick_speaking (ptr_channel, nick);
+ }
+ }
+ else
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s channel \"%s\" not found for \"%s\" command\n"),
+ WEECHAT_ERROR, arguments, "privmsg");
+ return -1;
+ }
+ }
+ }
+ else
+ {
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ if (pos[0] == ':')
+ pos++;
+
+ /* version asked by another user => answer with WeeChat version */
+ if (strncmp (pos, "\01VERSION", 8) == 0)
+ {
+ irc_cmd_reply_version (server, NULL, host, nick, pos);
+ return 0;
+ }
+
+ /* ping request from another user => answer */
+ if (strncmp (pos, "\01PING", 5) == 0)
+ {
+ command_ignored |= irc_ignore_check (host, "ctcp", NULL, server->name);
+ if (!command_ignored)
+ {
+ pos += 5;
+ while (pos[0] == ' ')
+ pos++;
+ pos2 = strchr (pos, '\01');
+ if (pos2)
+ pos2[0] = '\0';
+ else
+ pos = NULL;
+ if (pos && !pos[0])
+ pos = NULL;
+ if (pos)
+ irc_server_sendf (server, "NOTICE %s :\01PING %s\01",
+ nick, pos);
+ else
+ irc_server_sendf (server, "NOTICE %s :\01PING\01",
+ nick);
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_SERVER);
+ gui_printf (server->buffer,
+ _("CTCP %sPING%s received from %s%s\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ nick);
+#ifdef PLUGINS
+ (void) plugin_msg_handler_exec (server->name,
+ "weechat_ctcp",
+ irc_last_command_received);
+#endif
+ }
+ return 0;
+ }
+
+ /* incoming DCC file */
+ if (strncmp (pos, "\01DCC SEND", 9) == 0)
+ {
+ /* check if DCC SEND is ok, i.e. with 0x01 at end */
+ pos2 = strchr (pos + 1, '\01');
+ if (!pos2)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot parse \"%s\" command\n"),
+ WEECHAT_ERROR, "privmsg");
+ return -1;
+ }
+ pos2[0] = '\0';
+
+ command_ignored |= irc_ignore_check (host, "dcc", NULL, server->name);
+
+ if (!command_ignored)
+ {
+ /* DCC filename */
+ pos_file = pos + 9;
+ while (pos_file[0] == ' ')
+ pos_file++;
+
+ /* look for file size */
+ pos_size = strrchr (pos_file, ' ');
+ if (!pos_size)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot parse \"%s\" command\n"),
+ WEECHAT_ERROR, "privmsg");
+ return -1;
+ }
+ pos2 = pos_size;
+ pos_size++;
+ while (pos2[0] == ' ')
+ pos2--;
+ pos2[1] = '\0';
+
+ /* look for DCC port */
+ pos_port = strrchr (pos_file, ' ');
+ if (!pos_port)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot parse \"%s\" command\n"),
+ WEECHAT_ERROR, "privmsg");
+ return -1;
+ }
+ pos2 = pos_port;
+ pos_port++;
+ while (pos2[0] == ' ')
+ pos2--;
+ pos2[1] = '\0';
+
+ /* look for DCC IP address */
+ pos_addr = strrchr (pos_file, ' ');
+ if (!pos_addr)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot parse \"%s\" command\n"),
+ WEECHAT_ERROR, "privmsg");
+ return -1;
+ }
+ pos2 = pos_addr;
+ pos_addr++;
+ while (pos2[0] == ' ')
+ pos2--;
+ pos2[1] = '\0';
+
+ irc_dcc_add (server, IRC_DCC_FILE_RECV,
+ strtoul (pos_addr, NULL, 10),
+ atoi (pos_port), nick, -1, pos_file, NULL,
+ strtoul (pos_size, NULL, 10));
+#ifdef PLUGINS
+ (void) plugin_msg_handler_exec (server->name,
+ "weechat_dcc",
+ irc_last_command_received);
+#endif
+ }
+ return 0;
+ }
+
+ /* incoming DCC RESUME (asked by receiver) */
+ if (strncmp (pos, "\01DCC RESUME", 11) == 0)
+ {
+ /* check if DCC RESUME is ok, i.e. with 0x01 at end */
+ pos2 = strchr (pos + 1, '\01');
+ if (!pos2)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot parse \"%s\" command\n"),
+ WEECHAT_ERROR, "privmsg");
+ return -1;
+ }
+ pos2[0] = '\0';
+
+ command_ignored |= irc_ignore_check (host, "dcc", NULL, server->name);
+
+ if (!command_ignored)
+ {
+ /* DCC filename */
+ pos_file = pos + 11;
+ while (pos_file[0] == ' ')
+ pos_file++;
+
+ /* look for resume start position */
+ pos_start_resume = strrchr (pos_file, ' ');
+ if (!pos_start_resume)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot parse \"%s\" command\n"),
+ WEECHAT_ERROR, "privmsg");
+ return -1;
+ }
+ pos2 = pos_start_resume;
+ pos_start_resume++;
+ while (pos2[0] == ' ')
+ pos2--;
+ pos2[1] = '\0';
+
+ /* look for DCC port */
+ pos_port = strrchr (pos_file, ' ');
+ if (!pos_port)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot parse \"%s\" command\n"),
+ WEECHAT_ERROR, "privmsg");
+ return -1;
+ }
+ pos2 = pos_port;
+ pos_port++;
+ while (pos2[0] == ' ')
+ pos2--;
+ pos2[1] = '\0';
+
+ irc_dcc_accept_resume (server, pos_file, atoi (pos_port),
+ strtoul (pos_start_resume, NULL, 10));
+#ifdef PLUGINS
+ (void) plugin_msg_handler_exec (server->name,
+ "weechat_dcc",
+ irc_last_command_received);
+#endif
+ }
+ return 0;
+ }
+
+ /* incoming DCC ACCEPT (resume accepted by sender) */
+ if (strncmp (pos, "\01DCC ACCEPT", 11) == 0)
+ {
+ /* check if DCC ACCEPT is ok, i.e. with 0x01 at end */
+ pos2 = strchr (pos + 1, '\01');
+ if (!pos2)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot parse \"%s\" command\n"),
+ WEECHAT_ERROR, "privmsg");
+ return -1;
+ }
+ pos2[0] = '\0';
+
+ command_ignored |= irc_ignore_check (host, "dcc", NULL, server->name);
+
+ if (!command_ignored)
+ {
+ /* DCC filename */
+ pos_file = pos + 11;
+ while (pos_file[0] == ' ')
+ pos_file++;
+
+ /* look for resume start position */
+ pos_start_resume = strrchr (pos_file, ' ');
+ if (!pos_start_resume)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot parse \"%s\" command\n"),
+ WEECHAT_ERROR, "privmsg");
+ return -1;
+ }
+ pos2 = pos_start_resume;
+ pos_start_resume++;
+ while (pos2[0] == ' ')
+ pos2--;
+ pos2[1] = '\0';
+
+ /* look for DCC port */
+ pos_port = strrchr (pos_file, ' ');
+ if (!pos_port)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot parse \"%s\" command\n"),
+ WEECHAT_ERROR, "privmsg");
+ return -1;
+ }
+ pos2 = pos_port;
+ pos_port++;
+ while (pos2[0] == ' ')
+ pos2--;
+ pos2[1] = '\0';
+
+ irc_dcc_start_resume (server, pos_file, atoi (pos_port),
+ strtoul (pos_start_resume, NULL, 10));
+#ifdef PLUGINS
+ (void) plugin_msg_handler_exec (server->name,
+ "weechat_dcc",
+ irc_last_command_received);
+#endif
+ }
+ return 0;
+ }
+
+ /* incoming DCC CHAT */
+ if (strncmp (pos, "\01DCC CHAT", 9) == 0)
+ {
+ /* check if DCC CHAT is ok, i.e. with 0x01 at end */
+ pos2 = strchr (pos + 1, '\01');
+ if (!pos2)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot parse \"%s\" command\n"),
+ WEECHAT_ERROR, "privmsg");
+ return -1;
+ }
+ pos2[0] = '\0';
+
+ command_ignored |= irc_ignore_check (host, "dcc", NULL, server->name);
+
+ if (!command_ignored)
+ {
+ /* CHAT type */
+ pos_file = pos + 9;
+ while (pos_file[0] == ' ')
+ pos_file++;
+
+ /* DCC IP address */
+ pos_addr = strchr (pos_file, ' ');
+ if (!pos_addr)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot parse \"%s\" command\n"),
+ WEECHAT_ERROR, "privmsg");
+ return -1;
+ }
+ pos_addr[0] = '\0';
+ pos_addr++;
+ while (pos_addr[0] == ' ')
+ pos_addr++;
+
+ /* look for DCC port */
+ pos_port = strchr (pos_addr, ' ');
+ if (!pos_port)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot parse \"%s\" command\n"),
+ WEECHAT_ERROR, "privmsg");
+ return -1;
+ }
+ pos_port[0] = '\0';
+ pos_port++;
+ while (pos_port[0] == ' ')
+ pos_port++;
+
+ if (ascii_strcasecmp (pos_file, "chat") != 0)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s unknown DCC CHAT type received from "),
+ WEECHAT_ERROR);
+ gui_printf (server->buffer, "%s%s%s: \"%s\"\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ nick,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ pos_file);
+ return -1;
+ }
+
+ irc_dcc_add (server, IRC_DCC_CHAT_RECV,
+ strtoul (pos_addr, NULL, 10),
+ atoi (pos_port), nick, -1, NULL, NULL, 0);
+#ifdef PLUGINS
+ (void) plugin_msg_handler_exec (server->name,
+ "weechat_dcc",
+ irc_last_command_received);
+#endif
+ }
+ return 0;
+ }
+
+ /* private message received => display it */
+ ptr_channel = irc_channel_search (server, nick);
+
+ if (strncmp (pos, "\01ACTION ", 8) == 0)
+ {
+ command_ignored |= irc_ignore_check (host, "action", NULL, server->name);
+ command_ignored |= irc_ignore_check (host, "pv", NULL, server->name);
+
+ if (!command_ignored)
+ {
+ if (!ptr_channel)
+ {
+ ptr_channel = irc_channel_new (server,
+ IRC_CHANNEL_TYPE_PRIVATE,
+ nick);
+ if (!ptr_channel)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot create new private window \"%s\"\n"),
+ WEECHAT_ERROR, nick);
+ return -1;
+ }
+ gui_buffer_new (gui_current_window, server, ptr_channel,
+ GUI_BUFFER_TYPE_STANDARD, 0);
+ }
+ if (!ptr_channel->topic)
+ {
+ ptr_channel->topic = strdup (host2);
+ gui_chat_draw_title (ptr_channel->buffer, 1);
+ }
+
+ pos += 8;
+ pos2 = strchr (pos, '\01');
+ if (pos2)
+ pos2[0] = '\0';
+ irc_display_prefix (server, ptr_channel->buffer, GUI_PREFIX_ACTION_ME);
+ if (irc_recv_is_highlight (pos, server->nick))
+ {
+ gui_printf_type (ptr_channel->buffer,
+ GUI_MSG_TYPE_MSG | GUI_MSG_TYPE_HIGHLIGHT,
+ "%s%s",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_HIGHLIGHT),
+ nick);
+ if ( (cfg_look_infobar)
+ && (cfg_look_infobar_delay_highlight > 0)
+ && (ptr_channel->buffer != gui_current_window->buffer) )
+ gui_infobar_printf (cfg_look_infobar_delay_highlight,
+ GUI_COLOR_WIN_INFOBAR_HIGHLIGHT,
+ _("Channel %s: * %s %s"),
+ ptr_channel->name, nick, pos);
+ gui_printf (ptr_channel->buffer, " %s%s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT), pos);
+#ifdef PLUGINS
+ (void) plugin_msg_handler_exec (server->name,
+ "weechat_highlight",
+ irc_last_command_received);
+#endif
+ }
+ else
+ {
+ gui_printf_type (ptr_channel->buffer, GUI_MSG_TYPE_MSG,
+ "%s%s",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ nick);
+ gui_printf (ptr_channel->buffer, " %s%s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT), pos);
+#ifdef PLUGINS
+ (void) plugin_msg_handler_exec (server->name,
+ "weechat_pv",
+ irc_last_command_received);
+#endif
+ }
+ }
+ }
+ else
+ {
+ /* unknown CTCP ? */
+ pos2 = strchr (pos + 1, '\01');
+ if ((pos[0] == '\01') && pos2 && (pos2[1] == '\0'))
+ {
+ command_ignored |= irc_ignore_check (host, "ctcp", NULL, server->name);
+
+ if (!command_ignored)
+ {
+ pos++;
+ pos2[0] = '\0';
+ pos2 = strchr (pos, ' ');
+ if (pos2)
+ {
+ pos2[0] = '\0';
+ pos2++;
+ while (pos2[0] == ' ')
+ pos2++;
+ if (!pos2[0])
+ pos2 = NULL;
+ }
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_SERVER);
+ gui_printf (server->buffer,
+ _("Unknown CTCP %s%s%s received from %s%s"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ pos,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ nick);
+ if (pos2)
+ gui_printf (server->buffer, "%s: %s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ pos2);
+ else
+ gui_printf (server->buffer, "\n");
+#ifdef PLUGINS
+ (void) plugin_msg_handler_exec (server->name,
+ "weechat_ctcp",
+ irc_last_command_received);
+#endif
+ }
+ return 0;
+ }
+ else
+ {
+ command_ignored |= irc_ignore_check (host, "pv", NULL, server->name);
+
+ if (!command_ignored)
+ {
+ if (!ptr_channel)
+ {
+ ptr_channel = irc_channel_new (server,
+ IRC_CHANNEL_TYPE_PRIVATE,
+ nick);
+ if (!ptr_channel)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot create new private window \"%s\"\n"),
+ WEECHAT_ERROR, nick);
+ return -1;
+ }
+ gui_buffer_new (gui_current_window, server, ptr_channel,
+ GUI_BUFFER_TYPE_STANDARD, 0);
+ }
+ if (!ptr_channel->topic)
+ {
+ ptr_channel->topic = strdup (host2);
+ gui_chat_draw_title (ptr_channel->buffer, 1);
+ }
+
+ if (irc_recv_is_highlight (pos, server->nick))
+ {
+ irc_display_nick (ptr_channel->buffer, NULL, nick,
+ GUI_MSG_TYPE_NICK | GUI_MSG_TYPE_HIGHLIGHT, 1,
+ GUI_COLOR_WIN_CHAT_HIGHLIGHT, 0);
+ if ((cfg_look_infobar_delay_highlight > 0)
+ && (ptr_channel->buffer != gui_current_window->buffer))
+ gui_infobar_printf (cfg_look_infobar_delay_highlight,
+ GUI_COLOR_WIN_INFOBAR_HIGHLIGHT,
+ _("Private %s> %s"),
+ nick, pos);
+ highlight = 1;
+ }
+ else
+ {
+ irc_display_nick (ptr_channel->buffer, NULL, nick,
+ GUI_MSG_TYPE_NICK, 1, GUI_COLOR_WIN_NICK_PRIVATE, 0);
+ highlight = 0;
+ }
+ gui_printf_type (ptr_channel->buffer, GUI_MSG_TYPE_MSG,
+ "%s%s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ pos);
+#ifdef PLUGINS
+ (void) plugin_msg_handler_exec (server->name,
+ "weechat_pv",
+ irc_last_command_received);
+ if (highlight)
+ (void) plugin_msg_handler_exec (server->name,
+ "weechat_highlight",
+ irc_last_command_received);
+#endif
+ }
+ }
+ }
+ }
+ else
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot parse \"%s\" command\n"),
+ WEECHAT_ERROR, "privmsg");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_quit: 'quit' command received
+ */
+
+int
+irc_recv_cmd_quit (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos;
+ t_irc_channel *ptr_channel;
+ t_irc_nick *ptr_nick;
+
+ /* no host => we can't identify sender of message! */
+ if (!host)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s \"%s\" command received without host\n"),
+ WEECHAT_ERROR, "quit");
+ return -1;
+ }
+
+ if (arguments[0] == ':')
+ arguments++;
+
+ for (ptr_channel = server->channels; ptr_channel;
+ ptr_channel = ptr_channel->next_channel)
+ {
+ if ((ptr_channel->type == IRC_CHANNEL_TYPE_PRIVATE)
+ || (ptr_channel->type == IRC_CHANNEL_TYPE_DCC_CHAT))
+ ptr_nick = NULL;
+ else
+ ptr_nick = irc_nick_search (ptr_channel, nick);
+
+ if (ptr_nick || (strcmp (ptr_channel->name, nick) == 0))
+ {
+ if (ptr_nick)
+ irc_nick_free (ptr_channel, ptr_nick);
+ if (!command_ignored
+ && !irc_ignore_check (host, "quit", ptr_channel->name, server->name))
+ {
+ pos = strchr (host, '!');
+ irc_display_prefix (server, ptr_channel->buffer, GUI_PREFIX_QUIT);
+ gui_printf (ptr_channel->buffer,
+ _("%s%s %s(%s%s%s)%s has quit"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ nick,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_HOST),
+ (pos) ? pos + 1 : "",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT));
+ gui_printf (ptr_channel->buffer,
+ " %s(%s%s%s)\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ arguments,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK));
+ }
+ gui_nicklist_draw (ptr_channel->buffer, 1, 1);
+ gui_status_draw (ptr_channel->buffer, 1);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_server_mode_reason: command received from server (numeric),
+ * format: "mode :reason"
+ */
+
+int
+irc_recv_cmd_server_mode_reason (t_irc_server *server, char *host,
+ char *nick, char *arguments)
+{
+ char *ptr_msg;
+
+ /* make C compiler happy */
+ (void) host;
+ (void) nick;
+
+ if (!command_ignored)
+ {
+ /* skip nickname if at beginning of server message */
+ if (strncmp (server->nick, arguments, strlen (server->nick)) == 0)
+ {
+ arguments += strlen (server->nick) + 1;
+ while (arguments[0] == ' ')
+ arguments++;
+ }
+
+ ptr_msg = strchr (arguments, ' ');
+ if (ptr_msg)
+ {
+ ptr_msg[0] = '\0';
+ ptr_msg++;
+ while (ptr_msg[0] == ' ')
+ ptr_msg++;
+ if (ptr_msg[0] == ':')
+ ptr_msg++;
+ }
+
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_SERVER);
+ gui_printf (server->buffer, "%s%s: %s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT), arguments,
+ (ptr_msg) ? ptr_msg : "");
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_server_msg: command received from server (numeric)
+ */
+
+int
+irc_recv_cmd_server_msg (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ /* make C compiler happy */
+ (void) host;
+ (void) nick;
+
+ if (!command_ignored)
+ {
+ while (arguments[0] == ' ')
+ arguments++;
+
+ /* skip nickname if at beginning of server message */
+ if (strncasecmp (server->nick, arguments, strlen (server->nick)) == 0)
+ {
+ arguments += strlen (server->nick) + 1;
+ while (arguments[0] == ' ')
+ arguments++;
+ }
+
+ if (arguments[0] == ':')
+ arguments++;
+
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_SERVER);
+ gui_printf (server->buffer, "%s%s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT), arguments);
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_server_reply: server reply
+ */
+
+int
+irc_recv_cmd_server_reply (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos, *pos2;
+ int first;
+
+ /* make C compiler happy */
+ (void) server;
+ (void) host;
+ (void) nick;
+
+ if (!command_ignored)
+ {
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ }
+ else
+ pos = arguments;
+
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ first = 1;
+
+ while (pos && pos[0])
+ {
+ pos2 = strchr (pos, ' ');
+ if ((pos[0] == ':') || (!pos2))
+ {
+ if (pos[0] == ':')
+ pos++;
+ gui_printf (server->buffer, "%s%s%s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ (first) ? "" : ": ",
+ pos);
+ pos = NULL;
+ }
+ else
+ {
+ pos2[0] = '\0';
+ gui_printf (server->buffer, "%s%s%s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ (first) ? "" : " ",
+ pos);
+ first = 0;
+ pos = pos2 + 1;
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_topic: 'topic' command received
+ */
+
+int
+irc_recv_cmd_topic (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos;
+ t_irc_channel *ptr_channel;
+ t_gui_buffer *buffer;
+
+ if (!irc_channel_is_channel (arguments))
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s \"%s\" command received without channel\n"),
+ WEECHAT_ERROR, "topic");
+ return -1;
+ }
+
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ if (pos[0] == ':')
+ pos++;
+ if (!pos[0])
+ pos = NULL;
+ }
+
+ command_ignored |= irc_ignore_check (host, "topic", arguments, server->name);
+
+ ptr_channel = irc_channel_search (server, arguments);
+ buffer = (ptr_channel) ? ptr_channel->buffer : server->buffer;
+
+ if (!command_ignored)
+ {
+ irc_display_prefix (server, buffer, GUI_PREFIX_INFO);
+ if (pos)
+ {
+ gui_printf (buffer,
+ _("%s%s%s has changed topic for %s%s%s to:"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ nick,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ arguments,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT));
+ gui_printf (buffer, " \"%s%s\"\n", pos, GUI_NO_COLOR);
+ }
+ else
+ gui_printf (buffer,
+ _("%s%s%s has unset topic for %s%s\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ nick,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ arguments);
+ }
+
+ if (ptr_channel)
+ {
+ if (ptr_channel->topic)
+ free (ptr_channel->topic);
+ if (pos)
+ ptr_channel->topic = strdup (pos);
+ else
+ ptr_channel->topic = strdup ("");
+ gui_chat_draw_title (ptr_channel->buffer, 1);
+ }
+
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_wallops: 'wallops' command received
+ */
+
+int
+irc_recv_cmd_wallops (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ command_ignored |= irc_ignore_check (host, "wallops", arguments, server->name);
+
+ if (!command_ignored)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_SERVER);
+ if (arguments[0] == ':')
+ arguments++;
+ gui_printf (server->buffer,
+ _("WALLOPS from %s%s%s: %s\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ nick,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ arguments);
+ }
+
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_001: '001' command (connected to irc server)
+ */
+
+int
+irc_recv_cmd_001 (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos;
+ char **commands, **ptr, *vars_replaced;
+ char *away_msg;
+
+ pos = strchr (arguments, ' ');
+ if (pos)
+ pos[0] = '\0';
+ if (strcmp (server->nick, arguments) != 0)
+ {
+ free (server->nick);
+ server->nick = strdup (arguments);
+ }
+
+ irc_recv_cmd_server_msg (server, host, nick, arguments);
+
+ /* connection to IRC server is ok! */
+ server->is_connected = 1;
+ server->lag_next_check = time (NULL) + cfg_irc_lag_check;
+
+ /* set away message if user was away (before disconnection for example) */
+ if (server->away_message && server->away_message[0])
+ {
+ away_msg = strdup (server->away_message);
+ if (away_msg)
+ {
+ irc_send_away (server, away_msg);
+ free (away_msg);
+ }
+ }
+
+ /* execute command when connected */
+ if (server->command && server->command[0])
+ {
+ /* splitting command on ';' which can be escaped with '\;' */
+ commands = split_multi_command (server->command, ';');
+ if (commands)
+ {
+ for (ptr = commands; *ptr; ptr++)
+ {
+ vars_replaced = alias_replace_vars (server, NULL, *ptr);
+ user_command (server, NULL,
+ (vars_replaced) ? vars_replaced : *ptr, 0);
+ if (vars_replaced)
+ free (vars_replaced);
+ }
+ free_multi_command (commands);
+ }
+
+ if (server->command_delay > 0)
+ server->command_time = time (NULL) + 1;
+ else
+ irc_server_autojoin_channels (server);
+ }
+ else
+ irc_server_autojoin_channels (server);
+
+ gui_status_draw (server->buffer, 1);
+ gui_input_draw (server->buffer, 1);
+
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_005: '005' command (some infos from server)
+ */
+
+int
+irc_recv_cmd_005 (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos, *pos2;
+
+ irc_recv_cmd_server_msg (server, host, nick, arguments);
+
+ pos = strstr (arguments, "PREFIX=");
+ if (pos)
+ {
+ pos += 7;
+ if (pos[0] == '(')
+ {
+ pos2 = strchr (pos, ')');
+ if (!pos2)
+ return 0;
+ pos = pos2 + 1;
+ }
+ pos2 = strchr (pos, ' ');
+ if (pos2)
+ pos2[0] = '\0';
+ if (server->prefix)
+ free (server->prefix);
+ server->prefix = strdup (pos);
+ if (pos2)
+ pos2[0] = ' ';
+ }
+
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_221: '221' command (user mode string)
+ */
+
+int
+irc_recv_cmd_221 (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos_mode;
+
+ /* make C compiler happy */
+ (void) server;
+ (void) host;
+ (void) nick;
+
+ pos_mode = strchr (arguments, ' ');
+ if (pos_mode)
+ {
+ pos_mode[0] = '\0';
+ pos_mode++;
+ while (pos_mode[0] == ' ')
+ pos_mode++;
+
+ if (!command_ignored)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_SERVER);
+ gui_printf (server->buffer,
+ _("User mode for %s%s%s is %s[%s%s%s]\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ arguments,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ pos_mode,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK));
+ }
+ }
+ else
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot parse \"%s\" command\n"),
+ WEECHAT_ERROR, "221");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_301: '301' command (away message)
+ */
+
+int
+irc_recv_cmd_301 (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos_nick, *pos_message;
+ t_irc_channel *ptr_channel;
+ t_gui_buffer *ptr_buffer;
+
+ /* make C compiler happy */
+ (void) server;
+ (void) host;
+ (void) nick;
+
+ pos_nick = strchr (arguments, ' ');
+ if (pos_nick)
+ {
+ while (pos_nick[0] == ' ')
+ pos_nick++;
+ pos_message = strchr (pos_nick, ' ');
+ if (pos_message)
+ {
+ pos_message[0] = '\0';
+ pos_message++;
+ while (pos_message[0] == ' ')
+ pos_message++;
+ if (pos_message[0] == ':')
+ pos_message++;
+
+ if (!command_ignored)
+ {
+ /* look for private buffer to display message */
+ ptr_channel = irc_channel_search (server, pos_nick);
+ if (!cfg_irc_show_away_once || !ptr_channel ||
+ !(ptr_channel->away_message) ||
+ (strcmp (ptr_channel->away_message, pos_message) != 0))
+ {
+ ptr_buffer = (ptr_channel) ? ptr_channel->buffer : server->buffer;
+ irc_display_prefix (server, ptr_buffer, GUI_PREFIX_INFO);
+ gui_printf (ptr_buffer,
+ _("%s%s%s is away: %s\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ pos_nick,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ pos_message);
+ if (ptr_channel)
+ {
+ if (ptr_channel->away_message)
+ free (ptr_channel->away_message);
+ ptr_channel->away_message = strdup (pos_message);
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_302: '302' command (userhost)
+ */
+
+int
+irc_recv_cmd_302 (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos_host, *ptr_next;
+
+ /* make C compiler happy */
+ (void) host;
+ (void) nick;
+
+ if (!command_ignored)
+ {
+ arguments = strchr (arguments, ' ');
+ if (arguments)
+ {
+ while (arguments[0] == ' ')
+ arguments++;
+ if (arguments[0] == ':')
+ arguments++;
+ while (arguments)
+ {
+ pos_host = strchr (arguments, '=');
+ if (pos_host)
+ {
+ pos_host[0] = '\0';
+ pos_host++;
+
+ ptr_next = strchr (pos_host, ' ');
+ if (ptr_next)
+ {
+ ptr_next[0] = '\0';
+ ptr_next++;
+ while (ptr_next[0] == ' ')
+ ptr_next++;
+ }
+
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_SERVER);
+ gui_printf (server->buffer, "%s%s%s=%s%s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ arguments,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_HOST),
+ pos_host);
+ }
+ else
+ ptr_next = NULL;
+ arguments = ptr_next;
+ if (arguments && !arguments[0])
+ arguments = NULL;
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_303: '303' command (ison)
+ */
+
+int
+irc_recv_cmd_303 (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *ptr_next;
+
+ /* make C compiler happy */
+ (void) host;
+ (void) nick;
+
+ if (!command_ignored)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_SERVER);
+ gui_printf (server->buffer, _("Users online: "));
+
+ arguments = strchr (arguments, ' ');
+ if (arguments)
+ {
+ while (arguments[0] == ' ')
+ arguments++;
+ if (arguments[0] == ':')
+ arguments++;
+ while (arguments)
+ {
+ ptr_next = strchr (arguments, ' ');
+ if (ptr_next)
+ {
+ ptr_next[0] = '\0';
+ ptr_next++;
+ while (ptr_next[0] == ' ')
+ ptr_next++;
+ }
+ gui_printf (server->buffer, "%s%s ",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ arguments);
+ arguments = ptr_next;
+ if (arguments && !arguments[0])
+ arguments = NULL;
+ }
+ }
+ gui_printf (server->buffer, "\n");
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_305: '305' command (unaway)
+ */
+
+int
+irc_recv_cmd_305 (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ t_gui_window *ptr_win;
+
+ /* make C compiler happy */
+ (void) host;
+ (void) nick;
+
+ if (!command_ignored)
+ {
+ arguments = strchr (arguments, ' ');
+ if (arguments)
+ {
+ while (arguments[0] == ' ')
+ arguments++;
+ if (arguments[0] == ':')
+ arguments++;
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_SERVER);
+ gui_printf (server->buffer, "%s\n", arguments);
+ }
+ }
+ server->is_away = 0;
+ server->away_time = 0;
+ for (ptr_win = gui_windows; ptr_win; ptr_win = ptr_win->next_window)
+ {
+ if (GUI_SERVER(ptr_win->buffer) == server)
+ gui_status_draw (ptr_win->buffer, 1);
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_306: '306' command (now away)
+ */
+
+int
+irc_recv_cmd_306 (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ t_gui_window *ptr_win;
+
+ /* make C compiler happy */
+ (void) host;
+ (void) nick;
+
+ if (!command_ignored)
+ {
+ arguments = strchr (arguments, ' ');
+ if (arguments)
+ {
+ while (arguments[0] == ' ')
+ arguments++;
+ if (arguments[0] == ':')
+ arguments++;
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_SERVER);
+ gui_printf (server->buffer, "%s\n", arguments);
+ }
+ }
+ server->is_away = 1;
+ server->away_time = time (NULL);
+ for (ptr_win = gui_windows; ptr_win; ptr_win = ptr_win->next_window)
+ {
+ if (GUI_SERVER(ptr_win->buffer) == server)
+ gui_status_draw (ptr_win->buffer, 1);
+ if (GUI_SERVER(ptr_win->buffer) == server)
+ ptr_win->buffer->last_read_line =
+ ptr_win->buffer->last_line;
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_whois_nick_msg: a whois command with nick and message
+ */
+
+int
+irc_recv_cmd_whois_nick_msg (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos_nick, *pos_msg;
+
+ /* make C compiler happy */
+ (void) host;
+ (void) nick;
+
+ if (!command_ignored)
+ {
+ pos_nick = strchr (arguments, ' ');
+ if (pos_nick)
+ {
+ while (pos_nick[0] == ' ')
+ pos_nick++;
+ pos_msg = strchr (pos_nick, ' ');
+ if (pos_msg)
+ {
+ pos_msg[0] = '\0';
+ pos_msg++;
+ while (pos_msg[0] == ' ')
+ pos_msg++;
+ if (pos_msg[0] == ':')
+ pos_msg++;
+
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_SERVER);
+ gui_printf (server->buffer, "%s[%s%s%s] %s%s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ pos_nick,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ pos_msg);
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_310: '310' command (whois, help mode)
+ */
+
+int
+irc_recv_cmd_310 (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos_nick;
+
+ /* make C compiler happy */
+ (void) host;
+ (void) nick;
+
+ if (!command_ignored)
+ {
+ pos_nick = strchr (arguments, ' ');
+ if (pos_nick)
+ {
+ while (pos_nick[0] == ' ')
+ pos_nick++;
+
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_SERVER);
+ gui_printf (server->buffer, _("%s[%s%s%s]%s help mode (+h)\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ pos_nick,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT));
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_311: '311' command (whois, user)
+ */
+
+int
+irc_recv_cmd_311 (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos_nick, *pos_user, *pos_host, *pos_realname;
+
+ /* make C compiler happy */
+ (void) host;
+ (void) nick;
+
+ if (!command_ignored)
+ {
+ pos_nick = strchr (arguments, ' ');
+ if (pos_nick)
+ {
+ while (pos_nick[0] == ' ')
+ pos_nick++;
+ pos_user = strchr (pos_nick, ' ');
+ if (pos_user)
+ {
+ pos_user[0] = '\0';
+ pos_user++;
+ while (pos_user[0] == ' ')
+ pos_user++;
+ pos_host = strchr (pos_user, ' ');
+ if (pos_host)
+ {
+ pos_host[0] = '\0';
+ pos_host++;
+ while (pos_host[0] == ' ')
+ pos_host++;
+ pos_realname = strchr (pos_host, ' ');
+ if (pos_realname)
+ {
+ pos_realname[0] = '\0';
+ pos_realname++;
+ while (pos_realname[0] == ' ')
+ pos_realname++;
+ if (pos_realname[0] == '*')
+ pos_realname++;
+ while (pos_realname[0] == ' ')
+ pos_realname++;
+ if (pos_realname[0] == ':')
+ pos_realname++;
+
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_SERVER);
+ gui_printf (server->buffer,
+ "%s[%s%s%s] (%s%s@%s%s)%s: %s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ pos_nick,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_HOST),
+ pos_user,
+ pos_host,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ pos_realname);
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_312: '312' command (whois, server)
+ */
+
+int
+irc_recv_cmd_312 (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos_nick, *pos_server, *pos_serverinfo;
+
+ /* make C compiler happy */
+ (void) host;
+ (void) nick;
+
+ if (!command_ignored)
+ {
+ pos_nick = strchr (arguments, ' ');
+ if (pos_nick)
+ {
+ while (pos_nick[0] == ' ')
+ pos_nick++;
+ pos_server = strchr (pos_nick, ' ');
+ if (pos_server)
+ {
+ pos_server[0] = '\0';
+ pos_server++;
+ while (pos_server[0] == ' ')
+ pos_server++;
+ pos_serverinfo = strchr (pos_server, ' ');
+ if (pos_serverinfo)
+ {
+ pos_serverinfo[0] = '\0';
+ pos_serverinfo++;
+ while (pos_serverinfo[0] == ' ')
+ pos_serverinfo++;
+ if (pos_serverinfo[0] == ':')
+ pos_serverinfo++;
+
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_SERVER);
+ gui_printf (server->buffer,
+ "%s[%s%s%s] %s%s %s(%s%s%s)\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ pos_nick,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ pos_server,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ pos_serverinfo,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK));
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_314: '314' command (whowas)
+ */
+
+int
+irc_recv_cmd_314 (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos_nick, *pos_user, *pos_host, *pos_realname;
+
+ /* make C compiler happy */
+ (void) host;
+ (void) nick;
+
+ if (!command_ignored)
+ {
+ pos_nick = strchr (arguments, ' ');
+ if (pos_nick)
+ {
+ while (pos_nick[0] == ' ')
+ pos_nick++;
+ pos_user = strchr (pos_nick, ' ');
+ if (pos_user)
+ {
+ pos_user[0] = '\0';
+ pos_user++;
+ while (pos_user[0] == ' ')
+ pos_user++;
+ pos_host = strchr (pos_user, ' ');
+ if (pos_host)
+ {
+ pos_host[0] = '\0';
+ pos_host++;
+ while (pos_host[0] == ' ')
+ pos_host++;
+ pos_realname = strchr (pos_host, ' ');
+ if (pos_realname)
+ {
+ pos_realname[0] = '\0';
+ pos_realname++;
+ while (pos_realname[0] == ' ')
+ pos_realname++;
+ pos_realname = strchr (pos_realname, ' ');
+ if (pos_realname)
+ {
+ pos_realname[0] = '\0';
+ pos_realname++;
+ while (pos_realname[0] == ' ')
+ pos_realname++;
+ if (pos_realname[0] == ':')
+ pos_realname++;
+
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_SERVER);
+ gui_printf (server->buffer,
+ _("%s%s %s(%s%s@%s%s)%s was %s\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ pos_nick,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_HOST),
+ pos_user,
+ pos_host,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ pos_realname);
+ }
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_315: '315' command (end of /who)
+ */
+
+int
+irc_recv_cmd_315 (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos;
+ t_irc_channel *ptr_channel;
+
+ /* make C compiler happy */
+ (void) host;
+ (void) nick;
+
+ /* skip nickname if at beginning of server message */
+ if (strncmp (server->nick, arguments, strlen (server->nick)) == 0)
+ {
+ arguments += strlen (server->nick) + 1;
+ while (arguments[0] == ' ')
+ arguments++;
+ }
+
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ ptr_channel = irc_channel_search (server, arguments);
+ if (ptr_channel && (ptr_channel->checking_away > 0))
+ {
+ ptr_channel->checking_away--;
+ return 0;
+ }
+ if (!command_ignored)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_SERVER);
+ gui_printf (server->buffer, "%s%s %s%s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ arguments,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ pos);
+ }
+ }
+ else
+ {
+ if (!command_ignored)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_SERVER);
+ gui_printf (server->buffer, "%s\n", arguments);
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_317: '317' command (whois, idle)
+ */
+
+int
+irc_recv_cmd_317 (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos_nick, *pos_idle, *pos_signon, *pos_message;
+ int idle_time, day, hour, min, sec;
+ time_t datetime;
+
+ /* make C compiler happy */
+ (void) host;
+ (void) nick;
+
+ if (!command_ignored)
+ {
+ pos_nick = strchr (arguments, ' ');
+ if (pos_nick)
+ {
+ while (pos_nick[0] == ' ')
+ pos_nick++;
+ pos_idle = strchr (pos_nick, ' ');
+ if (pos_idle)
+ {
+ pos_idle[0] = '\0';
+ pos_idle++;
+ while (pos_idle[0] == ' ')
+ pos_idle++;
+ pos_signon = strchr (pos_idle, ' ');
+ if (pos_signon)
+ {
+ pos_signon[0] = '\0';
+ pos_signon++;
+ while (pos_signon[0] == ' ')
+ pos_signon++;
+ pos_message = strchr (pos_signon, ' ');
+ if (pos_message)
+ {
+ pos_message[0] = '\0';
+
+ idle_time = atoi (pos_idle);
+ day = idle_time / (60 * 60 * 24);
+ hour = (idle_time % (60 * 60 * 24)) / (60 * 60);
+ min = ((idle_time % (60 * 60 * 24)) % (60 * 60)) / 60;
+ sec = ((idle_time % (60 * 60 * 24)) % (60 * 60)) % 60;
+
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_SERVER);
+ gui_printf (server->buffer, _("%s[%s%s%s]%s idle: "),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ pos_nick,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT));
+
+ if (day > 0)
+ gui_printf (server->buffer, "%s%d %s%s, ",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ day,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ (day > 1) ? _("days") : _("day"));
+
+ datetime = (time_t)(atol (pos_signon));
+ gui_printf (server->buffer,
+ _("%s%02d %s%s %s%02d %s%s %s%02d %s%s, signon at: %s%s"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ hour,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ (hour > 1) ? _("hours") : _("hour"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ min,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ (min > 1) ? _("minutes") : _("minute"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ sec,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ (sec > 1) ? _("seconds") : _("second"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ ctime (&datetime));
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_319: '319' command (whois, channels)
+ */
+
+int
+irc_recv_cmd_319 (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos_nick, *pos_channel, *pos;
+ int color;
+
+ /* make C compiler happy */
+ (void) host;
+ (void) nick;
+
+ if (!command_ignored)
+ {
+ pos_nick = strchr (arguments, ' ');
+ if (pos_nick)
+ {
+ while (pos_nick[0] == ' ')
+ pos_nick++;
+ pos_channel = strchr (pos_nick, ' ');
+ if (pos_channel)
+ {
+ pos_channel[0] = '\0';
+ pos_channel++;
+ while (pos_channel[0] == ' ')
+ pos_channel++;
+ if (pos_channel[0] == ':')
+ pos_channel++;
+
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_SERVER);
+ gui_printf (server->buffer, "%s[%s%s%s]%s Channels: ",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ pos_nick,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT));
+ while (pos_channel && pos_channel[0])
+ {
+ if (irc_mode_nick_prefix_allowed (server, pos_channel[0]))
+ {
+ switch (pos_channel[0])
+ {
+ case '@': /* op */
+ color = GUI_COLOR_WIN_NICK_OP;
+ break;
+ case '%': /* half-op */
+ color = GUI_COLOR_WIN_NICK_HALFOP;
+ break;
+ case '+': /* voice */
+ color = GUI_COLOR_WIN_NICK_VOICE;
+ break;
+ case '~': /* channel owner */
+ color = GUI_COLOR_WIN_NICK_CHANOWNER;
+ break;
+ case '&': /* channel admin */
+ color = GUI_COLOR_WIN_NICK_CHANADMIN;
+ break;
+ case '!': /* channel admin (2) */
+ color = GUI_COLOR_WIN_NICK_CHANADMIN;
+ break;
+ case '-': /* channel user */
+ color = GUI_COLOR_WIN_NICK_CHANUSER;
+ break;
+ default:
+ color = GUI_COLOR_WIN_CHAT;
+ break;
+ }
+ gui_printf (server->buffer, "%s%c",
+ GUI_COLOR(GUI_COLOR_WIN_NICK_OP),
+ pos_channel[0]);
+ pos_channel++;
+ }
+
+ pos = strchr (pos_channel, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ }
+ gui_printf (server->buffer, "%s%s%s",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ pos_channel,
+ (pos && pos[0]) ? " " : "\n");
+ pos_channel = pos;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_321: '321' command (/list start)
+ */
+
+int
+irc_recv_cmd_321 (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos;
+
+ /* make C compiler happy */
+ (void) host;
+ (void) nick;
+
+ if (!command_ignored)
+ {
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ }
+ else
+ pos = arguments;
+
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_SERVER);
+ gui_printf (server->buffer, "%s\n", pos);
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_322: '322' command (channel for /list)
+ */
+
+int
+irc_recv_cmd_322 (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos;
+
+ /* make C compiler happy */
+ (void) host;
+ (void) nick;
+
+ if (!command_ignored)
+ {
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ }
+ else
+ pos = arguments;
+
+ if (server->cmd_list_regexp)
+ {
+ if (regexec (server->cmd_list_regexp, pos, 0, NULL, 0) == 0) {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_SERVER);
+ gui_printf (server->buffer, "%s\n", pos);
+ }
+ }
+ else
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_SERVER);
+ gui_printf (server->buffer, "%s\n", pos);
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_323: '323' command (/list end)
+ */
+
+int
+irc_recv_cmd_323 (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos;
+
+ /* make C compiler happy */
+ (void) host;
+ (void) nick;
+
+ if (!command_ignored)
+ {
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ }
+ else
+ pos = arguments;
+
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_SERVER);
+ gui_printf (server->buffer, "%s\n", pos);
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_324: '324' command (channel mode)
+ */
+
+int
+irc_recv_cmd_324 (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos_channel, *pos_modes, *pos;
+ t_irc_channel *ptr_channel;
+
+ /* make C compiler happy */
+ (void) host;
+ (void) nick;
+
+ pos_channel = strchr (arguments, ' ');
+ if (pos_channel)
+ {
+ pos_channel[0] = '\0';
+ pos_channel++;
+ while (pos_channel[0] == ' ')
+ pos_channel++;
+
+ pos_modes = strchr (pos_channel, ' ');
+ if (pos_modes)
+ {
+ pos_modes[0] = '\0';
+ pos_modes++;
+ while (pos_modes[0] == ' ')
+ pos_modes++;
+
+ /* remove spaces after modes */
+ pos = pos_modes + strlen (pos_modes) - 1;
+ while ((pos >= pos_modes) && (pos[0] == ' '))
+ {
+ pos[0] = '\0';
+ pos--;
+ }
+
+ /* search channel */
+ ptr_channel = irc_channel_search (server, pos_channel);
+ if (ptr_channel)
+ {
+ if (pos_modes[0])
+ {
+ if (ptr_channel->modes)
+ ptr_channel->modes = (char *) realloc (ptr_channel->modes,
+ strlen (pos_modes) + 1);
+ else
+ ptr_channel->modes = (char *) malloc (strlen (pos_modes) + 1);
+ strcpy (ptr_channel->modes, pos_modes);
+ irc_mode_channel_set (server, ptr_channel, pos_modes);
+ }
+ else
+ {
+ if (ptr_channel->modes)
+ {
+ free (ptr_channel->modes);
+ ptr_channel->modes = NULL;
+ }
+ }
+ gui_status_draw (ptr_channel->buffer, 1);
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_327: '327' command (whois, host)
+ */
+
+int
+irc_recv_cmd_327 (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos_nick, *pos_host1, *pos_host2, *pos_other;
+
+ /* make C compiler happy */
+ (void) host;
+ (void) nick;
+
+ if (!command_ignored)
+ {
+ pos_nick = strchr (arguments, ' ');
+ if (pos_nick)
+ {
+ while (pos_nick[0] == ' ')
+ pos_nick++;
+ pos_host1 = strchr (pos_nick, ' ');
+ if (pos_host1)
+ {
+ pos_host1[0] = '\0';
+ pos_host1++;
+ while (pos_host1[0] == ' ')
+ pos_host1++;
+ pos_host2 = strchr (pos_host1, ' ');
+ if (pos_host2)
+ {
+ pos_host2[0] = '\0';
+ pos_host2++;
+ while (pos_host2[0] == ' ')
+ pos_host2++;
+
+ pos_other = strchr (pos_host2, ' ');
+ if (pos_other)
+ {
+ pos_other[0] = '\0';
+ pos_other++;
+ while (pos_other[0] == ' ')
+ pos_other++;
+ }
+
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_SERVER);
+ gui_printf (server->buffer,
+ "%s[%s%s%s] %s%s %s %s%s%s%s%s%s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ pos_nick,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_HOST),
+ pos_host1,
+ pos_host2,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ (pos_other) ? "(" : "",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ (pos_other) ? pos_other : "",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ (pos_other) ? ")" : "");
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_329: '329' command received (channel creation date)
+ */
+
+int
+irc_recv_cmd_329 (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos_channel, *pos_date;
+ t_irc_channel *ptr_channel;
+ time_t datetime;
+
+ /* make C compiler happy */
+ (void) nick;
+
+ pos_channel = strchr (arguments, ' ');
+ if (pos_channel)
+ {
+ while (pos_channel[0] == ' ')
+ pos_channel++;
+ pos_date = strchr (pos_channel, ' ');
+ if (pos_date)
+ {
+ pos_date[0] = '\0';
+ pos_date++;
+ while (pos_date[0] == ' ')
+ pos_date++;
+
+ ptr_channel = irc_channel_search (server, pos_channel);
+ if (!ptr_channel)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s channel \"%s\" not found for \"%s\" command\n"),
+ WEECHAT_ERROR, pos_channel, "329");
+ return -1;
+ }
+
+ command_ignored |= irc_ignore_check (host, "329",
+ pos_channel, server->name);
+ if (!command_ignored && (ptr_channel->display_creation_date))
+ {
+ datetime = (time_t)(atol (pos_date));
+ irc_display_prefix (server, ptr_channel->buffer, GUI_PREFIX_INFO);
+ gui_printf (ptr_channel->buffer, _("Channel created on %s"),
+ ctime (&datetime));
+ }
+ ptr_channel->display_creation_date = 0;
+ }
+ else
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot identify date/time for \"%s\" command\n"),
+ WEECHAT_ERROR, "329");
+ return -1;
+ }
+ }
+ else
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot identify channel for \"%s\" command\n"),
+ WEECHAT_ERROR, "329");
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_331: '331' command received (no topic for channel)
+ */
+
+int
+irc_recv_cmd_331 (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos_channel, *pos;
+ t_irc_channel *ptr_channel;
+
+ /* make C compiler happy */
+ (void) server;
+ (void) nick;
+
+ if (!command_ignored)
+ {
+ pos_channel = strchr (arguments, ' ');
+ if (pos_channel)
+ {
+ pos_channel++;
+ while (pos_channel[0] == ' ')
+ pos_channel++;
+ pos = strchr (pos_channel, ' ');
+ if (pos)
+ pos[0] = '\0';
+ }
+ else
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s channel \"%s\" not found for \"%s\" command\n"),
+ WEECHAT_ERROR, "", "331");
+ return -1;
+ }
+
+ ptr_channel = irc_channel_search (server, pos_channel);
+ command_ignored |= irc_ignore_check (host, "331",
+ (ptr_channel) ? ptr_channel->name : NULL,
+ server->name);
+ if (!command_ignored)
+ {
+ irc_display_prefix (server,
+ (ptr_channel) ? ptr_channel->buffer : NULL,
+ GUI_PREFIX_INFO);
+ gui_printf ((ptr_channel) ? ptr_channel->buffer : NULL,
+ _("No topic set for %s%s\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ pos_channel);
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_332: '332' command received (topic of channel)
+ */
+
+int
+irc_recv_cmd_332 (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos, *pos2;
+ t_irc_channel *ptr_channel;
+ t_gui_buffer *ptr_buffer;
+
+ /* make C compiler happy */
+ (void) nick;
+
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ while (pos[0] == ' ')
+ pos++;
+ pos2 = strchr (pos, ' ');
+ if (pos2)
+ {
+ pos2[0] = '\0';
+ ptr_channel = irc_channel_search (server, pos);
+ ptr_buffer = (ptr_channel) ?
+ ptr_channel->buffer : server->buffer;
+ pos2++;
+ while (pos2[0] == ' ')
+ pos2++;
+ if (pos2[0] == ':')
+ pos2++;
+ if (ptr_channel)
+ {
+ if (ptr_channel->topic)
+ free (ptr_channel->topic);
+ ptr_channel->topic = strdup (pos2);
+ }
+
+ command_ignored |= irc_ignore_check (host, "332", pos, server->name);
+ if (!command_ignored)
+ {
+ irc_display_prefix (server, ptr_buffer, GUI_PREFIX_INFO);
+ gui_printf (ptr_buffer, _("Topic for %s%s%s is: "),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ pos,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT));
+ gui_printf (ptr_buffer, "\"%s%s\"\n", pos2, GUI_NO_COLOR);
+ }
+
+ if (ptr_channel)
+ gui_chat_draw_title (ptr_buffer, 1);
+ }
+ }
+ else
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot identify channel for \"%s\" command\n"),
+ WEECHAT_ERROR, "332");
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_333: '333' command received (infos about topic (nick / date))
+ */
+
+int
+irc_recv_cmd_333 (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos_channel, *pos_nick, *pos_date;
+ t_irc_channel *ptr_channel;
+ t_gui_buffer *ptr_buffer;
+ time_t datetime;
+
+ /* make C compiler happy */
+ (void) nick;
+
+ pos_channel = strchr (arguments, ' ');
+ if (pos_channel)
+ {
+ while (pos_channel[0] == ' ')
+ pos_channel++;
+ pos_nick = strchr (pos_channel, ' ');
+ if (pos_nick)
+ {
+ pos_nick[0] = '\0';
+ pos_nick++;
+ while (pos_nick[0] == ' ')
+ pos_nick++;
+ pos_date = strchr (pos_nick, ' ');
+ if (pos_date)
+ {
+ pos_date[0] = '\0';
+ pos_date++;
+ while (pos_date[0] == ' ')
+ pos_date++;
+
+ ptr_channel = irc_channel_search (server, pos_channel);
+ ptr_buffer = (ptr_channel) ?
+ ptr_channel->buffer : server->buffer;
+
+ command_ignored |= irc_ignore_check (host, "333",
+ pos_channel, server->name);
+ if (!command_ignored)
+ {
+ datetime = (time_t)(atol (pos_date));
+ irc_display_prefix (server, ptr_buffer, GUI_PREFIX_INFO);
+ gui_printf (ptr_buffer, _("Topic set by %s%s%s, %s"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ pos_nick,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ ctime (&datetime));
+ }
+ }
+ else
+ return 0;
+ }
+ else
+ return 0;
+ }
+ else
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot identify channel for \"%s\" command\n"),
+ WEECHAT_ERROR, "333");
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_338: '338' command (whois, host)
+ */
+
+int
+irc_recv_cmd_338 (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos_nick, *pos_host, *pos_message;
+
+ /* make C compiler happy */
+ (void) host;
+ (void) nick;
+
+ if (!command_ignored)
+ {
+ pos_nick = strchr (arguments, ' ');
+ if (pos_nick)
+ {
+ while (pos_nick[0] == ' ')
+ pos_nick++;
+ pos_host = strchr (pos_nick, ' ');
+ if (pos_host)
+ {
+ pos_host[0] = '\0';
+ pos_host++;
+ while (pos_host[0] == ' ')
+ pos_host++;
+ pos_message = strchr (pos_host, ' ');
+ if (pos_message)
+ {
+ pos_message[0] = '\0';
+ pos_message++;
+ while (pos_message[0] == ' ')
+ pos_message++;
+ if (pos_message[0] == ':')
+ pos_message++;
+
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_SERVER);
+ gui_printf (server->buffer, "%s[%s%s%s] %s%s %s%s %s%s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ pos_nick,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ pos_nick,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ pos_message,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_HOST),
+ pos_host);
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_341: '341' command received (inviting)
+ */
+
+int
+irc_recv_cmd_341 (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos_nick, *pos_channel;
+
+ /* make C compiler happy */
+ (void) host;
+ (void) nick;
+
+ pos_nick = strchr (arguments, ' ');
+ if (pos_nick)
+ {
+ pos_nick[0] = '\0';
+ pos_nick++;
+ while (pos_nick[0] == ' ')
+ pos_nick++;
+
+ pos_channel = strchr (pos_nick, ' ');
+ if (pos_channel)
+ {
+ pos_channel[0] = '\0';
+ pos_channel++;
+ while (pos_channel[0] == ' ')
+ pos_channel++;
+ if (pos_channel[0] == ':')
+ pos_channel++;
+
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_SERVER);
+ gui_printf (server->buffer,
+ _("%s%s%s has invited %s%s%s on %s%s\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ arguments,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ pos_nick,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ pos_channel);
+ gui_status_draw (gui_current_window->buffer, 1);
+ }
+ else
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot identify channel for \"%s\" command\n"),
+ WEECHAT_ERROR, "341");
+ return -1;
+ }
+ }
+ else
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot identify nickname for \"%s\" command\n"),
+ WEECHAT_ERROR, "341");
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_344: '344' command (channel reop)
+ */
+
+int
+irc_recv_cmd_344 (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos_channel, *pos_host;
+
+ /* make C compiler happy */
+ (void) host;
+ (void) nick;
+
+ if (!command_ignored)
+ {
+ pos_channel = strchr (arguments, ' ');
+ if (pos_channel)
+ {
+ while (pos_channel[0] == ' ')
+ pos_channel++;
+ pos_host = strchr (pos_channel, ' ');
+ if (pos_host)
+ {
+ pos_host[0] = '\0';
+ pos_host++;
+ while (pos_host[0] == ' ')
+ pos_host++;
+
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_SERVER);
+ gui_printf (server->buffer, _("Channel reop %s%s%s: %s%s\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ pos_channel,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_HOST),
+ pos_host);
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_345: '345' command (end of channel reop)
+ */
+
+int
+irc_recv_cmd_345 (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos;
+
+ /* make C compiler happy */
+ (void) host;
+ (void) nick;
+
+ /* skip nickname if at beginning of server message */
+ if (strncmp (server->nick, arguments, strlen (server->nick)) == 0)
+ {
+ arguments += strlen (server->nick) + 1;
+ while (arguments[0] == ' ')
+ arguments++;
+ }
+
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ if (!command_ignored)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_SERVER);
+ gui_printf (server->buffer, "%s%s %s%s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ arguments,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ pos);
+ }
+ }
+ else
+ {
+ if (!command_ignored)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_SERVER);
+ gui_printf (server->buffer, "%s\n", arguments);
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_348: '348' command received (channel exception list)
+ */
+
+int
+irc_recv_cmd_348 (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos_channel, *pos_exception, *pos_user, *pos_date, *pos;
+ t_irc_channel *ptr_channel;
+ t_gui_buffer *buffer;
+ time_t datetime;
+
+ /* make C compiler happy */
+ (void) nick;
+
+ /* look for channel */
+ pos_channel = strchr (arguments, ' ');
+ if (!pos_channel)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot parse \"%s\" command\n"),
+ WEECHAT_ERROR, "348");
+ return -1;
+ }
+ pos_channel[0] = '\0';
+ pos_channel++;
+ while (pos_channel[0] == ' ')
+ pos_channel++;
+
+ /* look for exception mask */
+ pos_exception = strchr (pos_channel, ' ');
+ if (!pos_exception)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot parse \"%s\" command\n"),
+ WEECHAT_ERROR, "348");
+ return -1;
+ }
+ pos_exception[0] = '\0';
+ pos_exception++;
+ while (pos_exception[0] == ' ')
+ pos_exception++;
+
+ /* look for user who set exception */
+ pos_user = strchr (pos_exception, ' ');
+ if (pos_user)
+ {
+ pos_user[0] = '\0';
+ pos_user++;
+ while (pos_user[0] == ' ')
+ pos_user++;
+
+ /* look for date/time */
+ pos_date = strchr (pos_user, ' ');
+ if (pos_date)
+ {
+ pos_date[0] = '\0';
+ pos_date++;
+ while (pos_date[0] == ' ')
+ pos_date++;
+ }
+ }
+ else
+ pos_date = NULL;
+
+ ptr_channel = irc_channel_search (server, pos_channel);
+ buffer = (ptr_channel) ? ptr_channel->buffer : server->buffer;
+
+ command_ignored |= irc_ignore_check (host, "348", pos_channel, server->name);
+
+ if (!command_ignored)
+ {
+ irc_display_prefix (server, buffer, GUI_PREFIX_INFO);
+ gui_printf (buffer, "%s[%s%s%s]%s exception %s%s%s",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ pos_channel,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_HOST),
+ pos_exception,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT));
+ if (pos_user)
+ {
+ pos = strchr (pos_user, '!');
+ if (pos)
+ {
+ pos[0] = '\0';
+ gui_printf (buffer, _(" by %s%s %s(%s%s%s)"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ pos_user,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_HOST),
+ pos + 1,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK));
+ }
+ else
+ gui_printf (buffer, _(" by %s%s"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ pos_user);
+ }
+ if (pos_date)
+ {
+ datetime = (time_t)(atol (pos_date));
+ gui_printf_nolog (buffer, "%s, %s",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ ctime (&datetime));
+ }
+ else
+ gui_printf_nolog (buffer, "\n");
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_349: '349' command received (end of channel exception list)
+ */
+
+int
+irc_recv_cmd_349 (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos_channel, *pos_msg;
+ t_irc_channel *ptr_channel;
+ t_gui_buffer *buffer;
+
+ /* make C compiler happy */
+ (void) nick;
+
+ pos_channel = strchr (arguments, ' ');
+ if (!pos_channel)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot parse \"%s\" command\n"),
+ WEECHAT_ERROR, "349");
+ return -1;
+ }
+ pos_channel[0] = '\0';
+ pos_channel++;
+ while (pos_channel[0] == ' ')
+ pos_channel++;
+
+ pos_msg = strchr (pos_channel, ' ');
+ if (!pos_msg)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot parse \"%s\" command\n"),
+ WEECHAT_ERROR, "349");
+ return -1;
+ }
+ pos_msg[0] = '\0';
+ pos_msg++;
+ while (pos_msg[0] == ' ')
+ pos_msg++;
+ if (pos_msg[0] == ':')
+ pos_msg++;
+
+ ptr_channel = irc_channel_search (server, pos_channel);
+ buffer = (ptr_channel) ? ptr_channel->buffer : server->buffer;
+
+ command_ignored |= irc_ignore_check (host, "349", pos_channel, server->name);
+
+ if (!command_ignored)
+ {
+ irc_display_prefix (server, buffer, GUI_PREFIX_INFO);
+ gui_printf (buffer, "%s[%s%s%s] %s%s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ pos_channel,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ pos_msg);
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_351: '351' command received (server version)
+ */
+
+int
+irc_recv_cmd_351 (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos, *pos2;
+
+ /* make C compiler happy */
+ (void) server;
+ (void) host;
+ (void) nick;
+
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ }
+ else
+ pos = arguments;
+
+ pos2 = strstr (pos, " :");
+ if (pos2)
+ {
+ pos2[0] = '\0';
+ pos2 += 2;
+ }
+
+ if (!command_ignored)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_SERVER);
+ if (pos2)
+ gui_printf (server->buffer, "%s %s\n", pos, pos2);
+ else
+ gui_printf (server->buffer, "%s\n", pos);
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_352: '352' command (who)
+ */
+
+int
+irc_recv_cmd_352 (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos_channel, *pos_user, *pos_host, *pos_server, *pos_nick;
+ char *pos_attr, *pos_hopcount, *pos_realname;
+ int length;
+ t_irc_channel *ptr_channel;
+ t_irc_nick *ptr_nick;
+
+ /* make C compiler happy */
+ (void) nick;
+
+ pos_channel = strchr (arguments, ' ');
+ if (pos_channel)
+ {
+ while (pos_channel[0] == ' ')
+ pos_channel++;
+ pos_user = strchr (pos_channel, ' ');
+ if (pos_user)
+ {
+ pos_user[0] = '\0';
+ pos_user++;
+ while (pos_user[0] == ' ')
+ pos_user++;
+ pos_host = strchr (pos_user, ' ');
+ if (pos_host)
+ {
+ pos_host[0] = '\0';
+ pos_host++;
+ while (pos_host[0] == ' ')
+ pos_host++;
+ pos_server = strchr (pos_host, ' ');
+ if (pos_server)
+ {
+ pos_server[0] = '\0';
+ pos_server++;
+ while (pos_server[0] == ' ')
+ pos_server++;
+ pos_nick = strchr (pos_server, ' ');
+ if (pos_nick)
+ {
+ pos_nick[0] = '\0';
+ pos_nick++;
+ while (pos_nick[0] == ' ')
+ pos_nick++;
+ pos_attr = strchr (pos_nick, ' ');
+ if (pos_attr)
+ {
+ pos_attr[0] = '\0';
+ pos_attr++;
+ while (pos_attr[0] == ' ')
+ pos_attr++;
+ pos_hopcount = strchr (pos_attr, ' ');
+ if (pos_hopcount)
+ {
+ pos_hopcount[0] = '\0';
+ pos_hopcount++;
+ while (pos_hopcount[0] == ' ')
+ pos_hopcount++;
+ if (pos_hopcount[0] == ':')
+ pos_hopcount++;
+ pos_realname = strchr (pos_hopcount, ' ');
+ if (pos_realname)
+ {
+ pos_realname[0] = '\0';
+ pos_realname++;
+ while (pos_realname[0] == ' ')
+ pos_realname++;
+
+ command_ignored |= irc_ignore_check (host, "352", pos_channel, server->name);
+
+ ptr_channel = irc_channel_search (server, pos_channel);
+ if (ptr_channel && (ptr_channel->checking_away > 0))
+ {
+ ptr_nick = irc_nick_search (ptr_channel, pos_nick);
+ if (ptr_nick)
+ {
+ if (ptr_nick->host)
+ free (ptr_nick->host);
+ length = strlen (pos_user) + 1 + strlen (pos_host) + 1;
+ ptr_nick->host = (char *) malloc (length);
+ if (ptr_nick->host)
+ snprintf (ptr_nick->host, length, "%s@%s", pos_user, pos_host);
+ irc_nick_set_away (ptr_channel, ptr_nick,
+ (pos_attr[0] == 'G') ? 1 : 0);
+ }
+ return 0;
+ }
+
+ if (!command_ignored)
+ {
+ irc_display_prefix (server, server->buffer,
+ GUI_PREFIX_SERVER);
+ gui_printf (server->buffer,
+ "%s%s%s on %s%s%s %s %s %s%s@%s %s(%s%s%s)\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ pos_nick,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ pos_channel,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ pos_attr,
+ pos_hopcount,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_HOST),
+ pos_user,
+ pos_host,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ pos_realname,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK));
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_353: '353' command received (list of users on a channel)
+ */
+
+int
+irc_recv_cmd_353 (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos, *pos_nick;
+ int is_chanowner, is_chanadmin, is_chanadmin2, is_op, is_halfop;
+ int has_voice, is_chanuser;
+ int prefix_found, color;
+ t_irc_channel *ptr_channel;
+ t_gui_buffer *ptr_buffer;
+
+ /* make C compiler happy */
+ (void) nick;
+
+ pos = strstr (arguments, " = ");
+ if (pos)
+ arguments = pos + 3;
+ else
+ {
+ pos = strstr (arguments, " * ");
+ if (pos)
+ arguments = pos + 3;
+ else
+ {
+ pos = strstr (arguments, " @ ");
+ if (pos)
+ arguments = pos + 3;
+ }
+ }
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+
+ ptr_channel = irc_channel_search (server, arguments);
+ if (ptr_channel)
+ ptr_buffer = ptr_channel->buffer;
+ else
+ ptr_buffer = server->buffer;
+
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ if (pos[0] != ':')
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot parse \"%s\" command\n"),
+ WEECHAT_ERROR, "353");
+ return -1;
+ }
+
+ command_ignored |= irc_ignore_check (host, "353",
+ (ptr_channel) ? ptr_channel->name : NULL,
+ server->name);
+
+ /* channel is not joined => display users on server buffer */
+ if (!command_ignored && !ptr_channel)
+ {
+ /* display users on channel */
+ irc_display_prefix (server, ptr_buffer, GUI_PREFIX_SERVER);
+ gui_printf (ptr_buffer, _("Nicks %s%s%s: %s["),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ arguments,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK));
+ }
+
+ pos++;
+ if (pos[0])
+ {
+ while (pos && pos[0])
+ {
+ is_chanowner = 0;
+ is_chanadmin = 0;
+ is_chanadmin2 = 0;
+ is_op = 0;
+ is_halfop = 0;
+ has_voice = 0;
+ is_chanuser = 0;
+ prefix_found = 1;
+
+ while (prefix_found)
+ {
+ prefix_found = 0;
+
+ if (irc_mode_nick_prefix_allowed (server, pos[0]))
+ {
+ prefix_found = 1;
+ switch (pos[0])
+ {
+ case '@': /* op */
+ is_op = 1;
+ color = GUI_COLOR_WIN_NICK_OP;
+ break;
+ case '%': /* half-op */
+ is_halfop = 1;
+ color = GUI_COLOR_WIN_NICK_HALFOP;
+ break;
+ case '+': /* voice */
+ has_voice = 1;
+ color = GUI_COLOR_WIN_NICK_VOICE;
+ break;
+ case '~': /* channel owner */
+ is_chanowner = 1;
+ color = GUI_COLOR_WIN_NICK_CHANOWNER;
+ break;
+ case '&': /* channel admin */
+ is_chanadmin = 1;
+ color = GUI_COLOR_WIN_NICK_CHANADMIN;
+ break;
+ case '!': /* channel admin (2) */
+ is_chanadmin2 = 1;
+ color = GUI_COLOR_WIN_NICK_CHANADMIN;
+ break;
+ case '-': /* channel user */
+ is_chanuser = 1;
+ color = GUI_COLOR_WIN_NICK_CHANUSER;
+ break;
+ default:
+ color = GUI_COLOR_WIN_CHAT;
+ break;
+ }
+ if (!command_ignored && !ptr_channel)
+ gui_printf (ptr_buffer, "%s%c",
+ GUI_COLOR(color),
+ pos[0]);
+ }
+ if (prefix_found)
+ pos++;
+ }
+ pos_nick = pos;
+ pos = strchr (pos, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ }
+ if (ptr_channel)
+ {
+ if (!irc_nick_new (server, ptr_channel, pos_nick,
+ is_chanowner, is_chanadmin, is_chanadmin2,
+ is_op, is_halfop, has_voice, is_chanuser))
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot create nick \"%s\" for channel \"%s\"\n"),
+ WEECHAT_ERROR, pos_nick, ptr_channel->name);
+ }
+ }
+ else
+ {
+ if (!command_ignored)
+ {
+ gui_printf (ptr_buffer, "%s%s",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT), pos_nick);
+ if (pos && pos[0])
+ gui_printf (ptr_buffer, " ");
+ }
+ }
+ }
+ }
+ if (ptr_channel)
+ {
+ gui_nicklist_draw (ptr_channel->buffer, 1, 1);
+ gui_status_draw (ptr_channel->buffer, 1);
+ }
+ else
+ {
+ if (!command_ignored)
+ gui_printf (ptr_buffer, "%s]\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK));
+ }
+ }
+ else
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot parse \"%s\" command\n"),
+ WEECHAT_ERROR, "353");
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_366: '366' command received (end of /names list)
+ */
+
+int
+irc_recv_cmd_366 (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos, *pos2;
+ t_irc_channel *ptr_channel;
+ t_irc_nick *ptr_nick;
+ int num_nicks, num_op, num_halfop, num_voice, num_normal;
+
+ /* make C compiler happy */
+ (void) nick;
+
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ while (pos[0] == ' ')
+ pos++;
+ pos2 = strchr (pos, ' ');
+ if (pos2)
+ {
+ pos2[0] = '\0';
+ pos2++;
+ while (pos2[0] == ' ')
+ pos2++;
+ if (pos2[0] == ':')
+ pos2++;
+
+ ptr_channel = irc_channel_search (server, pos);
+ if (ptr_channel)
+ {
+ command_ignored |= irc_ignore_check (host, "366", ptr_channel->name, server->name);
+
+ if (!command_ignored)
+ {
+ /* display users on channel */
+ irc_display_prefix (server, ptr_channel->buffer, GUI_PREFIX_SERVER);
+ gui_printf (ptr_channel->buffer, _("Nicks %s%s%s: %s["),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ ptr_channel->name,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK));
+
+ for (ptr_nick = ptr_channel->nicks; ptr_nick; ptr_nick = ptr_nick->next_nick)
+ {
+ irc_display_nick (ptr_channel->buffer, ptr_nick, NULL,
+ GUI_MSG_TYPE_MSG, 0, GUI_COLOR_WIN_CHAT, 1);
+ if (ptr_nick != ptr_channel->last_nick)
+ gui_printf (ptr_channel->buffer, " ");
+ }
+ gui_printf (ptr_channel->buffer, "%s]\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK));
+
+ /* display number of nicks, ops, halfops & voices on the channel */
+ irc_nick_count (ptr_channel, &num_nicks, &num_op, &num_halfop, &num_voice,
+ &num_normal);
+ irc_display_prefix (server, ptr_channel->buffer, GUI_PREFIX_INFO);
+ gui_printf (ptr_channel->buffer,
+ _("Channel %s%s%s: %s%d%s %s %s(%s%d%s %s, "
+ "%s%d%s %s, %s%d%s %s, %s%d%s %s%s)\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ ptr_channel->name,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ num_nicks,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ (num_nicks > 1) ? _("nicks") : _("nick"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ num_op,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ (num_op > 1) ? _("ops") : _("op"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ num_halfop,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ (num_halfop > 1) ? _("halfops") : _("halfop"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ num_voice,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ (num_voice > 1) ? _("voices") : _("voice"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ num_normal,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ _("normal"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK));
+ }
+ irc_send_cmd_mode (server, NULL, ptr_channel->name);
+ irc_channel_check_away (server, ptr_channel, 1);
+ }
+ else
+ {
+ if (!command_ignored)
+ {
+ irc_display_prefix (server, gui_current_window->buffer, GUI_PREFIX_INFO);
+ gui_printf (gui_current_window->buffer, "%s%s%s: %s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ pos,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ pos2);
+ }
+ return 0;
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_367: '367' command received (banlist)
+ */
+
+int
+irc_recv_cmd_367 (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos_channel, *pos_ban, *pos_user, *pos_date, *pos;
+ t_irc_channel *ptr_channel;
+ t_gui_buffer *buffer;
+ time_t datetime;
+
+ /* make C compiler happy */
+ (void) nick;
+
+ /* look for channel */
+ pos_channel = strchr (arguments, ' ');
+ if (!pos_channel)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot parse \"%s\" command\n"),
+ WEECHAT_ERROR, "367");
+ return -1;
+ }
+ pos_channel[0] = '\0';
+ pos_channel++;
+ while (pos_channel[0] == ' ')
+ pos_channel++;
+
+ /* look for ban mask */
+ pos_ban = strchr (pos_channel, ' ');
+ if (!pos_ban)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot parse \"%s\" command\n"),
+ WEECHAT_ERROR, "367");
+ return -1;
+ }
+ pos_ban[0] = '\0';
+ pos_ban++;
+ while (pos_ban[0] == ' ')
+ pos_ban++;
+
+ /* look for user who set ban */
+ pos_date = NULL;
+ pos_user = strchr (pos_ban, ' ');
+ if (pos_user)
+ {
+ pos_user[0] = '\0';
+ pos_user++;
+ while (pos_user[0] == ' ')
+ pos_user++;
+
+ /* look for date/time */
+ pos_date = strchr (pos_user, ' ');
+ if (pos_date)
+ {
+ pos_date[0] = '\0';
+ pos_date++;
+ while (pos_date[0] == ' ')
+ pos_date++;
+ }
+ }
+
+ ptr_channel = irc_channel_search (server, pos_channel);
+ buffer = (ptr_channel) ? ptr_channel->buffer : server->buffer;
+
+ command_ignored |= irc_ignore_check (host, "367", pos_channel, server->name);
+
+ if (!command_ignored)
+ {
+ irc_display_prefix (server, buffer, GUI_PREFIX_INFO);
+ if (pos_user)
+ {
+ gui_printf_nolog (buffer, _("%s[%s%s%s] %s%s%s banned by "),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ pos_channel,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_HOST),
+ pos_ban,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT));
+ pos = strchr (pos_user, '!');
+ if (pos)
+ {
+ pos[0] = '\0';
+ gui_printf (buffer, "%s%s %s(%s%s%s)",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ pos_user,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_HOST),
+ pos + 1,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK));
+ }
+ else
+ gui_printf (buffer, "%s%s",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ pos_user);
+ if (pos_date)
+ {
+ datetime = (time_t)(atol (pos_date));
+ gui_printf (buffer, "%s, %s",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ ctime (&datetime));
+ }
+ else
+ gui_printf (buffer, "\n");
+ }
+ else
+ gui_printf_nolog (buffer, _("%s[%s%s%s] %s%s%s banned\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ pos_channel,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_HOST),
+ pos_ban,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT));
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_368: '368' command received (end of banlist)
+ */
+
+int
+irc_recv_cmd_368 (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos_channel, *pos_msg;
+ t_irc_channel *ptr_channel;
+ t_gui_buffer *buffer;
+
+ /* make C compiler happy */
+ (void) nick;
+
+ pos_channel = strchr (arguments, ' ');
+ if (!pos_channel)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot parse \"%s\" command\n"),
+ WEECHAT_ERROR, "368");
+ return -1;
+ }
+ pos_channel[0] = '\0';
+ pos_channel++;
+ while (pos_channel[0] == ' ')
+ pos_channel++;
+
+ pos_msg = strchr (pos_channel, ' ');
+ if (!pos_msg)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot parse \"%s\" command\n"),
+ WEECHAT_ERROR, "368");
+ return -1;
+ }
+ pos_msg[0] = '\0';
+ pos_msg++;
+ while (pos_msg[0] == ' ')
+ pos_msg++;
+ if (pos_msg[0] == ':')
+ pos_msg++;
+
+ ptr_channel = irc_channel_search (server, pos_channel);
+ buffer = (ptr_channel) ? ptr_channel->buffer : server->buffer;
+
+ command_ignored |= irc_ignore_check (host, "368", pos_channel, server->name);
+
+ if (!command_ignored)
+ {
+ irc_display_prefix (server, buffer, GUI_PREFIX_INFO);
+ gui_printf_nolog (buffer, "%s[%s%s%s] %s%s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ pos_channel,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ pos_msg);
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_432: '432' command received (erroneous nickname)
+ */
+
+int
+irc_recv_cmd_432 (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ /* Note: this IRC command can not be ignored */
+
+ irc_recv_cmd_error (server, host, nick, arguments);
+
+ if (!server->is_connected)
+ {
+ if (strcmp (server->nick, server->nick1) == 0)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_INFO);
+ gui_printf (server->buffer,
+ _("%s: trying 2nd nickname \"%s\"\n"),
+ PACKAGE_NAME, server->nick2);
+ free (server->nick);
+ server->nick = strdup (server->nick2);
+ }
+ else
+ {
+ if (strcmp (server->nick, server->nick2) == 0)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_INFO);
+ gui_printf (server->buffer,
+ _("%s: trying 3rd nickname \"%s\"\n"),
+ PACKAGE_NAME, server->nick3);
+ free (server->nick);
+ server->nick = strdup (server->nick3);
+ }
+ else
+ {
+ if (strcmp (server->nick, server->nick3) == 0)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_INFO);
+ gui_printf (server->buffer,
+ _("%s: all declared nicknames are already in "
+ "use or invalid, closing connection with "
+ "server!\n"),
+ PACKAGE_NAME);
+ irc_server_disconnect (server, 1);
+ return 0;
+ }
+ else
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_INFO);
+ gui_printf (server->buffer,
+ _("%s: trying 1st nickname \"%s\"\n"),
+ PACKAGE_NAME, server->nick1);
+ free (server->nick);
+ server->nick = strdup (server->nick1);
+ }
+ }
+ }
+ irc_server_sendf (server, "NICK %s", server->nick);
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_433: '433' command received (nickname already in use)
+ */
+
+int
+irc_recv_cmd_433 (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ /* Note: this IRC command can not be ignored */
+
+ if (!server->is_connected)
+ {
+ if (strcmp (server->nick, server->nick1) == 0)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_INFO);
+ gui_printf (server->buffer,
+ _("%s: nickname \"%s\" is already in use, "
+ "trying 2nd nickname \"%s\"\n"),
+ PACKAGE_NAME, server->nick, server->nick2);
+ free (server->nick);
+ server->nick = strdup (server->nick2);
+ }
+ else
+ {
+ if (strcmp (server->nick, server->nick2) == 0)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_INFO);
+ gui_printf (server->buffer,
+ _("%s: nickname \"%s\" is already in use, "
+ "trying 3rd nickname \"%s\"\n"),
+ PACKAGE_NAME, server->nick, server->nick3);
+ free (server->nick);
+ server->nick = strdup (server->nick3);
+ }
+ else
+ {
+ if (strcmp (server->nick, server->nick3) == 0)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_INFO);
+ gui_printf (server->buffer,
+ _("%s: all declared nicknames are already in use, "
+ "closing connection with server!\n"),
+ PACKAGE_NAME);
+ irc_server_disconnect (server, 1);
+ return 0;
+ }
+ else
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_INFO);
+ gui_printf (server->buffer,
+ _("%s: nickname \"%s\" is already in use, "
+ "trying 1st nickname \"%s\"\n"),
+ PACKAGE_NAME, server->nick, server->nick1);
+ free (server->nick);
+ server->nick = strdup (server->nick1);
+ }
+ }
+ }
+ irc_server_sendf (server, "NICK %s", server->nick);
+ }
+ else
+ return irc_recv_cmd_error (server, host, nick, arguments);
+
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_438: '438' command received (not authorized to change nickname)
+ */
+
+int
+irc_recv_cmd_438 (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos, *pos2;
+
+ /* make C compiler happy */
+ (void) server;
+ (void) host;
+ (void) nick;
+
+ if (!command_ignored)
+ {
+ pos = strchr (arguments, ' ');
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_SERVER);
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+
+ pos2 = strstr (pos, " :");
+ if (pos2)
+ {
+ pos2[0] = '\0';
+ pos2 += 2;
+ gui_printf (server->buffer, "%s (%s => %s)\n", pos2, arguments, pos);
+ }
+ else
+ gui_printf (server->buffer, "%s (%s)\n", pos, arguments);
+ }
+ else
+ gui_printf (server->buffer, "%s\n", arguments);
+ }
+ return 0;
+}
+
+/*
+ * irc_recv_cmd_671: '671' command (whois, secure connection)
+ */
+
+int
+irc_recv_cmd_671 (t_irc_server *server, char *host, char *nick, char *arguments)
+{
+ char *pos_nick, *pos_message;
+
+ /* make C compiler happy */
+ (void) host;
+ (void) nick;
+
+ if (!command_ignored)
+ {
+ pos_nick = strchr (arguments, ' ');
+ if (pos_nick)
+ {
+ while (pos_nick[0] == ' ')
+ pos_nick++;
+ pos_message = strchr (pos_nick, ' ');
+ if (pos_message)
+ {
+ pos_message[0] = '\0';
+ pos_message++;
+ while (pos_message[0] == ' ')
+ pos_message++;
+ if (pos_message[0] == ':')
+ pos_message++;
+
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_SERVER);
+ gui_printf (server->buffer, "%s[%s%s%s] %s%s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ pos_nick,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ pos_message);
+ }
+ }
+ }
+ return 0;
+}
diff --git a/src/plugins/irc/irc-send.c b/src/plugins/irc/irc-send.c
new file mode 100644
index 000000000..a4d71d498
--- /dev/null
+++ b/src/plugins/irc/irc-send.c
@@ -0,0 +1,2281 @@
+/*
+ * 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/>.
+ */
+
+/* irc-send.c: implementation of IRC commands (client to server),
+ according to RFC 1459,2810,2811,2812 */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/time.h>
+#include <netdb.h>
+#include <time.h>
+#include <sys/utsname.h>
+#include <regex.h>
+
+#include "../../common/weechat.h"
+#include "irc.h"
+#include "../../common/command.h"
+#include "../../common/util.h"
+#include "../../common/weeconfig.h"
+#include "../../gui/gui.h"
+
+
+/*
+ * irc_send_login: login to irc server
+ */
+
+void
+irc_send_login (t_irc_server *server)
+{
+ if ((server->password) && (server->password[0]))
+ irc_server_sendf (server, "PASS %s", server->password);
+
+ if (!server->nick)
+ server->nick = strdup (server->nick1);
+ irc_server_sendf (server,
+ "NICK %s\n"
+ "USER %s %s %s :%s",
+ server->nick, server->username, server->username,
+ server->address, server->realname);
+ gui_input_draw (gui_current_window->buffer, 1);
+}
+
+/*
+ * irc_send_cmd_admin: find information about the administrator of the server
+ */
+
+int
+irc_send_cmd_admin (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ /* make C compiler happy */
+ (void) channel;
+
+ if (arguments)
+ irc_server_sendf (server, "ADMIN %s", arguments);
+ else
+ irc_server_sendf (server, "ADMIN");
+ return 0;
+}
+
+/*
+ * irc_send_me: send a ctcp action to a channel
+ */
+
+int
+irc_send_me (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ char *string;
+
+ irc_server_sendf (server, "PRIVMSG %s :\01ACTION %s\01",
+ channel->name,
+ (arguments && arguments[0]) ? arguments : "");
+ irc_display_prefix (NULL, channel->buffer, GUI_PREFIX_ACTION_ME);
+ string = (arguments && arguments[0]) ?
+ (char *)gui_color_decode ((unsigned char *)arguments, 1, 0) : NULL;
+ gui_printf (channel->buffer, "%s%s %s%s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ server->nick,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ (string) ? string : "");
+ if (string)
+ free (string);
+ return 0;
+}
+
+/*
+ * irc_send_me_all_channels: send a ctcp action to all channels of a server
+ */
+
+int
+irc_send_me_all_channels (t_irc_server *server, char *arguments)
+{
+ t_irc_channel *ptr_channel;
+
+ for (ptr_channel = server->channels; ptr_channel;
+ ptr_channel = ptr_channel->next_channel)
+ {
+ if (ptr_channel->type == IRC_CHANNEL_TYPE_CHANNEL)
+ irc_send_me (server, ptr_channel, arguments);
+ }
+ return 0;
+}
+
+/*
+ * irc_send_cmd_ame: send a ctcp action to all channels of all connected servers
+ */
+
+int
+irc_send_cmd_ame (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ t_irc_server *ptr_server;
+ t_irc_channel *ptr_channel;
+
+ /* make C compiler happy */
+ (void) server;
+ (void) channel;
+
+ gui_add_hotlist = 0;
+ 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)
+ {
+ if (ptr_channel->type == IRC_CHANNEL_TYPE_CHANNEL)
+ irc_send_me (ptr_server, ptr_channel, arguments);
+ }
+ }
+ }
+ gui_add_hotlist = 1;
+ return 0;
+}
+
+/*
+ * irc_send_cmd_amsg: send message to all channels of all connected servers
+ */
+
+int
+irc_send_cmd_amsg (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ t_irc_server *ptr_server;
+ t_irc_channel *ptr_channel;
+ t_irc_nick *ptr_nick;
+ char *string;
+
+ /* make C compiler happy */
+ (void) server;
+ (void) channel;
+
+ if (arguments)
+ {
+ gui_add_hotlist = 0;
+ 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)
+ {
+ if (ptr_channel->type == IRC_CHANNEL_TYPE_CHANNEL)
+ {
+ irc_server_sendf (ptr_server, "PRIVMSG %s :%s",
+ ptr_channel->name, arguments);
+ ptr_nick = irc_nick_search (ptr_channel, ptr_server->nick);
+ if (ptr_nick)
+ {
+ irc_display_nick (ptr_channel->buffer, ptr_nick, NULL,
+ GUI_MSG_TYPE_NICK, 1, -1, 0);
+ string = (char *)gui_color_decode ((unsigned char *)arguments, 1, 0);
+ gui_printf (ptr_channel->buffer, "%s\n", (string) ? string : arguments);
+ if (string)
+ free (string);
+ }
+ else
+ {
+ irc_display_prefix (ptr_server, ptr_server->buffer, GUI_PREFIX_ERROR);
+ gui_printf (ptr_server->buffer,
+ _("%s cannot find nick for sending message\n"),
+ WEECHAT_ERROR);
+ }
+ }
+ }
+ }
+ }
+ gui_add_hotlist = 1;
+ }
+ else
+ return -1;
+ return 0;
+}
+
+/*
+ * irc_send_away: toggle away status for one server
+ */
+
+void
+irc_send_away (t_irc_server *server, char *arguments)
+{
+ char *string, buffer[4096];
+ t_gui_window *ptr_window;
+ time_t time_now, elapsed;
+
+ if (!server)
+ return;
+
+ if (arguments)
+ {
+ if (server->away_message)
+ free (server->away_message);
+ server->away_message = (char *) malloc (strlen (arguments) + 1);
+ if (server->away_message)
+ strcpy (server->away_message, arguments);
+
+ /* if server is connected, send away command now */
+ if (server->is_connected)
+ {
+ server->is_away = 1;
+ server->away_time = time (NULL);
+ irc_server_sendf (server, "AWAY :%s", arguments);
+ if (cfg_irc_display_away != CFG_IRC_DISPLAY_AWAY_OFF)
+ {
+ string = (char *)gui_color_decode ((unsigned char *)arguments, 1, 0);
+ if (cfg_irc_display_away == CFG_IRC_DISPLAY_AWAY_LOCAL)
+ irc_display_away (server, "away", (string) ? string : arguments);
+ else
+ {
+ snprintf (buffer, sizeof (buffer), "is away: %s", (string) ? string : arguments);
+ irc_send_me_all_channels (server, buffer);
+ }
+ if (string)
+ free (string);
+ }
+ irc_server_set_away (server, server->nick, 1);
+ for (ptr_window = gui_windows; ptr_window;
+ ptr_window = ptr_window->next_window)
+ {
+ if (GUI_SERVER(ptr_window->buffer) == server)
+ ptr_window->buffer->last_read_line =
+ ptr_window->buffer->last_line;
+ }
+ }
+ else
+ {
+ /* server not connected, store away for future usage
+ (when connecting to server) */
+ string = (char *)gui_color_decode ((unsigned char *)arguments, 1, 0);
+ irc_display_prefix (NULL, server->buffer, GUI_PREFIX_INFO);
+ gui_printf_nolog (server->buffer,
+ _("Future away on %s%s%s: %s\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_SERVER),
+ server->name,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ (string) ? string : arguments);
+ if (string)
+ free (string);
+ }
+ }
+ else
+ {
+ if (server->away_message)
+ {
+ free (server->away_message);
+ server->away_message = NULL;
+ }
+
+ /* if server is connected, send away command now */
+ if (server->is_connected)
+ {
+ irc_server_sendf (server, "AWAY");
+ server->is_away = 0;
+ if (server->away_time != 0)
+ {
+ time_now = time (NULL);
+ elapsed = (time_now >= server->away_time) ?
+ time_now - server->away_time : 0;
+ server->away_time = 0;
+ if (cfg_irc_display_away != CFG_IRC_DISPLAY_AWAY_OFF)
+ {
+ if (cfg_irc_display_away == CFG_IRC_DISPLAY_AWAY_LOCAL)
+ {
+ snprintf (buffer, sizeof (buffer),
+ "gone %.2ld:%.2ld:%.2ld",
+ (long int)(elapsed / 3600),
+ (long int)((elapsed / 60) % 60),
+ (long int)(elapsed % 60));
+ irc_display_away (server, "back", buffer);
+ }
+ else
+ {
+ snprintf (buffer, sizeof (buffer),
+ "is back (gone %.2ld:%.2ld:%.2ld)",
+ (long int)(elapsed / 3600),
+ (long int)((elapsed / 60) % 60),
+ (long int)(elapsed % 60));
+ irc_send_me_all_channels (server, buffer);
+ }
+ }
+ }
+ irc_server_set_away (server, server->nick, 0);
+ }
+ else
+ {
+ /* server not connected, remove away message but do not send anything */
+ irc_display_prefix (NULL, server->buffer, GUI_PREFIX_INFO);
+ gui_printf_nolog (server->buffer,
+ _("Future away on %s%s%s removed.\n"),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_SERVER),
+ server->name,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT));
+ }
+ }
+}
+
+/*
+ * irc_send_cmd_away: toggle away status
+ */
+
+int
+irc_send_cmd_away (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ t_gui_buffer *buffer;
+ char *pos;
+ t_irc_server *ptr_server;
+
+ gui_buffer_find_context (server, channel, NULL, &buffer);
+
+ /* make C compiler happy */
+ (void) channel;
+
+ gui_add_hotlist = 0;
+ if (arguments && (strncmp (arguments, "-all", 4) == 0))
+ {
+ pos = arguments + 4;
+ while (pos[0] == ' ')
+ pos++;
+ if (!pos[0])
+ pos = NULL;
+
+ for (ptr_server = irc_servers; ptr_server;
+ ptr_server = ptr_server->next_server)
+ {
+ if (ptr_server->is_connected)
+ irc_send_away (ptr_server, pos);
+ }
+ }
+ else
+ irc_send_away (server, arguments);
+
+ gui_status_draw (buffer, 1);
+ gui_add_hotlist = 1;
+ return 0;
+}
+
+/*
+ * irc_send_cmd_ban: bans nicks or hosts
+ */
+
+int
+irc_send_cmd_ban (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ t_gui_buffer *buffer;
+ char *pos_channel, *pos, *pos2;
+
+ gui_buffer_find_context (server, channel, NULL, &buffer);
+
+ if (arguments)
+ {
+ pos_channel = NULL;
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+
+ if (irc_channel_is_channel (arguments))
+ {
+ pos_channel = arguments;
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ }
+ else
+ {
+ pos[0] = ' ';
+ pos = arguments;
+ }
+ }
+ else
+ pos = arguments;
+
+ /* channel not given, use default buffer */
+ if (!pos_channel)
+ {
+ if (!GUI_BUFFER_IS_CHANNEL(buffer))
+ {
+ irc_display_prefix (NULL, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s \"%s\" command can only be executed in a channel buffer\n"),
+ WEECHAT_ERROR, "ban");
+ return -1;
+ }
+ pos_channel = GUI_CHANNEL(buffer)->name;
+ }
+
+ /* loop on users */
+ while (pos && pos[0])
+ {
+ pos2 = strchr (pos, ' ');
+ if (pos2)
+ {
+ pos2[0] = '\0';
+ pos2++;
+ while (pos2[0] == ' ')
+ pos2++;
+ }
+ irc_server_sendf (server, "MODE %s +b %s", pos_channel, pos);
+ pos = pos2;
+ }
+ }
+ else
+ {
+ if (!GUI_BUFFER_IS_CHANNEL(buffer))
+ {
+ irc_display_prefix (NULL, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s \"%s\" command can only be executed in a channel buffer\n"),
+ WEECHAT_ERROR, "ban");
+ return -1;
+ }
+ irc_server_sendf (server, "MODE %s +b", GUI_CHANNEL(buffer)->name);
+ }
+
+ return 0;
+}
+
+/*
+ * irc_send_cmd_ctcp: send a ctcp message
+ */
+
+int
+irc_send_cmd_ctcp (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ char *pos_type, *pos_args, *pos;
+ struct timeval tv;
+
+ /* make C compiler happy */
+ (void) channel;
+
+ pos_type = strchr (arguments, ' ');
+ if (pos_type)
+ {
+ pos_type[0] = '\0';
+ pos_type++;
+ while (pos_type[0] == ' ')
+ pos_type++;
+ pos_args = strchr (pos_type, ' ');
+ if (pos_args)
+ {
+ pos_args[0] = '\0';
+ pos_args++;
+ while (pos_args[0] == ' ')
+ pos_args++;
+ }
+ else
+ pos_args = NULL;
+
+ pos = pos_type;
+ while (pos[0])
+ {
+ pos[0] = toupper (pos[0]);
+ pos++;
+ }
+
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_SERVER);
+ gui_printf (server->buffer, "CTCP%s(%s%s%s)%s: %s%s",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ arguments,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_CHANNEL),
+ pos_type);
+
+ if ((ascii_strcasecmp (pos_type, "ping") == 0) && (!pos_args))
+ {
+ gettimeofday (&tv, NULL);
+ irc_server_sendf (server, "PRIVMSG %s :\01PING %d %d\01",
+ arguments, tv.tv_sec, tv.tv_usec);
+ gui_printf (server->buffer, " %s%d %d\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ tv.tv_sec, tv.tv_usec);
+ }
+ else
+ {
+ if (pos_args)
+ {
+ irc_server_sendf (server, "PRIVMSG %s :\01%s %s\01",
+ arguments, pos_type, pos_args);
+ gui_printf (server->buffer, " %s%s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ pos_args);
+ }
+ else
+ {
+ irc_server_sendf (server, "PRIVMSG %s :\01%s\01",
+ arguments, pos_type);
+ gui_printf (server->buffer, "\n");
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * irc_send_cmd_cycle: leave and rejoin a channel
+ */
+
+int
+irc_send_cmd_cycle (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ t_gui_buffer *buffer;
+ char *channel_name, *pos_args, *ptr_arg, *buf;
+ t_irc_channel *ptr_channel;
+ char **channels;
+ int i, argc;
+
+ gui_buffer_find_context (server, channel, NULL, &buffer);
+
+ if (arguments)
+ {
+ if (irc_channel_is_channel (arguments))
+ {
+ channel_name = arguments;
+ pos_args = strchr (arguments, ' ');
+ if (pos_args)
+ {
+ pos_args[0] = '\0';
+ pos_args++;
+ while (pos_args[0] == ' ')
+ pos_args++;
+ }
+ channels = explode_string (channel_name, ",", 0, &argc);
+ if (channels)
+ {
+ for (i = 0; i < argc; i++)
+ {
+ ptr_channel = irc_channel_search (server, channels[i]);
+ /* mark channal as cycling */
+ if (ptr_channel &&
+ (ptr_channel->type == IRC_CHANNEL_TYPE_CHANNEL))
+ ptr_channel->cycle = 1;
+ }
+ free_exploded_string (channels);
+ }
+ }
+ else
+ {
+ if (GUI_BUFFER_IS_SERVER(buffer))
+ {
+ irc_display_prefix (NULL, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s \"%s\" command can not be executed on a server buffer\n"),
+ WEECHAT_ERROR, "cycle");
+ return -1;
+ }
+
+ /* does nothing on private buffer (cycle has no sense!) */
+ if (GUI_BUFFER_IS_PRIVATE(buffer))
+ return 0;
+
+ channel_name = GUI_CHANNEL(buffer)->name;
+ pos_args = arguments;
+ GUI_CHANNEL(buffer)->cycle = 1;
+ }
+ }
+ else
+ {
+ if (GUI_BUFFER_IS_SERVER(buffer))
+ {
+ irc_display_prefix (NULL, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s \"%s\" command can not be executed on a server buffer\n"),
+ WEECHAT_ERROR, "part");
+ return -1;
+ }
+
+ /* does nothing on private buffer (cycle has no sense!) */
+ if (GUI_BUFFER_IS_PRIVATE(buffer))
+ return 0;
+
+ channel_name = GUI_CHANNEL(buffer)->name;
+ pos_args = NULL;
+ GUI_CHANNEL(buffer)->cycle = 1;
+ }
+
+ ptr_arg = (pos_args) ? pos_args :
+ (cfg_irc_default_msg_part && cfg_irc_default_msg_part[0]) ?
+ cfg_irc_default_msg_part : NULL;
+
+ if (ptr_arg)
+ {
+ buf = weechat_strreplace (ptr_arg, "%v", PACKAGE_VERSION);
+ irc_server_sendf (server, "PART %s :%s", channel_name,
+ (buf) ? buf : ptr_arg);
+ if (buf)
+ free (buf);
+ }
+ else
+ irc_server_sendf (server, "PART %s", channel_name);
+
+ return 0;
+}
+
+/*
+ * irc_send_cmd_dehalfop: remove half operator privileges from nickname(s)
+ */
+
+int
+irc_send_cmd_dehalfop (t_irc_server *server, t_irc_channel *channel,
+ int argc, char **argv)
+{
+ t_gui_buffer *buffer;
+
+ gui_buffer_find_context (server, channel, NULL, &buffer);
+
+ if (GUI_BUFFER_IS_CHANNEL(buffer))
+ {
+ if (argc == 0)
+ irc_server_sendf (server, "MODE %s -h %s",
+ GUI_CHANNEL(buffer)->name,
+ server->nick);
+ else
+ irc_send_mode_nicks (server, GUI_CHANNEL(buffer)->name,
+ "-", "h", argc, argv);
+ }
+ else
+ {
+ irc_display_prefix (NULL, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s \"%s\" command can only be executed in a channel buffer\n"),
+ WEECHAT_ERROR, "dehalfop");
+ }
+ return 0;
+}
+
+/*
+ * irc_send_cmd_deop: remove operator privileges from nickname(s)
+ */
+
+int
+irc_send_cmd_deop (t_irc_server *server, t_irc_channel *channel,
+ int argc, char **argv)
+{
+ t_gui_buffer *buffer;
+
+ gui_buffer_find_context (server, channel, NULL, &buffer);
+
+ if (GUI_BUFFER_IS_CHANNEL(buffer))
+ {
+ if (argc == 0)
+ irc_server_sendf (server, "MODE %s -o %s",
+ GUI_CHANNEL(buffer)->name,
+ server->nick);
+ else
+ irc_send_mode_nicks (server, GUI_CHANNEL(buffer)->name,
+ "-", "o", argc, argv);
+ }
+ else
+ {
+ irc_display_prefix (NULL, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s \"%s\" command can only be executed in a channel buffer\n"),
+ WEECHAT_ERROR, "deop");
+ }
+ return 0;
+}
+
+/*
+ * irc_send_cmd_devoice: remove voice from nickname(s)
+ */
+
+int
+irc_send_cmd_devoice (t_irc_server *server, t_irc_channel *channel,
+ int argc, char **argv)
+{
+ t_gui_buffer *buffer;
+
+ gui_buffer_find_context (server, channel, NULL, &buffer);
+
+ if (GUI_BUFFER_IS_CHANNEL(buffer))
+ {
+ if (argc == 0)
+ irc_server_sendf (server, "MODE %s -v %s",
+ GUI_CHANNEL(buffer)->name,
+ server->nick);
+ else
+ irc_send_mode_nicks (server, GUI_CHANNEL(buffer)->name,
+ "-", "v", argc, argv);
+ }
+ else
+ {
+ irc_display_prefix (NULL, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s \"%s\" command can only be executed in a channel buffer\n"),
+ WEECHAT_ERROR, "devoice");
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * irc_send_cmd_die: shotdown the server
+ */
+
+int
+irc_send_cmd_die (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ /* make C compiler happy */
+ (void) channel;
+ (void) arguments;
+
+ irc_server_sendf (server, "DIE");
+ return 0;
+}
+
+/*
+ * irc_send_cmd_halfop: give half operator privileges to nickname(s)
+ */
+
+int
+irc_send_cmd_halfop (t_irc_server *server, t_irc_channel *channel,
+ int argc, char **argv)
+{
+ t_gui_buffer *buffer;
+
+ gui_buffer_find_context (server, channel, NULL, &buffer);
+
+ if (GUI_BUFFER_IS_CHANNEL(buffer))
+ {
+ if (argc == 0)
+ irc_server_sendf (server, "MODE %s +h %s",
+ GUI_CHANNEL(buffer)->name,
+ server->nick);
+ else
+ irc_send_mode_nicks (server, GUI_CHANNEL(buffer)->name,
+ "+", "h", argc, argv);
+ }
+ else
+ {
+ irc_display_prefix (NULL, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s \"%s\" command can only be executed in a channel buffer\n"),
+ WEECHAT_ERROR, "halfop");
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * irc_send_cmd_info: get information describing the server
+ */
+
+int
+irc_send_cmd_info (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ /* make C compiler happy */
+ (void) channel;
+
+ if (arguments)
+ irc_server_sendf (server, "INFO %s", arguments);
+ else
+ irc_server_sendf (server, "INFO");
+ return 0;
+}
+
+/*
+ * irc_send_cmd_invite: invite a nick on a channel
+ */
+
+int
+irc_send_cmd_invite (t_irc_server *server, t_irc_channel *channel,
+ int argc, char **argv)
+{
+ t_gui_buffer *buffer;
+
+ gui_buffer_find_context (server, channel, NULL, &buffer);
+
+ if (argc == 2)
+ irc_server_sendf (server, "INVITE %s %s", argv[0], argv[1]);
+ else
+ {
+ if (!GUI_BUFFER_IS_CHANNEL(buffer))
+ {
+ irc_display_prefix (NULL, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s \"%s\" command can only be executed in a channel buffer\n"),
+ WEECHAT_ERROR, "invite");
+ return -1;
+ }
+ irc_server_sendf (server, "INVITE %s %s",
+ argv[0], GUI_CHANNEL(buffer)->name);
+ }
+ return 0;
+}
+
+/*
+ * irc_send_cmd_ison: check if a nickname is currently on IRC
+ */
+
+int
+irc_send_cmd_ison (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ /* make C compiler happy */
+ (void) channel;
+
+ irc_server_sendf (server, "ISON %s", arguments);
+ return 0;
+}
+
+/*
+ * irc_send_cmd_join: join a new channel
+ */
+
+int
+irc_send_cmd_join (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ /* make C compiler happy */
+ (void) channel;
+
+ if (irc_channel_is_channel (arguments))
+ irc_server_sendf (server, "JOIN %s", arguments);
+ else
+ irc_server_sendf (server, "JOIN #%s", arguments);
+ return 0;
+}
+
+/*
+ * irc_send_cmd_kick: forcibly remove a user from a channel
+ */
+
+int
+irc_send_cmd_kick (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ t_gui_buffer *buffer;
+ char *pos_channel, *pos_nick, *pos_comment;
+
+ gui_buffer_find_context (server, channel, NULL, &buffer);
+
+ if (irc_channel_is_channel (arguments))
+ {
+ pos_channel = arguments;
+ pos_nick = strchr (arguments, ' ');
+ if (!pos_nick)
+ {
+ irc_display_prefix (NULL, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s wrong arguments for \"%s\" command\n"),
+ WEECHAT_ERROR, "kick");
+ return -1;
+ }
+ pos_nick[0] = '\0';
+ pos_nick++;
+ while (pos_nick[0] == ' ')
+ pos_nick++;
+ }
+ else
+ {
+ if (!GUI_BUFFER_IS_CHANNEL(buffer))
+ {
+ irc_display_prefix (NULL, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s \"%s\" command can only be executed in a channel buffer\n"),
+ WEECHAT_ERROR, "kick");
+ return -1;
+ }
+ pos_channel = GUI_CHANNEL(buffer)->name;
+ pos_nick = arguments;
+ }
+
+ pos_comment = strchr (pos_nick, ' ');
+ if (pos_comment)
+ {
+ pos_comment[0] = '\0';
+ pos_comment++;
+ while (pos_comment[0] == ' ')
+ pos_comment++;
+ }
+
+ if (pos_comment)
+ irc_server_sendf (server, "KICK %s %s :%s", pos_channel, pos_nick, pos_comment);
+ else
+ irc_server_sendf (server, "KICK %s %s", pos_channel, pos_nick);
+
+ return 0;
+}
+
+/*
+ * irc_send_cmd_kickban: forcibly remove a user from a channel and ban it
+ */
+
+int
+irc_send_cmd_kickban (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ t_gui_buffer *buffer;
+ char *pos_channel, *pos_nick, *pos_comment;
+
+ gui_buffer_find_context (server, channel, NULL, &buffer);
+
+ if (irc_channel_is_channel (arguments))
+ {
+ pos_channel = arguments;
+ pos_nick = strchr (arguments, ' ');
+ if (!pos_nick)
+ {
+ irc_display_prefix (NULL, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s wrong arguments for \"%s\" command\n"),
+ WEECHAT_ERROR, "kickban");
+ return -1;
+ }
+ pos_nick[0] = '\0';
+ pos_nick++;
+ while (pos_nick[0] == ' ')
+ pos_nick++;
+ }
+ else
+ {
+ if (!GUI_BUFFER_IS_CHANNEL(buffer))
+ {
+ irc_display_prefix (NULL, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s \"%s\" command can only be executed in a channel buffer\n"),
+ WEECHAT_ERROR, "kickban");
+ return -1;
+ }
+ pos_channel = GUI_CHANNEL(buffer)->name;
+ pos_nick = arguments;
+ }
+
+ pos_comment = strchr (pos_nick, ' ');
+ if (pos_comment)
+ {
+ pos_comment[0] = '\0';
+ pos_comment++;
+ while (pos_comment[0] == ' ')
+ pos_comment++;
+ }
+
+ irc_server_sendf (server, "MODE %s +b %s", pos_channel, pos_nick);
+ if (pos_comment)
+ irc_server_sendf (server, "KICK %s %s :%s", pos_channel, pos_nick, pos_comment);
+ else
+ irc_server_sendf (server, "KICK %s %s", pos_channel, pos_nick);
+
+ return 0;
+}
+
+/*
+ * irc_send_cmd_kill: close client-server connection
+ */
+
+int
+irc_send_cmd_kill (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ char *pos;
+
+ /* make C compiler happy */
+ (void) channel;
+
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ irc_server_sendf (server, "KILL %s :%s", arguments, pos);
+ }
+ else
+ irc_server_sendf (server, "KILL %s", arguments);
+ return 0;
+}
+
+/*
+ * irc_send_cmd_links: list all servernames which are known by the server
+ * answering the query
+ */
+
+int
+irc_send_cmd_links (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ /* make C compiler happy */
+ (void) channel;
+
+ if (arguments)
+ irc_server_sendf (server, "LINKS %s", arguments);
+ else
+ irc_server_sendf (server, "LINKS");
+ return 0;
+}
+
+/*
+ * irc_send_cmd_list: close client-server connection
+ */
+
+int
+irc_send_cmd_list (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ char buffer[512];
+ int ret;
+ /* make C compiler happy */
+ (void) channel;
+
+ if (server->cmd_list_regexp)
+ {
+ regfree (server->cmd_list_regexp);
+ free (server->cmd_list_regexp);
+ server->cmd_list_regexp = NULL;
+ }
+
+ if (arguments)
+ {
+ server->cmd_list_regexp = (regex_t *) malloc (sizeof (regex_t));
+ if (server->cmd_list_regexp)
+ {
+ if ((ret = regcomp (server->cmd_list_regexp, arguments, REG_NOSUB | REG_ICASE)) != 0)
+ {
+ regerror (ret, server->cmd_list_regexp, buffer, sizeof(buffer));
+ gui_printf (server->buffer,
+ _("%s \"%s\" is not a valid regular expression (%s)\n"),
+ WEECHAT_ERROR, arguments, buffer);
+ }
+ else
+ irc_server_sendf (server, "LIST");
+ }
+ else
+ {
+ gui_printf (server->buffer,
+ _("%s not enough memory for regular expression\n"),
+ WEECHAT_ERROR);
+ }
+ }
+ else
+ irc_server_sendf (server, "LIST");
+
+ return 0;
+}
+
+/*
+ * irc_send_cmd_lusers: get statistics about ths size of the IRC network
+ */
+
+int
+irc_send_cmd_lusers (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ /* make C compiler happy */
+ (void) channel;
+
+ if (arguments)
+ irc_server_sendf (server, "LUSERS %s", arguments);
+ else
+ irc_server_sendf (server, "LUSERS");
+ return 0;
+}
+
+/*
+ * irc_send_cmd_me: send a ctcp action to the current channel
+ */
+
+int
+irc_send_cmd_me (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ t_gui_buffer *buffer;
+
+ gui_buffer_find_context (server, channel, NULL, &buffer);
+
+ if (GUI_BUFFER_IS_SERVER(buffer))
+ {
+ irc_display_prefix (NULL, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s \"%s\" command can not be executed on a server buffer\n"),
+ WEECHAT_ERROR, "me");
+ return -1;
+ }
+ irc_send_me (server, GUI_CHANNEL(buffer), arguments);
+ return 0;
+}
+
+/*
+ * irc_send_cmd_mode: change mode for channel/nickname
+ */
+
+int
+irc_send_cmd_mode (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ /* make C compiler happy */
+ (void) channel;
+
+ irc_server_sendf (server, "MODE %s", arguments);
+ return 0;
+}
+
+/*
+ * irc_send_mode_nicks: send mode change for many nicks on a channel
+ */
+
+void
+irc_send_mode_nicks (t_irc_server *server, char *channel,
+ char *set, char *mode, int argc, char **argv)
+{
+ int i, length;
+ char *command;
+
+ length = 0;
+ for (i = 0; i < argc; i++)
+ length += strlen (argv[i]) + 1;
+ length += strlen (channel) + (argc * strlen (mode)) + 32;
+ command = (char *)malloc (length);
+ if (command)
+ {
+ snprintf (command, length, "MODE %s %s", channel, set);
+ for (i = 0; i < argc; i++)
+ strcat (command, mode);
+ for (i = 0; i < argc; i++)
+ {
+ strcat (command, " ");
+ strcat (command, argv[i]);
+ }
+ irc_server_sendf (server, "%s", command);
+ free (command);
+ }
+}
+
+/*
+ * irc_send_cmd_motd: get the "Message Of The Day"
+ */
+
+int
+irc_send_cmd_motd (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ /* make C compiler happy */
+ (void) channel;
+
+ if (arguments)
+ irc_server_sendf (server, "MOTD %s", arguments);
+ else
+ irc_server_sendf (server, "MOTD");
+ return 0;
+}
+
+/*
+ * irc_send_cmd_msg: send a message to a nick or channel
+ */
+
+int
+irc_send_cmd_msg (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ t_gui_window *window;
+ t_gui_buffer *buffer;
+ char *pos, *pos_comma;
+ char *msg_pwd_hidden;
+ t_irc_channel *ptr_channel;
+ t_irc_nick *ptr_nick;
+ char *string;
+
+ gui_buffer_find_context (server, channel, &window, &buffer);
+
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+
+ while (arguments && arguments[0])
+ {
+ pos_comma = strchr (arguments, ',');
+ if (pos_comma)
+ {
+ pos_comma[0] = '\0';
+ pos_comma++;
+ }
+ if (strcmp (arguments, "*") == 0)
+ {
+ if (!GUI_BUFFER_IS_CHANNEL(buffer) &&
+ !GUI_BUFFER_IS_PRIVATE(buffer))
+ {
+ irc_display_prefix (NULL, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s \"%s\" command can only be executed in a channel or private buffer\n"),
+ WEECHAT_ERROR, "msg *");
+ return -1;
+ }
+ ptr_channel = GUI_CHANNEL(buffer);
+ if (GUI_BUFFER_IS_CHANNEL(buffer))
+ ptr_nick = irc_nick_search (ptr_channel, server->nick);
+ else
+ ptr_nick = NULL;
+ irc_display_nick (buffer, ptr_nick,
+ (ptr_nick) ? NULL : server->nick,
+ GUI_MSG_TYPE_NICK, 1, -1, 0);
+ string = (char *)gui_color_decode ((unsigned char *)pos, 1, 0);
+ gui_printf_type (buffer, GUI_MSG_TYPE_MSG, "%s\n",
+ (string) ? string : "");
+ if (string)
+ free (string);
+
+ irc_server_sendf (server, "PRIVMSG %s :%s", ptr_channel->name, pos);
+ }
+ else
+ {
+ if (irc_channel_is_channel (arguments))
+ {
+ ptr_channel = irc_channel_search (server, arguments);
+ if (ptr_channel)
+ {
+ ptr_nick = irc_nick_search (ptr_channel, server->nick);
+ if (ptr_nick)
+ {
+ irc_display_nick (ptr_channel->buffer, ptr_nick, NULL,
+ GUI_MSG_TYPE_NICK, 1, -1, 0);
+ string = (char *)gui_color_decode ((unsigned char *)pos, 1, 0);
+ gui_printf_type (ptr_channel->buffer, GUI_MSG_TYPE_MSG, "%s\n",
+ (string) ? string : "");
+ if (string)
+ free (string);
+ }
+ else
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s nick \"%s\" not found for \"%s\" command\n"),
+ WEECHAT_ERROR, server->nick, "msg");
+ }
+ }
+ irc_server_sendf (server, "PRIVMSG %s :%s", arguments, pos);
+ }
+ else
+ {
+ /* message to nickserv with identify ? */
+ if (strcmp (arguments, "nickserv") == 0)
+ {
+ msg_pwd_hidden = strdup (pos);
+ if (cfg_log_hide_nickserv_pwd)
+ irc_display_hide_password (msg_pwd_hidden, 0);
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_SERVER);
+ gui_printf_type (server->buffer, GUI_MSG_TYPE_NICK,
+ "%s-%s%s%s- ",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ arguments,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK));
+ string = (char *)gui_color_decode ((unsigned char *)msg_pwd_hidden, 1, 0);
+ gui_printf (server->buffer, "%s%s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ (string) ? string : "");
+ if (string)
+ free (string);
+ irc_server_sendf (server, "PRIVMSG %s :%s", arguments, pos);
+ free (msg_pwd_hidden);
+ return 0;
+ }
+
+ string = (char *)gui_color_decode ((unsigned char *)pos, 1, 0);
+ ptr_channel = irc_channel_search (server, arguments);
+ if (ptr_channel)
+ {
+ irc_display_nick (ptr_channel->buffer, NULL, server->nick,
+ GUI_MSG_TYPE_NICK, 1, GUI_COLOR_WIN_NICK_SELF, 0);
+ gui_printf_type (ptr_channel->buffer, GUI_MSG_TYPE_MSG,
+ "%s%s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ (string) ? string : "");
+ }
+ else
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_SERVER);
+ gui_printf (server->buffer, "MSG%s(%s%s%s)%s: ",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ arguments,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT));
+ gui_printf_type (server->buffer, GUI_MSG_TYPE_MSG,
+ "%s\n",
+ (string) ? string : pos);
+ }
+ if (string)
+ free (string);
+ irc_server_sendf (server, "PRIVMSG %s :%s", arguments, pos);
+ }
+ }
+ arguments = pos_comma;
+ }
+ }
+ else
+ {
+ irc_display_prefix (NULL, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s wrong argument count for \"%s\" command\n"),
+ WEECHAT_ERROR, "msg");
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * irc_send_cmd_names: list nicknames on channels
+ */
+
+int
+irc_send_cmd_names (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ t_gui_buffer *buffer;
+
+ gui_buffer_find_context (server, channel, NULL, &buffer);
+
+ if (arguments)
+ irc_server_sendf (server, "NAMES %s", arguments);
+ else
+ {
+ if (!GUI_BUFFER_IS_CHANNEL(buffer))
+ {
+ irc_display_prefix (NULL, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s \"%s\" command can only be executed in a channel buffer\n"),
+ WEECHAT_ERROR, "names");
+ return -1;
+ }
+ else
+ irc_server_sendf (server, "NAMES %s",
+ GUI_CHANNEL(buffer)->name);
+ }
+ return 0;
+}
+
+/*
+ * irc_send_cmd_nick_server: change nickname on a server
+ */
+
+void
+irc_send_cmd_nick_server (t_irc_server *server, char *nickname)
+{
+ t_irc_channel *ptr_channel;
+
+ if (server->is_connected)
+ irc_server_sendf (server, "NICK %s", nickname);
+ else
+ {
+ if (server->nick)
+ free (server->nick);
+ server->nick = strdup (nickname);
+ gui_input_draw (server->buffer, 1);
+ for (ptr_channel = server->channels; ptr_channel;
+ ptr_channel = ptr_channel->next_channel)
+ {
+ gui_input_draw (ptr_channel->buffer, 1);
+ }
+ }
+}
+
+/*
+ * irc_send_cmd_nick: change nickname
+ */
+
+int
+irc_send_cmd_nick (t_irc_server *server, t_irc_channel *channel,
+ int argc, char **argv)
+{
+ t_irc_server *ptr_server;
+
+ /* make C compiler happy */
+ (void) channel;
+
+ if (!server)
+ return 0;
+
+ if (argc == 2)
+ {
+ if (strncmp (argv[0], "-all", 4) != 0)
+ return -1;
+
+ for (ptr_server = irc_servers; ptr_server;
+ ptr_server = ptr_server->next_server)
+ {
+ irc_send_cmd_nick_server (ptr_server, argv[1]);
+ }
+ }
+ else
+ {
+ if (argc == 1)
+ irc_send_cmd_nick_server (server, argv[0]);
+ else
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * irc_send_cmd_notice: send notice message
+ */
+
+int
+irc_send_cmd_notice (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ char *pos, *string;
+
+ /* make C compiler happy */
+ (void) channel;
+
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_SERVER);
+ string = (char *)gui_color_decode ((unsigned char *)pos, 1, 0);
+ gui_printf (server->buffer, "notice%s(%s%s%s)%s: %s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_NICK),
+ arguments,
+ GUI_COLOR(GUI_COLOR_WIN_CHAT_DARK),
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ (string) ? string : "");
+ if (string)
+ free (string);
+ irc_server_sendf (server, "NOTICE %s :%s", arguments, pos);
+ }
+ else
+ {
+ irc_display_prefix (NULL, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s wrong argument count for \"%s\" command\n"),
+ WEECHAT_ERROR, "notice");
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * irc_send_cmd_op: give operator privileges to nickname(s)
+ */
+
+int
+irc_send_cmd_op (t_irc_server *server, t_irc_channel *channel,
+ int argc, char **argv)
+{
+ t_gui_buffer *buffer;
+
+ gui_buffer_find_context (server, channel, NULL, &buffer);
+
+ if (GUI_BUFFER_IS_CHANNEL(buffer))
+ {
+ if (argc == 0)
+ irc_server_sendf (server, "MODE %s +o %s",
+ GUI_CHANNEL(buffer)->name,
+ server->nick);
+ else
+ irc_send_mode_nicks (server, GUI_CHANNEL(buffer)->name,
+ "+", "o", argc, argv);
+ }
+ else
+ {
+ irc_display_prefix (NULL, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s \"%s\" command can only be executed in a channel buffer\n"),
+ WEECHAT_ERROR, "op");
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * irc_send_cmd_oper: get oper privileges
+ */
+
+int
+irc_send_cmd_oper (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ /* make C compiler happy */
+ (void) channel;
+
+ irc_server_sendf (server, "OPER %s", arguments);
+ return 0;
+}
+
+/*
+ * irc_send_cmd_part: leave a channel or close a private window
+ */
+
+int
+irc_send_cmd_part (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ t_gui_buffer *buffer;
+ char *channel_name, *pos_args, *ptr_arg, *buf;
+ t_irc_channel *ptr_channel;
+
+ gui_buffer_find_context (server, channel, NULL, &buffer);
+
+ if (arguments)
+ {
+ if (irc_channel_is_channel (arguments))
+ {
+ channel_name = arguments;
+ pos_args = strchr (arguments, ' ');
+ if (pos_args)
+ {
+ pos_args[0] = '\0';
+ pos_args++;
+ while (pos_args[0] == ' ')
+ pos_args++;
+ }
+ }
+ else
+ {
+ if (!GUI_CHANNEL(buffer))
+ {
+ irc_display_prefix (NULL, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s \"%s\" command can only be executed in a channel or private buffer\n"),
+ WEECHAT_ERROR, "part");
+ return -1;
+ }
+ channel_name = GUI_CHANNEL(buffer)->name;
+ pos_args = arguments;
+ }
+ }
+ else
+ {
+ if (!GUI_CHANNEL(buffer))
+ {
+ irc_display_prefix (NULL, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s \"%s\" command can only be executed in a channel or private buffer\n"),
+ WEECHAT_ERROR, "part");
+ return -1;
+ }
+ if (GUI_BUFFER_IS_PRIVATE(buffer))
+ {
+ ptr_channel = GUI_CHANNEL(buffer);
+ gui_buffer_free (ptr_channel->buffer, 1);
+ irc_channel_free (server, ptr_channel);
+ gui_status_draw (buffer, 1);
+ gui_input_draw (buffer, 1);
+ return 0;
+ }
+ channel_name = GUI_CHANNEL(buffer)->name;
+ pos_args = NULL;
+ }
+
+ ptr_arg = (pos_args) ? pos_args :
+ (cfg_irc_default_msg_part && cfg_irc_default_msg_part[0]) ?
+ cfg_irc_default_msg_part : NULL;
+
+ if (ptr_arg)
+ {
+ buf = weechat_strreplace (ptr_arg, "%v", PACKAGE_VERSION);
+ irc_server_sendf (server, "PART %s :%s", channel_name,
+ (buf) ? buf : ptr_arg);
+ if (buf)
+ free (buf);
+ }
+ else
+ irc_server_sendf (server, "PART %s", channel_name);
+
+ return 0;
+}
+
+/*
+ * irc_send_cmd_ping: ping a server
+ */
+
+int
+irc_send_cmd_ping (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ /* make C compiler happy */
+ (void) channel;
+
+ irc_server_sendf (server, "PING %s", arguments);
+ return 0;
+}
+
+/*
+ * irc_send_cmd_pong: send pong answer to a daemon
+ */
+
+int
+irc_send_cmd_pong (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ /* make C compiler happy */
+ (void) channel;
+
+ irc_server_sendf (server, "PONG %s", arguments);
+ return 0;
+}
+
+/*
+ * irc_send_cmd_query: start private conversation with a nick
+ */
+
+int
+irc_send_cmd_query (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ t_gui_window *window;
+ t_gui_buffer *buffer;
+ char *pos, *string;
+ t_irc_channel *ptr_channel;
+ t_gui_buffer *ptr_buffer;
+
+ gui_buffer_find_context (server, channel, &window, &buffer);
+
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ if (!pos[0])
+ pos = NULL;
+ }
+
+ /* create private window if not already opened */
+ ptr_channel = irc_channel_search (server, arguments);
+ if (!ptr_channel)
+ {
+ ptr_channel = irc_channel_new (server, IRC_CHANNEL_TYPE_PRIVATE, arguments);
+ if (!ptr_channel)
+ {
+ irc_display_prefix (NULL, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s cannot create new private buffer \"%s\"\n"),
+ WEECHAT_ERROR, arguments);
+ return -1;
+ }
+ gui_buffer_new (window, server, ptr_channel,
+ GUI_BUFFER_TYPE_STANDARD, 1);
+ gui_chat_draw_title (ptr_channel->buffer, 1);
+ }
+ else
+ {
+ for (ptr_buffer = gui_buffers; ptr_buffer; ptr_buffer = ptr_buffer->next_buffer)
+ {
+ if (ptr_buffer->channel == ptr_channel)
+ {
+ gui_window_switch_to_buffer (window, ptr_buffer);
+ gui_window_redraw_buffer (ptr_buffer);
+ break;
+ }
+ }
+ }
+
+ /* display text if given */
+ if (pos)
+ {
+ irc_display_nick (ptr_channel->buffer, NULL, server->nick,
+ GUI_MSG_TYPE_NICK, 1, GUI_COLOR_WIN_NICK_SELF, 0);
+ string = (char *)gui_color_decode ((unsigned char *)pos, 1, 0);
+ gui_printf_type (ptr_channel->buffer, GUI_MSG_TYPE_MSG,
+ "%s%s\n",
+ GUI_COLOR(GUI_COLOR_WIN_CHAT),
+ (string) ? string : "");
+ if (string)
+ free (string);
+ irc_server_sendf (server, "PRIVMSG %s :%s", arguments, pos);
+ }
+ return 0;
+}
+
+/*
+ * irc_send_quit_server: send QUIT to a server
+ */
+
+void
+irc_send_quit_server (t_irc_server *server, char *arguments)
+{
+ char *ptr_arg, *buf;
+
+ if (server->is_connected)
+ {
+ ptr_arg = (arguments) ? arguments :
+ (cfg_irc_default_msg_quit && cfg_irc_default_msg_quit[0]) ?
+ cfg_irc_default_msg_quit : NULL;
+
+ if (ptr_arg)
+ {
+ buf = weechat_strreplace (ptr_arg, "%v", PACKAGE_VERSION);
+ irc_server_sendf (server, "QUIT :%s",
+ (buf) ? buf : ptr_arg);
+ if (buf)
+ free (buf);
+ }
+ else
+ irc_server_sendf (server, "QUIT");
+ }
+}
+
+/*
+ * irc_send_cmd_quit: disconnect from all servers and quit WeeChat
+ */
+
+int
+irc_send_cmd_quit (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ t_irc_server *ptr_server;
+
+ /* make C compiler happy */
+ (void) server;
+ (void) channel;
+
+ for (ptr_server = irc_servers; ptr_server;
+ ptr_server = ptr_server->next_server)
+ {
+ irc_send_quit_server (ptr_server, arguments);
+ }
+ quit_weechat = 1;
+ return 0;
+}
+
+/*
+ * irc_send_cmd_quote: send raw data to server
+ */
+
+int
+irc_send_cmd_quote (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ /* make C compiler happy */
+ (void) channel;
+
+ if (!server || server->sock < 0)
+ {
+ irc_display_prefix (NULL, NULL, GUI_PREFIX_ERROR);
+ gui_printf_nolog (NULL,
+ _("%s command \"%s\" needs a server connection!\n"),
+ WEECHAT_ERROR, "quote");
+ return -1;
+ }
+ irc_server_sendf (server, "%s", arguments);
+ return 0;
+}
+
+/*
+ * irc_send_cmd_rehash: tell the server to reload its config file
+ */
+
+int
+irc_send_cmd_rehash (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ /* make C compiler happy */
+ (void) channel;
+ (void) arguments;
+
+ irc_server_sendf (server, "REHASH");
+ return 0;
+}
+
+/*
+ * irc_send_cmd_restart: tell the server to restart itself
+ */
+
+int
+irc_send_cmd_restart (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ /* make C compiler happy */
+ (void) channel;
+ (void) arguments;
+
+ irc_server_sendf (server, "RESTART");
+ return 0;
+}
+
+/*
+ * irc_send_cmd_service: register a new service
+ */
+
+int
+irc_send_cmd_service (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ /* make C compiler happy */
+ (void) channel;
+
+ irc_server_sendf (server, "SERVICE %s", arguments);
+ return 0;
+}
+
+/*
+ * irc_send_cmd_servlist: list services currently connected to the network
+ */
+
+int
+irc_send_cmd_servlist (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ /* make C compiler happy */
+ (void) channel;
+
+ if (arguments)
+ irc_server_sendf (server, "SERVLIST %s", arguments);
+ else
+ irc_server_sendf (server, "SERVLIST");
+ return 0;
+}
+
+/*
+ * irc_send_cmd_squery: deliver a message to a service
+ */
+
+int
+irc_send_cmd_squery (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ char *pos;
+
+ /* make C compiler happy */
+ (void) channel;
+
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ {
+ pos++;
+ }
+ irc_server_sendf (server, "SQUERY %s :%s", arguments, pos);
+ }
+ else
+ irc_server_sendf (server, "SQUERY %s", arguments);
+
+ return 0;
+}
+
+/*
+ * irc_send_cmd_squit: disconnect server links
+ */
+
+int
+irc_send_cmd_squit (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ /* make C compiler happy */
+ (void) channel;
+
+ irc_server_sendf (server, "SQUIT %s", arguments);
+ return 0;
+}
+
+/*
+ * irc_send_cmd_stats: query statistics about server
+ */
+
+int
+irc_send_cmd_stats (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ /* make C compiler happy */
+ (void) channel;
+
+ if (arguments)
+ irc_server_sendf (server, "STATS %s", arguments);
+ else
+ irc_server_sendf (server, "STATS");
+ return 0;
+}
+
+/*
+ * irc_send_cmd_summon: give users who are on a host running an IRC server
+ * a message asking them to please join IRC
+ */
+
+int
+irc_send_cmd_summon (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ /* make C compiler happy */
+ (void) channel;
+
+ irc_server_sendf (server, "SUMMON %s", arguments);
+ return 0;
+}
+
+/*
+ * irc_send_cmd_time: query local time from server
+ */
+
+int
+irc_send_cmd_time (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ /* make C compiler happy */
+ (void) channel;
+
+ if (arguments)
+ irc_server_sendf (server, "TIME %s", arguments);
+ else
+ irc_server_sendf (server, "TIME");
+ return 0;
+}
+
+/*
+ * irc_send_cmd_topic: get/set topic for a channel
+ */
+
+int
+irc_send_cmd_topic (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ t_gui_buffer *buffer;
+ char *channel_name, *new_topic, *pos;
+
+ gui_buffer_find_context (server, channel, NULL, &buffer);
+
+ channel_name = NULL;
+ new_topic = NULL;
+
+ if (arguments)
+ {
+ if (irc_channel_is_channel (arguments))
+ {
+ channel_name = arguments;
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ new_topic = (pos[0]) ? pos : NULL;
+ }
+ }
+ else
+ new_topic = arguments;
+ }
+
+ /* look for current channel if not specified */
+ if (!channel_name)
+ {
+ if (GUI_BUFFER_IS_SERVER(buffer))
+ {
+ irc_display_prefix (NULL, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s \"%s\" command can not be executed on a server buffer\n"),
+ WEECHAT_ERROR, "topic");
+ return -1;
+ }
+ channel_name = GUI_CHANNEL(buffer)->name;
+ }
+
+ if (new_topic)
+ {
+ if (strcmp (new_topic, "-delete") == 0)
+ irc_server_sendf (server, "TOPIC %s :", channel_name);
+ else
+ irc_server_sendf (server, "TOPIC %s :%s", channel_name, new_topic);
+ }
+ else
+ irc_server_sendf (server, "TOPIC %s", channel_name);
+
+ return 0;
+}
+
+/*
+ * irc_send_cmd_trace: find the route to specific server
+ */
+
+int
+irc_send_cmd_trace (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ /* make C compiler happy */
+ (void) channel;
+
+ if (arguments)
+ irc_server_sendf (server, "TRACE %s", arguments);
+ else
+ irc_server_sendf (server, "TRACE");
+ return 0;
+}
+
+/*
+ * irc_send_cmd_unban: unbans nicks or hosts
+ */
+
+int
+irc_send_cmd_unban (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ t_gui_buffer *buffer;
+ char *pos_channel, *pos, *pos2;
+
+ gui_buffer_find_context (server, channel, NULL, &buffer);
+
+ if (arguments)
+ {
+ pos_channel = NULL;
+ pos = strchr (arguments, ' ');
+ if (pos)
+ {
+ pos[0] = '\0';
+
+ if (irc_channel_is_channel (arguments))
+ {
+ pos_channel = arguments;
+ pos++;
+ while (pos[0] == ' ')
+ pos++;
+ }
+ else
+ {
+ pos[0] = ' ';
+ pos = arguments;
+ }
+ }
+ else
+ pos = arguments;
+
+ /* channel not given, use default buffer */
+ if (!pos_channel)
+ {
+ if (!GUI_BUFFER_IS_CHANNEL(buffer))
+ {
+ irc_display_prefix (NULL, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s \"%s\" command can only be executed in a channel buffer\n"),
+ WEECHAT_ERROR, "unban");
+ return -1;
+ }
+ pos_channel = GUI_CHANNEL(buffer)->name;
+ }
+
+ /* loop on users */
+ while (pos && pos[0])
+ {
+ pos2 = strchr (pos, ' ');
+ if (pos2)
+ {
+ pos2[0] = '\0';
+ pos2++;
+ while (pos2[0] == ' ')
+ pos2++;
+ }
+ irc_server_sendf (server, "MODE %s -b %s", pos_channel, pos);
+ pos = pos2;
+ }
+ }
+ else
+ {
+ irc_display_prefix (NULL, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s wrong argument count for \"%s\" command\n"),
+ WEECHAT_ERROR, "unban");
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * irc_send_cmd_userhost: return a list of information about nicknames
+ */
+
+int
+irc_send_cmd_userhost (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ /* make C compiler happy */
+ (void) channel;
+
+ irc_server_sendf (server, "USERHOST %s", arguments);
+ return 0;
+}
+
+/*
+ * irc_send_cmd_users: list of users logged into the server
+ */
+
+int
+irc_send_cmd_users (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ /* make C compiler happy */
+ (void) channel;
+
+ if (arguments)
+ irc_server_sendf (server, "USERS %s", arguments);
+ else
+ irc_server_sendf (server, "USERS");
+ return 0;
+}
+
+/*
+ * irc_send_cmd_version: gives the version info of nick or server (current or specified)
+ */
+
+int
+irc_send_cmd_version (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ t_gui_buffer *buffer;
+
+ gui_buffer_find_context (server, channel, NULL, &buffer);
+
+ if (arguments)
+ {
+ if (GUI_BUFFER_IS_CHANNEL(buffer) &&
+ irc_nick_search (GUI_CHANNEL(buffer), arguments))
+ irc_server_sendf (server, "PRIVMSG %s :\01VERSION\01",
+ arguments);
+ else
+ irc_server_sendf (server, "VERSION %s",
+ arguments);
+ }
+ else
+ {
+ irc_display_prefix (NULL, server->buffer, GUI_PREFIX_INFO);
+ gui_printf (server->buffer, _("%s, compiled on %s %s\n"),
+ PACKAGE_STRING,
+ __DATE__, __TIME__);
+ irc_server_sendf (server, "VERSION");
+ }
+ return 0;
+}
+
+/*
+ * irc_send_cmd_voice: give voice to nickname(s)
+ */
+
+int
+irc_send_cmd_voice (t_irc_server *server, t_irc_channel *channel,
+ int argc, char **argv)
+{
+ t_gui_buffer *buffer;
+
+ gui_buffer_find_context (server, channel, NULL, &buffer);
+
+ if (GUI_BUFFER_IS_CHANNEL(buffer))
+ {
+ if (argc == 0)
+ irc_server_sendf (server, "MODE %s +v %s",
+ GUI_CHANNEL(buffer)->name,
+ server->nick);
+ else
+ irc_send_mode_nicks (server, GUI_CHANNEL(buffer)->name,
+ "+", "v", argc, argv);
+ }
+ else
+ {
+ irc_display_prefix (NULL, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf_nolog (server->buffer,
+ _("%s \"%s\" command can only be executed in a channel buffer\n"),
+ WEECHAT_ERROR, "voice");
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * irc_send_cmd_wallops: send a message to all currently connected users who
+ * have set the 'w' user mode for themselves
+ */
+
+int
+irc_send_cmd_wallops (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ /* make C compiler happy */
+ (void) channel;
+
+ irc_server_sendf (server, "WALLOPS :%s", arguments);
+ return 0;
+}
+
+/*
+ * irc_send_cmd_who: generate a query which returns a list of information
+ */
+
+int
+irc_send_cmd_who (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ /* make C compiler happy */
+ (void) channel;
+
+ if (arguments)
+ irc_server_sendf (server, "WHO %s", arguments);
+ else
+ irc_server_sendf (server, "WHO");
+ return 0;
+}
+
+/*
+ * irc_send_cmd_whois: query information about user(s)
+ */
+
+int
+irc_send_cmd_whois (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ /* make C compiler happy */
+ (void) channel;
+
+ irc_server_sendf (server, "WHOIS %s", arguments);
+ return 0;
+}
+
+/*
+ * irc_send_cmd_whowas: ask for information about a nickname which no longer exists
+ */
+
+int
+irc_send_cmd_whowas (t_irc_server *server, t_irc_channel *channel,
+ char *arguments)
+{
+ /* make C compiler happy */
+ (void) channel;
+
+ irc_server_sendf (server, "WHOWAS %s", arguments);
+ return 0;
+}
diff --git a/src/plugins/irc/irc-server.c b/src/plugins/irc/irc-server.c
new file mode 100644
index 000000000..0c119ceb1
--- /dev/null
+++ b/src/plugins/irc/irc-server.c
@@ -0,0 +1,2415 @@
+/*
+ * 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/>.
+ */
+
+/* irc-server.c: connection and communication with IRC server */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <pwd.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#ifdef HAVE_GNUTLS
+#include <gnutls/gnutls.h>
+#endif
+
+#include "../../common/weechat.h"
+#include "irc.h"
+#include "../../common/log.h"
+#include "../../common/util.h"
+#include "../../common/weeconfig.h"
+#include "../../gui/gui.h"
+
+#ifdef PLUGINS
+#include "../../plugins/plugins.h"
+#endif
+
+
+t_irc_server *irc_servers = NULL;
+t_irc_server *last_irc_server = NULL;
+
+t_irc_message *irc_recv_msgq = NULL;
+t_irc_message *irc_msgq_last_msg = NULL;
+
+int irc_check_away = 0;
+
+#ifdef HAVE_GNUTLS
+const int gnutls_cert_type_prio[] = { GNUTLS_CRT_X509, GNUTLS_CRT_OPENPGP, 0 };
+#if LIBGNUTLS_VERSION_NUMBER >= 0x010700
+ const int gnutls_prot_prio[] = { GNUTLS_TLS1_2, GNUTLS_TLS1_1,
+ GNUTLS_TLS1_0, GNUTLS_SSL3, 0 };
+#else
+ const int gnutls_prot_prio[] = { GNUTLS_TLS1_1, GNUTLS_TLS1_0,
+ GNUTLS_SSL3, 0 };
+#endif
+#endif
+
+
+/*
+ * irc_server_init: init server struct with default values
+ */
+
+void
+irc_server_init (t_irc_server *server)
+{
+ /* user choices */
+ server->name = NULL;
+ server->autoconnect = 0;
+ server->autoreconnect = 1;
+ server->autoreconnect_delay = 30;
+ server->temp_server = 0;
+ server->address = NULL;
+ server->port = -1;
+ server->ipv6 = 0;
+ server->ssl = 0;
+ server->password = NULL;
+ server->nick1 = NULL;
+ server->nick2 = NULL;
+ server->nick3 = NULL;
+ server->username = NULL;
+ server->realname = NULL;
+ server->hostname = NULL;
+ server->command = NULL;
+ server->command_delay = 1;
+ server->autojoin = NULL;
+ server->autorejoin = 0;
+ server->notify_levels = NULL;
+
+ /* internal vars */
+ server->child_pid = 0;
+ server->child_read = -1;
+ server->child_write = -1;
+ server->sock = -1;
+ server->is_connected = 0;
+ server->ssl_connected = 0;
+ server->unterminated_message = NULL;
+ server->nick = NULL;
+ server->nick_modes = NULL;
+ server->prefix = NULL;
+ server->reconnect_start = 0;
+ server->command_time = 0;
+ server->reconnect_join = 0;
+ server->disable_autojoin = 0;
+ server->is_away = 0;
+ server->away_message = NULL;
+ server->away_time = 0;
+ server->lag = 0;
+ server->lag_check_time.tv_sec = 0;
+ server->lag_check_time.tv_usec = 0;
+ server->lag_next_check = time (NULL) + cfg_irc_lag_check;
+ server->cmd_list_regexp = NULL;
+ server->queue_msg = 0;
+ server->last_user_message = 0;
+ server->outqueue = NULL;
+ server->last_outqueue = NULL;
+ server->buffer = NULL;
+ server->saved_buffer = NULL;
+ server->channels = NULL;
+ server->last_channel = NULL;
+}
+
+/*
+ * irc_server_init_with_url: init a server with url of this form:
+ * irc://nick:pass@irc.toto.org:6667
+ * returns: 0 = ok
+ * -1 = invalid syntax
+ */
+
+int
+irc_server_init_with_url (char *irc_url, t_irc_server *server)
+{
+ char *url, *pos_server, *pos_channel, *pos, *pos2;
+ int ipv6, ssl;
+ struct passwd *my_passwd;
+
+ irc_server_init (server);
+ ipv6 = 0;
+ ssl = 0;
+ if (strncasecmp (irc_url, "irc6://", 7) == 0)
+ {
+ pos = irc_url + 7;
+ ipv6 = 1;
+ }
+ else if (strncasecmp (irc_url, "ircs://", 7) == 0)
+ {
+ pos = irc_url + 7;
+ ssl = 1;
+ }
+ else if ((strncasecmp (irc_url, "irc6s://", 8) == 0)
+ || (strncasecmp (irc_url, "ircs6://", 8) == 0))
+ {
+ pos = irc_url + 8;
+ ipv6 = 1;
+ ssl = 1;
+ }
+ else if (strncasecmp (irc_url, "irc://", 6) == 0)
+ {
+ pos = irc_url + 6;
+ }
+ else
+ return -1;
+
+ url = strdup (pos);
+ pos_server = strchr (url, '@');
+ if (pos_server)
+ {
+ pos_server[0] = '\0';
+ pos_server++;
+ if (!pos[0])
+ {
+ free (url);
+ return -1;
+ }
+ pos2 = strchr (url, ':');
+ if (pos2)
+ {
+ pos2[0] = '\0';
+ server->password = strdup (pos2 + 1);
+ }
+ server->nick1 = strdup (url);
+ }
+ else
+ {
+ if ((my_passwd = getpwuid (geteuid ())) != NULL)
+ server->nick1 = strdup (my_passwd->pw_name);
+ else
+ {
+ weechat_iconv_fprintf (stderr, "%s: %s (%s).",
+ WEECHAT_WARNING,
+ _("Unable to get user's name"),
+ strerror (errno));
+ free (url);
+ return -1;
+ }
+ pos_server = url;
+ }
+ if (!pos_server[0])
+ {
+ free (url);
+ return -1;
+ }
+ pos_channel = strchr (pos_server, '/');
+ if (pos_channel)
+ {
+ pos_channel[0] = '\0';
+ pos_channel++;
+ }
+ pos = strchr (pos_server, ':');
+ if (pos)
+ {
+ pos[0] = '\0';
+ server->port = atoi (pos + 1);
+ }
+ server->name = strdup (pos_server);
+ server->address = strdup (pos_server);
+ if (pos_channel && pos_channel[0])
+ {
+ if (irc_channel_is_channel (pos_channel))
+ server->autojoin = strdup (pos_channel);
+ else
+ {
+ server->autojoin = (char *) malloc (strlen (pos_channel) + 2);
+ strcpy (server->autojoin, "#");
+ strcat (server->autojoin, pos_channel);
+ }
+ }
+
+ free (url);
+
+ server->ipv6 = ipv6;
+ server->ssl = ssl;
+
+ /* some default values */
+ if (server->port < 0)
+ server->port = IRC_DEFAULT_PORT;
+ server->nick2 = (char *) malloc (strlen (server->nick1) + 2);
+ strcpy (server->nick2, server->nick1);
+ server->nick2 = strcat (server->nick2, "1");
+ server->nick3 = (char *) malloc (strlen (server->nick1) + 2);
+ strcpy (server->nick3, server->nick1);
+ server->nick3 = strcat (server->nick3, "2");
+
+ return 0;
+}
+
+/*
+ * irc_server_alloc: allocate a new server and add it to the servers queue
+ */
+
+t_irc_server *
+irc_server_alloc ()
+{
+ t_irc_server *new_server;
+
+ /* alloc memory for new server */
+ if ((new_server = (t_irc_server *) malloc (sizeof (t_irc_server))) == NULL)
+ {
+ weechat_iconv_fprintf (stderr,
+ _("%s cannot allocate new server\n"),
+ WEECHAT_ERROR);
+ return NULL;
+ }
+
+ /* initialize new server */
+ irc_server_init (new_server);
+
+ /* add new server to queue */
+ new_server->prev_server = last_irc_server;
+ new_server->next_server = NULL;
+ if (irc_servers)
+ last_irc_server->next_server = new_server;
+ else
+ irc_servers = new_server;
+ last_irc_server = new_server;
+
+ /* all is ok, return address of new server */
+ return new_server;
+}
+
+/*
+ * irc_server_outqueue_add: add a message in out queue
+ */
+
+void
+irc_server_outqueue_add (t_irc_server *server, char *msg1, char *msg2,
+ int modified)
+{
+ t_irc_outqueue *new_outqueue;
+
+ new_outqueue = (t_irc_outqueue *)malloc (sizeof (t_irc_outqueue));
+ if (new_outqueue)
+ {
+ new_outqueue->message_before_mod = (msg1) ? strdup (msg1) : NULL;
+ new_outqueue->message_after_mod = (msg2) ? strdup (msg2) : NULL;
+ new_outqueue->modified = modified;
+
+ new_outqueue->prev_outqueue = server->last_outqueue;
+ new_outqueue->next_outqueue = NULL;
+ if (server->outqueue)
+ server->last_outqueue->next_outqueue = new_outqueue;
+ else
+ server->outqueue = new_outqueue;
+ server->last_outqueue = new_outqueue;
+ }
+}
+
+/*
+ * irc_server_outqueue_free: free a message in out queue
+ */
+
+void
+irc_server_outqueue_free (t_irc_server *server, t_irc_outqueue *outqueue)
+{
+ t_irc_outqueue *new_outqueue;
+
+ /* remove outqueue message */
+ if (server->last_outqueue == outqueue)
+ server->last_outqueue = outqueue->prev_outqueue;
+ if (outqueue->prev_outqueue)
+ {
+ (outqueue->prev_outqueue)->next_outqueue = outqueue->next_outqueue;
+ new_outqueue = server->outqueue;
+ }
+ else
+ new_outqueue = outqueue->next_outqueue;
+
+ if (outqueue->next_outqueue)
+ (outqueue->next_outqueue)->prev_outqueue = outqueue->prev_outqueue;
+
+ if (outqueue->message_before_mod)
+ free (outqueue->message_before_mod);
+ if (outqueue->message_after_mod)
+ free (outqueue->message_after_mod);
+ free (outqueue);
+ server->outqueue = new_outqueue;
+}
+
+/*
+ * irc_server_outqueue_free_all: free all outqueued messages
+ */
+
+void
+irc_server_outqueue_free_all (t_irc_server *server)
+{
+ while (server->outqueue)
+ irc_server_outqueue_free (server, server->outqueue);
+}
+
+/*
+ * irc_server_destroy: free server data (not struct himself)
+ */
+
+void
+irc_server_destroy (t_irc_server *server)
+{
+ if (!server)
+ return;
+
+ /* free data */
+ if (server->name)
+ free (server->name);
+ if (server->address)
+ free (server->address);
+ if (server->password)
+ free (server->password);
+ if (server->nick1)
+ free (server->nick1);
+ if (server->nick2)
+ free (server->nick2);
+ if (server->nick3)
+ free (server->nick3);
+ if (server->username)
+ free (server->username);
+ if (server->realname)
+ free (server->realname);
+ if (server->hostname)
+ free (server->hostname);
+ if (server->command)
+ free (server->command);
+ if (server->autojoin)
+ free (server->autojoin);
+ if (server->notify_levels)
+ free (server->notify_levels);
+ if (server->unterminated_message)
+ free (server->unterminated_message);
+ if (server->nick)
+ free (server->nick);
+ if (server->nick_modes)
+ free (server->nick_modes);
+ if (server->prefix)
+ free (server->prefix);
+ if (server->away_message)
+ free (server->away_message);
+ if (server->outqueue)
+ irc_server_outqueue_free_all (server);
+ if (server->channels)
+ irc_channel_free_all (server);
+}
+
+/*
+ * irc_server_free: free a server and remove it from servers queue
+ */
+
+void
+irc_server_free (t_irc_server *server)
+{
+ t_irc_server *new_irc_servers;
+
+ if (!server)
+ return;
+
+ /* close any opened channel/private */
+ while (server->channels)
+ irc_channel_free (server, server->channels);
+
+ /* remove server from queue */
+ if (last_irc_server == server)
+ last_irc_server = server->prev_server;
+ if (server->prev_server)
+ {
+ (server->prev_server)->next_server = server->next_server;
+ new_irc_servers = irc_servers;
+ }
+ else
+ new_irc_servers = server->next_server;
+
+ if (server->next_server)
+ (server->next_server)->prev_server = server->prev_server;
+
+ irc_server_destroy (server);
+ free (server);
+ irc_servers = new_irc_servers;
+}
+
+/*
+ * irc_server_free_all: free all allocated servers
+ */
+
+void
+irc_server_free_all ()
+{
+ /* for each server in memory, remove it */
+ while (irc_servers)
+ irc_server_free (irc_servers);
+}
+
+/*
+ * irc_server_new: creates a new server, and initialize it
+ */
+
+t_irc_server *
+irc_server_new (char *name, int autoconnect, int autoreconnect,
+ int autoreconnect_delay, int temp_server, char *address,
+ int port, int ipv6, int ssl, char *password,
+ char *nick1, char *nick2, char *nick3, char *username,
+ char *realname, char *hostname, char *command, int command_delay,
+ char *autojoin, int autorejoin, char *notify_levels)
+{
+ t_irc_server *new_server;
+
+ if (!name || !address || (port < 0))
+ return NULL;
+
+#ifdef DEBUG
+ weechat_log_printf ("Creating new server (name:%s, address:%s, port:%d, pwd:%s, "
+ "nick1:%s, nick2:%s, nick3:%s, username:%s, realname:%s, "
+ "hostname: %s, command:%s, autojoin:%s, autorejoin:%s, "
+ "notify_levels:%s)\n",
+ name, address, port, (password) ? password : "",
+ (nick1) ? nick1 : "", (nick2) ? nick2 : "", (nick3) ? nick3 : "",
+ (username) ? username : "", (realname) ? realname : "",
+ (hostname) ? hostname : "", (command) ? command : "",
+ (autojoin) ? autojoin : "", (autorejoin) ? "on" : "off",
+ (notify_levels) ? notify_levels : "");
+#endif
+
+ if ((new_server = irc_server_alloc ()))
+ {
+ new_server->name = strdup (name);
+ new_server->autoconnect = autoconnect;
+ new_server->autoreconnect = autoreconnect;
+ new_server->autoreconnect_delay = autoreconnect_delay;
+ new_server->temp_server = temp_server;
+ new_server->address = strdup (address);
+ new_server->port = port;
+ new_server->ipv6 = ipv6;
+ new_server->ssl = ssl;
+ new_server->password = (password) ? strdup (password) : strdup ("");
+ new_server->nick1 = (nick1) ? strdup (nick1) : strdup ("weechat_user");
+ new_server->nick2 = (nick2) ? strdup (nick2) : strdup ("weechat2");
+ new_server->nick3 = (nick3) ? strdup (nick3) : strdup ("weechat3");
+ new_server->username =
+ (username) ? strdup (username) : strdup ("weechat");
+ new_server->realname =
+ (realname) ? strdup (realname) : strdup ("realname");
+ new_server->hostname =
+ (hostname) ? strdup (hostname) : NULL;
+ new_server->command =
+ (command) ? strdup (command) : NULL;
+ new_server->command_delay = command_delay;
+ new_server->autojoin =
+ (autojoin) ? strdup (autojoin) : NULL;
+ new_server->autorejoin = autorejoin;
+ new_server->notify_levels =
+ (notify_levels) ? strdup (notify_levels) : NULL;
+ }
+ else
+ return NULL;
+ return new_server;
+}
+
+/*
+ * irc_server_duplicate: duplicate a server
+ * return: pointer to new server, NULL if error
+ */
+
+t_irc_server *
+irc_server_duplicate (t_irc_server *server, char *new_name)
+{
+ t_irc_server *new_server;
+
+ /* check if another server exists with this name */
+ if (irc_server_search (new_name))
+ return 0;
+
+ /* duplicate server */
+ new_server = irc_server_new (new_name,
+ server->autoconnect,
+ server->autoreconnect,
+ server->autoreconnect_delay,
+ server->temp_server,
+ server->address,
+ server->port,
+ server->ipv6,
+ server->ssl,
+ server->password,
+ server->nick1,
+ server->nick2,
+ server->nick3,
+ server->username,
+ server->realname,
+ server->hostname,
+ server->command,
+ server->command_delay,
+ server->autojoin,
+ server->autorejoin,
+ server->notify_levels);
+
+ return new_server;
+}
+
+/*
+ * irc_server_rename: rename server (internal name)
+ * return: 1 if ok, 0 if error
+ */
+
+int
+irc_server_rename (t_irc_server *server, char *new_name)
+{
+ char *str;
+
+ /* check if another server exists with this name */
+ if (irc_server_search (new_name))
+ return 0;
+
+ /* rename server */
+ str = strdup (new_name);
+ if (str)
+ {
+ if (server->name)
+ free (server->name);
+ server->name = str;
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * irc_server_send: send data to IRC server
+ * return number of bytes sent, -1 if error
+ */
+
+int
+irc_server_send (t_irc_server *server, char *buffer, int size_buf)
+{
+ if (!server)
+ return -1;
+
+#ifdef HAVE_GNUTLS
+ if (server->ssl_connected)
+ return gnutls_record_send (server->gnutls_sess, buffer, size_buf);
+ else
+#endif
+ return send (server->sock, buffer, size_buf, 0);
+}
+
+/*
+ * irc_server_outqueue_send: send a message from outqueue
+ */
+
+void
+irc_server_outqueue_send (t_irc_server *server)
+{
+ time_t time_now;
+ char *pos;
+
+ if (server->outqueue)
+ {
+ time_now = time (NULL);
+ if (time_now >= server->last_user_message + cfg_irc_anti_flood)
+ {
+ if (server->outqueue->message_before_mod)
+ {
+ pos = strchr (server->outqueue->message_before_mod, '\r');
+ if (pos)
+ pos[0] = '\0';
+ gui_printf_raw_data (server, 1, 0,
+ server->outqueue->message_before_mod);
+ if (pos)
+ pos[0] = '\r';
+ }
+ if (server->outqueue->message_after_mod)
+ {
+ pos = strchr (server->outqueue->message_after_mod, '\r');
+ if (pos)
+ pos[0] = '\0';
+ gui_printf_raw_data (server, 1, server->outqueue->modified,
+ server->outqueue->message_after_mod);
+ if (pos)
+ pos[0] = '\r';
+ }
+ if (irc_server_send (server, server->outqueue->message_after_mod,
+ strlen (server->outqueue->message_after_mod)) <= 0)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf (server->buffer, _("%s error sending data to IRC server\n"),
+ WEECHAT_ERROR);
+ }
+ server->last_user_message = time_now;
+ irc_server_outqueue_free (server, server->outqueue);
+ }
+ }
+}
+
+/*
+ * irc_server_send_one_msg: send one message to IRC server
+ */
+
+int
+irc_server_send_one_msg (t_irc_server *server, char *message)
+{
+ static char buffer[4096];
+ char *new_msg, *ptr_msg, *pos;
+ int rc, queue, first_message;
+ time_t time_now;
+
+ rc = 1;
+
+#ifdef DEBUG
+ gui_printf (server->buffer, "[DEBUG] Sending to server >>> %s\n", message);
+#endif
+#ifdef PLUGINS
+ new_msg = plugin_modifier_exec (PLUGIN_MODIFIER_IRC_OUT,
+ server->name,
+ message);
+#else
+ new_msg = NULL;
+#endif
+
+ /* no changes in new message */
+ if (new_msg && (strcmp (buffer, new_msg) == 0))
+ {
+ free (new_msg);
+ new_msg = NULL;
+ }
+
+ /* message not dropped? */
+ if (!new_msg || new_msg[0])
+ {
+ first_message = 1;
+ ptr_msg = (new_msg) ? new_msg : message;
+
+ while (rc && ptr_msg && ptr_msg[0])
+ {
+ pos = strchr (ptr_msg, '\n');
+ if (pos)
+ pos[0] = '\0';
+
+ snprintf (buffer, sizeof (buffer) - 1, "%s\r\n", ptr_msg);
+
+ /* anti-flood: look whether we should queue outgoing message or not */
+ time_now = time (NULL);
+ queue = 0;
+ if ((server->queue_msg)
+ && ((server->outqueue)
+ || ((cfg_irc_anti_flood > 0)
+ && (time_now - server->last_user_message < cfg_irc_anti_flood))))
+ queue = 1;
+
+ /* if queue, then only queue message and send nothing now */
+ if (queue)
+ {
+ irc_server_outqueue_add (server,
+ (new_msg && first_message) ? message : NULL,
+ buffer,
+ (new_msg) ? 1 : 0);
+ }
+ else
+ {
+ if (first_message)
+ gui_printf_raw_data (server, 1, 0, message);
+ if (new_msg)
+ gui_printf_raw_data (server, 1, 1, ptr_msg);
+ if (irc_server_send (server, buffer, strlen (buffer)) <= 0)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf (server->buffer, _("%s error sending data to IRC server\n"),
+ WEECHAT_ERROR);
+ rc = 0;
+ }
+ else
+ {
+ if (server->queue_msg)
+ server->last_user_message = time_now;
+ }
+ }
+ if (pos)
+ {
+ pos[0] = '\n';
+ ptr_msg = pos + 1;
+ }
+ else
+ ptr_msg = NULL;
+
+ first_message = 0;
+ }
+ }
+ else
+ gui_printf_raw_data (server, 1, 1, _("(message dropped)"));
+ if (new_msg)
+ free (new_msg);
+
+ return rc;
+}
+
+/*
+ * irc_server_sendf: send formatted data to IRC server
+ * many messages may be sent, separated by '\n'
+ */
+
+void
+irc_server_sendf (t_irc_server *server, char *fmt, ...)
+{
+ va_list args;
+ static char buffer[4096];
+ char *ptr_buf, *pos;
+ int rc;
+
+ if (!server)
+ return;
+
+ va_start (args, fmt);
+ vsnprintf (buffer, sizeof (buffer) - 1, fmt, args);
+ va_end (args);
+
+ ptr_buf = buffer;
+ while (ptr_buf && ptr_buf[0])
+ {
+ pos = strchr (ptr_buf, '\n');
+ if (pos)
+ pos[0] = '\0';
+
+ rc = irc_server_send_one_msg (server, ptr_buf);
+
+ if (pos)
+ {
+ pos[0] = '\n';
+ ptr_buf = pos + 1;
+ }
+ else
+ ptr_buf = NULL;
+
+ if (!rc)
+ ptr_buf = NULL;
+ }
+}
+
+/*
+ * irc_server_parse_message: parse IRC message and return pointer to
+ * host, command and arguments (if any)
+ */
+
+void
+irc_server_parse_message (char *message, char **host, char **command, char **args)
+{
+ char *pos, *pos2;
+
+ *host = NULL;
+ *command = NULL;
+ *args = NULL;
+
+ if (message[0] == ':')
+ {
+ pos = strchr (message, ' ');
+ if (pos)
+ {
+ *host = strndup (message + 1, pos - (message + 1));
+ pos++;
+ }
+ else
+ pos = message;
+ }
+ else
+ pos = message;
+
+ if (pos && pos[0])
+ {
+ while (pos[0] == ' ')
+ pos++;
+ pos2 = strchr (pos, ' ');
+ if (pos2)
+ {
+ *command = strndup (pos, pos2 - pos);
+ pos2++;
+ while (pos2[0] == ' ')
+ pos2++;
+ *args = strdup (pos2);
+ }
+ }
+}
+
+/*
+ * irc_server_msgq_add_msg: add a message to received messages queue (at the end)
+ */
+
+void
+irc_server_msgq_add_msg (t_irc_server *server, char *msg)
+{
+ t_irc_message *message;
+
+ if (!server->unterminated_message && !msg[0])
+ return;
+
+ message = (t_irc_message *) malloc (sizeof (t_irc_message));
+ if (!message)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf (server->buffer,
+ _("%s not enough memory for received IRC message\n"),
+ WEECHAT_ERROR);
+ return;
+ }
+ message->server = server;
+ if (server->unterminated_message)
+ {
+ message->data = (char *) malloc (strlen (server->unterminated_message) +
+ strlen (msg) + 1);
+ if (!message->data)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf (server->buffer,
+ _("%s not enough memory for received IRC message\n"),
+ WEECHAT_ERROR);
+ }
+ else
+ {
+ strcpy (message->data, server->unterminated_message);
+ strcat (message->data, msg);
+ }
+ free (server->unterminated_message);
+ server->unterminated_message = NULL;
+ }
+ else
+ message->data = strdup (msg);
+ message->next_message = NULL;
+
+ if (irc_msgq_last_msg)
+ {
+ irc_msgq_last_msg->next_message = message;
+ irc_msgq_last_msg = message;
+ }
+ else
+ {
+ irc_recv_msgq = message;
+ irc_msgq_last_msg = message;
+ }
+}
+
+/*
+ * irc_server_msgq_add_unterminated: add an unterminated message to queue
+ */
+
+void
+irc_server_msgq_add_unterminated (t_irc_server *server, char *string)
+{
+ if (!string[0])
+ return;
+
+ if (server->unterminated_message)
+ {
+ server->unterminated_message =
+ (char *) realloc (server->unterminated_message,
+ strlen (server->unterminated_message) +
+ strlen (string) + 1);
+ if (!server->unterminated_message)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf (server->buffer,
+ _("%s not enough memory for received IRC message\n"),
+ WEECHAT_ERROR);
+ }
+ else
+ strcat (server->unterminated_message, string);
+ }
+ else
+ {
+ server->unterminated_message = strdup (string);
+ if (!server->unterminated_message)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf (server->buffer,
+ _("%s not enough memory for received IRC message\n"),
+ WEECHAT_ERROR);
+ }
+ }
+}
+
+/*
+ * irc_server_msgq_add_buffer: explode received buffer, creating queued messages
+ */
+
+void
+irc_server_msgq_add_buffer (t_irc_server *server, char *buffer)
+{
+ char *pos_cr, *pos_lf;
+
+ while (buffer[0])
+ {
+ pos_cr = strchr (buffer, '\r');
+ pos_lf = strchr (buffer, '\n');
+
+ if (!pos_cr && !pos_lf)
+ {
+ /* no CR/LF found => add to unterminated and return */
+ irc_server_msgq_add_unterminated (server, buffer);
+ return;
+ }
+
+ if (pos_cr && ((!pos_lf) || (pos_lf > pos_cr)))
+ {
+ /* found '\r' first => ignore this char */
+ pos_cr[0] = '\0';
+ irc_server_msgq_add_unterminated (server, buffer);
+ buffer = pos_cr + 1;
+ }
+ else
+ {
+ /* found: '\n' first => terminate message */
+ pos_lf[0] = '\0';
+ irc_server_msgq_add_msg (server, buffer);
+ buffer = pos_lf + 1;
+ }
+ }
+}
+
+/*
+ * irc_server_msgq_flush: flush message queue
+ */
+
+void
+irc_server_msgq_flush ()
+{
+ t_irc_message *next;
+ char *ptr_data, *new_msg, *ptr_msg, *pos;
+ char *host, *command, *args;
+
+ while (irc_recv_msgq)
+ {
+ if (irc_recv_msgq->data)
+ {
+#ifdef DEBUG
+ gui_printf (gui_current_window->buffer, "[DEBUG] %s\n", irc_recv_msgq->data);
+#endif
+ ptr_data = irc_recv_msgq->data;
+ while (ptr_data[0] == ' ')
+ ptr_data++;
+
+ if (ptr_data[0])
+ {
+ gui_printf_raw_data (irc_recv_msgq->server, 0, 0, ptr_data);
+#ifdef DEBUG
+ gui_printf (NULL, "[DEBUG] data received from server: %s\n", ptr_data);
+#endif
+#ifdef PLUGINS
+ new_msg = plugin_modifier_exec (PLUGIN_MODIFIER_IRC_IN,
+ irc_recv_msgq->server->name,
+ ptr_data);
+#else
+ new_msg = NULL;
+#endif
+ /* no changes in new message */
+ if (new_msg && (strcmp (ptr_data, new_msg) == 0))
+ {
+ free (new_msg);
+ new_msg = NULL;
+ }
+
+ /* message not dropped? */
+ if (!new_msg || new_msg[0])
+ {
+ /* use new message (returned by plugin) */
+ ptr_msg = (new_msg) ? new_msg : ptr_data;
+
+ while (ptr_msg && ptr_msg[0])
+ {
+ pos = strchr (ptr_msg, '\n');
+ if (pos)
+ pos[0] = '\0';
+
+ if (new_msg)
+ gui_printf_raw_data (irc_recv_msgq->server, 0, 1, ptr_msg);
+
+ irc_server_parse_message (ptr_msg, &host, &command, &args);
+
+ switch (irc_recv_command (irc_recv_msgq->server, ptr_msg, host, command, args))
+ {
+ case -1:
+ irc_display_prefix (irc_recv_msgq->server,
+ irc_recv_msgq->server->buffer, GUI_PREFIX_ERROR);
+ gui_printf (irc_recv_msgq->server->buffer,
+ _("%s Command \"%s\" failed!\n"), WEECHAT_ERROR, command);
+ break;
+ case -2:
+ irc_display_prefix (irc_recv_msgq->server,
+ irc_recv_msgq->server->buffer, GUI_PREFIX_ERROR);
+ gui_printf (irc_recv_msgq->server->buffer,
+ _("%s No command to execute!\n"), WEECHAT_ERROR);
+ break;
+ case -3:
+ irc_display_prefix (irc_recv_msgq->server,
+ irc_recv_msgq->server->buffer, GUI_PREFIX_ERROR);
+ gui_printf (irc_recv_msgq->server->buffer,
+ _("%s Unknown command: cmd=\"%s\", host=\"%s\", args=\"%s\"\n"),
+ WEECHAT_WARNING, command, host, args);
+ break;
+ }
+ if (host)
+ free (host);
+ if (command)
+ free (command);
+ if (args)
+ free (args);
+
+ if (pos)
+ {
+ pos[0] = '\n';
+ ptr_msg = pos + 1;
+ }
+ else
+ ptr_msg = NULL;
+ }
+ }
+ else
+ gui_printf_raw_data (irc_recv_msgq->server, 0, 1, _("(message dropped)"));
+ if (new_msg)
+ free (new_msg);
+ }
+ free (irc_recv_msgq->data);
+ }
+
+ next = irc_recv_msgq->next_message;
+ free (irc_recv_msgq);
+ irc_recv_msgq = next;
+ if (irc_recv_msgq == NULL)
+ irc_msgq_last_msg = NULL;
+ }
+}
+
+/*
+ * irc_server_recv: receive data from an irc server
+ */
+
+void
+irc_server_recv (t_irc_server *server)
+{
+ static char buffer[4096 + 2];
+ int num_read;
+
+ if (!server)
+ return;
+
+#ifdef HAVE_GNUTLS
+ if (server->ssl_connected)
+ num_read = gnutls_record_recv (server->gnutls_sess, buffer, sizeof (buffer) - 2);
+ else
+#endif
+ num_read = recv (server->sock, buffer, sizeof (buffer) - 2, 0);
+
+ if (num_read > 0)
+ {
+ buffer[num_read] = '\0';
+ irc_server_msgq_add_buffer (server, buffer);
+ irc_server_msgq_flush ();
+ }
+ else
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf (server->buffer,
+ _("%s cannot read data from socket, disconnecting from server...\n"),
+ WEECHAT_ERROR);
+ irc_server_disconnect (server, 1);
+ }
+}
+
+/*
+ * irc_server_child_kill: kill child process and close pipe
+ */
+
+void
+irc_server_child_kill (t_irc_server *server)
+{
+ /* kill process */
+ if (server->child_pid > 0)
+ {
+ kill (server->child_pid, SIGKILL);
+ waitpid (server->child_pid, NULL, 0);
+ server->child_pid = 0;
+ }
+
+ /* close pipe used with child */
+ if (server->child_read != -1)
+ {
+ close (server->child_read);
+ server->child_read = -1;
+ }
+ if (server->child_write != -1)
+ {
+ close (server->child_write);
+ server->child_write = -1;
+ }
+}
+
+/*
+ * irc_server_close_connection: close server connection
+ * (kill child, close socket/pipes)
+ */
+
+void
+irc_server_close_connection (t_irc_server *server)
+{
+ irc_server_child_kill (server);
+
+ /* close network socket */
+ if (server->sock != -1)
+ {
+#ifdef HAVE_GNUTLS
+ if (server->ssl_connected)
+ gnutls_bye (server->gnutls_sess, GNUTLS_SHUT_WR);
+#endif
+ close (server->sock);
+ server->sock = -1;
+#ifdef HAVE_GNUTLS
+ if (server->ssl_connected)
+ gnutls_deinit (server->gnutls_sess);
+#endif
+ }
+
+ /* free any pending message */
+ if (server->unterminated_message)
+ {
+ free (server->unterminated_message);
+ server->unterminated_message = NULL;
+ }
+ irc_server_outqueue_free_all (server);
+
+ /* server is now disconnected */
+ server->is_connected = 0;
+ server->ssl_connected = 0;
+}
+
+/*
+ * irc_server_reconnect_schedule: schedule reconnect for a server
+ */
+
+void
+irc_server_reconnect_schedule (t_irc_server *server)
+{
+ if (server->autoreconnect)
+ {
+ server->reconnect_start = time (NULL);
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_INFO);
+ gui_printf (server->buffer, _("%s: Reconnecting to server in %d seconds\n"),
+ PACKAGE_NAME, server->autoreconnect_delay);
+ }
+ else
+ server->reconnect_start = 0;
+}
+
+/*
+ * irc_server_child_read: read connection progress from child process
+ */
+
+void
+irc_server_child_read (t_irc_server *server)
+{
+ char buffer[1];
+ int num_read;
+
+ num_read = read (server->child_read, buffer, sizeof (buffer));
+ if (num_read > 0)
+ {
+ switch (buffer[0])
+ {
+ /* connection OK */
+ case '0':
+ /* enable SSL if asked */
+#ifdef HAVE_GNUTLS
+ if (server->ssl_connected)
+ {
+ gnutls_transport_set_ptr (server->gnutls_sess,
+ (gnutls_transport_ptr) ((unsigned long) server->sock));
+ if (gnutls_handshake (server->gnutls_sess) < 0)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf (server->buffer,
+ _("%s gnutls handshake failed\n"),
+ WEECHAT_ERROR);
+ irc_server_close_connection (server);
+ irc_server_reconnect_schedule (server);
+ return;
+ }
+ }
+#endif
+ /* kill child and login to server */
+ irc_server_child_kill (server);
+ irc_send_login (server);
+ break;
+ /* adress not found */
+ case '1':
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ if (cfg_proxy_use)
+ gui_printf (server->buffer,
+ _("%s proxy address \"%s\" not found\n"),
+ WEECHAT_ERROR, server->address);
+ else
+ gui_printf (server->buffer,
+ _("%s address \"%s\" not found\n"),
+ WEECHAT_ERROR, server->address);
+ irc_server_close_connection (server);
+ irc_server_reconnect_schedule (server);
+ break;
+ /* IP address not found */
+ case '2':
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ if (cfg_proxy_use)
+ gui_printf (server->buffer,
+ _("%s proxy IP address not found\n"), WEECHAT_ERROR);
+ else
+ gui_printf (server->buffer,
+ _("%s IP address not found\n"), WEECHAT_ERROR);
+ irc_server_close_connection (server);
+ irc_server_reconnect_schedule (server);
+ break;
+ /* connection refused */
+ case '3':
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ if (cfg_proxy_use)
+ gui_printf (server->buffer,
+ _("%s proxy connection refused\n"), WEECHAT_ERROR);
+ else
+ gui_printf (server->buffer,
+ _("%s connection refused\n"), WEECHAT_ERROR);
+ irc_server_close_connection (server);
+ irc_server_reconnect_schedule (server);
+ break;
+ /* proxy fails to connect to server */
+ case '4':
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf (server->buffer,
+ _("%s proxy fails to establish connection to "
+ "server (check username/password if used)\n"),
+ WEECHAT_ERROR);
+ irc_server_close_connection (server);
+ irc_server_reconnect_schedule (server);
+ break;
+ /* fails to set local hostname/IP */
+ case '5':
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf (server->buffer,
+ _("%s unable to set local hostname/IP\n"),
+ WEECHAT_ERROR);
+ irc_server_close_connection (server);
+ irc_server_reconnect_schedule (server);
+ break;
+ }
+ }
+}
+
+/*
+ * irc_server_convbase64_8x3_to_6x4 : convert 3 bytes of 8 bits in 4 bytes of 6 bits
+ */
+
+void
+irc_server_convbase64_8x3_to_6x4 (char *from, char* to)
+{
+ unsigned char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+ to[0] = base64_table [ (from[0] & 0xfc) >> 2 ];
+ to[1] = base64_table [ ((from[0] & 0x03) << 4) + ((from[1] & 0xf0) >> 4) ];
+ to[2] = base64_table [ ((from[1] & 0x0f) << 2) + ((from[2] & 0xc0) >> 6) ];
+ to[3] = base64_table [ from[2] & 0x3f ];
+}
+
+/*
+ * irc_server_base64encode: encode a string in base64
+ */
+
+void
+irc_server_base64encode (char *from, char *to)
+{
+ char *f, *t;
+ int from_len;
+
+ from_len = strlen(from);
+
+ f = from;
+ t = to;
+
+ while (from_len >= 3)
+ {
+ irc_server_convbase64_8x3_to_6x4 (f, t);
+ f += 3 * sizeof (*f);
+ t += 4 * sizeof (*t);
+ from_len -= 3;
+ }
+
+ if (from_len > 0)
+ {
+ char rest[3] = { 0, 0, 0 };
+ switch (from_len)
+ {
+ case 1 :
+ rest[0] = f[0];
+ irc_server_convbase64_8x3_to_6x4 (rest, t);
+ t[2] = t[3] = '=';
+ break;
+ case 2 :
+ rest[0] = f[0];
+ rest[1] = f[1];
+ irc_server_convbase64_8x3_to_6x4 (rest, t);
+ t[3] = '=';
+ break;
+ }
+ t[4] = 0;
+ }
+}
+
+/*
+ * irc_server_pass_httpproxy: establish connection/authentification to an
+ * http proxy
+ * return :
+ * - 0 if connexion throw proxy was successful
+ * - 1 if connexion fails
+ */
+
+int
+irc_server_pass_httpproxy (int sock, char *address, int port)
+{
+
+ char buffer[256];
+ char authbuf[128];
+ char authbuf_base64[196];
+ int n, m;
+
+ if (cfg_proxy_username && cfg_proxy_username[0])
+ {
+ /* authentification */
+ snprintf (authbuf, sizeof (authbuf), "%s:%s",
+ cfg_proxy_username, cfg_proxy_password);
+ irc_server_base64encode (authbuf, authbuf_base64);
+ n = snprintf (buffer, sizeof (buffer),
+ "CONNECT %s:%d HTTP/1.0\r\nProxy-Authorization: Basic %s\r\n\r\n",
+ address, port, authbuf_base64);
+ }
+ else
+ {
+ /* no authentification */
+ n = snprintf (buffer, sizeof (buffer),
+ "CONNECT %s:%d HTTP/1.0\r\n\r\n", address, port);
+ }
+
+ m = send (sock, buffer, n, 0);
+ if (n != m)
+ return 1;
+
+ n = recv (sock, buffer, sizeof (buffer), 0);
+
+ /* success result must be like: "HTTP/1.0 200 OK" */
+ if (n < 12)
+ return 1;
+
+ if (memcmp (buffer, "HTTP/", 5) || memcmp (buffer + 9, "200", 3))
+ return 1;
+
+ return 0;
+}
+
+/*
+ * irc_server_resolve: resolve hostname on its IP address
+ * (works with ipv4 and ipv6)
+ * return :
+ * - 0 if resolution was successful
+ * - 1 if resolution fails
+ */
+
+int
+irc_server_resolve (char *hostname, char *ip, int *version)
+{
+ char ipbuffer[NI_MAXHOST];
+ struct addrinfo *res;
+
+ if (version != NULL)
+ *version = 0;
+
+ res = NULL;
+
+ if (getaddrinfo (hostname, NULL, NULL, &res) != 0)
+ return 1;
+
+ if (!res)
+ return 1;
+
+ if (getnameinfo (res->ai_addr, res->ai_addrlen, ipbuffer, sizeof(ipbuffer), NULL, 0, NI_NUMERICHOST) != 0)
+ {
+ freeaddrinfo (res);
+ return 1;
+ }
+
+ if ((res->ai_family == AF_INET) && (version != NULL))
+ *version = 4;
+ if ((res->ai_family == AF_INET6) && (version != NULL))
+ *version = 6;
+
+ strcpy (ip, ipbuffer);
+
+ freeaddrinfo (res);
+
+ return 0;
+}
+
+/*
+ * irc_server_pass_socks4proxy: establish connection/authentification thru a
+ * socks4 proxy
+ * return :
+ * - 0 if connexion thru proxy was successful
+ * - 1 if connexion fails
+ */
+
+int
+irc_server_pass_socks4proxy (int sock, char *address, int port, char *username)
+{
+ /*
+ * socks4 protocol is explained here:
+ * http://archive.socks.permeo.com/protocol/socks4.protocol
+ *
+ */
+
+ struct s_socks4
+ {
+ char version; /* 1 byte */ /* socks version : 4 or 5 */
+ char method; /* 1 byte */ /* socks method : connect (1) or bind (2) */
+ unsigned short port; /* 2 bytes */ /* destination port */
+ unsigned long address; /* 4 bytes */ /* destination address */
+ char user[64]; /* username (64 characters seems to be enought) */
+ } socks4;
+ unsigned char buffer[24];
+ char ip_addr[NI_MAXHOST];
+
+ socks4.version = 4;
+ socks4.method = 1;
+ socks4.port = htons (port);
+ irc_server_resolve (address, ip_addr, NULL);
+ socks4.address = inet_addr (ip_addr);
+ strncpy (socks4.user, username, sizeof (socks4.user) - 1);
+
+ send (sock, (char *) &socks4, 8 + strlen (socks4.user) + 1, 0);
+ recv (sock, buffer, sizeof (buffer), 0);
+
+ if (buffer[0] == 0 && buffer[1] == 90)
+ return 0;
+
+ return 1;
+}
+
+/*
+ * irc_server_pass_socks5proxy: establish connection/authentification thru a
+ * socks5 proxy
+ * return :
+ * - 0 if connexion thru proxy was successful
+ * - 1 if connexion fails
+ */
+
+int
+irc_server_pass_socks5proxy (int sock, char *address, int port)
+{
+ /*
+ * socks5 protocol is explained in RFC 1928
+ * socks5 authentication with username/pass is explained in RFC 1929
+ */
+
+ struct s_sock5
+ {
+ char version; /* 1 byte */ /* socks version : 4 or 5 */
+ char nmethods; /* 1 byte */ /* size in byte(s) of field 'method', here 1 byte */
+ char method; /* 1-255 bytes */ /* socks method : noauth (0), auth(user/pass) (2), ... */
+ } socks5;
+ unsigned char buffer[288];
+ int username_len, password_len, addr_len, addr_buffer_len;
+ unsigned char *addr_buffer;
+
+ socks5.version = 5;
+ socks5.nmethods = 1;
+
+ if (cfg_proxy_username && cfg_proxy_username[0])
+ socks5.method = 2; /* with authentication */
+ else
+ socks5.method = 0; /* without authentication */
+
+ send (sock, (char *) &socks5, sizeof(socks5), 0);
+ /* server socks5 must respond with 2 bytes */
+ if (recv (sock, buffer, 2, 0) != 2)
+ return 1;
+
+ if (cfg_proxy_username && cfg_proxy_username[0])
+ {
+ /* with authentication */
+ /* -> socks server must respond with :
+ * - socks version (buffer[0]) = 5 => socks5
+ * - socks method (buffer[1]) = 2 => authentication
+ */
+
+ if (buffer[0] != 5 || buffer[1] != 2)
+ return 1;
+
+ /* authentication as in RFC 1929 */
+ username_len = strlen(cfg_proxy_username);
+ password_len = strlen(cfg_proxy_password);
+
+ /* make username/password buffer */
+ buffer[0] = 1;
+ buffer[1] = (unsigned char) username_len;
+ memcpy(buffer + 2, cfg_proxy_username, username_len);
+ buffer[2 + username_len] = (unsigned char) password_len;
+ memcpy (buffer + 3 + username_len, cfg_proxy_password, password_len);
+
+ send (sock, buffer, 3 + username_len + password_len, 0);
+
+ /* server socks5 must respond with 2 bytes */
+ if (recv (sock, buffer, 2, 0) != 2)
+ return 1;
+
+ /* buffer[1] = auth state, must be 0 for success */
+ if (buffer[1] != 0)
+ return 1;
+ }
+ else
+ {
+ /* without authentication */
+ /* -> socks server must respond with :
+ * - socks version (buffer[0]) = 5 => socks5
+ * - socks method (buffer[1]) = 0 => no authentication
+ */
+ if (!(buffer[0] == 5 && buffer[1] == 0))
+ return 1;
+ }
+
+ /* authentication successful then giving address/port to connect */
+ addr_len = strlen(address);
+ addr_buffer_len = 4 + 1 + addr_len + 2;
+ addr_buffer = (unsigned char *) malloc (addr_buffer_len * sizeof(*addr_buffer));
+ if (!addr_buffer)
+ return 1;
+ addr_buffer[0] = 5; /* version 5 */
+ addr_buffer[1] = 1; /* command: 1 for connect */
+ addr_buffer[2] = 0; /* reserved */
+ addr_buffer[3] = 3; /* address type : ipv4 (1), domainname (3), ipv6 (4) */
+ addr_buffer[4] = (unsigned char) addr_len;
+ memcpy (addr_buffer + 5, address, addr_len); /* server address */
+ *((unsigned short *) (addr_buffer + 5 + addr_len)) = htons (port); /* server port */
+
+ send (sock, addr_buffer, addr_buffer_len, 0);
+ free (addr_buffer);
+
+ /* dialog with proxy server */
+ if (recv (sock, buffer, 4, 0) != 4)
+ return 1;
+
+ if (!(buffer[0] == 5 && buffer[1] == 0))
+ return 1;
+
+ /* buffer[3] = address type */
+ switch(buffer[3])
+ {
+ case 1 :
+ /* ipv4
+ * server socks return server bound address and port
+ * address of 4 bytes and port of 2 bytes (= 6 bytes)
+ */
+ if (recv (sock, buffer, 6, 0) != 6)
+ return 1;
+ break;
+ case 3:
+ /* domainname
+ * server socks return server bound address and port
+ */
+ /* reading address length */
+ if (recv (sock, buffer, 1, 0) != 1)
+ return 1;
+ addr_len = buffer[0];
+ /* reading address + port = addr_len + 2 */
+ if (recv (sock, buffer, addr_len + 2, 0) != (addr_len + 2))
+ return 1;
+ break;
+ case 4 :
+ /* ipv6
+ * server socks return server bound address and port
+ * address of 16 bytes and port of 2 bytes (= 18 bytes)
+ */
+ if (recv (sock, buffer, 18, 0) != 18)
+ return 1;
+ break;
+ default:
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * irc_server_pass_proxy: establish connection/authentification to a proxy
+ * return :
+ * - 0 if connexion throw proxy was successful
+ * - 1 if connexion fails
+ */
+
+int
+irc_server_pass_proxy (int sock, char *address, int port, char *username)
+{
+ if (strcmp (cfg_proxy_type_values[cfg_proxy_type], "http") == 0)
+ return irc_server_pass_httpproxy (sock, address, port);
+ if (strcmp (cfg_proxy_type_values[cfg_proxy_type], "socks4") == 0)
+ return irc_server_pass_socks4proxy (sock, address, port, username);
+ if (strcmp (cfg_proxy_type_values[cfg_proxy_type], "socks5") == 0)
+ return irc_server_pass_socks5proxy (sock, address, port);
+
+ return 1;
+}
+
+/*
+ * irc_server_child: child process trying to connect to server
+ */
+
+int
+irc_server_child (t_irc_server *server)
+{
+ struct addrinfo hints, *res, *res_local;
+ int rc;
+
+ res = NULL;
+ res_local = NULL;
+
+ if (cfg_proxy_use)
+ {
+ /* get info about server */
+ memset (&hints, 0, sizeof (hints));
+ hints.ai_family = (cfg_proxy_ipv6) ? AF_INET6 : AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ if (getaddrinfo (cfg_proxy_address, NULL, &hints, &res) !=0)
+ {
+ write(server->child_write, "1", 1);
+ return 0;
+ }
+ if (!res)
+ {
+ write(server->child_write, "1", 1);
+ return 0;
+ }
+ if ((cfg_proxy_ipv6 && (res->ai_family != AF_INET6))
+ || ((!cfg_proxy_ipv6 && (res->ai_family != AF_INET))))
+ {
+ write (server->child_write, "2", 1);
+ freeaddrinfo (res);
+ return 0;
+ }
+
+ if (cfg_proxy_ipv6)
+ ((struct sockaddr_in6 *)(res->ai_addr))->sin6_port = htons (cfg_proxy_port);
+ else
+ ((struct sockaddr_in *)(res->ai_addr))->sin_port = htons (cfg_proxy_port);
+
+ /* connect to server */
+ if (connect (server->sock, res->ai_addr, res->ai_addrlen) != 0)
+ {
+ write(server->child_write, "3", 1);
+ freeaddrinfo (res);
+ return 0;
+ }
+
+ if (irc_server_pass_proxy (server->sock, server->address, server->port, server->username))
+ {
+ write(server->child_write, "4", 1);
+ freeaddrinfo (res);
+ return 0;
+ }
+ }
+ else
+ {
+ /* set local hostname/IP if asked by user */
+ if (server->hostname && server->hostname[0])
+ {
+ memset (&hints, 0, sizeof(hints));
+ hints.ai_family = (server->ipv6) ? AF_INET6 : AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ rc = getaddrinfo (server->hostname, NULL, &hints, &res_local);
+ if ((rc != 0) || !res_local
+ || (server->ipv6 && (res_local->ai_family != AF_INET6))
+ || ((!server->ipv6 && (res_local->ai_family != AF_INET))))
+ {
+ write (server->child_write, "5", 1);
+ if (res_local)
+ freeaddrinfo (res_local);
+ return 0;
+ }
+ if (bind (server->sock, res_local->ai_addr, res_local->ai_addrlen) < 0)
+ {
+ write (server->child_write, "5", 1);
+ if (res_local)
+ freeaddrinfo (res_local);
+ return 0;
+ }
+ }
+
+ /* get info about server */
+ memset (&hints, 0, sizeof(hints));
+ hints.ai_family = (server->ipv6) ? AF_INET6 : AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ rc = getaddrinfo (server->address, NULL, &hints, &res);
+ if ((rc != 0) || !res)
+ {
+ write (server->child_write, "1", 1);
+ if (res)
+ freeaddrinfo (res);
+ return 0;
+ }
+ if ((server->ipv6 && (res->ai_family != AF_INET6))
+ || ((!server->ipv6 && (res->ai_family != AF_INET))))
+ {
+ write (server->child_write, "2", 1);
+ if (res)
+ freeaddrinfo (res);
+ if (res_local)
+ freeaddrinfo (res_local);
+ return 0;
+ }
+
+ /* connect to server */
+ if (server->ipv6)
+ ((struct sockaddr_in6 *)(res->ai_addr))->sin6_port = htons (server->port);
+ else
+ ((struct sockaddr_in *)(res->ai_addr))->sin_port = htons (server->port);
+
+ if (connect (server->sock, res->ai_addr, res->ai_addrlen) != 0)
+ {
+ write (server->child_write, "3", 1);
+ if (res)
+ freeaddrinfo (res);
+ if (res_local)
+ freeaddrinfo (res_local);
+ return 0;
+ }
+ }
+
+ write (server->child_write, "0", 1);
+ if (res)
+ freeaddrinfo (res);
+ if (res_local)
+ freeaddrinfo (res_local);
+ return 0;
+}
+
+/*
+ * irc_server_connect: connect to an IRC server
+ */
+
+int
+irc_server_connect (t_irc_server *server, int disable_autojoin)
+{
+ int child_pipe[2], set;
+#ifndef __CYGWIN__
+ pid_t pid;
+#endif
+
+#ifndef HAVE_GNUTLS
+ if (server->ssl)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf (server->buffer,
+ _("%s cannot connect with SSL since WeeChat was not built "
+ "with GNUtls support\n"), WEECHAT_ERROR);
+ return 0;
+ }
+#endif
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_INFO);
+ if (cfg_proxy_use)
+ {
+ gui_printf (server->buffer,
+ _("%s: connecting to server %s:%d%s%s via %s proxy %s:%d%s...\n"),
+ PACKAGE_NAME, server->address, server->port,
+ (server->ipv6) ? " (IPv6)" : "",
+ (server->ssl) ? " (SSL)" : "",
+ cfg_proxy_type_values[cfg_proxy_type], cfg_proxy_address, cfg_proxy_port,
+ (cfg_proxy_ipv6) ? " (IPv6)" : "");
+ weechat_log_printf (_("Connecting to server %s:%d%s%s via %s proxy %s:%d%s...\n"),
+ server->address, server->port,
+ (server->ipv6) ? " (IPv6)" : "",
+ (server->ssl) ? " (SSL)" : "",
+ cfg_proxy_type_values[cfg_proxy_type], cfg_proxy_address, cfg_proxy_port,
+ (cfg_proxy_ipv6) ? " (IPv6)" : "");
+ }
+ else
+ {
+ gui_printf (server->buffer,
+ _("%s: connecting to server %s:%d%s%s...\n"),
+ PACKAGE_NAME, server->address, server->port,
+ (server->ipv6) ? " (IPv6)" : "",
+ (server->ssl) ? " (SSL)" : "");
+ weechat_log_printf (_("Connecting to server %s:%d%s%s...\n"),
+ server->address, server->port,
+ (server->ipv6) ? " (IPv6)" : "",
+ (server->ssl) ? " (SSL)" : "");
+ }
+
+ /* close any opened connection and kill child process if running */
+ irc_server_close_connection (server);
+
+ /* init SSL if asked */
+ server->ssl_connected = 0;
+#ifdef HAVE_GNUTLS
+ if (server->ssl)
+ {
+ if (gnutls_init (&server->gnutls_sess, GNUTLS_CLIENT) != 0)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf (server->buffer,
+ _("%s gnutls init error\n"), WEECHAT_ERROR);
+ return 0;
+ }
+ gnutls_set_default_priority (server->gnutls_sess);
+ gnutls_certificate_type_set_priority (server->gnutls_sess, gnutls_cert_type_prio);
+ gnutls_protocol_set_priority (server->gnutls_sess, gnutls_prot_prio);
+ gnutls_credentials_set (server->gnutls_sess, GNUTLS_CRD_CERTIFICATE, gnutls_xcred);
+ server->ssl_connected = 1;
+ }
+#endif
+
+ /* create pipe for child process */
+ if (pipe (child_pipe) < 0)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf (server->buffer,
+ _("%s cannot create pipe\n"), WEECHAT_ERROR);
+ return 0;
+ }
+ server->child_read = child_pipe[0];
+ server->child_write = child_pipe[1];
+
+ /* create socket and set options */
+ if (cfg_proxy_use)
+ server->sock = socket ((cfg_proxy_ipv6) ? AF_INET6 : AF_INET, SOCK_STREAM, 0);
+ else
+ server->sock = socket ((server->ipv6) ? AF_INET6 : AF_INET, SOCK_STREAM, 0);
+ if (server->sock == -1)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf (server->buffer,
+ _("%s cannot create socket\n"), WEECHAT_ERROR);
+ return 0;
+ }
+
+ /* set SO_REUSEADDR option for socket */
+ set = 1;
+ if (setsockopt (server->sock, SOL_SOCKET, SO_REUSEADDR,
+ (void *) &set, sizeof (set)) == -1)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf (server->buffer,
+ _("%s cannot set socket option \"SO_REUSEADDR\"\n"),
+ WEECHAT_WARNING);
+ }
+
+ /* set SO_KEEPALIVE option for socket */
+ set = 1;
+ if (setsockopt (server->sock, SOL_SOCKET, SO_KEEPALIVE,
+ (void *) &set, sizeof (set)) == -1)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_ERROR);
+ gui_printf (server->buffer,
+ _("%s cannot set socket option \"SO_KEEPALIVE\"\n"),
+ WEECHAT_WARNING);
+ }
+
+#ifdef __CYGWIN__
+ /* connection may block under Cygwin, there's no other known way
+ to do better today, since connect() in child process seems not to work
+ any suggestion is welcome to improve that!
+ */
+ irc_server_child (server);
+ server->child_pid = 0;
+ irc_server_child_read (server);
+#else
+ switch (pid = fork ())
+ {
+ /* fork failed */
+ case -1:
+ irc_server_close_connection (server);
+ return 0;
+ /* child process */
+ case 0:
+ setuid (getuid ());
+ irc_server_child (server);
+ _exit (EXIT_SUCCESS);
+ }
+ /* parent process */
+ server->child_pid = pid;
+#endif
+
+ server->disable_autojoin = disable_autojoin;
+
+ return 1;
+}
+
+/*
+ * irc_server_reconnect: reconnect to a server (after disconnection)
+ */
+
+void
+irc_server_reconnect (t_irc_server *server)
+{
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_INFO);
+ gui_printf (server->buffer, _("%s: Reconnecting to server...\n"),
+ PACKAGE_NAME);
+ server->reconnect_start = 0;
+
+ if (irc_server_connect (server, 0))
+ server->reconnect_join = 1;
+ else
+ irc_server_reconnect_schedule (server);
+}
+
+/*
+ * irc_server_auto_connect: auto-connect to servers (called at startup)
+ */
+
+void
+irc_server_auto_connect (int auto_connect, int temp_server)
+{
+ t_irc_server *ptr_server;
+
+ for (ptr_server = irc_servers; ptr_server;
+ ptr_server = ptr_server->next_server)
+ {
+ if ( ((temp_server) && (ptr_server->temp_server))
+ || ((!temp_server) && (auto_connect) && (ptr_server->autoconnect)) )
+ {
+ (void) gui_buffer_new (gui_current_window, ptr_server, NULL,
+ GUI_BUFFER_TYPE_STANDARD, 1);
+ gui_window_redraw_buffer (gui_current_window->buffer);
+ if (!irc_server_connect (ptr_server, 0))
+ irc_server_reconnect_schedule (ptr_server);
+ }
+ }
+}
+
+/*
+ * irc_server_disconnect: disconnect from an irc server
+ */
+
+void
+irc_server_disconnect (t_irc_server *server, int reconnect)
+{
+ t_irc_channel *ptr_channel;
+
+ if (server->is_connected)
+ {
+ /* write disconnection message on each channel/private buffer */
+ for (ptr_channel = server->channels; ptr_channel;
+ ptr_channel = ptr_channel->next_channel)
+ {
+ irc_nick_free_all (ptr_channel);
+ irc_display_prefix (NULL, ptr_channel->buffer, GUI_PREFIX_INFO);
+ gui_printf (ptr_channel->buffer, _("Disconnected from server!\n"));
+ gui_nicklist_draw (ptr_channel->buffer, 1, 1);
+ gui_status_draw (ptr_channel->buffer, 1);
+ }
+ }
+
+ irc_server_close_connection (server);
+
+ if (server->buffer)
+ {
+ irc_display_prefix (server, server->buffer, GUI_PREFIX_INFO);
+ gui_printf (server->buffer, _("Disconnected from server!\n"));
+ }
+
+ if (server->nick_modes)
+ {
+ free (server->nick_modes);
+ server->nick_modes = NULL;
+ }
+ if (server->prefix)
+ {
+ free (server->prefix);
+ server->prefix = NULL;
+ }
+ server->is_away = 0;
+ server->away_time = 0;
+ server->lag = 0;
+ server->lag_check_time.tv_sec = 0;
+ server->lag_check_time.tv_usec = 0;
+ server->lag_next_check = time (NULL) + cfg_irc_lag_check;
+
+ if ((reconnect) && (server->autoreconnect))
+ irc_server_reconnect_schedule (server);
+ else
+ server->reconnect_start = 0;
+
+ /* discard current nick if no reconnection asked */
+ if (!reconnect && server->nick)
+ {
+ free (server->nick);
+ server->nick = NULL;
+ }
+
+ gui_window_redraw_buffer (gui_current_window->buffer);
+}
+
+/*
+ * irc_server_disconnect_all: disconnect from all irc servers
+ */
+
+void
+irc_server_disconnect_all ()
+{
+ t_irc_server *ptr_server;
+
+ for (ptr_server = irc_servers; ptr_server; ptr_server = ptr_server->next_server)
+ irc_server_disconnect (ptr_server, 0);
+}
+
+/*
+ * irc_server_autojoin_channels: autojoin (or rejoin) channels
+ */
+
+void
+irc_server_autojoin_channels (t_irc_server *server)
+{
+ t_irc_channel *ptr_channel;
+
+ /* auto-join after disconnection (only rejoins opened channels) */
+ if (!server->disable_autojoin && server->reconnect_join && server->channels)
+ {
+ for (ptr_channel = server->channels; ptr_channel;
+ ptr_channel = ptr_channel->next_channel)
+ {
+ if (ptr_channel->type == IRC_CHANNEL_TYPE_CHANNEL)
+ {
+ if (ptr_channel->key)
+ irc_server_sendf (server, "JOIN %s %s",
+ ptr_channel->name, ptr_channel->key);
+ else
+ irc_server_sendf (server, "JOIN %s",
+ ptr_channel->name);
+ }
+ }
+ server->reconnect_join = 0;
+ }
+ else
+ {
+ /* auto-join when connecting to server for first time */
+ if (!server->disable_autojoin && server->autojoin && server->autojoin[0])
+ irc_send_cmd_join (server, NULL, server->autojoin);
+ }
+
+ server->disable_autojoin = 0;
+}
+
+/*
+ * irc_server_search: return pointer on a server with a name
+ */
+
+t_irc_server *
+irc_server_search (char *servername)
+{
+ t_irc_server *ptr_server;
+
+ if (!servername)
+ return NULL;
+
+ for (ptr_server = irc_servers; ptr_server;
+ ptr_server = ptr_server->next_server)
+ {
+ if (strcmp (ptr_server->name, servername) == 0)
+ return ptr_server;
+ }
+ return NULL;
+}
+
+/*
+ * irc_server_get_number_connected: returns number of connected server
+ */
+
+int
+irc_server_get_number_connected ()
+{
+ t_irc_server *ptr_server;
+ int number;
+
+ number = 0;
+ for (ptr_server = irc_servers; ptr_server; ptr_server = ptr_server->next_server)
+ {
+ if (ptr_server->is_connected)
+ number++;
+ }
+ return number;
+}
+
+/*
+ * irc_server_get_number_buffer: returns position of a server and total number of
+ * buffers with a buffer
+ */
+
+void
+irc_server_get_number_buffer (t_irc_server *server,
+ int *server_pos, int *server_total)
+{
+ t_irc_server *ptr_server;
+
+ *server_pos = 0;
+ *server_total = 0;
+ for (ptr_server = irc_servers; ptr_server;
+ ptr_server = ptr_server->next_server)
+ {
+ if (ptr_server->buffer)
+ {
+ (*server_total)++;
+ if (ptr_server == server)
+ *server_pos = *server_total;
+ }
+ }
+}
+
+/*
+ * irc_server_name_already_exists: return 1 if server name already exists
+ * otherwise return 0
+ */
+
+int
+irc_server_name_already_exists (char *name)
+{
+ t_irc_server *ptr_server;
+
+ if (!name)
+ return 0;
+
+ for (ptr_server = irc_servers; ptr_server; ptr_server = ptr_server->next_server)
+ {
+ if (strcmp (ptr_server->name, name) == 0)
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * irc_server_get_channel_count: return number of channels for server
+ */
+
+int
+irc_server_get_channel_count (t_irc_server *server)
+{
+ int count;
+ t_irc_channel *ptr_channel;
+
+ count = 0;
+ for (ptr_channel = server->channels; ptr_channel;
+ ptr_channel = ptr_channel->next_channel)
+ {
+ if (ptr_channel->type == IRC_CHANNEL_TYPE_CHANNEL)
+ count++;
+ }
+ return count;
+}
+
+/*
+ * irc_server_get_pv_count: return number of pv for server
+ */
+
+int
+irc_server_get_pv_count (t_irc_server *server)
+{
+ int count;
+ t_irc_channel *ptr_channel;
+
+ count = 0;
+ for (ptr_channel = server->channels; ptr_channel;
+ ptr_channel = ptr_channel->next_channel)
+ {
+ if (ptr_channel->type != IRC_CHANNEL_TYPE_CHANNEL)
+ count++;
+ }
+ return count;
+}
+
+/*
+ * irc_server_remove_away: remove away for all chans/nicks (for all servers)
+ */
+
+void
+irc_server_remove_away ()
+{
+ t_irc_server *ptr_server;
+ t_irc_channel *ptr_channel;
+
+ 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)
+ {
+ if (ptr_channel->type == IRC_CHANNEL_TYPE_CHANNEL)
+ irc_channel_remove_away (ptr_channel);
+ }
+ }
+ }
+}
+
+/*
+ * irc_server_check_away: check for away on all channels (for all servers)
+ */
+
+void
+irc_server_check_away ()
+{
+ t_irc_server *ptr_server;
+ t_irc_channel *ptr_channel;
+
+ 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)
+ {
+ if (ptr_channel->type == IRC_CHANNEL_TYPE_CHANNEL)
+ irc_channel_check_away (ptr_server, ptr_channel, 0);
+ }
+ }
+ }
+}
+
+/*
+ * irc_server_set_away: set/unset away status for a server (all channels)
+ */
+
+void
+irc_server_set_away (t_irc_server *server, char *nick, int is_away)
+{
+ t_irc_channel *ptr_channel;
+
+ for (ptr_channel = server->channels; ptr_channel; ptr_channel = ptr_channel->next_channel)
+ {
+ if (server->is_connected)
+ {
+ if (ptr_channel->type == IRC_CHANNEL_TYPE_CHANNEL)
+ irc_channel_set_away (ptr_channel, nick, is_away);
+ }
+ }
+}
+
+/*
+ * irc_server_get_default_notify_level: get default notify level for server
+ */
+
+int
+irc_server_get_default_notify_level (t_irc_server *server)
+{
+ int notify, value;
+ char *pos;
+
+ notify = GUI_NOTIFY_LEVEL_DEFAULT;
+
+ if (!server || !server->notify_levels)
+ return notify;
+
+ pos = strstr (server->notify_levels, "*:");
+ if (pos)
+ {
+ pos += 2;
+ if (pos[0])
+ {
+ value = (int)(pos[0] - '0');
+ if ((value >= GUI_NOTIFY_LEVEL_MIN)
+ && (value <= GUI_NOTIFY_LEVEL_MAX))
+ notify = value;
+ }
+ }
+
+ return notify;
+}
+
+/*
+ * irc_server_set_default_notify_level: set default notify level for server
+ */
+
+void
+irc_server_set_default_notify_level (t_irc_server *server, int notify)
+{
+ char level_string[2];
+
+ if (server)
+ {
+ level_string[0] = notify + '0';
+ level_string[1] = '\0';
+ config_option_list_set (&(server->notify_levels), "*", level_string);
+ }
+}
+
+/*
+ * irc_server_print_log: print server infos in log (usually for crash dump)
+ */
+
+void
+irc_server_print_log (t_irc_server *server)
+{
+ weechat_log_printf ("[server %s (addr:0x%X)]\n", server->name, server);
+ weechat_log_printf (" autoconnect . . . . : %d\n", server->autoconnect);
+ weechat_log_printf (" autoreconnect . . . : %d\n", server->autoreconnect);
+ weechat_log_printf (" autoreconnect_delay : %d\n", server->autoreconnect_delay);
+ weechat_log_printf (" temp_server . . . . : %d\n", server->temp_server);
+ weechat_log_printf (" address . . . . . . : '%s'\n", server->address);
+ weechat_log_printf (" port. . . . . . . . : %d\n", server->port);
+ weechat_log_printf (" ipv6. . . . . . . . : %d\n", server->ipv6);
+ weechat_log_printf (" ssl . . . . . . . . : %d\n", server->ssl);
+ weechat_log_printf (" password. . . . . . : '%s'\n",
+ (server->password && server->password[0]) ?
+ "(hidden)" : server->password);
+ weechat_log_printf (" nick1 . . . . . . . : '%s'\n", server->nick1);
+ weechat_log_printf (" nick2 . . . . . . . : '%s'\n", server->nick2);
+ weechat_log_printf (" nick3 . . . . . . . : '%s'\n", server->nick3);
+ weechat_log_printf (" username. . . . . . : '%s'\n", server->username);
+ weechat_log_printf (" realname. . . . . . : '%s'\n", server->realname);
+ weechat_log_printf (" command . . . . . . : '%s'\n",
+ (server->command && server->command[0]) ?
+ "(hidden)" : server->command);
+ weechat_log_printf (" command_delay . . . : %d\n", server->command_delay);
+ weechat_log_printf (" autojoin. . . . . . : '%s'\n", server->autojoin);
+ weechat_log_printf (" autorejoin. . . . . : %d\n", server->autorejoin);
+ weechat_log_printf (" notify_levels . . . : %s\n", server->notify_levels);
+ weechat_log_printf (" child_pid . . . . . : %d\n", server->child_pid);
+ weechat_log_printf (" child_read . . . . : %d\n", server->child_read);
+ weechat_log_printf (" child_write . . . . : %d\n", server->child_write);
+ weechat_log_printf (" sock. . . . . . . . : %d\n", server->sock);
+ weechat_log_printf (" is_connected. . . . : %d\n", server->is_connected);
+ weechat_log_printf (" ssl_connected . . . : %d\n", server->ssl_connected);
+ weechat_log_printf (" unterminated_message: '%s'\n", server->unterminated_message);
+ weechat_log_printf (" nick. . . . . . . . : '%s'\n", server->nick);
+ weechat_log_printf (" nick_modes. . . . . : '%s'\n", server->nick_modes);
+ weechat_log_printf (" prefix. . . . . . . : '%s'\n", server->prefix);
+ weechat_log_printf (" reconnect_start . . : %ld\n", server->reconnect_start);
+ weechat_log_printf (" command_time. . . . : %ld\n", server->command_time);
+ weechat_log_printf (" reconnect_join. . . : %d\n", server->reconnect_join);
+ weechat_log_printf (" disable_autojoin. . : %d\n", server->disable_autojoin);
+ weechat_log_printf (" is_away . . . . . . : %d\n", server->is_away);
+ weechat_log_printf (" away_message. . . . : '%s'\n", server->away_message);
+ weechat_log_printf (" away_time . . . . . : %ld\n", server->away_time);
+ weechat_log_printf (" lag . . . . . . . . : %d\n", server->lag);
+ weechat_log_printf (" lag_check_time. . . : tv_sec:%d, tv_usec:%d\n",
+ server->lag_check_time.tv_sec,
+ server->lag_check_time.tv_usec);
+ weechat_log_printf (" lag_next_check. . . : %ld\n", server->lag_next_check);
+ weechat_log_printf (" last_user_message . : %ld\n", server->last_user_message);
+ weechat_log_printf (" outqueue. . . . . . : 0x%X\n", server->outqueue);
+ weechat_log_printf (" last_outqueue . . . : 0x%X\n", server->last_outqueue);
+ weechat_log_printf (" buffer. . . . . . . : 0x%X\n", server->buffer);
+ weechat_log_printf (" channels. . . . . . : 0x%X\n", server->channels);
+ weechat_log_printf (" last_channel. . . . : 0x%X\n", server->last_channel);
+ weechat_log_printf (" prev_server . . . . : 0x%X\n", server->prev_server);
+ weechat_log_printf (" next_server . . . . : 0x%X\n", server->next_server);
+}
diff --git a/src/plugins/irc/irc.h b/src/plugins/irc/irc.h
new file mode 100644
index 000000000..9a94570c3
--- /dev/null
+++ b/src/plugins/irc/irc.h
@@ -0,0 +1,613 @@
+/*
+ * 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_IRC_H
+#define __WEECHAT_IRC_H 1
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <time.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <regex.h>
+
+#ifdef HAVE_GNUTLS
+#include <gnutls/gnutls.h>
+#endif
+
+#include "../../gui/gui.h"
+
+#ifndef NI_MAXHOST
+#define NI_MAXHOST 256
+#endif
+
+#define IRC_DEFAULT_PORT 6667
+#define IRC_DEFAULT_PREFIXES_LIST "@%+~&!-"
+
+/* nick types */
+
+#define IRC_NICK_CHANOWNER 1
+#define IRC_NICK_CHANADMIN 2
+#define IRC_NICK_OP 4
+#define IRC_NICK_HALFOP 8
+#define IRC_NICK_VOICE 16
+#define IRC_NICK_AWAY 32
+#define IRC_NICK_CHANADMIN2 64
+#define IRC_NICK_CHANUSER 128
+#define IRC_NICK_SET_FLAG(nick, set, flag) \
+ if (set) \
+ nick->flags |= flag; \
+ else \
+ nick->flags &= 0xFFFF - flag;
+
+#define irc_server_sendf_queued(server, fmt, argz...) \
+ if (server) \
+ { \
+ server->queue_msg = 1; \
+ irc_server_sendf (server, fmt, ##argz); \
+ server->queue_msg = 0; \
+ }
+
+typedef struct t_irc_nick t_irc_nick;
+
+struct t_irc_nick
+{
+ char *nick; /* nickname */
+ char *host; /* full hostname */
+ int flags; /* chanowner/chanadmin (unrealircd), */
+ /* op, halfop, voice, away */
+ int color; /* color for nickname in chat window */
+ t_irc_nick *prev_nick; /* link to previous nick on the channel */
+ t_irc_nick *next_nick; /* link to next nick on the channel */
+};
+
+#define IRC_CHANNEL_PREFIX "#&+!"
+
+/* channel types */
+#define IRC_CHANNEL_TYPE_UNKNOWN -1
+#define IRC_CHANNEL_TYPE_CHANNEL 0
+#define IRC_CHANNEL_TYPE_PRIVATE 1
+#define IRC_CHANNEL_TYPE_DCC_CHAT 2
+
+#define IRC_CHANNEL_NICKS_SPEAKING_LIMIT 32
+
+typedef struct t_irc_channel t_irc_channel;
+
+struct t_irc_channel
+{
+ int type; /* channel type */
+ void *dcc_chat; /* DCC CHAT pointer (NULL if not DCC) */
+ char *name; /* name of channel (exemple: "#abc") */
+ char *topic; /* topic of channel (host for private) */
+ char *modes; /* channel modes */
+ int limit; /* user limit (0 is limit not set) */
+ char *key; /* channel key (NULL if no key is set) */
+ int nicks_count; /* # nicks on channel (0 if dcc/pv) */
+ int checking_away; /* = 1 if checking away with WHO cmd */
+ char *away_message; /* to display away only once in private */
+ int cycle; /* currently cycling (/part then /join) */
+ int close; /* close request (/buffer close) */
+ int display_creation_date; /* 1 if creation date should be displayed */
+ int nick_completion_reset; /* 1 if nick completion should be rebuilt */
+ /* there was some join/part on channel */
+ t_irc_nick *nicks; /* nicks on the channel */
+ t_irc_nick *last_nick; /* last nick on the channel */
+ t_weelist *nicks_speaking; /* nicks speaking (for smart completion) */
+ t_weelist *last_nick_speaking; /* last nick speaking */
+ t_gui_buffer *buffer; /* GUI buffer allocated for channel */
+ t_irc_channel *prev_channel; /* link to previous channel */
+ t_irc_channel *next_channel; /* link to next channel */
+};
+
+/* server types */
+
+typedef struct t_irc_outqueue t_irc_outqueue;
+
+struct t_irc_outqueue
+{
+ char *message_before_mod; /* message before any modifier */
+ char *message_after_mod; /* message after modifier(s) */
+ int modified; /* message was modified by modifier(s) */
+ t_irc_outqueue *next_outqueue; /* pointer to next message in queue */
+ t_irc_outqueue *prev_outqueue; /* pointer to previous message in queue */
+};
+
+typedef struct t_irc_server t_irc_server;
+
+struct t_irc_server
+{
+ /* user choices */
+ char *name; /* internal name of server */
+ int autoconnect; /* = 1 if auto connect at startup */
+ int autoreconnect; /* = 1 if auto reco when disconnected */
+ int autoreconnect_delay; /* delay before trying again reconnect */
+ int temp_server; /* server is temporary (will not be saved)*/
+ char *address; /* address of server (IP or name) */
+ int port; /* port for server (6667 by default) */
+ int ipv6; /* use IPv6 protocol */
+ int ssl; /* SSL protocol */
+ char *password; /* password for server */
+ char *nick1; /* first nickname for the server */
+ char *nick2; /* alternate nickname */
+ char *nick3; /* 2nd alternate nickname */
+ char *username; /* user name */
+ char *realname; /* real name */
+ char *hostname; /* custom hostname */
+ char *command; /* command to run once connected */
+ int command_delay; /* delay after execution of command */
+ char *autojoin; /* channels to automatically join */
+ int autorejoin; /* auto rejoin channels when kicked */
+ char *notify_levels; /* channels notify levels */
+
+ /* internal vars */
+ pid_t child_pid; /* pid of child process (connecting) */
+ int child_read; /* to read into child pipe */
+ int child_write; /* to write into child pipe */
+ int sock; /* socket for server (IPv4 or IPv6) */
+ int is_connected; /* 1 if WeeChat is connected to server */
+ int ssl_connected; /* = 1 if connected with SSL */
+#ifdef HAVE_GNUTLS
+ gnutls_session gnutls_sess; /* gnutls session (only if SSL is used) */
+#endif
+ char *unterminated_message; /* beginning of a message in input buf */
+ char *nick; /* current nickname */
+ char *nick_modes; /* nick modes */
+ char *prefix; /* nick prefix allowed (from msg 005) */
+ time_t reconnect_start; /* this time + delay = reconnect time */
+ time_t command_time; /* this time + command_delay = time to */
+ /* autojoin channels */
+ int reconnect_join; /* 1 if channels opened to rejoin */
+ int disable_autojoin; /* 1 if user asked to not autojoin chans */
+ int is_away; /* 1 is user is marked as away */
+ char *away_message; /* away message, NULL if not away */
+ time_t away_time; /* time() when user marking as away */
+ int lag; /* lag (in milliseconds) */
+ struct timeval lag_check_time; /* last time lag was checked (ping sent) */
+ time_t lag_next_check; /* time for next check */
+ regex_t *cmd_list_regexp; /* compiled Regular Expression for /list */
+ int queue_msg; /* set to 1 when queue (out) is required */
+ time_t last_user_message; /* time of last user message (anti flood) */
+ t_irc_outqueue *outqueue; /* queue for outgoing user messages */
+ t_irc_outqueue *last_outqueue; /* last outgoing user message */
+ t_gui_buffer *buffer; /* GUI buffer allocated for server */
+ t_gui_buffer *saved_buffer; /* channel before jumping to next server */
+ t_irc_channel *channels; /* opened channels on server */
+ t_irc_channel *last_channel; /* last opened channal on server */
+ t_irc_server *prev_server; /* link to previous server */
+ t_irc_server *next_server; /* link to next server */
+};
+
+/* irc commands */
+
+typedef int (t_irc_recv_func)(t_irc_server *, char *, char *, char *);
+
+typedef struct t_irc_command t_irc_command;
+
+struct t_irc_command
+{
+ char *command_name; /* IRC 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 sending to server */
+ int needs_connection; /* = 1 if cmd needs server connection */
+ 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 */
+ t_irc_recv_func *recv_function; /* function called when cmd is received */
+};
+
+/* irc messages */
+
+typedef struct t_irc_message t_irc_message;
+
+struct t_irc_message
+{
+ t_irc_server *server; /* server pointer for received msg */
+ char *data; /* message content */
+ t_irc_message *next_message; /* link to next message */
+};
+
+/* DCC types */
+
+#define IRC_DCC_CHAT_RECV 0 /* receiving DCC chat */
+#define IRC_DCC_CHAT_SEND 1 /* sending DCC chat */
+#define IRC_DCC_FILE_RECV 2 /* incoming DCC file */
+#define IRC_DCC_FILE_SEND 3 /* sending DCC file */
+
+/* DCC status */
+
+#define IRC_DCC_WAITING 0 /* waiting for host answer */
+#define IRC_DCC_CONNECTING 1 /* connecting to host */
+#define IRC_DCC_ACTIVE 2 /* sending/receiving data */
+#define IRC_DCC_DONE 3 /* transfer done */
+#define IRC_DCC_FAILED 4 /* DCC failed */
+#define IRC_DCC_ABORTED 5 /* DCC aborted by user */
+
+/* DCC blocksize (for file) */
+
+#define IRC_DCC_MIN_BLOCKSIZE 1024 /* min DCC block size when sending file */
+#define IRC_DCC_MAX_BLOCKSIZE 102400 /* max DCC block size when sending file */
+
+/* DCC errors (for file) */
+
+#define IRC_DCC_NO_ERROR 0 /* no error to report, all ok! */
+#define IRC_DCC_ERROR_READ_LOCAL 1 /* unable to read local file */
+#define IRC_DCC_ERROR_SEND_BLOCK 2 /* unable to send block to receiver */
+#define IRC_DCC_ERROR_READ_ACK 3 /* unable to read ACK from receiver */
+#define IRC_DCC_ERROR_CONNECT_SENDER 4 /* unable to connect to sender */
+#define IRC_DCC_ERROR_RECV_BLOCK 5 /* unable to recv block from sender */
+#define IRC_DCC_ERROR_WRITE_LOCAL 6 /* unable to write to local file */
+
+/* DCC macros for type */
+
+#define IRC_DCC_IS_CHAT(type) ((type == IRC_DCC_CHAT_RECV) || \
+ (type == IRC_DCC_CHAT_SEND))
+#define IRC_DCC_IS_FILE(type) ((type == IRC_DCC_FILE_RECV) || \
+ (type == IRC_DCC_FILE_SEND))
+#define IRC_DCC_IS_RECV(type) ((type == IRC_DCC_CHAT_RECV) || \
+ (type == IRC_DCC_FILE_RECV))
+#define IRC_DCC_IS_SEND(type) ((type == IRC_DCC_CHAT_SEND) || \
+ (type == IRC_DCC_FILE_SEND))
+
+/* DCC macro for status */
+
+#define IRC_DCC_ENDED(status) ((status == IRC_DCC_DONE) || \
+ (status == IRC_DCC_FAILED) || \
+ (status == IRC_DCC_ABORTED))
+
+typedef struct t_irc_dcc t_irc_dcc;
+
+struct t_irc_dcc
+{
+ t_irc_server *server; /* irc server */
+ t_irc_channel *channel; /* irc channel (for DCC chat only) */
+ int type; /* DCC type (file/chat, send/receive) */
+ int status; /* DCC status (waiting, sending, ..) */
+ time_t start_time; /* the time when DCC started */
+ time_t start_transfer; /* the time when DCC transfer started */
+ unsigned long addr; /* IP address */
+ int port; /* port */
+ char *nick; /* remote nick */
+ int sock; /* socket for connection */
+ pid_t child_pid; /* pid of child process (sending/recving) */
+ int child_read; /* to read into child pipe */
+ int child_write; /* to write into child pipe */
+ char *unterminated_message; /* beginning of a message in input buf */
+ int fast_send; /* fase send for files: does not wait ACK */
+ int file; /* local file (for reading or writing) */
+ char *filename; /* filename (given by sender) */
+ char *local_filename; /* local filename (with path) */
+ int filename_suffix; /* suffix (.1 for ex) if renaming file */
+ int blocksize; /* block size for sending file */
+ unsigned long size; /* file size */
+ unsigned long pos; /* number of bytes received/sent */
+ unsigned long ack; /* number of bytes received OK */
+ unsigned long start_resume; /* start of resume (in bytes) */
+ time_t last_check_time; /* last time we looked at bytes sent/recv */
+ unsigned long last_check_pos; /* bytes sent/recv at last check */
+ time_t last_activity; /* time of last byte received/sent */
+ unsigned long bytes_per_sec; /* bytes per second */
+ unsigned long eta; /* estimated time of arrival */
+ t_irc_dcc *prev_dcc; /* link to previous dcc file/chat */
+ t_irc_dcc *next_dcc; /* link to next dcc file/chat */
+};
+
+/* ignore types */
+
+/* pre-defined ignore types, all other types are made with IRC commands */
+/* for example: part join quit notice invite ... */
+
+#define IRC_IGNORE_ACTION "action"
+#define IRC_IGNORE_CTCP "ctcp"
+#define IRC_IGNORE_DCC "dcc"
+#define IRC_IGNORE_PRIVATE "pv"
+
+typedef struct t_irc_ignore t_irc_ignore;
+
+struct t_irc_ignore
+{
+ char *mask; /* nickname or mask */
+ char *type; /* type of ignore */
+ char *channel_name; /* name of channel, "*" == all */
+ char *server_name; /* name of server, "*" == all */
+ t_irc_ignore *prev_ignore; /* pointer to previous ignore */
+ t_irc_ignore *next_ignore; /* pointer to next ignore */
+};
+
+/* variables */
+
+extern t_irc_command irc_commands[];
+extern t_irc_server *irc_servers;
+#ifdef HAVE_GNUTLS
+extern const int gnutls_cert_type_prio[];
+extern const int gnutls_prot_prio[];
+#endif
+extern t_irc_message *irc_recv_msgq, *irc_msgq_last_msg;
+extern int irc_check_away;
+extern t_irc_dcc *irc_dcc_list;
+extern t_irc_dcc *irc_last_dcc;
+extern char *irc_dcc_status_string[6];
+extern t_irc_ignore *irc_ignore;
+extern t_irc_ignore *irc_last_ignore;
+
+/* server functions (irc-server.c) */
+
+extern void irc_server_init (t_irc_server *);
+extern int irc_server_init_with_url (char *, t_irc_server *);
+extern t_irc_server *irc_server_alloc ();
+extern void irc_server_outqueue_free_all (t_irc_server *);
+extern void irc_server_destroy (t_irc_server *);
+extern void irc_server_free (t_irc_server *);
+extern void irc_server_free_all ();
+extern t_irc_server *irc_server_new (char *, int, int, int, int, char *, int, int, int,
+ char *, char *, char *, char *, char *, char *,
+ char *, char *, int, char *, int, char *);
+extern t_irc_server *irc_server_duplicate (t_irc_server *, char *);
+extern int irc_server_rename (t_irc_server *, char *);
+extern int irc_server_send (t_irc_server *, char *, int);
+extern void irc_server_outqueue_send (t_irc_server *);
+extern void irc_server_sendf (t_irc_server *, char *, ...);
+extern void irc_server_parse_message (char *, char **, char **, char **);
+extern void irc_server_recv (t_irc_server *);
+extern void irc_server_child_read (t_irc_server *);
+extern void irc_server_convbase64_8x3_to_6x4 (char *, char*);
+extern void irc_server_base64encode (char *, char *);
+extern int irc_server_pass_httpproxy (int, char*, int);
+extern int irc_server_resolve (char *, char *, int *);
+extern int irc_server_pass_socks4proxy (int, char*, int, char*);
+extern int irc_server_pass_socks5proxy (int, char*, int);
+extern int irc_server_pass_proxy (int, char*, int, char*);
+extern int irc_server_connect (t_irc_server *, int);
+extern void irc_server_reconnect (t_irc_server *);
+extern void irc_server_auto_connect (int, int);
+extern void irc_server_disconnect (t_irc_server *, int);
+extern void irc_server_disconnect_all ();
+extern void irc_server_autojoin_channels ();
+extern t_irc_server *irc_server_search (char *);
+extern int irc_server_get_number_connected ();
+extern void irc_server_get_number_buffer (t_irc_server *, int *, int *);
+extern int irc_server_name_already_exists (char *);
+extern int irc_server_get_channel_count (t_irc_server *);
+extern int irc_server_get_pv_count (t_irc_server *);
+extern void irc_server_remove_away ();
+extern void irc_server_check_away ();
+extern void irc_server_set_away (t_irc_server *, char *, int);
+extern int irc_server_get_default_notify_level (t_irc_server *);
+extern void irc_server_set_default_notify_level (t_irc_server *, int);
+extern void irc_server_print_log (t_irc_server *);
+
+/* channel functions (irc-channel.c) */
+
+extern t_irc_channel *irc_channel_new (t_irc_server *, int, char *);
+extern void irc_channel_free (t_irc_server *, t_irc_channel *);
+extern void irc_channel_free_all (t_irc_server *);
+extern t_irc_channel *irc_channel_search (t_irc_server *, char *);
+extern t_irc_channel *irc_channel_search_any (t_irc_server *, char *);
+extern t_irc_channel *irc_channel_search_any_without_buffer (t_irc_server *, char *);
+extern t_irc_channel *irc_channel_search_dcc (t_irc_server *, char *);
+extern int irc_channel_is_channel (char *);
+extern void irc_channel_remove_away (t_irc_channel *);
+extern void irc_channel_check_away (t_irc_server *, t_irc_channel *, int);
+extern void irc_channel_set_away (t_irc_channel *, char *, int);
+extern int irc_channel_create_dcc (t_irc_dcc *);
+extern int irc_channel_get_notify_level (t_irc_server *, t_irc_channel *);
+extern void irc_channel_set_notify_level (t_irc_server *, t_irc_channel *, int);
+extern void irc_channel_add_nick_speaking (t_irc_channel *, char *);
+extern void irc_channel_print_log (t_irc_channel *);
+
+/* nick functions (irc-nick.c) */
+
+extern int irc_nick_find_color (t_irc_nick *);
+extern t_irc_nick *irc_nick_new (t_irc_server *, t_irc_channel *, char *,
+ int, int, int, int, int, int, int);
+extern void irc_nick_resort (t_irc_channel *, t_irc_nick *);
+extern void irc_nick_change (t_irc_channel *, t_irc_nick *, char *);
+extern void irc_nick_free (t_irc_channel *, t_irc_nick *);
+extern void irc_nick_free_all (t_irc_channel *);
+extern t_irc_nick *irc_nick_search (t_irc_channel *, char *);
+extern void irc_nick_count (t_irc_channel *, int *, int *, int *, int *, int *);
+extern int irc_nick_get_max_length (t_irc_channel *);
+extern void irc_nick_set_away (t_irc_channel *, t_irc_nick *, int);
+extern void irc_nick_print_log (t_irc_nick *);
+
+/* mode functions (irc-mode.c) */
+
+extern void irc_mode_channel_set (t_irc_server *, t_irc_channel *, char *);
+extern void irc_mode_user_set (t_irc_server *, char *);
+extern int irc_mode_nick_prefix_allowed (t_irc_server *, char);
+
+/* DCC functions (irc-dcc.c) */
+
+extern void irc_dcc_redraw (int);
+extern void irc_dcc_free (t_irc_dcc *);
+extern void irc_dcc_close (t_irc_dcc *, int);
+extern void irc_dcc_chat_remove_channel (t_irc_channel *);
+extern void irc_dcc_accept (t_irc_dcc *);
+extern void irc_dcc_accept_resume (t_irc_server *, char *, int, unsigned long);
+extern void irc_dcc_start_resume (t_irc_server *, char *, int, unsigned long);
+extern t_irc_dcc *irc_dcc_alloc ();
+extern t_irc_dcc *irc_dcc_add (t_irc_server *, int, unsigned long, int, char *, int,
+ char *, char *, unsigned long);
+extern void irc_dcc_send_request (t_irc_server *, int, char *, char *);
+extern void irc_dcc_chat_sendf (t_irc_dcc *, char *, ...);
+extern void irc_dcc_file_send_fork (t_irc_dcc *);
+extern void irc_dcc_file_recv_fork (t_irc_dcc *);
+extern void irc_dcc_handle ();
+extern void irc_dcc_end ();
+extern void irc_dcc_print_log ();
+
+/* IRC display (irc-diplay.c) */
+
+extern void irc_display_hide_password (char *, int);
+extern void irc_display_prefix (t_irc_server *, t_gui_buffer *, char *);
+extern void irc_display_nick (t_gui_buffer *, t_irc_nick *, char *, int,
+ int, int, int);
+extern void irc_display_away (t_irc_server *, char *, char *);
+extern void irc_display_mode (t_irc_server *, t_gui_buffer *, char *, char *,
+ char, char *, char *, char *, char *);
+extern void irc_display_server (t_irc_server *ptr_server, int);
+
+/* IRC commands issued by user (irc-send.c) */
+
+extern void irc_send_login (t_irc_server *);
+extern int irc_send_cmd_admin (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_ame (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_amsg (t_irc_server *, t_irc_channel *, char *);
+extern void irc_send_away (t_irc_server *, char *);
+extern int irc_send_cmd_away (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_ban (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_ctcp (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_cycle (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_dehalfop (t_irc_server *, t_irc_channel *, int, char **);
+extern int irc_send_cmd_deop (t_irc_server *, t_irc_channel *, int, char **);
+extern int irc_send_cmd_devoice (t_irc_server *, t_irc_channel *, int, char **);
+extern int irc_send_cmd_die (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_halfop (t_irc_server *, t_irc_channel *, int, char **);
+extern int irc_send_cmd_info (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_invite (t_irc_server *, t_irc_channel *, int, char **);
+extern int irc_send_cmd_ison (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_join (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_kick (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_kickban (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_kill (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_links (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_list (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_lusers (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_me (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_mode (t_irc_server *, t_irc_channel *, char *);
+extern void irc_send_mode_nicks (t_irc_server *, char *, char *, char *, int, char **);
+extern int irc_send_cmd_motd (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_msg (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_names (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_nick (t_irc_server *, t_irc_channel *, int, char **);
+extern int irc_send_cmd_notice (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_op (t_irc_server *, t_irc_channel *, int, char **);
+extern int irc_send_cmd_oper (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_part (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_ping (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_pong (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_query (t_irc_server *, t_irc_channel *, char *);
+extern void irc_send_quit_server (t_irc_server *, char *);
+extern int irc_send_cmd_quit (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_quote (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_rehash (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_restart (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_service (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_servlist (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_squery (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_squit (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_stats (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_summon (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_time (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_topic (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_trace (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_unban (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_userhost (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_users (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_version (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_voice (t_irc_server *, t_irc_channel *, int, char **);
+extern int irc_send_cmd_wallops (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_who (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_whois (t_irc_server *, t_irc_channel *, char *);
+extern int irc_send_cmd_whowas (t_irc_server *, t_irc_channel *, char *);
+
+/* IRC commands executed when received from server (irc-recv.c) */
+
+extern int irc_recv_is_highlight (char *, char *);
+extern int irc_recv_command (t_irc_server *, char *, char *, char *, char *);
+extern int irc_recv_cmd_error (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_invite (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_join (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_kick (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_kill (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_mode (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_nick (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_notice (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_part (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_ping (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_pong (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_privmsg (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_quit (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_server_mode_reason (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_server_msg (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_server_reply (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_topic (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_wallops (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_001 (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_005 (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_221 (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_301 (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_302 (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_303 (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_305 (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_306 (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_whois_nick_msg (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_310 (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_311 (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_312 (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_314 (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_315 (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_317 (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_319 (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_321 (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_322 (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_323 (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_324 (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_327 (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_329 (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_331 (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_332 (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_333 (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_338 (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_341 (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_344 (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_345 (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_348 (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_349 (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_351 (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_352 (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_353 (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_365 (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_366 (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_367 (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_368 (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_432 (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_433 (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_438 (t_irc_server *, char *, char *, char *);
+extern int irc_recv_cmd_671 (t_irc_server *, char *, char *, char *);
+
+/* ignore functions (irc-ignore.c) */
+
+extern int irc_ignore_check (char *, char *, char *, char *);
+extern t_irc_ignore *irc_ignore_add (char *, char *, char *, char *);
+extern t_irc_ignore *irc_ignore_add_from_config (char *);
+extern void irc_ignore_free_all ();
+extern int irc_ignore_search_free (char *, char *, char *, char *);
+extern int irc_ignore_search_free_by_number (int);
+extern void irc_ignore_print_log ();
+
+#endif /* irc.h */