use starttls

This commit is contained in:
ailin-nemui 2020-04-05 13:18:54 +02:00 committed by Ailin Nemui
parent 9b02424f30
commit 51508ff1d3
13 changed files with 346 additions and 138 deletions

View File

@ -71,8 +71,8 @@ static SERVER_CONNECT_REC *get_server_connect(const char *data, int *plus_addr,
if (chatnet == NULL) if (chatnet == NULL)
chatnet = g_hash_table_lookup(optlist, "network"); chatnet = g_hash_table_lookup(optlist, "network");
conn = server_create_conn(proto != NULL ? proto->id : -1, addr, conn = server_create_conn_opt(proto != NULL ? proto->id : -1, addr, atoi(portstr), chatnet,
atoi(portstr), chatnet, password, nick); password, nick, optlist);
if (conn == NULL) { if (conn == NULL) {
signal_emit("error command", 1, signal_emit("error command", 1,
GINT_TO_POINTER(CMDERR_NO_SERVER_DEFINED)); GINT_TO_POINTER(CMDERR_NO_SERVER_DEFINED));

View File

@ -140,8 +140,8 @@ void server_setup_fill_reconn(SERVER_CONNECT_REC *conn,
signal_emit("server setup fill reconn", 2, conn, sserver); signal_emit("server setup fill reconn", 2, conn, sserver);
} }
static void server_setup_fill(SERVER_CONNECT_REC *conn, static void server_setup_fill(SERVER_CONNECT_REC *conn, const char *address, int port,
const char *address, int port) GHashTable *optlist)
{ {
g_return_if_fail(conn != NULL); g_return_if_fail(conn != NULL);
g_return_if_fail(address != NULL); g_return_if_fail(address != NULL);
@ -177,7 +177,7 @@ static void server_setup_fill(SERVER_CONNECT_REC *conn,
memcpy(conn->own_ip6, source_host_ip6, sizeof(IPADDR)); memcpy(conn->own_ip6, source_host_ip6, sizeof(IPADDR));
} }
signal_emit("server setup fill connect", 1, conn); signal_emit("server setup fill connect", 2, conn, optlist);
} }
static void server_setup_fill_server(SERVER_CONNECT_REC *conn, static void server_setup_fill_server(SERVER_CONNECT_REC *conn,
@ -219,10 +219,9 @@ static void server_setup_fill_chatnet(SERVER_CONNECT_REC *conn,
signal_emit("server setup fill chatnet", 2, conn, chatnet); signal_emit("server setup fill chatnet", 2, conn, chatnet);
} }
static SERVER_CONNECT_REC * static SERVER_CONNECT_REC *create_addr_conn(int chat_type, const char *address, int port,
create_addr_conn(int chat_type, const char *address, int port,
const char *chatnet, const char *password, const char *chatnet, const char *password,
const char *nick) const char *nick, GHashTable *optlist)
{ {
CHAT_PROTOCOL_REC *proto; CHAT_PROTOCOL_REC *proto;
SERVER_CONNECT_REC *conn; SERVER_CONNECT_REC *conn;
@ -250,7 +249,7 @@ create_addr_conn(int chat_type, const char *address, int port,
conn->chatnet = g_strdup(chatnet); conn->chatnet = g_strdup(chatnet);
/* fill in the defaults */ /* fill in the defaults */
server_setup_fill(conn, address, port); server_setup_fill(conn, address, port, optlist);
/* fill the rest from chat network settings */ /* fill the rest from chat network settings */
chatnetrec = chatnet != NULL ? chatnet_find(chatnet) : chatnetrec = chatnet != NULL ? chatnet_find(chatnet) :
@ -279,9 +278,8 @@ create_addr_conn(int chat_type, const char *address, int port,
/* Connect to server where last connect succeeded (or we haven't tried to /* Connect to server where last connect succeeded (or we haven't tried to
connect yet). If there's no such server, connect to server where we connect yet). If there's no such server, connect to server where we
haven't connected for the longest time */ haven't connected for the longest time */
static SERVER_CONNECT_REC * static SERVER_CONNECT_REC *create_chatnet_conn(const char *dest, int port, const char *password,
create_chatnet_conn(const char *dest, int port, const char *nick, GHashTable *optlist)
const char *password, const char *nick)
{ {
SERVER_SETUP_REC *bestrec; SERVER_SETUP_REC *bestrec;
GSList *tmp; GSList *tmp;
@ -308,16 +306,15 @@ create_chatnet_conn(const char *dest, int port,
} }
return bestrec == NULL ? NULL : return bestrec == NULL ? NULL :
create_addr_conn(bestrec->chat_type, bestrec->address, 0, create_addr_conn(bestrec->chat_type, bestrec->address, 0, dest,
dest, NULL, nick); NULL, nick, optlist);
} }
/* Create server connection record. `dest' is required, rest can be NULL. /* Create server connection record. `dest' is required, rest can be NULL.
`dest' is either a server address or chat network */ `dest' is either a server address or chat network */
SERVER_CONNECT_REC * SERVER_CONNECT_REC *server_create_conn_opt(int chat_type, const char *dest, int port,
server_create_conn(int chat_type, const char *dest, int port,
const char *chatnet, const char *password, const char *chatnet, const char *password,
const char *nick) const char *nick, GHashTable *optlist)
{ {
SERVER_CONNECT_REC *rec; SERVER_CONNECT_REC *rec;
CHATNET_REC *chatrec; CHATNET_REC *chatrec;
@ -326,7 +323,7 @@ server_create_conn(int chat_type, const char *dest, int port,
chatrec = chatnet_find(dest); chatrec = chatnet_find(dest);
if (chatrec != NULL) { if (chatrec != NULL) {
rec = create_chatnet_conn(chatrec->name, port, password, nick); rec = create_chatnet_conn(chatrec->name, port, password, nick, optlist);
/* If rec is NULL the chatnet has no url to connect to */ /* If rec is NULL the chatnet has no url to connect to */
return rec; return rec;
} }
@ -335,8 +332,13 @@ server_create_conn(int chat_type, const char *dest, int port,
if (chatrec != NULL) if (chatrec != NULL)
chatnet = chatrec->name; chatnet = chatrec->name;
return create_addr_conn(chat_type, dest, port, return create_addr_conn(chat_type, dest, port, chatnet, password, nick, optlist);
chatnet, password, nick); }
SERVER_CONNECT_REC *server_create_conn(int chat_type, const char *dest, int port,
const char *chatnet, const char *password, const char *nick)
{
return server_create_conn_opt(chat_type, dest, port, chatnet, password, nick, NULL);
} }
/* Find matching server from setup. Try to find record with a same port, /* Find matching server from setup. Try to find record with a same port,

View File

@ -31,6 +31,10 @@ server_create_conn(int chat_type, const char *dest, int port,
const char *chatnet, const char *password, const char *chatnet, const char *password,
const char *nick); const char *nick);
SERVER_CONNECT_REC *server_create_conn_opt(int chat_type, const char *dest, int port,
const char *chatnet, const char *password,
const char *nick, GHashTable *optlist);
/* Find matching server from setup. Try to find record with a same port, /* Find matching server from setup. Try to find record with a same port,
but fallback to any server with the same address. */ but fallback to any server with the same address. */
SERVER_SETUP_REC *server_setup_find(const char *address, int port, SERVER_SETUP_REC *server_setup_find(const char *address, int port,

View File

@ -246,7 +246,7 @@ static void cmd_server_add_modify(const char *data, gboolean add)
rec->own_ip4 = rec->own_ip6 = NULL; rec->own_ip4 = rec->own_ip6 = NULL;
} }
signal_emit("server add fill", 2, rec, optlist); signal_emit("server add fill", 3, rec, optlist, GINT_TO_POINTER(add));
server_setup_add(rec); server_setup_add(rec);
printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE, printformat(NULL, NULL, MSGLEVEL_CLIENTNOTICE,

View File

@ -51,12 +51,12 @@ const char *get_visible_target(IRC_SERVER_REC *server, const char *target)
return target; return target;
} }
/* SYNTAX: SERVER ADD|MODIFY [-4 | -6] [-tls] [-tls_cert <cert>] [-tls_pkey <pkey>] [-tls_pass <password>] /* SYNTAX: SERVER ADD|MODIFY [-4 | -6] [-tls] [-tls_cert <cert>] [-tls_pkey <pkey>]
[-tls_verify] [-tls_cafile <cafile>] [-tls_capath <capath>] [-tls_pass <password>] [-tls_verify] [-tls_cafile <cafile>]
[-tls_ciphers <list>] [-tls_capath <capath>] [-tls_ciphers <list>] [-starttls | -nostarttls]
[-auto | -noauto] [-network <network>] [-host <hostname>] [-auto | -noauto] [-network <network>] [-host <hostname>]
[-cmdspeed <ms>] [-cmdmax <count>] [-port <port>] [-cmdspeed <ms>] [-cmdmax <count>] [-port <port>] <address> [<port>
<address> [<port> [<password>]] */ [<password>]] */
/* NOTE: -network replaces the old -ircnet flag. */ /* NOTE: -network replaces the old -ircnet flag. */
static void sig_server_add_fill(IRC_SERVER_SETUP_REC *rec, static void sig_server_add_fill(IRC_SERVER_SETUP_REC *rec,
GHashTable *optlist) GHashTable *optlist)
@ -85,6 +85,12 @@ static void sig_server_add_fill(IRC_SERVER_SETUP_REC *rec,
if (value != NULL && *value != '\0') rec->max_cmds_at_once = atoi(value); if (value != NULL && *value != '\0') rec->max_cmds_at_once = atoi(value);
value = g_hash_table_lookup(optlist, "querychans"); value = g_hash_table_lookup(optlist, "querychans");
if (value != NULL && *value != '\0') rec->max_query_chans = atoi(value); if (value != NULL && *value != '\0') rec->max_query_chans = atoi(value);
if (g_hash_table_lookup(optlist, "nonostarttls"))
rec->starttls = -1;
if (g_hash_table_lookup(optlist, "nostarttls"))
rec->starttls = 0;
if (g_hash_table_lookup(optlist, "starttls"))
rec->starttls = 1;
} }
/* SYNTAX: SERVER LIST */ /* SYNTAX: SERVER LIST */
@ -108,7 +114,9 @@ static void cmd_server_list(const char *data)
g_string_append(str, "autoconnect, "); g_string_append(str, "autoconnect, ");
if (rec->no_proxy) if (rec->no_proxy)
g_string_append(str, "noproxy, "); g_string_append(str, "noproxy, ");
if (rec->use_tls) { if (rec->starttls >= 0)
g_string_append_printf(str, "%sstarttls, ", rec->starttls ? "" : "no");
if (rec->use_tls)
g_string_append(str, "tls, "); g_string_append(str, "tls, ");
if (rec->tls_cert) { if (rec->tls_cert) {
g_string_append_printf(str, "tls_cert: %s, ", rec->tls_cert); g_string_append_printf(str, "tls_cert: %s, ", rec->tls_cert);
@ -128,9 +136,9 @@ static void cmd_server_list(const char *data)
if (rec->tls_pinned_cert) if (rec->tls_pinned_cert)
g_string_append_printf(str, "tls_pinned_cert: %s, ", rec->tls_pinned_cert); g_string_append_printf(str, "tls_pinned_cert: %s, ", rec->tls_pinned_cert);
if (rec->tls_pinned_pubkey) if (rec->tls_pinned_pubkey)
g_string_append_printf(str, "tls_pinned_pubkey: %s, ", rec->tls_pinned_pubkey); g_string_append_printf(str, "tls_pinned_pubkey: %s, ",
rec->tls_pinned_pubkey);
}
if (rec->max_cmds_at_once > 0) if (rec->max_cmds_at_once > 0)
g_string_append_printf(str, "cmdmax: %d, ", rec->max_cmds_at_once); g_string_append_printf(str, "cmdmax: %d, ", rec->max_cmds_at_once);
if (rec->cmd_queue_speed > 0) if (rec->cmd_queue_speed > 0)
@ -155,7 +163,12 @@ void fe_irc_server_init(void)
signal_add("server add fill", (SIGNAL_FUNC) sig_server_add_fill); signal_add("server add fill", (SIGNAL_FUNC) sig_server_add_fill);
command_bind("server list", NULL, (SIGNAL_FUNC) cmd_server_list); command_bind("server list", NULL, (SIGNAL_FUNC) cmd_server_list);
command_set_options("server add", "-ircnet -network -cmdspeed -cmdmax -querychans"); command_set_options(
"server add",
"-ircnet -network -cmdspeed -cmdmax -querychans starttls nostarttls nonostarttls");
command_set_options(
"server modify",
"-ircnet -network -cmdspeed -cmdmax -querychans starttls nostarttls nonostarttls");
} }
void fe_irc_server_deinit(void) void fe_irc_server_deinit(void)

View File

@ -104,12 +104,54 @@ static gboolean parse_cap_name(char *name, char **key, char **val)
return TRUE; return TRUE;
} }
static void event_cap (IRC_SERVER_REC *server, char *args, char *nick, char *address) static void cap_process_request_queue(IRC_SERVER_REC *server)
{ {
/* No CAP has been requested */
if (server->cap_queue == NULL) {
irc_cap_finish_negotiation(server);
} else {
GSList *tmp; GSList *tmp;
GString *cmd; GString *cmd;
int avail_caps = 0;
cmd = g_string_new("CAP REQ :");
/* To process the queue in order, we need to reverse the stack once */
server->cap_queue = g_slist_reverse(server->cap_queue);
/* Check whether the cap is supported by the server */
for (tmp = server->cap_queue; tmp != NULL; tmp = tmp->next) {
if (g_hash_table_lookup_extended(server->cap_supported, tmp->data, NULL,
NULL)) {
if (avail_caps > 0)
g_string_append_c(cmd, ' ');
g_string_append(cmd, tmp->data);
avail_caps++;
}
}
/* Clear the queue here */
i_slist_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) {
signal_emit("server cap req", 2, server,
cmd->str + sizeof("CAP REQ :") - 1);
irc_send_cmd_now(server, cmd->str);
} else {
irc_cap_finish_negotiation(server);
}
g_string_free(cmd, TRUE);
}
}
static void event_cap (IRC_SERVER_REC *server, char *args, char *nick, char *address)
{
char *params, *evt, *list, *star, **caps; char *params, *evt, *list, *star, **caps;
int i, caps_length, disable, avail_caps, multiline; int i, caps_length, disable, multiline;
params = event_get_params(args, 4, NULL, &evt, &star, &list); params = event_get_params(args, 4, NULL, &evt, &star, &list);
if (params == NULL) if (params == NULL)
@ -174,42 +216,20 @@ static void event_cap (IRC_SERVER_REC *server, char *args, char *nick, char *add
/* A multiline response is always terminated by a normal one, /* A multiline response is always terminated by a normal one,
* wait until we receive that one to require any CAP */ * wait until we receive that one to require any CAP */
if (multiline == FALSE) { if (multiline == FALSE) {
/* No CAP has been requested */ gboolean want_starttls =
if (server->cap_queue == NULL) { i_slist_find_string(server->cap_queue, CAP_STARTTLS) != NULL;
irc_cap_finish_negotiation(server); server->cap_queue =
} i_slist_delete_string(server->cap_queue, CAP_STARTTLS, g_free);
else { if (server->connrec->starttls) {
cmd = g_string_new("CAP REQ :"); /* the connection has requested starttls,
no more data must be sent now */
avail_caps = 0; } else if (want_starttls &&
g_hash_table_lookup_extended(server->cap_supported, CAP_STARTTLS,
/* To process the queue in order, we need to reverse the stack once */ NULL, NULL)) {
server->cap_queue = g_slist_reverse(server->cap_queue); irc_server_send_starttls(server);
/* no more data must be sent now */
/* Check whether the cap is supported by the server */
for (tmp = server->cap_queue; tmp != NULL; tmp = tmp->next) {
if (g_hash_table_lookup_extended(server->cap_supported, tmp->data, NULL, NULL)) {
if (avail_caps > 0)
g_string_append_c(cmd, ' ');
g_string_append(cmd, tmp->data);
avail_caps++;
}
}
/* Clear the queue here */
i_slist_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) {
signal_emit("server cap req", 2, server, cmd->str + sizeof("CAP REQ :") - 1);
irc_send_cmd_now(server, cmd->str);
} else { } else {
irc_cap_finish_negotiation(server); cap_process_request_queue(server);
}
g_string_free(cmd, TRUE);
} }
} }
} }
@ -301,12 +321,14 @@ static void event_invalid_cap (IRC_SERVER_REC *server, const char *data, const c
void irc_cap_init (void) void irc_cap_init (void)
{ {
signal_add_last("server cap continue", (SIGNAL_FUNC) cap_process_request_queue);
signal_add_first("event cap", (SIGNAL_FUNC) event_cap); signal_add_first("event cap", (SIGNAL_FUNC) event_cap);
signal_add_first("event 410", (SIGNAL_FUNC) event_invalid_cap); signal_add_first("event 410", (SIGNAL_FUNC) event_invalid_cap);
} }
void irc_cap_deinit (void) void irc_cap_deinit (void)
{ {
signal_remove("server cap continue", (SIGNAL_FUNC) cap_process_request_queue);
signal_remove("event cap", (SIGNAL_FUNC) event_cap); signal_remove("event cap", (SIGNAL_FUNC) event_cap);
signal_remove("event 410", (SIGNAL_FUNC) event_invalid_cap); signal_remove("event 410", (SIGNAL_FUNC) event_invalid_cap);
} }

View File

@ -1053,7 +1053,7 @@ void irc_commands_init(void)
signal_add("whois end", (SIGNAL_FUNC) event_end_of_whois); signal_add("whois end", (SIGNAL_FUNC) event_end_of_whois);
signal_add("whowas event", (SIGNAL_FUNC) event_whowas); signal_add("whowas event", (SIGNAL_FUNC) event_whowas);
command_set_options("connect", "+ircnet"); command_set_options("connect", "+ircnet starttls nostarttls");
command_set_options("topic", "delete"); command_set_options("topic", "delete");
command_set_options("list", "yes"); command_set_options("list", "yes");
command_set_options("away", "one all"); command_set_options("away", "one all");

View File

@ -51,6 +51,8 @@ static void sig_server_connect_copy(SERVER_CONNECT_REC **dest,
rec->sasl_mechanism = src->sasl_mechanism; rec->sasl_mechanism = src->sasl_mechanism;
rec->sasl_username = g_strdup(src->sasl_username); rec->sasl_username = g_strdup(src->sasl_username);
rec->sasl_password = g_strdup(src->sasl_password); rec->sasl_password = g_strdup(src->sasl_password);
rec->no_starttls = src->no_starttls;
rec->starttls = src->starttls;
*dest = (SERVER_CONNECT_REC *) rec; *dest = (SERVER_CONNECT_REC *) rec;
} }

View File

@ -44,9 +44,13 @@ static void sig_server_setup_fill_reconn(IRC_SERVER_CONNECT_REC *conn,
conn->max_cmds_at_once = sserver->max_cmds_at_once; conn->max_cmds_at_once = sserver->max_cmds_at_once;
if (sserver->max_query_chans > 0) if (sserver->max_query_chans > 0)
conn->max_query_chans = sserver->max_query_chans; conn->max_query_chans = sserver->max_query_chans;
if (sserver->starttls == 0)
conn->no_starttls = 1;
else if (sserver->starttls == 1)
conn->starttls = 1;
} }
static void sig_server_setup_fill_connect(IRC_SERVER_CONNECT_REC *conn) static void sig_server_setup_fill_connect(IRC_SERVER_CONNECT_REC *conn, GHashTable *optlist)
{ {
const char *value; const char *value;
@ -60,6 +64,11 @@ static void sig_server_setup_fill_connect(IRC_SERVER_CONNECT_REC *conn)
value = settings_get_str("usermode"); value = settings_get_str("usermode");
conn->usermode = (value != NULL && *value != '\0') ? conn->usermode = (value != NULL && *value != '\0') ?
g_strdup(value) : NULL; g_strdup(value) : NULL;
if (g_hash_table_lookup(optlist, "starttls") != NULL)
conn->starttls = 1;
else if (g_hash_table_lookup(optlist, "nostarttls") != NULL)
conn->no_starttls = 1;
} }
static void sig_server_setup_fill_chatnet(IRC_SERVER_CONNECT_REC *conn, static void sig_server_setup_fill_chatnet(IRC_SERVER_CONNECT_REC *conn,
@ -174,6 +183,7 @@ static void sig_server_setup_read(IRC_SERVER_SETUP_REC *rec, CONFIG_NODE *node)
rec->max_cmds_at_once = config_node_get_int(node, "cmds_max_at_once", 0); rec->max_cmds_at_once = config_node_get_int(node, "cmds_max_at_once", 0);
rec->cmd_queue_speed = config_node_get_int(node, "cmd_queue_speed", 0); rec->cmd_queue_speed = config_node_get_int(node, "cmd_queue_speed", 0);
rec->max_query_chans = config_node_get_int(node, "max_query_chans", 0); rec->max_query_chans = config_node_get_int(node, "max_query_chans", 0);
rec->starttls = config_node_get_bool(node, "starttls", -1);
} }
static void sig_server_setup_saved(IRC_SERVER_SETUP_REC *rec, static void sig_server_setup_saved(IRC_SERVER_SETUP_REC *rec,
@ -188,6 +198,10 @@ static void sig_server_setup_saved(IRC_SERVER_SETUP_REC *rec,
iconfig_node_set_int(node, "cmd_queue_speed", rec->cmd_queue_speed); iconfig_node_set_int(node, "cmd_queue_speed", rec->cmd_queue_speed);
if (rec->max_query_chans > 0) if (rec->max_query_chans > 0)
iconfig_node_set_int(node, "max_query_chans", rec->max_query_chans); iconfig_node_set_int(node, "max_query_chans", rec->max_query_chans);
if (rec->starttls >= 0)
iconfig_node_set_bool(node, "starttls", rec->starttls);
else
iconfig_node_set_str(node, "starttls", NULL);
} }
void irc_servers_setup_init(void) void irc_servers_setup_init(void)

View File

@ -18,6 +18,7 @@ typedef struct {
int max_cmds_at_once; int max_cmds_at_once;
int cmd_queue_speed; int cmd_queue_speed;
int max_query_chans; int max_query_chans;
int starttls;
} IRC_SERVER_SETUP_REC; } IRC_SERVER_SETUP_REC;
void irc_servers_setup_init(void); void irc_servers_setup_init(void);

View File

@ -20,10 +20,11 @@
#include "module.h" #include "module.h"
#include <irssi/src/core/net-sendbuffer.h>
#include <irssi/src/core/signals.h>
#include <irssi/src/core/rawlog.h>
#include <irssi/src/core/misc.h> #include <irssi/src/core/misc.h>
#include <irssi/src/core/net-sendbuffer.h>
#include <irssi/src/core/network.h>
#include <irssi/src/core/rawlog.h>
#include <irssi/src/core/signals.h>
#include <irssi/src/core/channels.h> #include <irssi/src/core/channels.h>
#include <irssi/src/core/queries.h> #include <irssi/src/core/queries.h>
@ -207,17 +208,17 @@ static char **split_message(SERVER_REC *server, const char *target,
strlen(target)); strlen(target));
} }
static void server_init(IRC_SERVER_REC *server) static void server_init_2(IRC_SERVER_REC *server);
static void server_init_1(IRC_SERVER_REC *server)
{ {
IRC_SERVER_CONNECT_REC *conn; IRC_SERVER_CONNECT_REC *conn;
char *address, *ptr, *username, *cmd; char *cmd;
g_return_if_fail(server != NULL); g_return_if_fail(server != NULL);
conn = server->connrec; conn = server->connrec;
if (conn->proxy != NULL && conn->proxy_password != NULL && if (conn->proxy != NULL && conn->proxy_password != NULL && *conn->proxy_password != '\0') {
*conn->proxy_password != '\0') {
cmd = g_strdup_printf("PASS %s", conn->proxy_password); cmd = g_strdup_printf("PASS %s", conn->proxy_password);
irc_send_cmd_now(server, cmd); irc_send_cmd_now(server, cmd);
g_free(cmd); g_free(cmd);
@ -243,8 +244,140 @@ static void server_init(IRC_SERVER_REC *server)
irc_cap_toggle(server, CAP_ACCOUNT_NOTIFY, TRUE); irc_cap_toggle(server, CAP_ACCOUNT_NOTIFY, TRUE);
irc_cap_toggle(server, CAP_SELF_MESSAGE, TRUE); irc_cap_toggle(server, CAP_SELF_MESSAGE, TRUE);
irc_cap_toggle(server, CAP_SERVER_TIME, TRUE); irc_cap_toggle(server, CAP_SERVER_TIME, TRUE);
if (!conn->use_tls && (conn->starttls || !conn->no_starttls)) {
irc_cap_toggle(server, CAP_STARTTLS, TRUE);
}
server->isupport = g_hash_table_new((GHashFunc) i_istr_hash, (GCompareFunc) i_istr_equal);
/* set the standards */
g_hash_table_insert(server->isupport, g_strdup("CHANMODES"), g_strdup("beI,k,l,imnpst"));
g_hash_table_insert(server->isupport, g_strdup("PREFIX"), g_strdup("(ohv)@%+"));
server->cmdcount = 0;
/* 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 */
server->wait_cmd = g_get_real_time();
server->wait_cmd += 120 * G_USEC_PER_SEC;
irc_send_cmd_now(server, "CAP LS " CAP_LS_VERSION); irc_send_cmd_now(server, "CAP LS " CAP_LS_VERSION);
/* to detect non-CAP servers, send this bogus join */
irc_send_cmd_now(server, "JOIN ");
if (conn->starttls)
irc_server_send_starttls(server);
}
static void init_ssl_loop(IRC_SERVER_REC *server, GIOChannel *handle)
{
int error;
if (server->starttls_tag) {
g_source_remove(server->starttls_tag);
server->starttls_tag = 0;
}
error = irssi_ssl_handshake(handle);
if (error == -1) {
server->connection_lost = TRUE;
server_disconnect((SERVER_REC *) server);
return;
}
if (error & 1) { /* wait */
server->starttls_tag =
i_input_add(handle, error == 1 ? I_INPUT_READ : I_INPUT_WRITE,
(GInputFunction) init_ssl_loop, server);
return;
}
/* continue */
rawlog_redirect(server->rawlog, "Now talking encrypted");
signal_emit("server connection switched", 1, server);
if (!server->cap_supported) {
server_init_2(server);
} else {
signal_emit("server cap continue", 1, server);
}
server->connrec->starttls = 1;
if (settings_get_bool("starttls_sts")) {
IRC_SERVER_SETUP_REC *ssetup = IRC_SERVER_SETUP(server_setup_find(
server->connrec->address, server->connrec->port, server->connrec->chatnet));
if (ssetup != NULL) {
ssetup->starttls = 1;
server_setup_add((SERVER_SETUP_REC *) ssetup);
}
}
}
#include <irssi/src/core/line-split.h>
void irc_server_send_starttls(IRC_SERVER_REC *server)
{
g_return_if_fail(server != NULL);
g_warning("Now attempting STARTTLS");
irc_send_cmd_now(server, "STARTTLS");
}
static void event_starttls(IRC_SERVER_REC *server, const char *data)
{
GIOChannel *ssl_handle;
g_return_if_fail(server != NULL);
if (!IS_IRC_SERVER(server))
return;
if (server->handle->readbuffer != NULL &&
!line_split_is_empty(server->handle->readbuffer)) {
char *str;
line_split("", -1, &str, &server->handle->readbuffer);
}
ssl_handle = net_start_ssl((SERVER_REC *) server);
if (ssl_handle != NULL) {
g_source_remove(server->readtag);
server->readtag = -1;
server->handle->handle = ssl_handle;
init_ssl_loop(server, server->handle->handle);
} else {
g_warning("net_start_ssl failed");
}
}
static void event_registerfirst(IRC_SERVER_REC *server, const char *data)
{
g_return_if_fail(server != NULL);
if (!IS_IRC_SERVER(server))
return;
if (server->connected)
return;
if (!server->cap_supported && !server->connrec->starttls)
server_init_2(server);
}
static void event_capend(IRC_SERVER_REC *server)
{
g_return_if_fail(server != NULL);
if (!IS_IRC_SERVER(server))
return;
if (server->connected)
return;
server_init_2(server);
}
static void server_init_2(IRC_SERVER_REC *server)
{
IRC_SERVER_CONNECT_REC *conn;
char *address, *ptr, *username, *cmd;
g_return_if_fail(server != NULL);
conn = server->connrec;
if (conn->password != NULL && *conn->password != '\0') { if (conn->password != NULL && *conn->password != '\0') {
/* send password */ /* send password */
@ -264,14 +397,15 @@ static void server_init(IRC_SERVER_REC *server)
if (ptr != NULL) { if (ptr != NULL) {
/* IPv6 address .. doesn't work here, use the string after /* IPv6 address .. doesn't work here, use the string after
the last : char */ the last : char */
address = ptr+1; address = ptr + 1;
if (*address == '\0') if (*address == '\0')
address = "x"; address = "x";
} }
username = g_strdup(conn->username); username = g_strdup(conn->username);
ptr = strchr(username, ' '); ptr = strchr(username, ' ');
if (ptr != NULL) *ptr = '\0'; if (ptr != NULL)
*ptr = '\0';
cmd = g_strdup_printf("USER %s %s %s :%s", username, username, address, conn->realname); cmd = g_strdup_printf("USER %s %s %s :%s", username, username, address, conn->realname);
irc_send_cmd_now(server, cmd); irc_send_cmd_now(server, cmd);
@ -283,19 +417,6 @@ static void server_init(IRC_SERVER_REC *server)
irc_send_cmd_now(server, cmd); irc_send_cmd_now(server, cmd);
g_free(cmd); g_free(cmd);
} }
server->isupport = g_hash_table_new((GHashFunc) i_istr_hash, (GCompareFunc) i_istr_equal);
/* set the standards */
g_hash_table_insert(server->isupport, g_strdup("CHANMODES"), g_strdup("beI,k,l,imnpst"));
g_hash_table_insert(server->isupport, g_strdup("PREFIX"), g_strdup("(ohv)@%+"));
server->cmdcount = 0;
/* 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 */
server->wait_cmd = g_get_real_time();
server->wait_cmd += 120 * G_USEC_PER_SEC;
} }
SERVER_REC *irc_server_init_connect(SERVER_CONNECT_REC *conn) SERVER_REC *irc_server_init_connect(SERVER_CONNECT_REC *conn)
@ -420,7 +541,7 @@ static void sig_connected(IRC_SERVER_REC *server)
server->splits = g_hash_table_new((GHashFunc) i_istr_hash, (GCompareFunc) i_istr_equal); server->splits = g_hash_table_new((GHashFunc) i_istr_hash, (GCompareFunc) i_istr_equal);
if (!server->session_reconnect) if (!server->session_reconnect)
server_init(server); server_init_1(server);
} }
static void isupport_destroy_hash(void *key, void *value) static void isupport_destroy_hash(void *key, void *value)
@ -429,6 +550,17 @@ static void isupport_destroy_hash(void *key, void *value)
g_free(value); g_free(value);
} }
static void sig_disconnected(IRC_SERVER_REC *server)
{
if (!IS_IRC_SERVER(server))
return;
if (server->starttls_tag) {
g_source_remove(server->starttls_tag);
server->starttls_tag = 0;
}
}
static void sig_destroyed(IRC_SERVER_REC *server) static void sig_destroyed(IRC_SERVER_REC *server)
{ {
GSList *tmp; GSList *tmp;
@ -1048,6 +1180,7 @@ void irc_server_init_isupport(IRC_SERVER_REC *server)
void irc_servers_init(void) void irc_servers_init(void)
{ {
settings_add_bool("servers", "starttls_sts", TRUE);
settings_add_choice("servers", "rejoin_channels_on_reconnect", 1, "off;on;auto"); settings_add_choice("servers", "rejoin_channels_on_reconnect", 1, "off;on;auto");
settings_add_str("misc", "usermode", DEFAULT_USER_MODE); settings_add_str("misc", "usermode", DEFAULT_USER_MODE);
settings_add_str("misc", "split_line_start", ""); settings_add_str("misc", "split_line_start", "");
@ -1059,9 +1192,13 @@ void irc_servers_init(void)
cmd_tag = -1; cmd_tag = -1;
signal_add_first("server connected", (SIGNAL_FUNC) sig_connected); signal_add_first("server connected", (SIGNAL_FUNC) sig_connected);
signal_add_first("server disconnected", (SIGNAL_FUNC) sig_disconnected);
signal_add_last("server destroyed", (SIGNAL_FUNC) sig_destroyed); signal_add_last("server destroyed", (SIGNAL_FUNC) sig_destroyed);
signal_add_last("server quit", (SIGNAL_FUNC) sig_server_quit); signal_add_last("server quit", (SIGNAL_FUNC) sig_server_quit);
signal_add("server cap ack " CAP_MAXLINE, (SIGNAL_FUNC) cap_maxline); signal_add("server cap ack " CAP_MAXLINE, (SIGNAL_FUNC) cap_maxline);
signal_add("event 670", (SIGNAL_FUNC) event_starttls);
signal_add("event 451", (SIGNAL_FUNC) event_registerfirst);
signal_add("server cap end", (SIGNAL_FUNC) event_capend);
signal_add("event 001", (SIGNAL_FUNC) event_connected); signal_add("event 001", (SIGNAL_FUNC) event_connected);
signal_add("event 004", (SIGNAL_FUNC) event_server_info); signal_add("event 004", (SIGNAL_FUNC) event_server_info);
signal_add("event 005", (SIGNAL_FUNC) event_isupport); signal_add("event 005", (SIGNAL_FUNC) event_isupport);
@ -1087,9 +1224,13 @@ void irc_servers_deinit(void)
g_source_remove(cmd_tag); g_source_remove(cmd_tag);
signal_remove("server connected", (SIGNAL_FUNC) sig_connected); signal_remove("server connected", (SIGNAL_FUNC) sig_connected);
signal_remove("server disconnected", (SIGNAL_FUNC) sig_disconnected);
signal_remove("server destroyed", (SIGNAL_FUNC) sig_destroyed); signal_remove("server destroyed", (SIGNAL_FUNC) sig_destroyed);
signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit); signal_remove("server quit", (SIGNAL_FUNC) sig_server_quit);
signal_remove("server cap ack " CAP_MAXLINE, (SIGNAL_FUNC) cap_maxline); signal_remove("server cap ack " CAP_MAXLINE, (SIGNAL_FUNC) cap_maxline);
signal_remove("event 670", (SIGNAL_FUNC) event_starttls);
signal_remove("event 451", (SIGNAL_FUNC) event_registerfirst);
signal_remove("server cap end", (SIGNAL_FUNC) event_capend);
signal_remove("event 001", (SIGNAL_FUNC) event_connected); signal_remove("event 001", (SIGNAL_FUNC) event_connected);
signal_remove("event 004", (SIGNAL_FUNC) event_server_info); signal_remove("event 004", (SIGNAL_FUNC) event_server_info);
signal_remove("event 005", (SIGNAL_FUNC) event_isupport); signal_remove("event 005", (SIGNAL_FUNC) event_isupport);

View File

@ -27,6 +27,7 @@
#define CAP_ACCOUNT_NOTIFY "account-notify" #define CAP_ACCOUNT_NOTIFY "account-notify"
#define CAP_SELF_MESSAGE "znc.in/self-message" #define CAP_SELF_MESSAGE "znc.in/self-message"
#define CAP_SERVER_TIME "server-time" #define CAP_SERVER_TIME "server-time"
#define CAP_STARTTLS "tls"
/* returns IRC_SERVER_REC if it's IRC server, NULL if it isn't */ /* returns IRC_SERVER_REC if it's IRC server, NULL if it isn't */
#define IRC_SERVER(server) \ #define IRC_SERVER(server) \
@ -42,6 +43,7 @@
#define IS_IRC_SERVER_CONNECT(conn) \ #define IS_IRC_SERVER_CONNECT(conn) \
(IRC_SERVER_CONNECT(conn) ? TRUE : FALSE) (IRC_SERVER_CONNECT(conn) ? TRUE : FALSE)
/* clang-format off */
/* all strings should be either NULL or dynamically allocated */ /* all strings should be either NULL or dynamically allocated */
/* address and nick are mandatory, rest are optional */ /* address and nick are mandatory, rest are optional */
struct _IRC_SERVER_CONNECT_REC { struct _IRC_SERVER_CONNECT_REC {
@ -59,7 +61,10 @@ struct _IRC_SERVER_CONNECT_REC {
int max_query_chans; int max_query_chans;
int max_kicks, max_msgs, max_modes, max_whois; int max_kicks, max_msgs, max_modes, max_whois;
int no_starttls:1;
int starttls:1;
}; };
/* clang-format on */
#define STRUCT_SERVER_CONNECT_REC IRC_SERVER_CONNECT_REC #define STRUCT_SERVER_CONNECT_REC IRC_SERVER_CONNECT_REC
struct _IRC_SERVER_REC { struct _IRC_SERVER_REC {
@ -136,6 +141,7 @@ struct _IRC_SERVER_REC {
GSList *rejoin_channels; /* try to join to these channels after a while - GSList *rejoin_channels; /* try to join to these channels after a while -
channels go here if they're "temporarily unavailable" channels go here if they're "temporarily unavailable"
because of netsplits */ because of netsplits */
guint starttls_tag; /* Holds the source id of the running timeout */
struct _SERVER_QUERY_REC *chanqueries; struct _SERVER_QUERY_REC *chanqueries;
GHashTable *isupport; GHashTable *isupport;
@ -155,6 +161,7 @@ void irc_server_purge_output(IRC_SERVER_REC *server, const char *target);
like "#a,#b,#c,#d x,b_chan_key,x,x" or just "#e,#f,#g" */ like "#a,#b,#c,#d x,b_chan_key,x,x" or just "#e,#f,#g" */
char *irc_server_get_channels(IRC_SERVER_REC *server); char *irc_server_get_channels(IRC_SERVER_REC *server);
void irc_server_send_starttls(IRC_SERVER_REC *server);
/* INTERNAL: */ /* INTERNAL: */
void irc_server_send_action(IRC_SERVER_REC *server, const char *target, void irc_server_send_action(IRC_SERVER_REC *server, const char *target,
const char *data); const char *data);

View File

@ -579,6 +579,7 @@ void irc_irc_init(void)
signal_add("server event", (SIGNAL_FUNC) irc_server_event); signal_add("server event", (SIGNAL_FUNC) irc_server_event);
signal_add("server event tags", (SIGNAL_FUNC) irc_server_event_tags); signal_add("server event tags", (SIGNAL_FUNC) irc_server_event_tags);
signal_add("server connected", (SIGNAL_FUNC) irc_init_server); signal_add("server connected", (SIGNAL_FUNC) irc_init_server);
signal_add("server connection switched", (SIGNAL_FUNC) irc_init_server);
signal_add("server incoming", (SIGNAL_FUNC) irc_parse_incoming_line); signal_add("server incoming", (SIGNAL_FUNC) irc_parse_incoming_line);
current_server_event = NULL; current_server_event = NULL;
@ -593,5 +594,6 @@ void irc_irc_deinit(void)
signal_remove("server event", (SIGNAL_FUNC) irc_server_event); signal_remove("server event", (SIGNAL_FUNC) irc_server_event);
signal_remove("server event tags", (SIGNAL_FUNC) irc_server_event_tags); signal_remove("server event tags", (SIGNAL_FUNC) irc_server_event_tags);
signal_remove("server connected", (SIGNAL_FUNC) irc_init_server); signal_remove("server connected", (SIGNAL_FUNC) irc_init_server);
signal_remove("server connection switched", (SIGNAL_FUNC) irc_init_server);
signal_remove("server incoming", (SIGNAL_FUNC) irc_parse_incoming_line); signal_remove("server incoming", (SIGNAL_FUNC) irc_parse_incoming_line);
} }