diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/core/misc.c | 24 | ||||
-rw-r--r-- | src/core/misc.h | 3 | ||||
-rw-r--r-- | src/fe-common/core/module-formats.c | 4 | ||||
-rw-r--r-- | src/fe-text/terminfo-core.c | 111 | ||||
-rw-r--r-- | src/fe-text/terminfo-core.h | 4 | ||||
-rw-r--r-- | src/irc/core/Makefile.am | 2 | ||||
-rw-r--r-- | src/irc/core/irc-cap.c | 191 | ||||
-rw-r--r-- | src/irc/core/irc-cap.h | 9 | ||||
-rw-r--r-- | src/irc/core/irc-core.c | 3 | ||||
-rw-r--r-- | src/irc/core/irc-servers.c | 16 | ||||
-rw-r--r-- | src/irc/core/irc-servers.h | 7 | ||||
-rw-r--r-- | src/irc/proxy/dump.c | 38 | ||||
-rw-r--r-- | src/irc/proxy/listen.c | 16 |
13 files changed, 348 insertions, 80 deletions
diff --git a/src/core/misc.c b/src/core/misc.c index ef8501d5..88c27255 100644 --- a/src/core/misc.c +++ b/src/core/misc.c @@ -211,6 +211,30 @@ void *gslist_foreach_find(GSList *list, FOREACH_FIND_FUNC func, const void *data return NULL; } +void gslist_free_full (GSList *list, GDestroyNotify free_func) +{ + GSList *tmp; + + if (list == NULL) + return; + + for (tmp = list; tmp != NULL; tmp = tmp->next) + free_func(tmp->data); + + g_slist_free(list); +} + +GSList *gslist_remove_string (GSList *list, const char *str) +{ + GSList *l; + + l = g_slist_find_custom(list, str, (GCompareFunc) g_strcmp0); + if (l != NULL) + return g_slist_remove_link(list, l); + + return list; +} + /* `list' contains pointer to structure with a char* to string. */ char *gslistptr_to_string(GSList *list, int offset, const char *delimiter) { diff --git a/src/core/misc.h b/src/core/misc.h index c6369489..7e78d3b9 100644 --- a/src/core/misc.h +++ b/src/core/misc.h @@ -21,6 +21,9 @@ GSList *gslist_find_string(GSList *list, const char *key); GSList *gslist_find_icase_string(GSList *list, const char *key); GList *glist_find_string(GList *list, const char *key); GList *glist_find_icase_string(GList *list, const char *key); +GSList *gslist_remove_string (GSList *list, const char *str); + +void gslist_free_full (GSList *list, GDestroyNotify free_func); void *gslist_foreach_find(GSList *list, FOREACH_FIND_FUNC func, const void *data); diff --git a/src/fe-common/core/module-formats.c b/src/fe-common/core/module-formats.c index db11fae1..4ae26950 100644 --- a/src/fe-common/core/module-formats.c +++ b/src/fe-common/core/module-formats.c @@ -42,8 +42,8 @@ FORMAT_REC fecommon_core_formats[] = { { "window_set_immortal", "Window is now immortal", 0 }, { "window_unset_immortal", "Window isn't immortal anymore", 0 }, { "window_immortal_error", "Window is immortal, if you really want to close it, say /WINDOW IMMORTAL OFF", 0 }, - { "windowlist_header", "%#Ref Name Active item Server Level", 0 }, - { "windowlist_line", "%#$[3]0 %|$[20]1 $[15]2 $[15]3 $4", 5, { 1, 0, 0, 0, 0 } }, + { "windowlist_header", "%#Ref Name Active item Server Level", 0 }, + { "windowlist_line", "%#$[4]0 %|$[20]1 $[15]2 $[15]3 $4", 5, { 1, 0, 0, 0, 0 } }, { "windowlist_footer", "", 0 }, { "windows_layout_saved", "Layout of windows is now remembered", 0 }, { "windows_layout_reset", "Layout of windows reset to defaults", 0 }, diff --git a/src/fe-text/terminfo-core.c b/src/fe-text/terminfo-core.c index 0516cc5f..6339e6f4 100644 --- a/src/fe-text/terminfo-core.c +++ b/src/fe-text/terminfo-core.c @@ -50,62 +50,66 @@ TERM_REC *current_term; /* Define only what we might need */ static TERMINFO_REC tcaps[] = { - /* Terminal size */ - { "cols", "co", CAP_TYPE_INT, G_STRUCT_OFFSET(TERM_REC, width) }, - { "lines", "li", CAP_TYPE_INT, G_STRUCT_OFFSET(TERM_REC, height) }, - - /* Cursor movement */ - { "smcup", "ti", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_smcup) }, - { "rmcup", "te", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_rmcup) }, - { "cup", "cm", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_cup) }, - { "hpa", "ch", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_hpa) }, - { "vpa", "vh", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_vpa) }, - { "cub1", "le", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_cub1) }, - { "cuf1", "nd", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_cuf1) }, - { "civis", "vi", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_civis) }, - { "cnorm", "ve", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_cnorm) }, + /* Terminal size */ + { "cols", "co", CAP_TYPE_INT, G_STRUCT_OFFSET(TERM_REC, width) }, + { "lines", "li", CAP_TYPE_INT, G_STRUCT_OFFSET(TERM_REC, height) }, - /* Scrolling */ - { "csr", "cs", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_csr) }, - { "wind", "wi", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_wind) }, - { "ri", "sr", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_ri) }, - { "rin", "SR", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_rin) }, - { "ind", "sf", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_ind) }, - { "indn", "SF", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_indn) }, - { "il", "AL", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_il) }, - { "il1", "al", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_il1) }, - { "dl", "DL", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_dl) }, - { "dl1", "dl", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_dl1) }, + /* Cursor movement */ + { "smcup", "ti", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_smcup) }, + { "rmcup", "te", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_rmcup) }, + { "cup", "cm", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_cup) }, + { "hpa", "ch", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_hpa) }, + { "vpa", "vh", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_vpa) }, + { "cub1", "le", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_cub1) }, + { "cuf1", "nd", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_cuf1) }, + { "civis", "vi", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_civis) }, + { "cnorm", "ve", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_cnorm) }, + + /* Scrolling */ + { "csr", "cs", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_csr) }, + { "wind", "wi", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_wind) }, + { "ri", "sr", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_ri) }, + { "rin", "SR", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_rin) }, + { "ind", "sf", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_ind) }, + { "indn", "SF", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_indn) }, + { "il", "AL", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_il) }, + { "il1", "al", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_il1) }, + { "dl", "DL", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_dl) }, + { "dl1", "dl", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_dl1) }, /* Clearing screen */ - { "clear", "cl", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_clear) }, - { "ed", "cd", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_ed) }, + { "clear", "cl", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_clear) }, + { "ed", "cd", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_ed) }, - /* Clearing to end of line */ - { "el", "ce", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_el) }, + /* Clearing to end of line */ + { "el", "ce", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_el) }, - /* Repeating character */ - { "rep", "rp", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_rep) }, + /* Repeating character */ + { "rep", "rp", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_rep) }, /* Colors */ - { "colors", "Co", CAP_TYPE_INT, G_STRUCT_OFFSET(TERM_REC, TI_colors) }, - { "sgr0", "me", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_sgr0) }, - { "smul", "us", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_smul) }, - { "rmul", "ue", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_rmul) }, - { "smso", "so", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_smso) }, - { "rmso", "se", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_rmso) }, - { "sitm", "ZH", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_sitm) }, - { "ritm", "ZR", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_ritm) }, - { "bold", "md", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_bold) }, - { "blink", "mb", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_blink) }, - { "rev", "mr", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_rev) }, - { "setaf", "AF", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_setaf) }, - { "setab", "AB", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_setab) }, - { "setf", "Sf", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_setf) }, - { "setb", "Sb", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_setb) }, - - /* Beep */ - { "bel", "bl", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_bel) }, + { "colors", "Co", CAP_TYPE_INT, G_STRUCT_OFFSET(TERM_REC, TI_colors) }, + { "sgr0", "me", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_sgr0) }, + { "smul", "us", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_smul) }, + { "rmul", "ue", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_rmul) }, + { "smso", "so", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_smso) }, + { "rmso", "se", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_rmso) }, + { "sitm", "ZH", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_sitm) }, + { "ritm", "ZR", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_ritm) }, + { "bold", "md", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_bold) }, + { "blink", "mb", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_blink) }, + { "rev", "mr", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_rev) }, + { "setaf", "AF", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_setaf) }, + { "setab", "AB", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_setab) }, + { "setf", "Sf", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_setf) }, + { "setb", "Sb", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_setb) }, + + /* Beep */ + { "bel", "bl", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_bel) }, + + /* Keyboard-transmit mode */ + { "smkx", "ks", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_smkx) }, + { "rmkx", "ke", CAP_TYPE_STR, G_STRUCT_OFFSET(TERM_REC, TI_rmkx) }, }; /* Move cursor (cursor_address / cup) */ @@ -523,7 +527,11 @@ static void terminfo_input_deinit(TERM_REC *term) void terminfo_cont(TERM_REC *term) { if (term->TI_smcup) - tput(tparm(term->TI_smcup)); + tput(tparm(term->TI_smcup)); + + if (term->TI_smkx) + tput(tparm(term->TI_smkx)); + terminfo_input_init(term); } @@ -538,6 +546,9 @@ void terminfo_stop(TERM_REC *term) if (term->TI_rmcup) tput(tparm(term->TI_rmcup)); + if (term->TI_rmkx) + tput(tparm(term->TI_rmkx)); + /* reset input settings */ terminfo_input_deinit(term); fflush(term->out); diff --git a/src/fe-text/terminfo-core.h b/src/fe-text/terminfo-core.h index 6ab4637d..21398791 100644 --- a/src/fe-text/terminfo-core.h +++ b/src/fe-text/terminfo-core.h @@ -88,6 +88,10 @@ struct _TERM_REC { /* Beep */ char *TI_bel; + + /* Keyboard-transmit mode */ + const char *TI_smkx; + const char *TI_rmkx; }; extern TERM_REC *current_term; diff --git a/src/irc/core/Makefile.am b/src/irc/core/Makefile.am index 3db5cf0e..7d885d20 100644 --- a/src/irc/core/Makefile.am +++ b/src/irc/core/Makefile.am @@ -26,6 +26,7 @@ libirc_core_a_SOURCES = \ irc-servers-reconnect.c \ irc-servers-setup.c \ irc-session.c \ + irc-cap.c \ lag.c \ massjoin.c \ modes.c \ @@ -48,6 +49,7 @@ pkginc_irc_core_HEADERS = \ irc-queries.h \ irc-servers.h \ irc-servers-setup.h \ + irc-cap.h \ modes.h \ mode-lists.h \ module.h \ diff --git a/src/irc/core/irc-cap.c b/src/irc/core/irc-cap.c new file mode 100644 index 00000000..cd3ae677 --- /dev/null +++ b/src/irc/core/irc-cap.c @@ -0,0 +1,191 @@ +/* irc-cap.c : irssi + + Copyright (C) 2015 The Lemon Man + + 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., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "module.h" +#include "signals.h" +#include "misc.h" + +#include "irc-cap.h" +#include "irc-servers.h" + +int cap_toggle (IRC_SERVER_REC *server, char *cap, int enable) +{ + if (cap == NULL || *cap == '\0') + return FALSE; + + /* If the negotiation hasn't been completed yet just queue the requests */ + if (!server->cap_complete) { + if (enable && !gslist_find_string(server->cap_queue, cap)) { + server->cap_queue = g_slist_prepend(server->cap_queue, g_strdup(cap)); + return TRUE; + } + else if (!enable && gslist_find_string(server->cap_queue, cap)) { + server->cap_queue = gslist_remove_string(server->cap_queue, cap); + return TRUE; + } + + return FALSE; + } + + if (enable && !gslist_find_string(server->cap_active, cap)) { + /* Make sure the required cap is supported by the server */ + if (!gslist_find_string(server->cap_supported, cap)) + return FALSE; + + irc_send_cmdv(server, "CAP REQ %s", cap); + return TRUE; + } + else if (!enable && gslist_find_string(server->cap_active, cap)) { + irc_send_cmdv(server, "CAP REQ -%s", cap); + return TRUE; + } + + return FALSE; +} + +void cap_finish_negotiation (IRC_SERVER_REC *server) +{ + if (server->cap_complete) + return; + + server->cap_complete = TRUE; + irc_send_cmd_now(server, "CAP END"); + + signal_emit("server cap end", 1, server); +} + +static void cap_emit_signal (IRC_SERVER_REC *server, char *cmd, char *args) +{ + char *signal_name; + + signal_name = g_strdup_printf("server cap %s %s", cmd, args? args: ""); + signal_emit(signal_name, 1, server); + g_free(signal_name); +} + +static void event_cap (IRC_SERVER_REC *server, char *args, char *nick, char *address) +{ + GSList *tmp; + GString *cmd; + char *params, *evt, *list, **caps; + int i, caps_length, disable, avail_caps; + + params = event_get_params(args, 3, NULL, &evt, &list); + if (params == NULL) + return; + + /* Strip the trailing whitespaces before splitting the string, some servers send responses with + * superfluous whitespaces that g_strsplit the interprets as tokens */ + caps = g_strsplit(g_strchomp(list), " ", -1); + caps_length = g_strv_length(caps); + + if (!g_strcmp0(evt, "LS")) { + /* Create a list of the supported caps */ + for (i = 0; i < caps_length; i++) + server->cap_supported = g_slist_prepend(server->cap_supported, g_strdup(caps[i])); + + /* Request the required caps, if any */ + if (server->cap_queue == NULL) { + cap_finish_negotiation(server); + } + else { + cmd = g_string_new("CAP REQ :"); + + avail_caps = 0; + + /* Check whether the cap is supported by the server */ + for (tmp = server->cap_queue; tmp != NULL; tmp = tmp->next) { + if (gslist_find_string(server->cap_supported, tmp->data)) { + g_string_append_c(cmd, ' '); + g_string_append(cmd, tmp->data); + + avail_caps++; + } + } + + /* Clear the queue here */ + gslist_free_full(server->cap_queue, (GDestroyNotify) g_free); + server->cap_queue = NULL; + + /* If the server doesn't support any cap we requested close the negotiation here */ + if (avail_caps > 0) + irc_send_cmd_now(server, cmd->str); + else + cap_finish_negotiation(server); + + g_string_free(cmd, TRUE); + } + } + else if (!g_strcmp0(evt, "ACK")) { + int got_sasl = FALSE; + + /* Emit a signal for every ack'd cap */ + for (i = 0; i < caps_length; i++) { + disable = (*caps[i] == '-'); + + if (disable) + server->cap_active = gslist_remove_string(server->cap_active, caps[i] + 1); + else + server->cap_active = g_slist_prepend(server->cap_active, g_strdup(caps[i])); + + if (!g_strcmp0(caps[i], "sasl")) + got_sasl = TRUE; + + cap_emit_signal(server, "ack", caps[i]); + } + + /* Hopefully the server has ack'd all the caps requested and we're ready to terminate the + * negotiation, unless sasl was requested. In this case we must not terminate the negotiation + * until the sasl handshake is over. */ + if (got_sasl == FALSE) + cap_finish_negotiation(server); + } + else if (!g_strcmp0(evt, "NAK")) { + g_warning("The server answered with a NAK to our CAP request, this should not happen"); + + /* A NAK'd request means that a required cap can't be enabled or disabled, don't update the + * list of active caps and notify the listeners. */ + for (i = 0; i < caps_length; i++) + cap_emit_signal(server, "nak", caps[i]); + } + + g_strfreev(caps); + g_free(params); +} + +static void event_invalid_cap (IRC_SERVER_REC *server, const char *data, const char *from) +{ + /* The server didn't understand one (or more) requested caps, terminate the negotiation. + * This could be handled in a graceful way but since it shouldn't really ever happen this seems a + * good way to deal with 410 errors. */ + server->cap_complete = FALSE; + irc_send_cmd_now(server, "CAP END"); +} + +void cap_init (void) +{ + signal_add_first("event cap", (SIGNAL_FUNC) event_cap); + signal_add_first("event 410", (SIGNAL_FUNC) event_invalid_cap); +} + +void cap_deinit (void) +{ + signal_remove("event cap", (SIGNAL_FUNC) event_cap); + signal_remove("event 410", (SIGNAL_FUNC) event_invalid_cap); +} diff --git a/src/irc/core/irc-cap.h b/src/irc/core/irc-cap.h new file mode 100644 index 00000000..df957cd2 --- /dev/null +++ b/src/irc/core/irc-cap.h @@ -0,0 +1,9 @@ +#ifndef __IRC_CAP_H +#define __IRC_CAP_H + +void cap_init(void); +void cap_deinit(void); +int cap_toggle (IRC_SERVER_REC *server, char *cap, int enable); +void cap_finish_negotiation (IRC_SERVER_REC *server); + +#endif diff --git a/src/irc/core/irc-core.c b/src/irc/core/irc-core.c index bf7386ad..e3ceeeef 100644 --- a/src/irc/core/irc-core.c +++ b/src/irc/core/irc-core.c @@ -26,6 +26,7 @@ #include "irc-chatnets.h" #include "irc-channels.h" #include "irc-queries.h" +#include "irc-cap.h" #include "irc-servers-setup.h" #include "channels-setup.h" @@ -117,6 +118,7 @@ void irc_core_init(void) lag_init(); netsplit_init(); irc_expandos_init(); + cap_init(); settings_check(); module_register("core", "irc"); @@ -126,6 +128,7 @@ void irc_core_deinit(void) { signal_emit("chat protocol deinit", 1, chat_protocol_find("IRC")); + cap_deinit(); irc_expandos_deinit(); netsplit_deinit(); lag_deinit(); diff --git a/src/irc/core/irc-servers.c b/src/irc/core/irc-servers.c index 31ba397b..b2718ae1 100644 --- a/src/irc/core/irc-servers.c +++ b/src/irc/core/irc-servers.c @@ -32,6 +32,7 @@ #include "irc-queries.h" #include "irc-servers-setup.h" #include "irc-servers.h" +#include "irc-cap.h" #include "channel-rejoin.h" #include "servers-idle.h" #include "servers-reconnect.h" @@ -221,6 +222,8 @@ static void server_init(IRC_SERVER_REC *server) g_free(cmd); } + irc_send_cmd_now(server, "CAP LS"); + if (conn->password != NULL && *conn->password != '\0') { /* send password */ cmd = g_strdup_printf("PASS %s", conn->password); @@ -321,6 +324,8 @@ SERVER_REC *irc_server_init_connect(SERVER_CONNECT_REC *conn) void irc_server_connect(SERVER_REC *server) { + g_return_if_fail(server != NULL); + if (!server_start_connect(server)) { server_connect_unref(server->connrec); g_free(server); @@ -416,7 +421,16 @@ static void sig_disconnected(IRC_SERVER_REC *server) server_redirect_destroy(tmp->next->data); } g_slist_free(server->cmdqueue); - server->cmdqueue = NULL; + server->cmdqueue = NULL; + + gslist_free_full(server->cap_active, (GDestroyNotify) g_free); + server->cap_active = NULL; + + gslist_free_full(server->cap_supported, (GDestroyNotify) g_free); + server->cap_supported = NULL; + + gslist_free_full(server->cap_queue, (GDestroyNotify) g_free); + server->cap_queue = NULL; /* these are dynamically allocated only if isupport was sent */ g_hash_table_foreach(server->isupport, diff --git a/src/irc/core/irc-servers.h b/src/irc/core/irc-servers.h index 7e4eeabf..f809fab5 100644 --- a/src/irc/core/irc-servers.h +++ b/src/irc/core/irc-servers.h @@ -69,6 +69,13 @@ struct _IRC_SERVER_REC { int max_whois_in_cmd; /* max. number of nicks in one /WHOIS command */ int max_msgs_in_cmd; /* max. number of targets in one /MSG */ + GSList *cap_supported; /* A list of caps supported by the server */ + GSList *cap_active; /* A list of caps active for this session */ + GSList *cap_queue; /* A list of caps to request on connection */ + int cap_complete:1; /* We've done the initial CAP negotiation */ + + guint sasl_timeout; /* Holds the source id of the running timeout */ + /* Command sending queue */ int cmdcount; /* number of commands in `cmdqueue'. Can be more than there actually is, to make flood control remember diff --git a/src/irc/proxy/dump.c b/src/irc/proxy/dump.c index 3d7bf546..455a2fe3 100644 --- a/src/irc/proxy/dump.c +++ b/src/irc/proxy/dump.c @@ -83,7 +83,7 @@ void proxy_outserver(CLIENT_REC *client, const char *data, ...) va_start(args, data); str = g_strdup_vprintf(data, args); - proxy_outdata(client, ":%s!%s@proxy %s\n", client->nick, + proxy_outdata(client, ":%s!%s@proxy %s\r\n", client->nick, settings_get_str("user_name"), str); g_free(str); @@ -106,7 +106,7 @@ void proxy_outserver_all(IRC_SERVER_REC *server, const char *data, ...) CLIENT_REC *rec = tmp->data; if (rec->connected && rec->server == server) { - proxy_outdata(rec, ":%s!%s@proxy %s\n", rec->nick, + proxy_outdata(rec, ":%s!%s@proxy %s\r\n", rec->nick, settings_get_str("user_name"), str); } } @@ -132,7 +132,7 @@ void proxy_outserver_all_except(CLIENT_REC *client, const char *data, ...) if (rec->connected && rec != client && rec->server == client->server) { - proxy_outdata(rec, ":%s!%s@proxy %s\n", rec->nick, + proxy_outdata(rec, ":%s!%s@proxy %s\r\n", rec->nick, settings_get_str("user_name"), str); } } @@ -169,7 +169,7 @@ static void dump_join(IRC_CHANNEL_REC *channel, CLIENT_REC *client) NICK_REC *nick = tmp->data; if (str->len >= 500) { - g_string_append_c(str, '\n'); + g_string_append_c(str, '\r\n'); proxy_outdata(client, "%s", str->str); create_names_start(str, channel, client); first = TRUE; @@ -186,21 +186,21 @@ static void dump_join(IRC_CHANNEL_REC *channel, CLIENT_REC *client) } g_slist_free(nicks); - g_string_append_c(str, '\n'); + g_string_append_c(str, '\r\n'); proxy_outdata(client, "%s", str->str); g_string_free(str, TRUE); - proxy_outdata(client, ":%s 366 %s %s :End of /NAMES list.\n", + proxy_outdata(client, ":%s 366 %s %s :End of /NAMES list.\r\n", client->proxy_address, client->nick, channel->name); if (channel->topic != NULL) { /* this is needed because the topic may be encoded into other charsets internaly */ recoded = recode_out(SERVER(client->server), channel->topic, channel->name); - proxy_outdata(client, ":%s 332 %s %s :%s\n", + proxy_outdata(client, ":%s 332 %s %s :%s\r\n", client->proxy_address, client->nick, channel->name, recoded); g_free(recoded); if (channel->topic_time > 0) - proxy_outdata(client, ":%s 333 %s %s %s %d\n", + proxy_outdata(client, ":%s 333 %s %s %s %d\r\n", client->proxy_address, client->nick, channel->name, channel->topic_by, channel->topic_time); } @@ -212,7 +212,7 @@ void proxy_client_reset_nick(CLIENT_REC *client) g_strcmp0(client->nick, client->server->nick) == 0) return; - proxy_outdata(client, ":%s!proxy NICK :%s\n", + proxy_outdata(client, ":%s!proxy NICK :%s\r\n", client->nick, client->server->nick); g_free(client->nick); @@ -236,13 +236,13 @@ void proxy_dump_data(CLIENT_REC *client) proxy_client_reset_nick(client); /* welcome info */ - proxy_outdata(client, ":%s 001 %s :Welcome to the Internet Relay Network %s!%s@proxy\n", client->proxy_address, client->nick, client->nick, settings_get_str("user_name")); - proxy_outdata(client, ":%s 002 %s :Your host is irssi-proxy, running version %s\n", client->proxy_address, client->nick, PACKAGE_VERSION); - proxy_outdata(client, ":%s 003 %s :This server was created ...\n", client->proxy_address, client->nick); + proxy_outdata(client, ":%s 001 %s :Welcome to the Internet Relay Network %s!%s@proxy\r\n", client->proxy_address, client->nick, client->nick, settings_get_str("user_name")); + proxy_outdata(client, ":%s 002 %s :Your host is irssi-proxy, running version %s\r\n", client->proxy_address, client->nick, PACKAGE_VERSION); + proxy_outdata(client, ":%s 003 %s :This server was created ...\r\n", client->proxy_address, client->nick); if (client->server == NULL || !client->server->emode_known) - proxy_outdata(client, ":%s 004 %s %s %s oirw abiklmnopqstv\n", client->proxy_address, client->nick, client->proxy_address, PACKAGE_VERSION); + proxy_outdata(client, ":%s 004 %s %s %s oirw abiklmnopqstv\r\n", client->proxy_address, client->nick, client->proxy_address, PACKAGE_VERSION); else - proxy_outdata(client, ":%s 004 %s %s %s oirw abeIiklmnopqstv\n", client->proxy_address, client->nick, client->proxy_address, PACKAGE_VERSION); + proxy_outdata(client, ":%s 004 %s %s %s oirw abeIiklmnopqstv\r\n", client->proxy_address, client->nick, client->proxy_address, PACKAGE_VERSION); if (client->server != NULL && client->server->isupport_sent) { isupport_out = g_string_new(NULL); @@ -267,7 +267,7 @@ void proxy_dump_data(CLIENT_REC *client) count = 0; if (paramstr->len > 0) g_string_truncate(paramstr, paramstr->len-1); - g_string_append_printf(paramstr, " :are supported by this server\n"); + g_string_append_printf(paramstr, " :are supported by this server\r\n"); proxy_outdata(client, "%s", paramstr->str); g_string_truncate(paramstr, 0); g_string_printf(paramstr, ":%s 005 %s ", client->proxy_address, client->nick); @@ -281,9 +281,9 @@ void proxy_dump_data(CLIENT_REC *client) g_strfreev(paramlist); } - proxy_outdata(client, ":%s 251 %s :There are 0 users and 0 invisible on 1 servers\n", client->proxy_address, client->nick); - proxy_outdata(client, ":%s 255 %s :I have 0 clients, 0 services and 0 servers\n", client->proxy_address, client->nick); - proxy_outdata(client, ":%s 422 %s :MOTD File is missing\n", client->proxy_address, client->nick); + proxy_outdata(client, ":%s 251 %s :There are 0 users and 0 invisible on 1 servers\r\n", client->proxy_address, client->nick); + proxy_outdata(client, ":%s 255 %s :I have 0 clients, 0 services and 0 servers\r\n", client->proxy_address, client->nick); + proxy_outdata(client, ":%s 422 %s :MOTD File is missing\r\n", client->proxy_address, client->nick); /* user mode / away status */ if (client->server != NULL) { @@ -293,7 +293,7 @@ void proxy_dump_data(CLIENT_REC *client) client->server->usermode); } if (client->server->usermode_away) { - proxy_outdata(client, ":%s 306 %s :You have been marked as being away\n", + proxy_outdata(client, ":%s 306 %s :You have been marked as being away\r\n", client->proxy_address, client->nick); } diff --git a/src/irc/proxy/listen.c b/src/irc/proxy/listen.c index ebbbdcfa..ae5af5fb 100644 --- a/src/irc/proxy/listen.c +++ b/src/irc/proxy/listen.c @@ -155,7 +155,7 @@ static void handle_client_cmd(CLIENT_REC *client, char *cmd, char *args, if (*target == '\0' || g_ascii_strcasecmp(target, client->proxy_address) == 0 || g_ascii_strcasecmp(target, client->nick) == 0) { - proxy_outdata(client, ":%s PONG %s :%s\n", + proxy_outdata(client, ":%s PONG %s :%s\r\n", client->proxy_address, client->proxy_address, origin); g_free(params); @@ -174,18 +174,18 @@ static void handle_client_cmd(CLIENT_REC *client, char *cmd, char *args, /* 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\n", + 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\n", + proxy_outdata(client, ":%s NOTICE %s :You're now receiving CTCPs sent to %s\r\n", 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->want_ctcp = 0; - proxy_outdata(client, ":%s NOTICE %s :Proxy is now handling itself CTCPs sent to %s\n", + 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); } else { signal_emit("proxy client command", 3, client, args, data); @@ -194,7 +194,7 @@ 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\n", + proxy_outdata(client, ":%s NOTICE %s :Not connected to server\r\n", client->proxy_address, client->nick); return; } @@ -371,7 +371,7 @@ static void sig_incoming(IRC_SERVER_REC *server, const char *line) g_return_if_fail(line != NULL); /* send server event to all clients */ - g_string_printf(next_line, "%s\n", line); + g_string_printf(next_line, "%s\r\n", line); } static void sig_server_event(IRC_SERVER_REC *server, const char *line, @@ -465,7 +465,7 @@ static void event_connected(IRC_SERVER_REC *server) (g_strcmp0(rec->listen->ircnet, "*") == 0 || (chatnet != NULL && g_ascii_strcasecmp(chatnet, rec->listen->ircnet) == 0))) { - proxy_outdata(rec, ":%s NOTICE %s :Connected to server\n", + proxy_outdata(rec, ":%s NOTICE %s :Connected to server\r\n", rec->proxy_address, rec->nick); rec->server = server; proxy_client_reset_nick(rec); @@ -478,7 +478,7 @@ static void proxy_server_disconnected(CLIENT_REC *client, { GSList *tmp; - proxy_outdata(client, ":%s NOTICE %s :Connection lost to server %s\n", + proxy_outdata(client, ":%s NOTICE %s :Connection lost to server %s\r\n", client->proxy_address, client->nick, server->connrec->address); |