diff options
author | ailin-nemui <ailin-nemui@users.noreply.github.com> | 2016-09-21 15:59:33 +0200 |
---|---|---|
committer | ailin-nemui <ailin-nemui@users.noreply.github.com> | 2016-09-21 15:59:33 +0200 |
commit | ac73255483a42851db6a54ae4f0d5040e94608a2 (patch) | |
tree | 23c38bc6224171640d44be3269053948dd1a92e8 /src/irc | |
parent | 13f4026ae0f0d5422f3163576d4c2eff8754176a (diff) | |
parent | d9b4cb34dccd7fb77e1d222333f3018ff947899c (diff) | |
download | irssi-ac73255483a42851db6a54ae4f0d5040e94608a2.zip |
Merge branch 'master' into integrate/0.8.20
Diffstat (limited to 'src/irc')
-rw-r--r-- | src/irc/core/irc-channels-setup.c | 6 | ||||
-rw-r--r-- | src/irc/core/irc-nicklist.c | 2 | ||||
-rw-r--r-- | src/irc/core/irc-servers.c | 44 | ||||
-rw-r--r-- | src/irc/dcc/dcc-chat.c | 2 | ||||
-rw-r--r-- | src/irc/dcc/dcc-get.c | 16 | ||||
-rw-r--r-- | src/irc/dcc/dcc-resume.c | 2 | ||||
-rw-r--r-- | src/irc/dcc/dcc-server.c | 2 | ||||
-rw-r--r-- | src/irc/dcc/dcc.c | 6 | ||||
-rw-r--r-- | src/irc/proxy/listen.c | 316 | ||||
-rw-r--r-- | src/irc/proxy/proxy.c | 9 | ||||
-rw-r--r-- | src/irc/proxy/proxy.h | 6 |
11 files changed, 263 insertions, 148 deletions
diff --git a/src/irc/core/irc-channels-setup.c b/src/irc/core/irc-channels-setup.c index 2320352d..bbbc095c 100644 --- a/src/irc/core/irc-channels-setup.c +++ b/src/irc/core/irc-channels-setup.c @@ -24,10 +24,12 @@ void irc_channels_setup_init(void) { - signal_add("channel wholist", (SIGNAL_FUNC) channel_send_autocommands); + signal_add("channel wholist", (SIGNAL_FUNC) channel_send_botcommands); + signal_add("channel joined", (SIGNAL_FUNC) channel_send_autocommands); } void irc_channels_setup_deinit(void) { - signal_remove("channel wholist", (SIGNAL_FUNC) channel_send_autocommands); + signal_remove("channel wholist", (SIGNAL_FUNC) channel_send_botcommands); + signal_remove("channel joined", (SIGNAL_FUNC) channel_send_autocommands); } diff --git a/src/irc/core/irc-nicklist.c b/src/irc/core/irc-nicklist.c index bcb9d1f6..b22f3269 100644 --- a/src/irc/core/irc-nicklist.c +++ b/src/irc/core/irc-nicklist.c @@ -48,7 +48,7 @@ NICK_REC *irc_nicklist_insert(IRC_CHANNEL_REC *channel, const char *nick, rec->send_massjoin = send_massjoin; if (prefixes != NULL) { - strocpy(rec->prefixes, prefixes, sizeof(rec->prefixes)); + g_strlcpy(rec->prefixes, prefixes, sizeof(rec->prefixes)); } nicklist_insert(CHANNEL(channel), rec); diff --git a/src/irc/core/irc-servers.c b/src/irc/core/irc-servers.c index f905a862..8148997b 100644 --- a/src/irc/core/irc-servers.c +++ b/src/irc/core/irc-servers.c @@ -214,7 +214,6 @@ static void server_init(IRC_SERVER_REC *server) { IRC_SERVER_CONNECT_REC *conn; char *address, *ptr, *username, *cmd; - GTimeVal now; g_return_if_fail(server != NULL); @@ -289,9 +288,8 @@ static void server_init(IRC_SERVER_REC *server) /* prevent the queue from sending too early, we have a max cut off of 120 secs */ /* this will reset to 1 sec after we get the 001 event */ - g_get_current_time(&now); - memcpy(&((IRC_SERVER_REC *)server)->wait_cmd, &now, sizeof(GTimeVal)); - ((IRC_SERVER_REC *)server)->wait_cmd.tv_sec += 120; + g_get_current_time(&server->wait_cmd); + g_time_val_add(&server->wait_cmd, 120 * G_USEC_PER_SEC); } SERVER_REC *irc_server_init_connect(SERVER_CONNECT_REC *conn) @@ -537,7 +535,7 @@ void irc_server_send_data(IRC_SERVER_REC *server, const char *data, int len) server->wait_cmd.tv_sec = 0; else { memcpy(&server->wait_cmd, &server->last_cmd, sizeof(GTimeVal)); - server->wait_cmd.tv_sec += 2 + len/100; + g_time_val_add(&server->wait_cmd, (2 + len/100) * G_USEC_PER_SEC); } } @@ -625,39 +623,25 @@ char *irc_server_get_channels(IRC_SERVER_REC *server) GString *chans, *keys; char *ret; int use_keys; - char *rejoin_channels_mode; + int rejoin_channels_mode; g_return_val_if_fail(server != NULL, FALSE); - rejoin_channels_mode = g_strdup(settings_get_str("rejoin_channels_on_reconnect")); + rejoin_channels_mode = settings_get_choice("rejoin_channels_on_reconnect"); - if (rejoin_channels_mode == NULL || - (g_ascii_strcasecmp(rejoin_channels_mode, "on") != 0 && - g_ascii_strcasecmp(rejoin_channels_mode, "off") != 0 && - g_ascii_strcasecmp(rejoin_channels_mode, "auto") != 0)) { - g_warning("Invalid value for 'rejoin_channels_on_reconnect', valid values are 'on', 'off', 'auto', using 'on' as default value."); - g_free(rejoin_channels_mode); - rejoin_channels_mode = g_strdup("on"); - } + /* do we want to rejoin channels in the first place? */ + if(rejoin_channels_mode == 0) + return g_strdup(""); chans = g_string_new(NULL); keys = g_string_new(NULL); use_keys = FALSE; - /* do we want to rejoin channels in the first place? */ - if(g_ascii_strcasecmp(rejoin_channels_mode, "off") == 0) { - g_string_free(chans, TRUE); - g_string_free(keys, TRUE); - g_free(rejoin_channels_mode); - return g_strdup(""); - } - /* get currently joined channels */ for (tmp = server->channels; tmp != NULL; tmp = tmp->next) { CHANNEL_REC *channel = tmp->data; CHANNEL_SETUP_REC *setup = channel_setup_find(channel->name, channel->server->connrec->chatnet); - if ((setup != NULL && setup->autojoin && g_ascii_strcasecmp(rejoin_channels_mode, "auto") == 0) || - g_ascii_strcasecmp(rejoin_channels_mode, "on") == 0) { + if ((setup != NULL && setup->autojoin && rejoin_channels_mode == 2) || rejoin_channels_mode == 1) { g_string_append_printf(chans, "%s,", channel->name); g_string_append_printf(keys, "%s,", channel->key == NULL ? "x" : channel->key); if (channel->key != NULL) @@ -670,8 +654,7 @@ char *irc_server_get_channels(IRC_SERVER_REC *server) REJOIN_REC *rec = tmp->data; CHANNEL_SETUP_REC *setup = channel_setup_find(rec->channel, server->tag); - if ((setup != NULL && setup->autojoin && g_ascii_strcasecmp(rejoin_channels_mode, "auto") == 0) || - g_ascii_strcasecmp(rejoin_channels_mode, "on") == 0) { + if ((setup != NULL && setup->autojoin && rejoin_channels_mode == 2) || rejoin_channels_mode == 1) { g_string_append_printf(chans, "%s,", rec->channel); g_string_append_printf(keys, "%s,", rec->key == NULL ? "x" : rec->key); @@ -689,7 +672,6 @@ char *irc_server_get_channels(IRC_SERVER_REC *server) ret = chans->str; g_string_free(chans, FALSE); g_string_free(keys, TRUE); - g_free(rejoin_channels_mode); return ret; } @@ -697,7 +679,6 @@ char *irc_server_get_channels(IRC_SERVER_REC *server) static void event_connected(IRC_SERVER_REC *server, const char *data, const char *from) { char *params, *nick; - GTimeVal now; g_return_if_fail(server != NULL); @@ -720,8 +701,7 @@ static void event_connected(IRC_SERVER_REC *server, const char *data, const char server->real_connect_time = time(NULL); /* let the queue send now that we are identified */ - g_get_current_time(&now); - memcpy(&server->wait_cmd, &now, sizeof(GTimeVal)); + g_get_current_time(&server->wait_cmd); if (server->connrec->usermode != NULL) { /* Send the user mode, before the autosendcmd. @@ -1035,7 +1015,7 @@ void irc_server_init_isupport(IRC_SERVER_REC *server) void irc_servers_init(void) { - settings_add_str("servers", "rejoin_channels_on_reconnect", "on"); + settings_add_choice("servers", "rejoin_channels_on_reconnect", 1, "off;on;auto"); settings_add_str("misc", "usermode", DEFAULT_USER_MODE); settings_add_str("misc", "split_line_start", ""); settings_add_str("misc", "split_line_end", ""); diff --git a/src/irc/dcc/dcc-chat.c b/src/irc/dcc/dcc-chat.c index e3dbe72d..ca90b8d8 100644 --- a/src/irc/dcc/dcc-chat.c +++ b/src/irc/dcc/dcc-chat.c @@ -619,7 +619,7 @@ static void ctcp_msg_dcc_chat(IRC_SERVER_REC *server, const char *data, /* CHAT <unused> <address> <port> */ /* CHAT <unused> <address> 0 <id> (DCC CHAT passive protocol) */ params = g_strsplit(data, " ", -1); - paramcount = strarray_length(params); + paramcount = g_strv_length(params); if (paramcount < 3) { g_strfreev(params); diff --git a/src/irc/dcc/dcc-get.c b/src/irc/dcc/dcc-get.c index a8b1c967..f7a95bb9 100644 --- a/src/irc/dcc/dcc-get.c +++ b/src/irc/dcc/dcc-get.c @@ -423,7 +423,7 @@ static void ctcp_msg_dcc_send(IRC_SERVER_REC *server, const char *data, /* SEND <file name> <address> <port> <size> [...] */ /* SEND <file name> <address> 0 <size> <id> (DCC SEND passive protocol) */ params = g_strsplit(data, " ", -1); - paramcount = strarray_length(params); + paramcount = g_strv_length(params); if (paramcount < 4) { signal_emit("dcc error ctcp", 5, "SEND", data, @@ -473,8 +473,8 @@ static void ctcp_msg_dcc_send(IRC_SERVER_REC *server, const char *data, net_ip2host(&temp_dcc->addr, temp_dcc->addrstr); else { /* with IPv6, show it to us as it was sent */ - strocpy(temp_dcc->addrstr, address, - sizeof(temp_dcc->addrstr)); + g_strlcpy(temp_dcc->addrstr, address, + sizeof(temp_dcc->addrstr)); } /* This new signal is added to let us invoke @@ -508,7 +508,7 @@ static void ctcp_msg_dcc_send(IRC_SERVER_REC *server, const char *data, net_ip2host(&dcc->addr, dcc->addrstr); else { /* with IPv6, show it to us as it was sent */ - strocpy(dcc->addrstr, address, sizeof(dcc->addrstr)); + g_strlcpy(dcc->addrstr, address, sizeof(dcc->addrstr)); } dcc->port = port; dcc->size = size; @@ -526,14 +526,14 @@ void cmd_dcc_receive(const char *data, DCC_GET_FUNC accept_func, { GET_DCC_REC *dcc; GSList *tmp, *next; - char *nick, *fname; + char *nick, *arg, *fname; void *free_arg; int found; g_return_if_fail(data != NULL); - if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_GETREST, - &nick, &fname)) + if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_GETREST | + PARAM_FLAG_STRIP_TRAILING_WS, &nick, &arg)) return; if (*nick == '\0') { @@ -548,6 +548,8 @@ void cmd_dcc_receive(const char *data, DCC_GET_FUNC accept_func, return; } + fname = cmd_get_quoted_param(&arg); + found = FALSE; for (tmp = dcc_conns; tmp != NULL; tmp = next) { GET_DCC_REC *dcc = tmp->data; diff --git a/src/irc/dcc/dcc-resume.c b/src/irc/dcc/dcc-resume.c index 11b28aef..36f84ddf 100644 --- a/src/irc/dcc/dcc-resume.c +++ b/src/irc/dcc/dcc-resume.c @@ -88,7 +88,7 @@ static int dcc_ctcp_resume_parse(int type, const char *data, const char *nick, /* RESUME|ACCEPT <file name> <port> <size> */ /* RESUME|ACCEPT <file name> 0 <size> <id> (passive protocol) */ params = g_strsplit(data, " ", -1); - paramcount = strarray_length(params); + paramcount = g_strv_length(params); if (paramcount < 3) return 0; diff --git a/src/irc/dcc/dcc-server.c b/src/irc/dcc/dcc-server.c index 30224ff9..7ae572cd 100644 --- a/src/irc/dcc/dcc-server.c +++ b/src/irc/dcc/dcc-server.c @@ -245,7 +245,7 @@ static void dcc_server_msg(SERVER_DCC_REC *dcc, const char *msg) /* 120 clientnickname filesize filename */ params = g_strsplit(msg, " ", -1); - paramcount = strarray_length(params); + paramcount = g_strv_length(params); if (paramcount < 3) { g_strfreev(params); diff --git a/src/irc/dcc/dcc.c b/src/irc/dcc/dcc.c index 17f6c477..c51f7c7a 100644 --- a/src/irc/dcc/dcc.c +++ b/src/irc/dcc/dcc.c @@ -490,7 +490,7 @@ static void event_no_such_nick(IRC_SERVER_REC *server, char *data) static void cmd_dcc_close(char *data, IRC_SERVER_REC *server) { GSList *tmp, *next; - char *typestr, *nick, *arg; + char *typestr, *nick, *arg, *fname; void *free_arg; int found, type; @@ -510,13 +510,15 @@ static void cmd_dcc_close(char *data, IRC_SERVER_REC *server) return; } + fname = cmd_get_quoted_param(&arg); + found = FALSE; for (tmp = dcc_conns; tmp != NULL; tmp = next) { DCC_REC *dcc = tmp->data; next = tmp->next; if (dcc->type == type && g_ascii_strcasecmp(dcc->nick, nick) == 0 && - (*arg == '\0' || g_strcmp0(dcc->arg, arg) == 0)) { + (*fname == '\0' || g_strcmp0(dcc->arg, fname) == 0)) { dcc_reject(dcc, server); found = TRUE; } diff --git a/src/irc/proxy/listen.c b/src/irc/proxy/listen.c index 5dc9a704..cde4c0be 100644 --- a/src/irc/proxy/listen.c +++ b/src/irc/proxy/listen.c @@ -31,6 +31,8 @@ #include "fe-common/core/printtext.h" /* FIXME: evil. need to do fe-proxy */ +#include <sys/un.h> + GSList *proxy_listens; GSList *proxy_clients; @@ -39,6 +41,66 @@ static int ignore_next; static int enabled = FALSE; +static int is_all_digits(const char *s) +{ + return strspn(s, "0123456789") == strlen(s); +} + +static GIOChannel *net_listen_unix(const char *path) +{ + struct sockaddr_un sa; + int saved_errno, handle; + + g_return_val_if_fail(path != NULL, NULL); + + handle = socket(AF_UNIX, SOCK_STREAM, 0); + if (handle == -1) { + return NULL; + } + + fcntl(handle, F_SETFL, O_NONBLOCK); + + memset(&sa, '\0', sizeof sa); + sa.sun_family = AF_UNIX; + strncpy(sa.sun_path, path, sizeof sa.sun_path - 1); + if (bind(handle, (struct sockaddr *)&sa, sizeof sa) == -1) { + saved_errno = errno; + goto error_close; + } + + if (listen(handle, 1) == -1) { + saved_errno = errno; + goto error_unlink; + } + + return g_io_channel_new(handle); + +error_unlink: + unlink(sa.sun_path); +error_close: + close(handle); + errno = saved_errno; + return NULL; +} + +static GIOChannel *net_accept_unix(GIOChannel *handle) +{ + struct sockaddr_un sa; + int ret; + socklen_t addrlen; + + g_return_val_if_fail(handle != NULL, NULL); + + addrlen = sizeof sa; + ret = accept(g_io_channel_unix_get_fd(handle), (struct sockaddr *)&sa, &addrlen); + + if (ret < 0) + return NULL; + + fcntl(ret, F_SETFL, O_NONBLOCK); + return g_io_channel_new(ret); +} + static void remove_client(CLIENT_REC *rec) { g_return_if_fail(rec != NULL); @@ -48,18 +110,18 @@ static void remove_client(CLIENT_REC *rec) signal_emit("proxy client disconnected", 1, rec); printtext(rec->server, NULL, MSGLEVEL_CLIENTNOTICE, - "Proxy: Client %s:%d disconnected", rec->host, rec->port); + "Proxy: Client %s disconnected", rec->addr); g_free(rec->proxy_address); net_sendbuffer_destroy(rec->handle, TRUE); g_source_remove(rec->recv_tag); g_free_not_null(rec->nick); - g_free_not_null(rec->host); + g_free_not_null(rec->addr); g_free(rec); } static void proxy_redirect_event(CLIENT_REC *client, const char *command, - int count, const char *arg, int remote) + int count, const char *arg, int remote) { char *str; @@ -67,7 +129,7 @@ static void proxy_redirect_event(CLIENT_REC *client, const char *command, str = g_strdup_printf("proxy %p", client); server_redirect_event(client->server, command, count, - arg, remote, NULL, "", str, NULL); + arg, remote, NULL, "", str, NULL); g_free(str); } @@ -94,28 +156,58 @@ static void grab_who(CLIENT_REC *client, const char *channel) } proxy_redirect_event(client, "who", - client->server->one_endofwho ? 1 : count, - arg->str, -1); + client->server->one_endofwho ? 1 : count, + arg->str, -1); g_strfreev(list); g_string_free(arg, TRUE); } static void handle_client_connect_cmd(CLIENT_REC *client, - const char *cmd, const char *args) + const char *cmd, const char *args) { const char *password; password = settings_get_str("irssiproxy_password"); - if (password != NULL && g_strcmp0(cmd, "PASS") == 0) { - if (g_strcmp0(password, args) == 0) - client->pass_sent = TRUE; - else { + if (g_strcmp0(cmd, "PASS") == 0) { + const char *args_pass; + + if (!client->multiplex) { + args_pass = args; + } else { + IRC_SERVER_REC *server; + char *tag; + const char *tag_end; + + if ((tag_end = strchr(args, ':')) != NULL) { + args_pass = tag_end + 1; + } else { + tag_end = args + strlen(args); + args_pass = ""; + } + + tag = g_strndup(args, tag_end - args); + server = IRC_SERVER(server_find_chatnet(tag)); + g_free(tag); + + if (!server) { + /* an invalid network was specified */ + remove_client(client); + return; + } + + client->server = server; + g_free(client->proxy_address); + client->proxy_address = g_strdup_printf("%.*s.proxy", (int)(tag_end - args), args); + } + + if (g_strcmp0(password, args_pass) != 0) { /* wrong password! */ remove_client(client); - return; + return; } + client->pass_sent = TRUE; } else if (g_strcmp0(cmd, "NICK") == 0) { g_free_not_null(client->nick); client->nick = g_strdup(args); @@ -124,14 +216,14 @@ static void handle_client_connect_cmd(CLIENT_REC *client, } if (client->nick != NULL && client->user_sent) { - if (*password != '\0' && !client->pass_sent) { + if ((*password != '\0' || client->multiplex) && !client->pass_sent) { /* client didn't send us PASS, kill it */ remove_client(client); } else { signal_emit("proxy client connected", 1, client); printtext(client->server, NULL, MSGLEVEL_CLIENTNOTICE, - "Proxy: Client %s:%d connected", - client->host, client->port); + "Proxy: Client %s connected", + client->addr); client->connected = TRUE; proxy_dump_data(client); } @@ -139,7 +231,7 @@ static void handle_client_connect_cmd(CLIENT_REC *client, } static void handle_client_cmd(CLIENT_REC *client, char *cmd, char *args, - const char *data) + const char *data) { GSList *tmp; if (!client->connected) { @@ -162,8 +254,8 @@ static void handle_client_cmd(CLIENT_REC *client, char *cmd, char *args, g_ascii_strcasecmp(target, client->proxy_address) == 0 || g_ascii_strcasecmp(target, client->nick) == 0) { proxy_outdata(client, ":%s PONG %s :%s\r\n", - client->proxy_address, - client->proxy_address, origin); + client->proxy_address, + client->proxy_address, origin); g_free(params); return; } @@ -172,27 +264,27 @@ static void handle_client_cmd(CLIENT_REC *client, char *cmd, char *args, if (g_strcmp0(cmd, "PROXY") == 0) { if (g_ascii_strcasecmp(args, "CTCP ON") == 0) { - /* client wants all ctcps */ + /* client wants all ctcps */ client->want_ctcp = 1; - for (tmp = proxy_clients; tmp != NULL; tmp = tmp->next) { + for (tmp = proxy_clients; tmp != NULL; tmp = tmp->next) { CLIENT_REC *rec = tmp->data; - if ((g_ascii_strcasecmp(client->listen->ircnet,rec->listen->ircnet) == 0) && - /* kludgy way to check if the clients aren't the same */ - (client->recv_tag != rec->recv_tag)) { - if (rec->want_ctcp == 1) - proxy_outdata(rec, ":%s NOTICE %s :Another client is now receiving CTCPs sent to %s\r\n", - rec->proxy_address, rec->nick, rec->listen->ircnet); - rec->want_ctcp = 0; - } + if (g_ascii_strcasecmp(client->listen->ircnet, rec->listen->ircnet) == 0 && + /* kludgy way to check if the clients aren't the same */ + client->recv_tag != rec->recv_tag) { + if (rec->want_ctcp == 1) + proxy_outdata(rec, ":%s NOTICE %s :Another client is now receiving CTCPs sent to %s\r\n", + rec->proxy_address, rec->nick, rec->listen->ircnet); + rec->want_ctcp = 0; + } } proxy_outdata(client, ":%s NOTICE %s :You're now receiving CTCPs sent to %s\r\n", - client->proxy_address, client->nick,client->listen->ircnet); + client->proxy_address, client->nick, client->listen->ircnet); } else if (g_ascii_strcasecmp(args, "CTCP OFF") == 0) { - /* client wants proxy to handle all ctcps */ + /* client wants proxy to handle all ctcps */ client->want_ctcp = 0; proxy_outdata(client, ":%s NOTICE %s :Proxy is now handling itself CTCPs sent to %s\r\n", - client->proxy_address, client->nick, client->listen->ircnet); + client->proxy_address, client->nick, client->listen->ircnet); } else { signal_emit("proxy client command", 3, client, args, data); } @@ -201,11 +293,11 @@ static void handle_client_cmd(CLIENT_REC *client, char *cmd, char *args, if (client->server == NULL || !client->server->connected) { proxy_outdata(client, ":%s NOTICE %s :Not connected to server\r\n", - client->proxy_address, client->nick); - return; + client->proxy_address, client->nick); + return; } - /* check if the command could be redirected */ + /* check if the command could be redirected */ if (g_strcmp0(cmd, "WHO") == 0) grab_who(client, args); else if (g_strcmp0(cmd, "WHOWAS") == 0) @@ -263,29 +355,29 @@ static void handle_client_cmd(CLIENT_REC *client, char *cmd, char *args, char *params, *target, *msg; params = event_get_params(args, 2 | PARAM_FLAG_GETREST, - &target, &msg); + &target, &msg); proxy_outserver_all_except(client, "PRIVMSG %s", args); ignore_next = TRUE; if (*msg != '\001' || msg[strlen(msg)-1] != '\001') { signal_emit(server_ischannel(SERVER(client->server), target) ? - "message own_public" : "message own_private", 4, - client->server, msg, target, target); + "message own_public" : "message own_private", 4, + client->server, msg, target, target); } else if (strncmp(msg+1, "ACTION ", 7) == 0) { /* action */ - msg[strlen(msg)-1] = '\0'; + msg[strlen(msg)-1] = '\0'; signal_emit("message irc own_action", 3, - client->server, msg+8, target); + client->server, msg+8, target); } else { - /* CTCP */ + /* CTCP */ char *p; msg[strlen(msg)-1] = '\0'; p = strchr(msg, ' '); - if (p != NULL) *p++ = '\0'; else p = ""; + if (p != NULL) *p++ = '\0'; else p = ""; signal_emit("message irc own_ctcp", 4, - client->server, msg+1, p, target); + client->server, msg+1, p, target); } ignore_next = FALSE; g_free(params); @@ -337,24 +429,38 @@ static void sig_listen(LISTEN_REC *listen) CLIENT_REC *rec; IPADDR ip; NET_SENDBUF_REC *sendbuf; - GIOChannel *handle; + GIOChannel *handle; char host[MAX_IP_LEN]; int port; + char *addr; g_return_if_fail(listen != NULL); /* accept connection */ - handle = net_accept(listen->handle, &ip, &port); - if (handle == NULL) - return; - net_ip2host(&ip, host); + if (listen->port) { + handle = net_accept(listen->handle, &ip, &port); + if (handle == NULL) + return; + net_ip2host(&ip, host); + addr = g_strdup_printf("%s:%d", host, port); + } else { + /* no port => this is a unix socket */ + handle = net_accept_unix(listen->handle); + if (handle == NULL) + return; + addr = g_strdup("(local)"); + } + sendbuf = net_sendbuffer_create(handle, 0); rec = g_new0(CLIENT_REC, 1); rec->listen = listen; rec->handle = sendbuf; - rec->host = g_strdup(host); - rec->port = port; - if (g_strcmp0(listen->ircnet, "*") == 0) { + rec->addr = addr; + if (g_strcmp0(listen->ircnet, "?") == 0) { + rec->multiplex = TRUE; + rec->proxy_address = g_strdup("multiplex.proxy"); + rec->server = NULL; + } else if (g_strcmp0(listen->ircnet, "*") == 0) { rec->proxy_address = g_strdup("irc.proxy"); rec->server = servers == NULL ? NULL : IRC_SERVER(servers->data); } else { @@ -363,15 +469,15 @@ static void sig_listen(LISTEN_REC *listen) IRC_SERVER(server_find_chatnet(listen->ircnet)); } rec->recv_tag = g_input_add(handle, G_INPUT_READ, - (GInputFunction) sig_listen_client, rec); + (GInputFunction) sig_listen_client, rec); proxy_clients = g_slist_prepend(proxy_clients, rec); - rec->listen->clients = g_slist_prepend(rec->listen->clients, rec); + listen->clients = g_slist_prepend(listen->clients, rec); signal_emit("proxy client connecting", 1, rec); printtext(rec->server, NULL, MSGLEVEL_CLIENTNOTICE, - "Proxy: New client %s:%d on port %d (%s)", - rec->host, rec->port, listen->port, listen->ircnet); + "Proxy: New client %s on port %s (%s)", + rec->addr, listen->port_or_path, listen->ircnet); } static void sig_incoming(IRC_SERVER_REC *server, const char *line) @@ -460,12 +566,12 @@ static void sig_server_event(IRC_SERVER_REC *server, const char *line, static void event_connected(IRC_SERVER_REC *server) { GSList *tmp; - const char *chatnet; + const char *chatnet; if (!IS_IRC_SERVER(server)) return; - chatnet = server->connrec->chatnet; + chatnet = server->connrec->chatnet; for (tmp = proxy_clients; tmp != NULL; tmp = tmp->next) { CLIENT_REC *rec = tmp->data; @@ -474,7 +580,7 @@ static void event_connected(IRC_SERVER_REC *server) (chatnet != NULL && g_ascii_strcasecmp(chatnet, rec->listen->ircnet) == 0))) { proxy_outdata(rec, ":%s NOTICE %s :Connected to server\r\n", - rec->proxy_address, rec->nick); + rec->proxy_address, rec->nick); rec->server = server; proxy_client_reset_nick(rec); } @@ -482,7 +588,7 @@ static void event_connected(IRC_SERVER_REC *server) } static void proxy_server_disconnected(CLIENT_REC *client, - IRC_SERVER_REC *server) + IRC_SERVER_REC *server) { GSList *tmp; @@ -567,14 +673,19 @@ static void sig_message_own_action(IRC_SERVER_REC *server, const char *msg, proxy_outserver_all(server, "PRIVMSG %s :\001ACTION %s\001", target, msg); } -static LISTEN_REC *find_listen(const char *ircnet, int port) +static LISTEN_REC *find_listen(const char *ircnet, int port, const char *port_or_path) { GSList *tmp; for (tmp = proxy_listens; tmp != NULL; tmp = tmp->next) { LISTEN_REC *rec = tmp->data; - if (rec->port == port && + if ((port + ? /* a tcp port */ + rec->port == port + : /* a unix socket path */ + g_strcmp0(rec->port_or_path, port_or_path) == 0 + ) && g_ascii_strcasecmp(rec->ircnet, ircnet) == 0) return rec; } @@ -582,48 +693,53 @@ static LISTEN_REC *find_listen(const char *ircnet, int port) return NULL; } -static void add_listen(const char *ircnet, int port) +static void add_listen(const char *ircnet, int port, const char *port_or_path) { LISTEN_REC *rec; IPADDR ip4, ip6, *my_ip; + GIOChannel *handle; - if (port <= 0 || *ircnet == '\0') + if (*port_or_path == '\0' || port < 0 || *ircnet == '\0') return; - /* bind to specific host/ip? */ - my_ip = NULL; - if (*settings_get_str("irssiproxy_bind") != '\0') { - if (net_gethostbyname(settings_get_str("irssiproxy_bind"), - &ip4, &ip6) != 0) { - printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, - "Proxy: can not resolve '%s' - aborting", - settings_get_str("irssiproxy_bind")); - return; + if (port == 0) { + /* listening on a unix socket */ + handle = net_listen_unix(port_or_path); + } else { + /* bind to specific host/ip? */ + my_ip = NULL; + if (*settings_get_str("irssiproxy_bind") != '\0') { + if (net_gethostbyname(settings_get_str("irssiproxy_bind"), + &ip4, &ip6) != 0) { + printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, + "Proxy: can not resolve '%s' - aborting", + settings_get_str("irssiproxy_bind")); + return; + } + + my_ip = ip6.family == 0 ? &ip4 : ip4.family == 0 || + settings_get_bool("resolve_prefer_ipv6") ? &ip6 : &ip4; } + handle = net_listen(my_ip, &port); + } - my_ip = ip6.family == 0 ? &ip4 : ip4.family == 0 || - settings_get_bool("resolve_prefer_ipv6") ? &ip6 : &ip4; + if (handle == NULL) { + printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, + "Proxy: Listen in port %s failed: %s", + port_or_path, g_strerror(errno)); + return; } rec = g_new0(LISTEN_REC, 1); + rec->handle = handle; rec->ircnet = g_strdup(ircnet); rec->port = port; - - rec->handle = net_listen(my_ip, &rec->port); - - if (rec->handle == NULL) { - printtext(NULL, NULL, MSGLEVEL_CLIENTERROR, - "Proxy: Listen in port %d failed: %s", - rec->port, g_strerror(errno)); - g_free(rec->ircnet); - g_free(rec); - return; - } + rec->port_or_path = g_strdup(port_or_path); rec->tag = g_input_add(rec->handle, G_INPUT_READ, - (GInputFunction) sig_listen, rec); + (GInputFunction) sig_listen, rec); - proxy_listens = g_slist_append(proxy_listens, rec); + proxy_listens = g_slist_append(proxy_listens, rec); } static void remove_listen(LISTEN_REC *rec) @@ -633,8 +749,13 @@ static void remove_listen(LISTEN_REC *rec) while (rec->clients != NULL) remove_client(rec->clients->data); + /* remove unix socket because bind wants to (re)create it */ + if (rec->port == 0) + unlink(rec->port_or_path); + net_disconnect(rec->handle); g_source_remove(rec->tag); + g_free(rec->port_or_path); g_free(rec->ircnet); g_free(rec); } @@ -644,7 +765,7 @@ static void read_settings(void) LISTEN_REC *rec; GSList *remove_listens = NULL; GSList *add_listens = NULL; - char **ports, **tmp, *ircnet, *port; + char **ports, **tmp, *ircnet, *port_or_path; int portnum; remove_listens = g_slist_copy(proxy_listens); @@ -652,20 +773,25 @@ static void read_settings(void) ports = g_strsplit(settings_get_str("irssiproxy_ports"), " ", -1); for (tmp = ports; *tmp != NULL; tmp++) { ircnet = *tmp; - port = strchr(ircnet, '='); - if (port == NULL) + port_or_path = strchr(ircnet, '='); + if (port_or_path == NULL) continue; - *port++ = '\0'; - portnum = atoi(port); - if (portnum <= 0) - continue; + *port_or_path++ = '\0'; + if (is_all_digits(port_or_path)) { + portnum = atoi(port_or_path); + if (portnum <= 0) + continue; + } else { + portnum = 0; + } - rec = find_listen(ircnet, portnum); + rec = find_listen(ircnet, portnum, port_or_path); if (rec == NULL) { rec = g_new0(LISTEN_REC, 1); rec->ircnet = ircnet; /* borrow */ rec->port = portnum; + rec->port_or_path = port_or_path; /* borrow */ add_listens = g_slist_prepend(add_listens, rec); } else { /* remove from the list of listens to remove == keep it */ @@ -680,7 +806,7 @@ static void read_settings(void) while (add_listens != NULL) { rec = add_listens->data; - add_listen(rec->ircnet, rec->port); + add_listen(rec->ircnet, rec->port, rec->port_or_path); add_listens = g_slist_remove(add_listens, rec); g_free(rec); } diff --git a/src/irc/proxy/proxy.c b/src/irc/proxy/proxy.c index 50a41b21..2875d2c2 100644 --- a/src/irc/proxy/proxy.c +++ b/src/irc/proxy/proxy.c @@ -28,13 +28,14 @@ /* SYNTAX: IRSSIPROXY STATUS */ static void cmd_irssiproxy_status(const char *data, IRC_SERVER_REC *server) { + GSList *tmp; + if (!settings_get_bool("irssiproxy")) { printtext(server, NULL, MSGLEVEL_CLIENTNOTICE, "Proxy is currently disabled"); return; } - GSList *tmp; printtext(server, NULL, MSGLEVEL_CLIENTNOTICE, "Proxy: Currently connected clients: %d", @@ -44,10 +45,10 @@ static void cmd_irssiproxy_status(const char *data, IRC_SERVER_REC *server) CLIENT_REC *rec = tmp->data; printtext(server, NULL, MSGLEVEL_CLIENTNOTICE, - " %s:%d connect%s to %d (%s)", - rec->host, rec->port, + " %s connect%s to %s (%s)", + rec->addr, rec->connected ? "ed" : "ing", - rec->listen->port, rec->listen->ircnet); + rec->listen->port_or_path, rec->listen->ircnet); } } diff --git a/src/irc/proxy/proxy.h b/src/irc/proxy/proxy.h index 158b0675..620ea605 100644 --- a/src/irc/proxy/proxy.h +++ b/src/irc/proxy/proxy.h @@ -9,17 +9,18 @@ typedef struct { int port; + char *port_or_path; char *ircnet; int tag; GIOChannel *handle; GSList *clients; + } LISTEN_REC; typedef struct { - char *nick, *host; - int port; + char *nick, *addr; NET_SENDBUF_REC *handle; int recv_tag; char *proxy_address; @@ -29,6 +30,7 @@ typedef struct { unsigned int user_sent:1; unsigned int connected:1; unsigned int want_ctcp:1; + unsigned int multiplex:1; } CLIENT_REC; #endif |