From a8c139d5e2f11b5f37bdffa83fbcef0d927bae9d Mon Sep 17 00:00:00 2001 From: Timo Sirainen Date: Mon, 6 Nov 2000 02:29:01 +0000 Subject: [PATCH] Proxy plugin fixes and cleanups. Supports now multiple servers, doesn't let clients see CTCP requests and if one client writes message, other clients will see it as well. git-svn-id: http://svn.irssi.org/repos/irssi/trunk@810 dbcabf3a-b0e7-0310-adc4-f8d773084564 --- src/irc/proxy/Makefile.am | 1 - src/irc/proxy/dump.c | 259 +++++++++----- src/irc/proxy/listen.c | 686 +++++++++++++++++++++++--------------- src/irc/proxy/module.h | 36 ++ src/irc/proxy/proxy.c | 125 ++----- src/irc/proxy/proxy.h | 55 --- 6 files changed, 643 insertions(+), 519 deletions(-) delete mode 100644 src/irc/proxy/proxy.h diff --git a/src/irc/proxy/Makefile.am b/src/irc/proxy/Makefile.am index e4fd73b6..a8259c7f 100644 --- a/src/irc/proxy/Makefile.am +++ b/src/irc/proxy/Makefile.am @@ -12,5 +12,4 @@ libproxy_la_SOURCES = \ listen.c noinst_HEADERS = \ - proxy.h \ module.h diff --git a/src/irc/proxy/dump.c b/src/irc/proxy/dump.c index eb222956..1b848974 100644 --- a/src/irc/proxy/dump.c +++ b/src/irc/proxy/dump.c @@ -18,107 +18,198 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "common.h" +#include "module.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, ...) +#include "irc-servers.h" +#include "irc-channels.h" +#include "irc-nicklist.h" +#include "modes.h" + +void proxy_outdata(CLIENT_REC *client, const char *data, ...) { - va_list args; - gchar *str; + va_list args; + char *str; - va_start(args, data); + g_return_if_fail(client != NULL); + g_return_if_fail(data != NULL); - str = g_strdup_vprintf(data, args); - net_transmit(handle, str, strlen(str)); - g_free(str); + va_start(args, data); - va_end(args); + str = g_strdup_vprintf(data, args); + net_transmit(client->handle, str, strlen(str)); + g_free(str); + + va_end(args); } -static void outserver(gint handle, SERVER_REC *server, gchar *data, ...) +void proxy_outdata_all(IRC_SERVER_REC *server, const char *data, ...) { - va_list args; - gchar *str; + va_list args; + GSList *tmp; + char *str; + int len; - va_start(args, data); + g_return_if_fail(server != NULL); + g_return_if_fail(data != NULL); - 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_start(args, data); - va_end(args); + str = g_strdup_vprintf(data, args); + len = strlen(str); + for (tmp = proxy_clients; tmp != NULL; tmp = tmp->next) { + CLIENT_REC *rec = tmp->data; + + if (rec->connected && rec->server == server) + net_transmit(rec->handle, str, len); + } + g_free(str); + + va_end(args); +} + +void proxy_outserver(CLIENT_REC *client, const char *data, ...) +{ + va_list args; + char *str; + + g_return_if_fail(client != NULL); + g_return_if_fail(data != NULL); + + va_start(args, data); + + str = g_strdup_vprintf(data, args); + proxy_outdata(client, ":%s!%s@proxy %s\n", client->nick, + settings_get_str("user_name"), str); + g_free(str); + + va_end(args); +} + +/*void proxy_outserver_all(IRC_SERVER_REC *server, const char *data, ...) +{ + va_list args; + GSList *tmp; + char *str; + + g_return_if_fail(server != NULL); + g_return_if_fail(data != NULL); + + va_start(args, data); + + str = g_strdup_vprintf(data, args); + for (tmp = proxy_clients; tmp != NULL; tmp = tmp->next) { + CLIENT_REC *rec = tmp->data; + + if (rec->connected && rec->server == server) { + proxy_outdata(rec, ":%s!%s@proxy %s\n", rec->nick, + settings_get_str("user_name"), str); + } + } + g_free(str); + + va_end(args); +}*/ + +void proxy_outserver_all_except(CLIENT_REC *client, const char *data, ...) +{ + va_list args; + GSList *tmp; + char *str; + + g_return_if_fail(client != NULL); + g_return_if_fail(data != NULL); + + va_start(args, data); + + str = g_strdup_vprintf(data, args); + for (tmp = proxy_clients; tmp != NULL; tmp = tmp->next) { + CLIENT_REC *rec = tmp->data; + + if (rec->connected && rec != client && + rec->server == client->server) { + proxy_outdata(rec, ":%s!%s@proxy %s\n", rec->nick, + settings_get_str("user_name"), str); + } + } + g_free(str); + + va_end(args); +} + +static void dump_join(IRC_CHANNEL_REC *channel, CLIENT_REC *client) +{ + GSList *tmp, *nicks; + GString *str; + + proxy_outserver(client, "JOIN %s", channel->name); + proxy_outdata(client, ":proxy 353 %s %c %s :", client->nick, + channel_mode_is_set(channel, 'p') ? '*' : + channel_mode_is_set(channel, 's') ? '@' : '=', + channel->name); + + str = g_string_new(NULL); + + nicks = nicklist_getnicks(CHANNEL(channel)); + for (tmp = nicks; tmp != NULL; tmp = tmp->next) { + NICK_REC *nick = tmp->data; + + if (tmp != nicks) + g_string_append_c(str, ' '); + + if (nick->op) + g_string_append_c(str, '@'); + else if (nick->halfop) + g_string_append_c(str, '%'); + else if (nick->voice) + g_string_append_c(str, '+'); + g_string_append(str, nick->nick); + } + g_slist_free(nicks); + + g_string_append_c(str, '\n'); + proxy_outdata(client, str->str); + g_string_free(str, TRUE); + + proxy_outdata(client, ":proxy 366 %s %s :End of /NAMES list.\n", + client->nick, channel->name); + if (channel->topic != NULL) { + proxy_outdata(client, ":proxy 332 %s %s :%s\n", + client->nick, channel->name, channel->topic); + } } 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)); + if (strcmp(client->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. */ + proxy_outdata(client, ":%s!proxy NICK :%s\n", + client->nick, client->server->nick); + g_free(client->nick); + client->nick = g_strdup(client->server->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); - } + /* welcome info */ + proxy_outdata(client, ":proxy 001 %s :Welcome to the Internet Relay Network\n", client->nick); + proxy_outdata(client, ":proxy 002 %s :Your host is irssi-proxy, running version %s\n", client->nick, VERSION); + proxy_outdata(client, ":proxy 003 %s :This server was created ...\n", client->nick); + if (!client->server->emode_known) + proxy_outdata(client, ":proxy 004 %s proxy %s oirw abiklmnopqstv\n", client->nick, VERSION); + else + proxy_outdata(client, ":proxy 004 %s proxy %s oirw abeIiklmnopqstv\n", client->nick, VERSION); + proxy_outdata(client, ":proxy 251 %s :There are 0 users and 0 invisible on 1 servers\n", client->nick); + proxy_outdata(client, ":proxy 255 %s :I have 0 clients, 0 services and 0 servers\n", client->nick); + proxy_outdata(client, ":proxy 422 %s :MOTD File is missing\n", client->nick); + + /* user mode / away status */ + proxy_outserver(client, "MODE %s :+%s", client->server->nick, + client->server->usermode); + if (client->server->usermode_away) + proxy_outdata(client, ":proxy 306 %s :You have been marked as being away\n", client->nick); + + /* Send channel joins */ + g_slist_foreach(client->server->channels, (GFunc) dump_join, client); } diff --git a/src/irc/proxy/listen.c b/src/irc/proxy/listen.c index c5453442..ac8c0f67 100644 --- a/src/irc/proxy/listen.c +++ b/src/irc/proxy/listen.c @@ -19,154 +19,148 @@ */ #include "module.h" -#include "proxy.h" +#include "signals.h" #include "net-sendbuffer.h" -#include "fe-common/core/printtext.h" +#include "servers-redirect.h" #include "levels.h" +#include "settings.h" + +#include "irc.h" +#include "irc-channels.h" + +#include "fe-common/core/printtext.h" + +GSList *proxy_listens; +GSList *proxy_clients; -static PLUGIN_DATA *proxy_data; static GString *next_line; -void remove_client(PLUGIN_DATA *data, CLIENT_REC *rec) +static void remove_client(CLIENT_REC *rec) { - data->clients = g_slist_remove(data->clients, rec); + g_return_if_fail(rec != NULL); - net_disconnect(rec->handle); - g_source_remove(rec->tag); - line_split_free(rec->buffer); - g_free(rec); + proxy_clients = g_slist_remove(proxy_clients, rec); + + net_disconnect(rec->handle); + g_source_remove(rec->tag); + line_split_free(rec->buffer); + g_free_not_null(rec->nick); + g_free(rec); } -static void proxy_redirect_event(CLIENT_REC *client, gchar *args, gint last, ...) +static void proxy_redirect_event(CLIENT_REC *client, + const char *args, int last, ...) { - va_list vargs; - gchar *event; - gint argpos, group; - GString *str; + va_list vargs; + GString *str; + char *event; + int argpos, group; - g_return_if_fail(client != NULL); + g_return_if_fail(client != NULL); - va_start(vargs, last); + 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 = '*'; + str = g_string_new(NULL); + group = 0; + while ((event = va_arg(vargs, char *)) != NULL) { + argpos = va_arg(vargs, int); + g_string_sprintf(str, "proxy %d", client->handle); + group = server_redirect_single_event(SERVER(client->server), args, last > 0, + group, event, str->str, argpos); + last--; } + g_string_free(str, TRUE); - 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); + va_end(vargs); } -static void sig_listen_client(CLIENT_REC *client, gint handle) +static void grab_who(CLIENT_REC *client, const char *channel) { - char tmpbuf[1024], *str, *cmd, *args, *p; - int ret, recvlen; + char *chlist, *chanevent; + char **list, **tmp; - g_return_if_fail(client != NULL); + /* /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 (;;) - { - 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; + for (tmp = list; *tmp != NULL; tmp++) { + if (strcmp(*tmp, "0") == 0) { + /* /who 0 displays everyone */ + **tmp = '*'; } - client->pass_sent = TRUE; - } - else if (strcmp(cmd, "NICK") == 0) + + chanevent = g_strdup_printf("%s %s", chlist, *tmp); + proxy_redirect_event(client, chanevent, 2, + "event 401", 1, "event 315", 1, + "event 352", -1, NULL); + g_free(chanevent); + } + g_strfreev(list); + g_free(chlist); +} + +static void handle_client_connect_cmd(CLIENT_REC *client, + const char *cmd, const char *args) +{ + const char *password; + + password = settings_get_str("irssiproxy_password"); + + if (password != NULL && strcmp(cmd, "PASS") == 0) { + if (strcmp(password, args) == 0) + client->pass_sent = TRUE; + else { + /* wrong password! */ + remove_client(client); + } + } else if (strcmp(cmd, "NICK") == 0) { + g_free_not_null(client->nick); 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; + } else if (strcmp(cmd, "USER") == 0) { + if (client->nick == NULL || + (*password != '\0' && !client->pass_sent)) { + /* stupid client didn't send us NICK/PASS, kill it */ + remove_client(client); + } else { + client->connected = TRUE; + plugin_proxy_dump_data(client); } - 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) - { +static void handle_client_cmd(CLIENT_REC *client, char *cmd, char *args) +{ + int server_handle; + + if (!client->connected) { + handle_client_connect_cmd(client, cmd, args); + return; + } + + if (strcmp(cmd, "QUIT") == 0) { + remove_client(client); + return; + } + if (strcmp(cmd, "PING") == 0) { + proxy_outdata(client, "PONG proxy :%s\n", args); + return; + } + + server_handle = net_sendbuffer_handle(client->server->handle); + net_transmit(server_handle, cmd, strlen(cmd)); + net_transmit(server_handle, " ", 1); + net_transmit(server_handle, args, strlen(args)); + net_transmit(server_handle, "\n", 1); + + if (strcmp(cmd, "WHO") == 0) grab_who(client, args); - } - else if (strcmp(cmd, "WHOIS") == 0) - { + else if (strcmp(cmd, "WHOIS") == 0) { + char *p; + /* convert dots to spaces */ for (p = args; *p != '\0'; p++) - if (*p == ',') *p = ' '; + if (*p == ',') *p = ' '; proxy_redirect_event(client, args, 2, "event 318", -1, "event 402", -1, @@ -174,20 +168,14 @@ static void sig_listen_client(CLIENT_REC *client, gint handle) "event 301", 1, "event 312", 1, "event 313", 1, "event 317", 1, "event 319", 1, NULL); - } - else if (strcmp(cmd, "ISON") == 0) - { + } else if (strcmp(cmd, "ISON") == 0) proxy_redirect_event(client, NULL, 1, "event 303", -1, NULL); - } - else if (strcmp(cmd, "USERHOST") == 0) - { + 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) - { + else if (strcmp(cmd, "MODE") == 0) { /* convert dots to spaces */ - gchar *slist, *str, mode; - gint argc; + char *slist, *str, mode, *p; + int argc; p = strchr(args, ' '); if (p != NULL) *p++ = '\0'; @@ -195,205 +183,355 @@ static void sig_listen_client(CLIENT_REC *client, gint handle) slist = g_strdup(args); argc = 1; - for (p = slist; *p != '\0'; p++) - { - if (*p == ',') - { - *p = ' '; - argc++; - } + 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': + switch (mode) { + case '\0': 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); + proxy_redirect_event(client, str, 3, "event 403", 1, + "event 443", 1, "event 324", 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); + 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); - } + } else if (strcmp(cmd, "PRIVMSG") == 0) { + /* send the message to other clients as well */ + char *params, *target, *msg; + + params = event_get_params(args, 2 | PARAM_FLAG_GETREST, + &target, &msg); + proxy_outserver_all_except(client, "PRIVMSG %s", args); + signal_emit("message public", 5, client->server, msg, + client->nick, "proxy", target); + g_free(params); } - g_free(cmd); - } } -static void sig_listen(PLUGIN_DATA *data, gint handle) +static void sig_listen_client(CLIENT_REC *client) { - CLIENT_REC *rec; - IPADDR ip; - gint port; + char tmpbuf[1024], *str, *cmd, *args; + int ret, recvlen; - g_return_if_fail(data != NULL); - if (servers == NULL) return; + g_return_if_fail(client != NULL); - /* accept connection */ - handle = net_accept(handle, &ip, &port); - if (handle == -1) - return; + while (g_slist_find(proxy_clients, client) != NULL) { + recvlen = net_receive(client->handle, tmpbuf, sizeof(tmpbuf)); + ret = line_split(tmpbuf, recvlen, &str, &client->buffer); + if (ret == -1) { + /* connection lost */ + remove_client(client); + break; + } - 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); + if (ret == 0) break; - data->clients = g_slist_append(data->clients, rec); + 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); + + handle_client_cmd(client, cmd, args); + + g_free(cmd); + } } -static gboolean sig_incoming(SERVER_REC *server, gchar *line) +static void sig_listen(LISTEN_REC *listen) { - g_return_val_if_fail(line != NULL, FALSE); + CLIENT_REC *rec; + IPADDR ip; + char host[MAX_IP_LEN]; + int port, handle; - /* send server event to all clients */ - g_string_sprintf(next_line, "%s\n", line); - return TRUE; + g_return_if_fail(listen != NULL); + + /* accept connection */ + handle = net_accept(listen->handle, &ip, &port); + if (handle == -1) + return; + net_ip2host(&ip, host); + + rec = g_new0(CLIENT_REC, 1); + rec->listen = listen; + rec->handle = handle; + rec->server = IRC_SERVER(server_find_chatnet(listen->ircnet)); + rec->tag = g_input_add(handle, G_INPUT_READ, + (GInputFunction) sig_listen_client, rec); + + proxy_clients = g_slist_append(proxy_clients, rec); + printtext(NULL, NULL, MSGLEVEL_CLIENTNOTICE, + "Proxy: Client connected from %s", host); } -static gboolean sig_server_event(gchar *line, SERVER_REC *server, gchar *nick, gchar *address) +static void sig_incoming(IRC_SERVER_REC *server, const char *line) { - GSList *tmp, *list; - gchar *event, *args; + g_return_if_fail(line != NULL); - g_return_val_if_fail(line != NULL, FALSE); + /* send server event to all clients */ + g_string_sprintf(next_line, "%s\n", line); +} - /* get command.. */ - event = g_strconcat("event ", line, NULL); - args = strchr(event+6, ' '); - if (args != NULL) *args++ = '\0'; else args = ""; - while (*args == ' ') args++; +static void sig_server_event(const char *line, IRC_SERVER_REC *server, + const char *nick, const char *address) +{ + GSList *list; + char *event, *args; - list = server_redirect_getqueue(server, event, args); + g_return_if_fail(line != NULL); + if (!IS_IRC_SERVER(server)) + return; - if (list != NULL) - { - /* we want to send this to one client (or proxy itself) only */ - REDIRECT_REC *rec; - gint handle; + /* get command.. */ + event = g_strconcat("event ", line, NULL); + args = strchr(event+6, ' '); + if (args != NULL) *args++ = '\0'; else args = ""; + while (*args == ' ') args++; - rec = list->data; - if (g_strncasecmp(rec->name, "proxy ", 6) != 0) - { - /* proxy only */ - g_free(event); - return TRUE; + list = server_redirect_getqueue(SERVER(server), event, args); + + if (list != NULL) { + /* we want to send this to one client (or proxy itself) only */ + REDIRECT_REC *rec; + int handle; + + rec = list->data; + if (g_strncasecmp(rec->name, "proxy ", 6) != 0) { + /* proxy only */ + g_free(event); + return; + } + + if (sscanf(rec->name+6, "%d", &handle) == 1) { + /* send it to specific client only */ + server_redirect_remove_next(SERVER(server), event, list); + net_transmit(handle, next_line->str, next_line->len); + g_free(event); + signal_stop(); + return; + } } - 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 || + (g_strcasecmp(event, "event privmsg") == 0 && + strstr(args, " :\001") != NULL)) { + /* We want to answer ourself to PINGs and CTCPs */ + g_free(event); + return; } - } - if (g_strcasecmp(event, "event ping") == 0) - { - /* We want to answer ourself to PINGs.. */ + /* send the data to clients.. */ + proxy_outdata_all(server, next_line->str); + 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) +static void sig_server_connected(IRC_SERVER_REC *server) { - GSList *tmp; + GSList *tmp; - g_return_val_if_fail(server != NULL, FALSE); + if (!IS_IRC_SERVER(server) || server->connrec->chatnet == NULL) + return; - for (tmp = proxy_data->clients; tmp != NULL; tmp = tmp->next) - { - CLIENT_REC *rec = tmp->data; + for (tmp = proxy_clients; tmp != NULL; tmp = tmp->next) { + CLIENT_REC *rec = tmp->data; - if (rec->server == NULL) - rec->server = server; - } - return TRUE; + if (rec->connected && rec->server == NULL && + g_strcasecmp(server->connrec->chatnet, rec->listen->ircnet) == 0) { + proxy_outserver(rec, "NOTICE %s :Connected to server", rec->nick); + rec->server = server; + } + } } -static gboolean sig_server_disconnected(SERVER_REC *server) +static void proxy_server_disconnected(CLIENT_REC *client, + IRC_SERVER_REC *server) { - GSList *tmp; + GSList *tmp; - g_return_val_if_fail(server != NULL, FALSE); + proxy_outdata(client, ":proxy NOTICE %s :Connection lost to server %s\n", + client->nick, server->connrec->address); - for (tmp = proxy_data->clients; tmp != NULL; tmp = tmp->next) - { - CLIENT_REC *rec = tmp->data; + for (tmp = server->channels; tmp != NULL; tmp = tmp->next) { + IRC_CHANNEL_REC *rec = tmp->data; - if (rec->server == server) - rec->server = NULL; - } - return TRUE; + proxy_outserver(client, "PART %s :Connection lost to server", + rec->name); + } } -void plugin_proxy_listen_init(PLUGIN_DATA *data) +static void sig_server_disconnected(IRC_SERVER_REC *server) { - proxy_data = data; - g_return_if_fail(proxy_data != NULL); + GSList *tmp; - next_line = g_string_new(NULL); + if (!IS_IRC_SERVER(server)) + return; - /* 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; - } + for (tmp = proxy_clients; tmp != NULL; tmp = tmp->next) { + CLIENT_REC *rec = tmp->data; - 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); + if (rec->connected && rec->server == server) { + proxy_server_disconnected(rec, server); + rec->server = NULL; + } + } } -void plugin_proxy_listen_deinit(PLUGIN_DATA *data) +static void event_nick(const char *data, IRC_SERVER_REC *server) { - g_return_if_fail(data != NULL); + GSList *tmp; - g_string_free(next_line, TRUE); - while (data->clients != NULL) - remove_client(data, data->clients->data); + if (*data == ':') data++; + for (tmp = proxy_clients; tmp != NULL; tmp = tmp->next) { + CLIENT_REC *rec = tmp->data; - net_disconnect(data->listen_handle); - g_source_remove(data->listen_tag); + if (rec->connected && rec->server == server) { + g_free(rec->nick); + rec->nick = g_strdup(data); + } + } +} + +static LISTEN_REC *find_listen(const char *ircnet, int port) +{ + GSList *tmp; + + for (tmp = proxy_listens; tmp != NULL; tmp = tmp->next) { + LISTEN_REC *rec = tmp->data; + + if (rec->port == port && + g_strcasecmp(rec->ircnet, ircnet) == 0) + return rec; + } + + return NULL; +} + +static void add_listen(const char *ircnet, int port) +{ + LISTEN_REC *rec; + + if (port <= 0 || *ircnet == '\0') return; + + rec = g_new0(LISTEN_REC, 1); + rec->ircnet = g_strdup(ircnet); + rec->port = port; + + /* start listening */ + rec->handle = net_listen(NULL, &rec->port); + if (rec->handle == -1) { + printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, + "Proxy: Listen in port %d failed: %s", + rec->port, g_strerror(errno)); + return; + } + + rec->tag = g_input_add(rec->handle, G_INPUT_READ, + (GInputFunction) sig_listen, rec); + + proxy_listens = g_slist_append(proxy_listens, rec); +} + +static void remove_listen(LISTEN_REC *rec) +{ + proxy_listens = g_slist_remove(proxy_listens, rec); + + net_disconnect(rec->handle); + g_source_remove(rec->tag); + g_free(rec->ircnet); + g_free(rec); +} + +static void read_settings(void) +{ + LISTEN_REC *rec; + GSList *remove_listens; + char **ports, **tmp, *ircnet, *port; + int portnum; + + remove_listens = g_slist_copy(proxy_listens); + + ports = g_strsplit(settings_get_str("irssiproxy_ports"), " ", -1); + for (tmp = ports; *tmp != NULL; tmp++) { + ircnet = *tmp; + port = strchr(ircnet, '='); + if (port == NULL) + continue; + + *port++ = '\0'; + portnum = atoi(port); + if (portnum <= 0) + continue; + + rec = find_listen(ircnet, portnum); + if (rec == NULL) + add_listen(ircnet, portnum); + else + remove_listens = g_slist_remove(remove_listens, rec); + } + g_strfreev(ports); + + while (remove_listens != NULL) { + remove_listen(remove_listens->data); + g_slist_remove(remove_listens, remove_listens->data); + } +} + +void plugin_proxy_listen_init(void) +{ + next_line = g_string_new(NULL); + + proxy_clients = NULL; + proxy_listens = NULL; + read_settings(); + + 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); + signal_add("event nick", (SIGNAL_FUNC) event_nick); + signal_add("setup changed", (SIGNAL_FUNC) read_settings); +} + +void plugin_proxy_listen_deinit(void) +{ + while (proxy_clients != NULL) + remove_client(proxy_clients->data); + while (proxy_listens != NULL) + remove_listen(proxy_listens->data); + g_string_free(next_line, TRUE); + + signal_remove("server incoming", (SIGNAL_FUNC) sig_incoming); + signal_remove("server event", (SIGNAL_FUNC) sig_server_event); + signal_remove("server connected", (SIGNAL_FUNC) sig_server_connected); + signal_remove("server disconnected", (SIGNAL_FUNC) sig_server_disconnected); + signal_remove("event nick", (SIGNAL_FUNC) event_nick); + signal_remove("setup changed", (SIGNAL_FUNC) read_settings); } diff --git a/src/irc/proxy/module.h b/src/irc/proxy/module.h index 809c2c51..e0ccf856 100644 --- a/src/irc/proxy/module.h +++ b/src/irc/proxy/module.h @@ -2,10 +2,46 @@ #define MODULE_NAME "proxy" +#include "network.h" +#include "line-split.h" +#include "irc-servers.h" +typedef struct { + int port; + char *ircnet; + int tag; + int handle; +} LISTEN_REC; +typedef struct { + LINEBUF_REC *buffer; + char *nick; + int handle; + int tag; + LISTEN_REC *listen; + IRC_SERVER_REC *server; + int pass_sent:1; + int connected:1; +} CLIENT_REC; +extern GSList *proxy_listens; +extern GSList *proxy_clients; +void plugin_proxy_setup_init(void); +void plugin_proxy_setup_deinit(void); + +void plugin_proxy_listen_init(void); +void plugin_proxy_listen_deinit(void); + +void proxy_settings_init(void); + +void plugin_proxy_dump_data(CLIENT_REC *client); + +void proxy_outdata(CLIENT_REC *client, const char *data, ...); +void proxy_outdata_all(IRC_SERVER_REC *server, const char *data, ...); +void proxy_outserver(CLIENT_REC *client, const char *data, ...); +/*void proxy_outserver_all(const char *data, ...);*/ +void proxy_outserver_all_except(CLIENT_REC *client, const char *data, ...); diff --git a/src/irc/proxy/proxy.c b/src/irc/proxy/proxy.c index 879d3205..ab7ef4cc 100644 --- a/src/irc/proxy/proxy.c +++ b/src/irc/proxy/proxy.c @@ -18,119 +18,34 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include "proxy.h" +#include "module.h" +#include "settings.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) +void proxy_deinit(void) { - return "IRC proxy plugin"; + plugin_proxy_listen_deinit(); } -/*gint plugin_version(void) +void proxy_init(void) { - return PLUGIN_LAYER_VERSION; -} -*/ + settings_add_str("irssiproxy", "irssiproxy_ports", ""); + settings_add_str("irssiproxy", "irssiproxy_password", ""); -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; + if (*settings_get_str("irssiproxy_password") == '\0') { + /* no password - bad idea! */ + printtext(NULL, NULL, MSGLEVEL_CLIENTNOTICE, + "Warning!! Password not specified, everyone can " + "use this proxy! Use /set irssiproxy_password " + " to set it"); + } + if (*settings_get_str("irssiproxy_ports") == '\0') { + printtext(NULL, NULL, MSGLEVEL_CLIENTNOTICE, + "No proxy ports specified. Use /SET " + "irssiproxy_ports = = " + "... to set them."); } - } - 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; + plugin_proxy_listen_init(); } diff --git a/src/irc/proxy/proxy.h b/src/irc/proxy/proxy.h deleted file mode 100644 index dadc044d..00000000 --- a/src/irc/proxy/proxy.h +++ /dev/null @@ -1,55 +0,0 @@ -#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