From d549526735bb77830e432be7e432eccbd42698ed Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Fri, 29 Sep 2000 23:59:51 +0000 Subject: Updated Irssi proxy to work with latest version, thanks to fuchs :) git-svn-id: http://svn.irssi.org/repos/irssi/trunk@697 dbcabf3a-b0e7-0310-adc4-f8d773084564 --- src/irc/Makefile.am | 6 +- src/irc/proxy/.cvsignore | 8 + src/irc/proxy/Makefile.am | 14 ++ src/irc/proxy/dump.c | 124 ++++++++++++++ src/irc/proxy/listen.c | 399 ++++++++++++++++++++++++++++++++++++++++++++++ src/irc/proxy/module.h | 11 ++ src/irc/proxy/proxy.c | 136 ++++++++++++++++ src/irc/proxy/proxy.h | 55 +++++++ 8 files changed, 752 insertions(+), 1 deletion(-) create mode 100644 src/irc/proxy/.cvsignore create mode 100644 src/irc/proxy/Makefile.am create mode 100644 src/irc/proxy/dump.c create mode 100644 src/irc/proxy/listen.c create mode 100644 src/irc/proxy/module.h create mode 100644 src/irc/proxy/proxy.c create mode 100644 src/irc/proxy/proxy.h (limited to 'src/irc') diff --git a/src/irc/Makefile.am b/src/irc/Makefile.am index 651fedc6..cdea8d60 100644 --- a/src/irc/Makefile.am +++ b/src/irc/Makefile.am @@ -2,7 +2,11 @@ if BUILD_IRSSIBOT BOT=bot endif -SUBDIRS = core $(BOT) dcc flood notifylist +if BUILD_IRSSIPROXY +PROXY=proxy +endif + +SUBDIRS = core $(BOT) dcc flood notifylist $(PROXY) noinst_LIBRARIES = libirc.a diff --git a/src/irc/proxy/.cvsignore b/src/irc/proxy/.cvsignore new file mode 100644 index 00000000..8553e9e9 --- /dev/null +++ b/src/irc/proxy/.cvsignore @@ -0,0 +1,8 @@ +*.la +*.lo +*.o +.deps +.libs +Makefile +Makefile.in +so_locations diff --git a/src/irc/proxy/Makefile.am b/src/irc/proxy/Makefile.am new file mode 100644 index 00000000..ebf7e4d9 --- /dev/null +++ b/src/irc/proxy/Makefile.am @@ -0,0 +1,14 @@ +moduledir = $(libdir)/irssi/modules +module_LTLIBRARIES = libproxy.la + +INCLUDES = $(GLIB_CFLAGS) -I$(top_srcdir)/src -I$(top_srcdir)/src/core/ \ + -I$(top_srcdir)/src/irc/core/ + +libproxy_la_SOURCES = \ + proxy.c \ + dump.c \ + listen.c \ + +noinst_HEADERS = \ + proxy.h \ + module.h diff --git a/src/irc/proxy/dump.c b/src/irc/proxy/dump.c new file mode 100644 index 00000000..eb222956 --- /dev/null +++ b/src/irc/proxy/dump.c @@ -0,0 +1,124 @@ +/* + dump.c : proxy plugin - output all information about irc session + + Copyright (C) 1999 Timo Sirainen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "common.h" +#include "network.h" +#include "servers.h" +#include "irc-servers.h" +#include "channels.h" +#include "modes.h" +#include "nicklist.h" +#include "settings.h" +#include "proxy.h" + +static void outdata(gint handle, gchar *data, ...) +{ + va_list args; + gchar *str; + + va_start(args, data); + + str = g_strdup_vprintf(data, args); + net_transmit(handle, str, strlen(str)); + g_free(str); + + va_end(args); +} + +static void outserver(gint handle, SERVER_REC *server, gchar *data, ...) +{ + va_list args; + gchar *str; + + va_start(args, data); + + str = g_strdup_vprintf(data, args); + outdata(handle, ":%s!%s@proxy %s\n", server->nick, settings_get_str("user_name"), str); + g_free(str); + + va_end(args); +} + +void plugin_proxy_dump_data(CLIENT_REC *client) +{ + SERVER_REC *server; + GSList *tmp, *tmp2, *nicks; + gint handle; + + handle = client->handle; + server = servers->data; + if (strcmp(server->nick, client->nick) != 0) + { + /* change nick first so that clients won't try to eg. set their own + user mode with wrong nick.. hopefully works with all clients. */ + outdata(handle, ":%s!proxy NICK :%s\n", client->nick, server->nick); + g_free(client->nick); + client->nick = g_strdup(server->nick); + } + outdata(handle, ":proxy 001 %s :Welcome to the Internet Relay Network\n", client->nick); + outdata(handle, ":proxy 002 %s :Your host is irssi-proxy, running version %s\n", client->nick, VERSION); + outdata(handle, ":proxy 003 %s :This server was created ...\n", client->nick); + if (!IRC_SERVER(server)->emode_known) + outdata(handle, ":proxy 004 %s proxy %s oirw abiklmnopqstv\n", client->nick, VERSION); + else + outdata(handle, ":proxy 004 %s proxy %s oirw abeIiklmnopqstv\n", client->nick, VERSION); + outdata(handle, ":proxy 251 %s :There are 0 users and 0 invisible on 1 servers\n", client->nick); + outdata(handle, ":proxy 255 %s :I have 0 clients, 0 services and 0 servers\n", client->nick); + outdata(handle, ":proxy 422 %s :MOTD File is missing\n", client->nick); + + /* nick / mode */ + outserver(handle, server, "MODE %s :+%s", server->nick, IRC_SERVER(server)->usermode); + + if (server->usermode_away) + outdata(handle, ":proxy 306 %s :You have been marked as being away\n", server->nick); + + /* Send channel joins */ + for (tmp = server->channels; tmp != NULL; tmp = tmp->next) + { + CHANNEL_REC *rec = tmp->data; + + outserver(handle, rec->server, "JOIN %s", rec->name); + outdata(handle, ":proxy 353 %s %c %s :", rec->server->nick, + channel_mode_is_set(IRC_CHANNEL(rec), 'p') ? '*' : + channel_mode_is_set(IRC_CHANNEL(rec), 's') ? '@' : '=', + rec->name); + + nicks = nicklist_getnicks(rec); + for (tmp2 = nicks; tmp2 != NULL; tmp2 = tmp2->next) + { + NICK_REC *nick = tmp2->data; + + if (tmp2 != nicks) + net_transmit(handle, " ", 1); + + if (nick->op) + net_transmit(handle, "@", 1); + else if (nick->voice) + net_transmit(handle, "+", 1); + net_transmit(handle, nick->nick, strlen(nick->nick)); + } + g_slist_free(nicks); + net_transmit(handle, "\n", 1); + + outdata(handle, ":proxy 366 %s %s :End of /NAMES list.\n", rec->server->nick, rec->name); + if (rec->topic != NULL) + outdata(handle, ":proxy 332 %s %s :%s\n", rec->server->nick, rec->name, rec->topic); + } +} diff --git a/src/irc/proxy/listen.c b/src/irc/proxy/listen.c new file mode 100644 index 00000000..c5453442 --- /dev/null +++ b/src/irc/proxy/listen.c @@ -0,0 +1,399 @@ +/* + listen.c : sample plugin for irssi + + Copyright (C) 1999 Timo Sirainen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "module.h" +#include "proxy.h" +#include "net-sendbuffer.h" +#include "fe-common/core/printtext.h" +#include "levels.h" + +static PLUGIN_DATA *proxy_data; +static GString *next_line; + +void remove_client(PLUGIN_DATA *data, CLIENT_REC *rec) +{ + data->clients = g_slist_remove(data->clients, rec); + + net_disconnect(rec->handle); + g_source_remove(rec->tag); + line_split_free(rec->buffer); + g_free(rec); +} + +static void proxy_redirect_event(CLIENT_REC *client, gchar *args, gint last, ...) +{ + va_list vargs; + gchar *event; + gint argpos, group; + GString *str; + + g_return_if_fail(client != NULL); + + va_start(vargs, last); + + str = g_string_new(NULL); + group = 0; + while ((event = va_arg(vargs, gchar *)) != NULL) + { + argpos = va_arg(vargs, gint); + g_string_sprintf(str, "proxy %d", client->handle); + group = server_redirect_single_event(client->server, args, last > 0, group, event, str->str, argpos); + last--; + } + g_string_free(str, TRUE); + + va_end(vargs); +} + +static void grab_who(CLIENT_REC *client, gchar *channel) +{ + gchar *chlist; + gchar **list, **tmp; + + /* /WHO a,b,c may respond with either one "a,b,c End of WHO" message or + three different "a End of WHO", "b End of WHO", .. messages */ + chlist = g_strdup(channel); + list = g_strsplit(channel, ",", -1); + + for (tmp = list; *tmp != NULL; tmp++) + { + if (strcmp(*tmp, "0") == 0) + { + /* /who 0 displays everyone */ + **tmp = '*'; + } + + channel = g_strdup_printf("%s %s", chlist, *tmp); + proxy_redirect_event(client, channel, 2, + "event 401", 1, "event 315", 1, + "event 352", -1, NULL); + g_free(channel); + } + g_strfreev(list); + g_free(chlist); +} + +static void sig_listen_client(CLIENT_REC *client, gint handle) +{ + char tmpbuf[1024], *str, *cmd, *args, *p; + int ret, recvlen; + + g_return_if_fail(client != NULL); + + for (;;) + { + recvlen = net_receive(handle, tmpbuf, sizeof(tmpbuf)); + ret = line_split(tmpbuf, recvlen, &str, &client->buffer); + if (ret == -1) + { + /* connection lost */ + remove_client(proxy_data, client); + break; + } + if (ret == 0) break; + + if (client->server == NULL) + continue; + + cmd = g_strdup(str); + args = strchr(cmd, ' '); + if (args != NULL) *args++ = '\0'; else args = ""; + if (*args == ':') args++; + g_strup(cmd); + + if (!client->connected) + { + if (proxy_data->password != NULL && strcmp(cmd, "PASS") == 0) + { + if (strcmp(proxy_data->password, args) != 0) + { + /* wrong password! */ + remove_client(proxy_data, client); + break; + } + client->pass_sent = TRUE; + } + else if (strcmp(cmd, "NICK") == 0) + client->nick = g_strdup(args); + else if (strcmp(cmd, "USER") == 0) + { + if (client->nick == NULL || (proxy_data->password != NULL && !client->pass_sent)) + { + /* stupid client didn't send us NICK/PASS or, kill it */ + remove_client(proxy_data, client); + break; + } + client->connected = TRUE; + plugin_proxy_dump_data(client); + } + } + else if (strcmp(cmd, "QUIT") == 0) + { + remove_client(proxy_data, client); + break; + } + else if (strcmp(cmd, "PING") == 0) + { + net_transmit(handle, "PONG proxy :nick\n", 17); + } + else + { + net_transmit(net_sendbuffer_handle(client->server->handle), str, strlen(str)); + net_transmit(net_sendbuffer_handle(client->server->handle), "\n", 1); + + if (strcmp(cmd, "WHO") == 0) + { + grab_who(client, args); + } + else if (strcmp(cmd, "WHOIS") == 0) + { + /* convert dots to spaces */ + for (p = args; *p != '\0'; p++) + if (*p == ',') *p = ' '; + + proxy_redirect_event(client, args, 2, + "event 318", -1, "event 402", -1, + "event 401", 1, "event 311", 1, + "event 301", 1, "event 312", 1, + "event 313", 1, "event 317", 1, + "event 319", 1, NULL); + } + else if (strcmp(cmd, "ISON") == 0) + { + proxy_redirect_event(client, NULL, 1, "event 303", -1, NULL); + } + else if (strcmp(cmd, "USERHOST") == 0) + { + proxy_redirect_event(client, args, 1, "event 302", -1, "event 401", 1, NULL); + } + else if (strcmp(cmd, "MODE") == 0) + { + /* convert dots to spaces */ + gchar *slist, *str, mode; + gint argc; + + p = strchr(args, ' '); + if (p != NULL) *p++ = '\0'; + mode = p == NULL ? '\0' : *p; + + slist = g_strdup(args); + argc = 1; + for (p = slist; *p != '\0'; p++) + { + if (*p == ',') + { + *p = ' '; + argc++; + } + } + + /* get channel mode / bans / exception / invite list */ + str = g_strdup_printf("%s %s", args, slist); + switch (mode) + { + case '\0': + while (argc-- > 0) + proxy_redirect_event(client, str, 3, "event 403", 1, + "event 443", 1, "event 324", 1, NULL); + break; + case 'b': + while (argc-- > 0) + proxy_redirect_event(client, str, 2, "event 403", 1, + "event 368", 1, "event 367", 1, NULL); + break; + case 'e': + while (argc-- > 0) + proxy_redirect_event(client, str, 4, "event 403", 1, + "event 482", 1, "event 472", -1, + "event 349", 1, "event 348", 1, NULL); + break; + case 'I': + while (argc-- > 0) + proxy_redirect_event(client, str, 4, "event 403", 1, + "event 482", 1, "event 472", -1, + "event 347", 1, "event 346", 1, NULL); + break; + } + g_free(str); + g_free(slist); + } + } + g_free(cmd); + } +} + +static void sig_listen(PLUGIN_DATA *data, gint handle) +{ + CLIENT_REC *rec; + IPADDR ip; + gint port; + + g_return_if_fail(data != NULL); + if (servers == NULL) return; + + /* accept connection */ + handle = net_accept(handle, &ip, &port); + if (handle == -1) + return; + + rec = g_new0(CLIENT_REC, 1); + rec->handle = handle; + rec->server = servers == NULL ? NULL : servers->data; + rec->tag = g_input_add(handle, G_INPUT_READ, (GInputFunction) sig_listen_client, rec); + + data->clients = g_slist_append(data->clients, rec); +} + +static gboolean sig_incoming(SERVER_REC *server, gchar *line) +{ + g_return_val_if_fail(line != NULL, FALSE); + + /* send server event to all clients */ + g_string_sprintf(next_line, "%s\n", line); + return TRUE; +} + +static gboolean sig_server_event(gchar *line, SERVER_REC *server, gchar *nick, gchar *address) +{ + GSList *tmp, *list; + gchar *event, *args; + + g_return_val_if_fail(line != NULL, FALSE); + + /* get command.. */ + event = g_strconcat("event ", line, NULL); + args = strchr(event+6, ' '); + if (args != NULL) *args++ = '\0'; else args = ""; + while (*args == ' ') args++; + + list = server_redirect_getqueue(server, event, args); + + if (list != NULL) + { + /* we want to send this to one client (or proxy itself) only */ + REDIRECT_REC *rec; + gint handle; + + rec = list->data; + if (g_strncasecmp(rec->name, "proxy ", 6) != 0) + { + /* proxy only */ + g_free(event); + return TRUE; + } + + if (sscanf(rec->name+6, "%d", &handle) == 1) + { + /* send it to specific client only */ + server_redirect_remove_next(server, event, list); + net_transmit(handle, next_line->str, next_line->len); + g_free(event); + return FALSE; + } + } + + if (g_strcasecmp(event, "event ping") == 0) + { + /* We want to answer ourself to PINGs.. */ + g_free(event); + return TRUE; + } + + /* send the data to clients.. */ + for (tmp = proxy_data->clients; tmp != NULL; tmp = tmp->next) + { + CLIENT_REC *rec = tmp->data; + + if (rec->server == server) + net_transmit(rec->handle, next_line->str, next_line->len); + } + + g_free(event); + return TRUE; +} + +static gboolean sig_server_connected(SERVER_REC *server) +{ + GSList *tmp; + + g_return_val_if_fail(server != NULL, FALSE); + + for (tmp = proxy_data->clients; tmp != NULL; tmp = tmp->next) + { + CLIENT_REC *rec = tmp->data; + + if (rec->server == NULL) + rec->server = server; + } + return TRUE; +} + +static gboolean sig_server_disconnected(SERVER_REC *server) +{ + GSList *tmp; + + g_return_val_if_fail(server != NULL, FALSE); + + for (tmp = proxy_data->clients; tmp != NULL; tmp = tmp->next) + { + CLIENT_REC *rec = tmp->data; + + if (rec->server == server) + rec->server = NULL; + } + return TRUE; +} + +void plugin_proxy_listen_init(PLUGIN_DATA *data) +{ + proxy_data = data; + g_return_if_fail(proxy_data != NULL); + + next_line = g_string_new(NULL); + + /* start listening */ + proxy_data->listen_handle = net_listen(&proxy_data->ip, &proxy_data->port); + if (proxy_data->listen_handle == -1) + { + printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "Listen failed"); + return; + } + + proxy_data->clients = NULL; + proxy_data->listen_tag = g_input_add(proxy_data->listen_handle, G_INPUT_READ, + (GInputFunction) sig_listen, proxy_data); + + signal_add("server incoming", (SIGNAL_FUNC) sig_incoming); + signal_add("server event", (SIGNAL_FUNC) sig_server_event); + signal_add("server connected", (SIGNAL_FUNC) sig_server_connected); + signal_add("server disconnected", (SIGNAL_FUNC) sig_server_disconnected); +} + +void plugin_proxy_listen_deinit(PLUGIN_DATA *data) +{ + g_return_if_fail(data != NULL); + + g_string_free(next_line, TRUE); + while (data->clients != NULL) + remove_client(data, data->clients->data); + + net_disconnect(data->listen_handle); + g_source_remove(data->listen_tag); +} diff --git a/src/irc/proxy/module.h b/src/irc/proxy/module.h new file mode 100644 index 00000000..809c2c51 --- /dev/null +++ b/src/irc/proxy/module.h @@ -0,0 +1,11 @@ +#include "common.h" + +#define MODULE_NAME "proxy" + + + + + + + + diff --git a/src/irc/proxy/proxy.c b/src/irc/proxy/proxy.c new file mode 100644 index 00000000..879d3205 --- /dev/null +++ b/src/irc/proxy/proxy.c @@ -0,0 +1,136 @@ +/* + sample.c : sample plugin for irssi + + Copyright (C) 1999 Timo Sirainen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "proxy.h" +#include "levels.h" +#include "fe-common/core/printtext.h" +#include "servers.h" +#include "net-sendbuffer.h" + +#include "lib-config/iconfig.h" +#include "settings.h" + +PLUGIN_DATA *proxy_data; +MODULE_REC *plug; + + + +gchar *plugin_description(void) +{ + return "IRC proxy plugin"; +} + +/*gint plugin_version(void) +{ + return PLUGIN_LAYER_VERSION; +} +*/ + +void proxy_settings_init(void) +{ + settings_add_str("proxy", "proxy_listen_addr", "localhost"); + settings_add_int("proxy", "proxy_listen_port", 2777); + settings_add_str("proxy", "proxy_listen_password", ""); +} + + + +/* If we call plugin_deinit() in this code, it doesn't necessarily point to + _THIS_ module's plugin_deinit() but instead some other module's.. So, + we create static deinit() function which should be used.. */ +static void deinit(/*MODULE_REC *plugin*/) +{ + plugin_proxy_listen_deinit(proxy_data); +} + + +void proxy_deinit(/*MODULE_REC *plugin*/) +{ + deinit(/*plugin*/); +} + +gboolean proxy_init(void) +{ + + gchar ipaddr[MAX_IP_LEN]; + + const char *password; + const char *addr; + int port; + + proxy_settings_init(); + + proxy_data = g_new0(PLUGIN_DATA, 1); + password = settings_get_str("proxy_listen_password"); + addr = settings_get_str("proxy_listen_addr"); + port = settings_get_int("proxy_listen_port"); + + plug = module_find("proxy"); + proxy_data->plugin = plug; + + if (*password != '\0') + { + /* args = password */ + proxy_data->password = g_strdup(password); + } + if (*addr != '\0') + { + /* specify ip address to listen */ + net_host2ip(addr, &proxy_data->ip); + } + if (port != 0) + { + /* specify port to use */ + proxy_data->port = port; + } + + if (proxy_data->password == NULL) + { + /* no password - bad idea! */ + printtext(NULL, NULL, MSGLEVEL_CLIENTNOTICE, "Warning!! Password not specified, everyone can use this proxy! Use /set proxy_listen_password to set it"); + } + + if (servers == NULL) + { + /* FIXME: not good */ + printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, "You need to specify IP address to listen with /set proxy_listen_addr
"); + deinit(); + return FALSE; + } + else + { + SERVER_REC *server; + + server = servers->data; + if (net_getsockname(net_sendbuffer_handle(server->handle), &proxy_data->ip, NULL)) + { + deinit(); + return FALSE; + } + } + + net_ip2host(&proxy_data->ip, ipaddr); + printtext(NULL, NULL, MSGLEVEL_CLIENTNOTICE, "Proxy plugin loaded - listening in interface %s port %d", ipaddr, proxy_data->port); + + plugin_proxy_listen_init(proxy_data); + + proxy_data->loaded = TRUE; + return TRUE; +} diff --git a/src/irc/proxy/proxy.h b/src/irc/proxy/proxy.h new file mode 100644 index 00000000..dadc044d --- /dev/null +++ b/src/irc/proxy/proxy.h @@ -0,0 +1,55 @@ +#ifndef __PROXY_H +#define __PROXY_H + + +#include "module.h" +#include "../../core/modules.h" + +#include "network.h" +#include +#include +#include "commands.h" + +typedef struct +{ + MODULE_REC *plugin; + gboolean loaded; + + IPADDR ip; + gint port; + gchar *password; + + gint listen_tag; + gint listen_handle; + + GSList *clients; +} +PLUGIN_DATA; + +typedef struct +{ + LINEBUF_REC *buffer; + + gchar *nick; + gint handle; + gint tag; + + SERVER_REC *server; + gboolean pass_sent; + gboolean connected; +} +CLIENT_REC; + +void plugin_proxy_setup_init(MODULE_REC *plugin); +void plugin_proxy_setup_deinit(MODULE_REC *plugin); + +void plugin_proxy_listen_init(); +void plugin_proxy_listen_deinit(); + +void proxy_settings_init(void); + +void plugin_proxy_dump_data(CLIENT_REC *client); + +/* #define MODULE_NAME "proxy" */ + +#endif -- cgit v1.2.3