summaryrefslogtreecommitdiff
path: root/src/plugins/relay/relay-protocol-irc.c
diff options
context:
space:
mode:
authorSebastien Helleu <flashcode@flashtux.org>2009-10-29 17:23:25 +0100
committerSebastien Helleu <flashcode@flashtux.org>2009-10-29 17:23:25 +0100
commit999de8bfc15bdaded7d85dc7d6e4617e07d2220c (patch)
treeb0d631b70611613825e366a85adbd9d5d12e0461 /src/plugins/relay/relay-protocol-irc.c
parent5a8c35f6b0e14e19ea6631b5e65153a368267a4d (diff)
downloadweechat-999de8bfc15bdaded7d85dc7d6e4617e07d2220c.zip
Add partial irc-proxy feature to relay plugin
Diffstat (limited to 'src/plugins/relay/relay-protocol-irc.c')
-rw-r--r--src/plugins/relay/relay-protocol-irc.c545
1 files changed, 545 insertions, 0 deletions
diff --git a/src/plugins/relay/relay-protocol-irc.c b/src/plugins/relay/relay-protocol-irc.c
new file mode 100644
index 000000000..ab9a45073
--- /dev/null
+++ b/src/plugins/relay/relay-protocol-irc.c
@@ -0,0 +1,545 @@
+/*
+ * Copyright (c) 2003-2009 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/>.
+ */
+
+/* relay-protocol-irc.c: IRC protocol for client
+ (relay acting as an IRC proxy/bouncer) */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <errno.h>
+
+#include "../weechat-plugin.h"
+#include "relay.h"
+#include "relay-protocol-irc.h"
+#include "relay-client.h"
+
+
+/*
+ * relay_protocol_irc_search_buffer: search IRC buffer with server and channel
+ * name
+ */
+
+struct t_gui_buffer *
+relay_protocol_irc_search_buffer (const char *server, const char *channel)
+{
+ char string[256];
+ long unsigned int value;
+ const char *str_ptr_buffer;
+
+ snprintf (string, sizeof (string), "%s,%s", server, channel);
+ str_ptr_buffer = weechat_info_get ("irc_buffer", string);
+ if (str_ptr_buffer && str_ptr_buffer[0])
+ {
+ sscanf (str_ptr_buffer, "%lx", &value);
+ return (struct t_gui_buffer *)value;
+ }
+
+ return NULL;
+}
+
+/*
+ * relay_protocol_irc_sendf: send formatted data to client
+ */
+
+int
+relay_protocol_irc_sendf (struct t_relay_client *client, const char *format, ...)
+{
+ va_list args;
+ static char buffer[4096];
+ int length, num_sent;
+
+ if (!client)
+ return 0;
+
+ va_start (args, format);
+ vsnprintf (buffer, sizeof (buffer) - 3, format, args);
+ va_end (args);
+
+ if (weechat_relay_plugin->debug)
+ {
+ weechat_printf (NULL, "relay: send: %s", buffer);
+ }
+
+ length = strlen (buffer);
+
+ buffer[length] = '\r';
+ buffer[length + 1] = '\n';
+ buffer[length + 2] = '\0';
+ length += 2;
+
+ num_sent = send (client->sock, buffer, length, 0);
+
+ if (num_sent >= 0)
+ client->bytes_sent += num_sent;
+ else
+ {
+ weechat_printf (NULL,
+ _("%s%s: error sending data to client %s"),
+ weechat_prefix ("error"), RELAY_PLUGIN_NAME,
+ strerror (errno));
+ }
+
+ return num_sent;
+}
+
+/*
+ * relay_protocol_irc_signal_irc_in2_cb: callback for "irc_in2" IRC signal
+ */
+
+int
+relay_protocol_irc_signal_irc_in2_cb (void *data, const char *signal,
+ const char *type_data, void *signal_data)
+{
+ struct t_relay_client *client;
+ const char *ptr_msg;
+ char *host, *pos, *pos_end_nick;
+
+ (void) signal;
+ (void) type_data;
+
+ client = (struct t_relay_client *)data;
+ ptr_msg = (const char *)signal_data;
+
+ if (weechat_relay_plugin->debug)
+ {
+ weechat_printf (NULL, "relay: irc_in2: client: %s, data: %s",
+ client->protocol_string,
+ ptr_msg);
+ }
+
+ if (ptr_msg[0] == ':')
+ {
+ pos = strchr (ptr_msg, ' ');
+ if (pos)
+ {
+ host = weechat_strndup (ptr_msg + 1, pos - ptr_msg);
+ if (host)
+ {
+ pos_end_nick = strchr (host, '!');
+ if (pos_end_nick)
+ pos_end_nick[0] = '\0';
+ else
+ host[0] = '\0';
+
+ pos++;
+ while (pos[0] == ' ')
+ {
+ pos++;
+ }
+
+ relay_protocol_irc_sendf (client, ":%s%s%s %s",
+ (host[0]) ? host : "",
+ (host[0]) ? "!" : "",
+ RELAY_IRC_DATA(client, address),
+ pos);
+ free (host);
+ }
+ return WEECHAT_RC_OK;
+ }
+ }
+
+ relay_protocol_irc_sendf (client, "%s", ptr_msg);
+
+ return WEECHAT_RC_OK;
+}
+
+/*
+ * relay_protocol_irc_signal_irc_out_cb: callback for "irc_out" IRC signal
+ */
+
+int
+relay_protocol_irc_signal_irc_out_cb (void *data, const char *signal,
+ const char *type_data, void *signal_data)
+{
+ struct t_relay_client *client;
+
+ (void) signal;
+ (void) type_data;
+
+ client = (struct t_relay_client *)data;
+
+ if (weechat_relay_plugin->debug)
+ {
+ weechat_printf (NULL, "relay: irc_out: client: %s, data: %s",
+ client->protocol_string,
+ (char *)signal_data);
+ }
+
+ return WEECHAT_RC_OK;
+}
+
+/*
+ * relay_protocol_irc_send_join: send join for a channel to client
+ */
+
+void
+relay_protocol_irc_send_join (struct t_relay_client *client,
+ const char *channel)
+{
+ char *infolist_name, *nicks;
+ const char *nick;
+ int length, length_nicks;
+ struct t_infolist *infolist_nicks;
+
+ length = strlen (client->protocol_string) + 1 + strlen (channel) + 1;
+ infolist_name = malloc (length);
+ if (infolist_name)
+ {
+ relay_protocol_irc_sendf (client,
+ ":%s!%s@proxy JOIN %s",
+ RELAY_IRC_DATA(client, nick),
+ "weechat",
+ channel);
+ snprintf (infolist_name, length, "%s,%s",
+ client->protocol_string,
+ channel);
+ infolist_nicks = weechat_infolist_get ("irc_nick", NULL, infolist_name);
+ if (infolist_nicks)
+ {
+ length_nicks = 0;
+ nicks = NULL;
+ while (weechat_infolist_next (infolist_nicks))
+ {
+ nick = weechat_infolist_string (infolist_nicks, "name");
+ if (nick && nick[0])
+ {
+ if (length_nicks == 0)
+ {
+ length_nicks = strlen (nick) + 1;
+ nicks = malloc (length_nicks);
+ strcpy (nicks, nick);
+ }
+ else
+ {
+ length_nicks += strlen (nick) + 1;
+ nicks = realloc (nicks, length_nicks);
+ strcat (nicks, " ");
+ strcat (nicks, nick);
+ }
+ }
+ }
+ if (nicks)
+ {
+ relay_protocol_irc_sendf (client,
+ ":%s 353 %s = %s :%s",
+ RELAY_IRC_DATA(client, address),
+ RELAY_IRC_DATA(client, nick),
+ channel, nicks);
+ free (nicks);
+ }
+ weechat_infolist_free (infolist_nicks);
+ }
+ relay_protocol_irc_sendf (client,
+ ":%s 366 %s %s :End of /NAMES list.",
+ RELAY_IRC_DATA(client, address),
+ RELAY_IRC_DATA(client, nick),
+ channel);
+ free (infolist_name);
+ }
+}
+
+/*
+ * relay_protocol_irc_send_join_channels: send join for all channels of server
+ * to client
+ */
+
+void
+relay_protocol_irc_send_join_channels (struct t_relay_client *client)
+{
+ struct t_infolist *infolist_channels;
+ const char *channel;
+
+ infolist_channels = weechat_infolist_get ("irc_channel", NULL,
+ client->protocol_string);
+ if (infolist_channels)
+ {
+ while (weechat_infolist_next (infolist_channels))
+ {
+ channel = weechat_infolist_string (infolist_channels, "name");
+ relay_protocol_irc_send_join (client, channel);
+ }
+ weechat_infolist_free (infolist_channels);
+ }
+}
+
+/*
+ * relay_protocol_irc_recv_one_msg: read one message from client
+ */
+
+void
+relay_protocol_irc_recv_one_msg (struct t_relay_client *client, char *data)
+{
+ char *pos, str_time[128], **argv, **argv_eol, str_signal_name[128];
+ char *command;
+ int argc, length;
+ const char *nick;
+ struct t_gui_buffer *ptr_buffer;
+
+ pos = strchr (data, '\r');
+ if (pos)
+ pos[0] = '\0';
+
+ if (weechat_relay_plugin->debug)
+ {
+ weechat_printf (NULL, "relay: recv from client: \"%s\"", data);
+ }
+
+ argv = weechat_string_split (data, " ", 0, 0, &argc);
+ argv_eol = weechat_string_split (data, " ", 1, 0, &argc);
+
+ if (!RELAY_IRC_DATA(client, connected))
+ {
+ if (weechat_strncasecmp (data, "nick ", 5) == 0)
+ {
+ if (data[5])
+ {
+ if (RELAY_IRC_DATA(client, nick))
+ free (RELAY_IRC_DATA(client, nick));
+ RELAY_IRC_DATA(client, nick) = strdup (data + 5);
+ }
+ }
+ if (weechat_strncasecmp (data, "user ", 5) == 0)
+ {
+ if (data[5])
+ {
+ RELAY_IRC_DATA(client, user_received) = 1;
+ }
+ }
+ if (RELAY_IRC_DATA(client, nick) && RELAY_IRC_DATA(client, user_received))
+ {
+ RELAY_IRC_DATA(client, connected) = 1;
+
+ /* send nick to client if server nick is different of nick asked
+ by client with command NICK */
+ nick = weechat_info_get ("irc_nick", client->protocol_string);
+ if (nick && (strcmp (nick, RELAY_IRC_DATA(client, nick)) != 0))
+ {
+ relay_protocol_irc_sendf (client,
+ ":%s!proxy NICK :%s",
+ RELAY_IRC_DATA(client, nick),
+ nick);
+ free (RELAY_IRC_DATA(client, nick));
+ RELAY_IRC_DATA(client, nick) = strdup (nick);
+ }
+
+ relay_protocol_irc_sendf (client,
+ ":%s 001 %s :Welcome to the Internet "
+ "Relay Network %s!%s@proxy",
+ RELAY_IRC_DATA(client, address),
+ RELAY_IRC_DATA(client, nick),
+ RELAY_IRC_DATA(client, nick),
+ "weechat");
+ relay_protocol_irc_sendf (client,
+ ":%s 002 %s :Your host is "
+ "weechat-relay-irc, running version %s",
+ RELAY_IRC_DATA(client, address),
+ RELAY_IRC_DATA(client, nick),
+ weechat_info_get("version", NULL));
+ snprintf (str_time, sizeof (str_time), "%s",
+ ctime (&client->listen_start_time));
+ if (str_time[0])
+ str_time[strlen (str_time) - 1] = '\0';
+ relay_protocol_irc_sendf (client,
+ ":%s 003 %s :This server was created "
+ "on %s",
+ RELAY_IRC_DATA(client, address),
+ RELAY_IRC_DATA(client, nick),
+ str_time);
+ relay_protocol_irc_sendf (client,
+ ":%s 004 %s %s %s oirw abiklmnopqstv",
+ RELAY_IRC_DATA(client, address),
+ RELAY_IRC_DATA(client, nick),
+ RELAY_IRC_DATA(client, address),
+ weechat_info_get("version", NULL));
+ relay_protocol_irc_sendf (client,
+ ":%s 251 %s :There are %d users and 0 "
+ "invisible on 1 servers",
+ RELAY_IRC_DATA(client, address),
+ RELAY_IRC_DATA(client, nick),
+ relay_client_count);
+ relay_protocol_irc_sendf (client,
+ ":%s 255 %s :I have %d clients, 0 "
+ "services and 0 servers",
+ RELAY_IRC_DATA(client, address),
+ RELAY_IRC_DATA(client, nick),
+ relay_client_count);
+ relay_protocol_irc_sendf (client,
+ ":%s 422 %s :MOTD File is missing",
+ RELAY_IRC_DATA(client, address),
+ RELAY_IRC_DATA(client, nick));
+
+ /* hook signal "xxx,irc_in2_*" to catch IRC data received from
+ this server */
+ snprintf (str_signal_name, sizeof (str_signal_name),
+ "%s,irc_in2_*",
+ client->protocol_string);
+ RELAY_IRC_DATA(client, hook_signal_irc_in2) =
+ weechat_hook_signal (str_signal_name,
+ &relay_protocol_irc_signal_irc_in2_cb,
+ client);
+
+ /* hook signal "xxx,irc_out_*" to catch IRC data sent to
+ this server */
+ snprintf (str_signal_name, sizeof (str_signal_name),
+ "%s,irc_out_*",
+ client->protocol_string);
+ RELAY_IRC_DATA(client, hook_signal_irc_out) =
+ weechat_hook_signal (str_signal_name,
+ &relay_protocol_irc_signal_irc_out_cb,
+ client);
+
+ /* send JOIN for all channels on server to client */
+ relay_protocol_irc_send_join_channels (client);
+ }
+ }
+ else
+ {
+ if (argc > 0)
+ {
+ if (weechat_strcasecmp (argv[0], "privmsg") == 0)
+ {
+ ptr_buffer = relay_protocol_irc_search_buffer (client->protocol_string,
+ argv[1]);
+ if (ptr_buffer)
+ {
+ weechat_printf (NULL,
+ "relay: send string \"%s\" on channel %s",
+ (argv_eol[2][0] == ':') ? argv_eol[2] + 1 : argv_eol[2],
+ argv[1]);
+ weechat_command (ptr_buffer,
+ (argv_eol[2][0] == ':') ? argv_eol[2] + 1 : argv_eol[2]);
+ }
+ else
+ {
+ weechat_printf (NULL,
+ _("%s%s: buffer not found for IRC server "
+ "\"%s\", channel \"%s\""),
+ weechat_prefix ("error"),
+ RELAY_PLUGIN_NAME,
+ client->protocol_string,
+ argv[1]);
+ }
+ }
+ else
+ {
+ length = 32 + strlen (client->protocol_string) + strlen (data);
+ command = malloc (length + 1);
+ if (command)
+ {
+ snprintf (command, length, "/quote -server %s %s",
+ client->protocol_string,
+ data);
+ weechat_command (NULL, command);
+ free (command);
+ }
+ }
+ }
+ }
+
+ if (argv)
+ weechat_string_free_split (argv);
+ if (argv_eol)
+ weechat_string_free_split (argv_eol);
+}
+
+/*
+ * relay_protocol_irc_recv: read data from client
+ */
+
+void
+relay_protocol_irc_recv (struct t_relay_client *client, const char *data)
+{
+ char **items;
+ int items_count, i;
+
+ items = weechat_string_split (data, "\n", 0, 0, &items_count);
+ for (i = 0; i < items_count; i++)
+ {
+ relay_protocol_irc_recv_one_msg (client, items[i]);
+ }
+ if (items)
+ weechat_string_free_split (items);
+}
+
+/*
+ * relay_protocol_irc_alloc: init relay data specific to IRC protocol
+ */
+
+void
+relay_protocol_irc_alloc (struct t_relay_client *client)
+{
+ struct t_relay_protocol_irc_data *irc_data;
+
+ client->protocol_data = malloc (sizeof (*irc_data));
+ if (client->protocol_data)
+ {
+ RELAY_IRC_DATA(client, address) = strdup ("weechat.relay.irc");
+ RELAY_IRC_DATA(client, nick) = NULL;
+ RELAY_IRC_DATA(client, user_received) = 0;
+ RELAY_IRC_DATA(client, connected) = 0;
+ RELAY_IRC_DATA(client, hook_signal_irc_in2) = NULL;
+ RELAY_IRC_DATA(client, hook_signal_irc_out) = NULL;
+ }
+}
+
+/*
+ * relay_protocol_irc_free: free relay data specific to IRC protocol
+ */
+
+void
+relay_protocol_irc_free (struct t_relay_client *client)
+{
+ if (client->protocol_data)
+ {
+ if (RELAY_IRC_DATA(client, address))
+ free (RELAY_IRC_DATA(client, address));
+ if (RELAY_IRC_DATA(client, nick))
+ free (RELAY_IRC_DATA(client, nick));
+ if (RELAY_IRC_DATA(client, hook_signal_irc_in2))
+ weechat_unhook (RELAY_IRC_DATA(client, hook_signal_irc_in2));
+ if (RELAY_IRC_DATA(client, hook_signal_irc_out))
+ weechat_unhook (RELAY_IRC_DATA(client, hook_signal_irc_out));
+
+ free (client->protocol_data);
+ }
+}
+
+/*
+ * relay_protocol_irc_print_log: print IRC client infos in log (usually for
+ * crash dump)
+ */
+
+void
+relay_protocol_irc_print_log (struct t_relay_client *client)
+{
+ if (client->protocol_data)
+ {
+ weechat_log_printf (" address. . . . . . : '%s'", RELAY_IRC_DATA(client, address));
+ weechat_log_printf (" nick . . . . . . . : '%s'", RELAY_IRC_DATA(client, nick));
+ weechat_log_printf (" user_received. . . : %d", RELAY_IRC_DATA(client, user_received));
+ weechat_log_printf (" connected. . . . . : %d", RELAY_IRC_DATA(client, connected));
+ weechat_log_printf (" hook_signal_irc_in2: 0x%lx", RELAY_IRC_DATA(client, hook_signal_irc_in2));
+ weechat_log_printf (" hook_signal_irc_out: 0x%lx", RELAY_IRC_DATA(client, hook_signal_irc_out));
+ }
+}