diff options
Diffstat (limited to 'src/core/servers-setup.c')
-rw-r--r-- | src/core/servers-setup.c | 780 |
1 files changed, 780 insertions, 0 deletions
diff --git a/src/core/servers-setup.c b/src/core/servers-setup.c new file mode 100644 index 0000000..82e5f6b --- /dev/null +++ b/src/core/servers-setup.c @@ -0,0 +1,780 @@ +/* + servers-setup.c : irssi + + Copyright (C) 1999-2001 Timo Sirainen + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include "module.h" +#include <irssi/src/core/signals.h> +#include <irssi/src/core/network.h> +#include <irssi/src/lib-config/iconfig.h> +#include <irssi/src/core/settings.h> + +#include <irssi/src/core/chat-protocols.h> +#include <irssi/src/core/chatnets.h> +#include <irssi/src/core/servers.h> +#include <irssi/src/core/servers-setup.h> + +GSList *setupservers; + +static char *old_source_host; +int source_host_ok; /* Use source_host_ip .. */ +IPADDR *source_host_ip4, *source_host_ip6; /* Resolved address */ + +static void save_ips(IPADDR *ip4, IPADDR *ip6, + IPADDR **save_ip4, IPADDR **save_ip6) +{ + if (ip4->family == 0) + g_free_and_null(*save_ip4); + else { + if (*save_ip4 == NULL) + *save_ip4 = g_new(IPADDR, 1); + memcpy(*save_ip4, ip4, sizeof(IPADDR)); + } + + if (ip6->family == 0) + g_free_and_null(*save_ip6); + else { + if (*save_ip6 == NULL) + *save_ip6 = g_new(IPADDR, 1); + memcpy(*save_ip6, ip6, sizeof(IPADDR)); + } +} + +static void get_source_host_ip(void) +{ + const char *hostname; + IPADDR ip4, ip6; + + if (source_host_ok) + return; + + /* FIXME: This will block! */ + hostname = settings_get_str("hostname"); + source_host_ok = *hostname != '\0' && + net_gethostbyname(hostname, &ip4, &ip6) == 0; + + if (source_host_ok) + save_ips(&ip4, &ip6, &source_host_ip4, &source_host_ip6); + else { + g_free_and_null(source_host_ip4); + g_free_and_null(source_host_ip6); + } +} + +static void conn_set_ip(SERVER_CONNECT_REC *conn, const char *own_host, + IPADDR **own_ip4, IPADDR **own_ip6) +{ + IPADDR ip4, ip6; + + if (*own_ip4 == NULL && *own_ip6 == NULL) { + /* resolve the IP */ + if (net_gethostbyname(own_host, &ip4, &ip6) == 0) + save_ips(&ip4, &ip6, own_ip4, own_ip6); + } + + server_connect_own_ip_save(conn, *own_ip4, *own_ip6); +} + +/* Fill information to connection from server setup record */ +void server_setup_fill_reconn(SERVER_CONNECT_REC *conn, + SERVER_SETUP_REC *sserver) +{ + g_return_if_fail(IS_SERVER_CONNECT(conn)); + g_return_if_fail(IS_SERVER_SETUP(sserver)); + + if (sserver->own_host != NULL) { + conn_set_ip(conn, sserver->own_host, + &sserver->own_ip4, &sserver->own_ip6); + } + + if (sserver->chatnet != NULL && conn->chatnet == NULL) + conn->chatnet = g_strdup(sserver->chatnet); + + if (sserver->password != NULL && conn->password == NULL) + conn->password = g_strdup(sserver->password); + + if (sserver->no_proxy) + g_free_and_null(conn->proxy); + + if (sserver->family != 0 && conn->family == 0) + conn->family = sserver->family; + if (sserver->address && !conn->address) + conn->address = g_strdup(sserver->address); + if (sserver->port > 0 && conn->port <= 0) + conn->port = sserver->port; + + conn->use_tls = sserver->use_tls; + if (conn->tls_cert == NULL && sserver->tls_cert != NULL && sserver->tls_cert[0] != '\0') + conn->tls_cert = g_strdup(sserver->tls_cert); + if (conn->tls_pkey == NULL && sserver->tls_pkey != NULL && sserver->tls_pkey[0] != '\0') + conn->tls_pkey = g_strdup(sserver->tls_pkey); + if (conn->tls_pass == NULL && sserver->tls_pass != NULL && sserver->tls_pass[0] != '\0') + conn->tls_pass = g_strdup(sserver->tls_pass); + conn->tls_verify = sserver->tls_verify; + if (conn->tls_cafile == NULL && sserver->tls_cafile != NULL && sserver->tls_cafile[0] != '\0') + conn->tls_cafile = g_strdup(sserver->tls_cafile); + if (conn->tls_capath == NULL && sserver->tls_capath != NULL && sserver->tls_capath[0] != '\0') + conn->tls_capath = g_strdup(sserver->tls_capath); + if (conn->tls_ciphers == NULL && sserver->tls_ciphers != NULL && sserver->tls_ciphers[0] != '\0') + conn->tls_ciphers = g_strdup(sserver->tls_ciphers); + if (conn->tls_pinned_cert == NULL && sserver->tls_pinned_cert != NULL && sserver->tls_pinned_cert[0] != '\0') + conn->tls_pinned_cert = g_strdup(sserver->tls_pinned_cert); + if (conn->tls_pinned_pubkey == NULL && sserver->tls_pinned_pubkey != NULL && sserver->tls_pinned_pubkey[0] != '\0') + conn->tls_pinned_pubkey = g_strdup(sserver->tls_pinned_pubkey); + + signal_emit("server setup fill reconn", 2, conn, sserver); +} + +static void server_setup_fill(SERVER_CONNECT_REC *conn, const char *address, int port, + GHashTable *optlist) +{ + g_return_if_fail(conn != NULL); + g_return_if_fail(address != NULL); + + conn->type = module_get_uniq_id("SERVER CONNECT", 0); + + conn->address = g_strdup(address); + if (port > 0) conn->port = port; + + if (strchr(address, '/') != NULL) + conn->unix_socket = TRUE; + + if (!conn->nick) conn->nick = g_strdup(settings_get_str("nick")); + conn->username = g_strdup(settings_get_str("user_name")); + conn->realname = g_strdup(settings_get_str("real_name")); + + /* proxy settings */ + if (settings_get_bool("use_proxy")) { + conn->proxy = g_strdup(settings_get_str("proxy_address")); + conn->proxy_port = settings_get_int("proxy_port"); + conn->proxy_string = g_strdup(settings_get_str("proxy_string")); + conn->proxy_string_after = g_strdup(settings_get_str("proxy_string_after")); + conn->proxy_password = g_strdup(settings_get_str("proxy_password")); + } + + /* source IP */ + if (source_host_ip4 != NULL) { + conn->own_ip4 = g_new(IPADDR, 1); + memcpy(conn->own_ip4, source_host_ip4, sizeof(IPADDR)); + } + if (source_host_ip6 != NULL) { + conn->own_ip6 = g_new(IPADDR, 1); + memcpy(conn->own_ip6, source_host_ip6, sizeof(IPADDR)); + } + + signal_emit("server setup fill connect", 2, conn, optlist); +} + +static void server_setup_fill_optlist(SERVER_CONNECT_REC *conn, GHashTable *optlist) +{ + char *tmp; + + if (g_hash_table_lookup(optlist, "6") != NULL) + conn->family = AF_INET6; + else if (g_hash_table_lookup(optlist, "4") != NULL) + conn->family = AF_INET; + + /* ad-hoc TLS settings from command optlist */ + if ((tmp = g_hash_table_lookup(optlist, "tls_cert")) != NULL || + (tmp = g_hash_table_lookup(optlist, "ssl_cert")) != NULL) { + conn->tls_cert = g_strdup(tmp); + conn->use_tls = TRUE; + } + if ((tmp = g_hash_table_lookup(optlist, "tls_pkey")) != NULL || + (tmp = g_hash_table_lookup(optlist, "ssl_pkey")) != NULL) + conn->tls_pkey = g_strdup(tmp); + if ((tmp = g_hash_table_lookup(optlist, "tls_pass")) != NULL || + (tmp = g_hash_table_lookup(optlist, "ssl_pass")) != NULL) + conn->tls_pass = g_strdup(tmp); + if ((tmp = g_hash_table_lookup(optlist, "tls_cafile")) != NULL || + (tmp = g_hash_table_lookup(optlist, "ssl_cafile")) != NULL) + conn->tls_cafile = g_strdup(tmp); + if ((tmp = g_hash_table_lookup(optlist, "tls_capath")) != NULL || + (tmp = g_hash_table_lookup(optlist, "ssl_capath")) != NULL) + conn->tls_capath = g_strdup(tmp); + if ((tmp = g_hash_table_lookup(optlist, "tls_ciphers")) != NULL || + (tmp = g_hash_table_lookup(optlist, "ssl_ciphers")) != NULL) + conn->tls_ciphers = g_strdup(tmp); + if ((tmp = g_hash_table_lookup(optlist, "tls_pinned_cert")) != NULL || + (tmp = g_hash_table_lookup(optlist, "ssl_pinned_cert")) != NULL) + conn->tls_pinned_cert = g_strdup(tmp); + if ((tmp = g_hash_table_lookup(optlist, "tls_pinned_pubkey")) != NULL || + (tmp = g_hash_table_lookup(optlist, "ssl_pinned_pubkey")) != NULL) + conn->tls_pinned_pubkey = g_strdup(tmp); + if ((conn->tls_capath != NULL && conn->tls_capath[0] != '\0') || + (conn->tls_cafile != NULL && conn->tls_cafile[0] != '\0')) + conn->tls_verify = TRUE; + if (g_hash_table_lookup(optlist, "notls_verify") != NULL) + conn->tls_verify = FALSE; + if (g_hash_table_lookup(optlist, "tls_verify") != NULL || + g_hash_table_lookup(optlist, "ssl_verify") != NULL) { + conn->tls_verify = TRUE; + conn->use_tls = TRUE; + } + if (g_hash_table_lookup(optlist, "notls") != NULL) + conn->use_tls = FALSE; + if (g_hash_table_lookup(optlist, "tls") != NULL || + g_hash_table_lookup(optlist, "ssl") != NULL) + conn->use_tls = TRUE; + + if (g_hash_table_lookup(optlist, "!") != NULL) + conn->no_autojoin_channels = TRUE; + + if (g_hash_table_lookup(optlist, "noautosendcmd") != NULL) + conn->no_autosendcmd = TRUE; + + if (g_hash_table_lookup(optlist, "noproxy") != NULL) + g_free_and_null(conn->proxy); + + signal_emit("server setup fill optlist", 2, conn, optlist); +} + +static void server_setup_fill_server(SERVER_CONNECT_REC *conn, + SERVER_SETUP_REC *sserver) +{ + g_return_if_fail(IS_SERVER_CONNECT(conn)); + g_return_if_fail(IS_SERVER_SETUP(sserver)); + + sserver->last_connect = time(NULL); + + server_setup_fill_reconn(conn, sserver); + + signal_emit("server setup fill server", 2, conn, sserver); +} + +static void server_setup_fill_chatnet(SERVER_CONNECT_REC *conn, + CHATNET_REC *chatnet) +{ + g_return_if_fail(IS_SERVER_CONNECT(conn)); + g_return_if_fail(IS_CHATNET(chatnet)); + + if (chatnet->nick != NULL) { + g_free(conn->nick); + conn->nick = g_strdup(chatnet->nick);; + } + if (chatnet->username != NULL) { + g_free(conn->username); + conn->username = g_strdup(chatnet->username);; + } + if (chatnet->realname != NULL) { + g_free(conn->realname); + conn->realname = g_strdup(chatnet->realname);; + } + if (chatnet->own_host != NULL) { + conn_set_ip(conn, chatnet->own_host, + &chatnet->own_ip4, &chatnet->own_ip6); + } + + signal_emit("server setup fill chatnet", 2, conn, chatnet); +} + +static SERVER_CONNECT_REC *create_addr_conn(int chat_type, const char *address, int port, + const char *chatnet, const char *password, + const char *nick, GHashTable *optlist) +{ + CHAT_PROTOCOL_REC *proto; + SERVER_CONNECT_REC *conn; + SERVER_SETUP_REC *sserver; + CHATNET_REC *chatnetrec; + + g_return_val_if_fail(address != NULL, NULL); + + sserver = server_setup_find(address, port, chatnet); + if (sserver != NULL) { + if (chat_type < 0) + chat_type = sserver->chat_type; + else if (chat_type != sserver->chat_type) + sserver = NULL; + } + + proto = chat_type >= 0 ? chat_protocol_find_id(chat_type) : + chat_protocol_get_default(); + + conn = proto->create_server_connect(); + server_connect_ref(conn); + + conn->chat_type = proto->id; + if (chatnet != NULL && *chatnet != '\0') + conn->chatnet = g_strdup(chatnet); + + /* fill in the defaults */ + server_setup_fill(conn, address, port, optlist); + + /* fill the rest from chat network settings */ + chatnetrec = chatnet != NULL ? chatnet_find(chatnet) : + (sserver == NULL || sserver->chatnet == NULL ? NULL : + chatnet_find(sserver->chatnet)); + if (chatnetrec != NULL) + server_setup_fill_chatnet(conn, chatnetrec); + + /* fill the information from setup */ + if (sserver != NULL) + server_setup_fill_server(conn, sserver); + + /* fill the optlist overrides */ + if (g_hash_table_size(optlist)) + server_setup_fill_optlist(conn, optlist); + + /* nick / password given in command line overrides all settings */ + if (password && *password) { + g_free_not_null(conn->password); + conn->password = g_strdup(password); + } + if (nick && *nick) { + g_free_not_null(conn->nick); + conn->nick = g_strdup(nick); + } + + return conn; +} + +/* 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 + haven't connected for the longest time */ +static SERVER_CONNECT_REC *create_chatnet_conn(const char *dest, int port, const char *password, + const char *nick, GHashTable *optlist) +{ + SERVER_SETUP_REC *bestrec; + GSList *tmp; + time_t now, besttime; + + now = time(NULL); + bestrec = NULL; besttime = now; + for (tmp = setupservers; tmp != NULL; tmp = tmp->next) { + SERVER_SETUP_REC *rec = tmp->data; + + if (rec->chatnet == NULL || + g_ascii_strcasecmp(rec->chatnet, dest) != 0) + continue; + + if (!rec->last_failed) { + bestrec = rec; + break; + } + + if (bestrec == NULL || besttime > rec->last_connect) { + bestrec = rec; + besttime = rec->last_connect; + } + } + + return bestrec == NULL ? NULL : + create_addr_conn(bestrec->chat_type, bestrec->address, 0, dest, + NULL, nick, optlist); +} + +/* Create server connection record. `dest' is required, rest can be NULL. + `dest' is either a server address or chat network */ +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) +{ + SERVER_CONNECT_REC *rec; + CHATNET_REC *chatrec; + + g_return_val_if_fail(dest != NULL, NULL); + + chatrec = chatnet_find(dest); + if (chatrec != NULL) { + rec = create_chatnet_conn(chatrec->name, port, password, nick, optlist); + /* If rec is NULL the chatnet has no url to connect to */ + return rec; + } + + chatrec = chatnet == NULL ? NULL : chatnet_find(chatnet); + if (chatrec != NULL) + chatnet = chatrec->name; + + return create_addr_conn(chat_type, dest, port, chatnet, password, nick, optlist); +} + +SERVER_CONNECT_REC *server_create_conn(int chat_type, const char *dest, int port, + const char *chatnet, const char *password, const char *nick) +{ + SERVER_CONNECT_REC *ret; + GHashTable *opt; + + opt = g_hash_table_new(NULL, NULL); + ret = server_create_conn_opt(chat_type, dest, port, chatnet, password, nick, opt); + g_hash_table_destroy(opt); + + return ret; +} + +/* Find matching server from setup. Try to find record with a same port, + but fallback to any server with the same address. */ +SERVER_SETUP_REC *server_setup_find(const char *address, int port, + const char *chatnet) +{ + SERVER_SETUP_REC *server; + GSList *tmp; + + g_return_val_if_fail(address != NULL, NULL); + + server = NULL; + for (tmp = setupservers; tmp != NULL; tmp = tmp->next) { + SERVER_SETUP_REC *rec = tmp->data; + + if (g_ascii_strcasecmp(rec->address, address) == 0 && + (chatnet == NULL || rec->chatnet == NULL || + g_ascii_strcasecmp(rec->chatnet, chatnet) == 0)) { + server = rec; + if (rec->port == port) + break; + } + } + + return server; +} + +static SERVER_SETUP_REC *server_setup_read(CONFIG_NODE *node) +{ + SERVER_SETUP_REC *rec; + CHATNET_REC *chatnetrec; + char *server, *chatnet, *family; + int port; + char *value = NULL; + + g_return_val_if_fail(node != NULL, NULL); + + server = config_node_get_str(node, "address", NULL); + if (server == NULL) + return NULL; + + port = config_node_get_int(node, "port", 0); + chatnet = config_node_get_str(node, "chatnet", NULL); + + if ((rec = server_setup_find(server, port, chatnet)) != NULL && rec->port == port) { + /* duplicate server setup */ + server_setup_remove(rec); + } + + rec = NULL; + + chatnetrec = chatnet == NULL ? NULL : chatnet_find(chatnet); + if (chatnetrec == NULL && chatnet != NULL) { + /* chat network not found, create it. */ + chatnetrec = chat_protocol_get_default()->create_chatnet(); + chatnetrec->chat_type = chat_protocol_get_default()->id; + chatnetrec->name = g_strdup(chatnet); + chatnet_create(chatnetrec); + } + + family = config_node_get_str(node, "family", ""); + + rec = CHAT_PROTOCOL(chatnetrec)->create_server_setup(); + rec->type = module_get_uniq_id("SERVER SETUP", 0); + rec->chat_type = CHAT_PROTOCOL(chatnetrec)->id; + rec->chatnet = chatnetrec == NULL ? NULL : g_strdup(chatnetrec->name); + rec->family = g_ascii_strcasecmp(family, "inet6") == 0 ? AF_INET6 : + (g_ascii_strcasecmp(family, "inet") == 0 ? AF_INET : 0); + rec->address = g_strdup(server); + rec->password = g_strdup(config_node_get_str(node, "password", NULL)); + + rec->use_tls = config_node_get_bool(node, "use_tls", FALSE) || config_node_get_bool(node, "use_ssl", FALSE); + rec->tls_verify = config_node_find(node, "tls_verify") != NULL ? + config_node_get_bool(node, "tls_verify", TRUE) : + config_node_get_bool(node, "ssl_verify", TRUE); + + value = config_node_get_str(node, "tls_cert", NULL); + if (value == NULL) + value = config_node_get_str(node, "ssl_cert", NULL); + rec->tls_cert = g_strdup(value); + + value = config_node_get_str(node, "tls_pkey", NULL); + if (value == NULL) + value = config_node_get_str(node, "ssl_pkey", NULL); + rec->tls_pkey = g_strdup(value); + + value = config_node_get_str(node, "tls_pass", NULL); + if (value == NULL) + value = config_node_get_str(node, "ssl_pass", NULL); + rec->tls_pass = g_strdup(value); + + value = config_node_get_str(node, "tls_cafile", NULL); + if (value == NULL) + value = config_node_get_str(node, "ssl_cafile", NULL); + rec->tls_cafile = g_strdup(value); + + value = config_node_get_str(node, "tls_capath", NULL); + if (value == NULL) + value = config_node_get_str(node, "ssl_capath", NULL); + rec->tls_capath = g_strdup(value); + + value = config_node_get_str(node, "tls_ciphers", NULL); + if (value == NULL) + value = config_node_get_str(node, "ssl_ciphers", NULL); + rec->tls_ciphers = g_strdup(value); + + value = config_node_get_str(node, "tls_pinned_cert", NULL); + if (value == NULL) + value = config_node_get_str(node, "ssl_pinned_cert", NULL); + rec->tls_pinned_cert = g_strdup(value); + + value = config_node_get_str(node, "tls_pinned_pubkey", NULL); + if (value == NULL) + value = config_node_get_str(node, "ssl_pinned_pubkey", NULL); + rec->tls_pinned_pubkey = g_strdup(value); + + rec->port = port; + rec->autoconnect = config_node_get_bool(node, "autoconnect", FALSE); + rec->no_proxy = config_node_get_bool(node, "no_proxy", FALSE); + rec->own_host = g_strdup(config_node_get_str(node, "own_host", NULL)); + + signal_emit("server setup read", 2, rec, node); + + setupservers = g_slist_append(setupservers, rec); + return rec; +} + +static int compare_server_setup (CONFIG_NODE *node, SERVER_SETUP_REC *server) +{ + char *address, *chatnet; + int port; + + /* skip comment nodes */ + if (node->type == NODE_TYPE_COMMENT) + return -1; + + address = config_node_get_str(node, "address", NULL); + chatnet = config_node_get_str(node, "chatnet", ""); + port = config_node_get_int(node, "port", 0); + + if (address == NULL || chatnet == NULL) { + return 0; + } + + if (g_ascii_strcasecmp(address, server->address) != 0 || + g_ascii_strcasecmp(chatnet, server->chatnet != NULL ? server->chatnet : "") != 0 || + port != server->port) { + return 1; + } + + return 0; +} + +static void server_setup_save(SERVER_SETUP_REC *rec, int old_port, const char *old_chatnet) +{ + CONFIG_NODE *parent_node, *node; + SERVER_SETUP_REC search_rec = { 0 }; + GSList *config_node; + + parent_node = iconfig_node_traverse("(servers", TRUE); + + /* Try to find this channel in the configuration */ + search_rec.address = rec->address; + search_rec.chatnet = old_chatnet != NULL ? (char *) old_chatnet : rec->chatnet; + search_rec.port = old_port; + config_node = g_slist_find_custom(parent_node->value, &search_rec, + (GCompareFunc) compare_server_setup); + if (config_node != NULL) + /* Let's update this server record */ + node = config_node->data; + else + /* Create a brand-new server record */ + node = iconfig_node_section(parent_node, NULL, NODE_TYPE_BLOCK); + + iconfig_node_clear(node); + iconfig_node_set_str(node, "address", rec->address); + iconfig_node_set_str(node, "chatnet", rec->chatnet); + + iconfig_node_set_int(node, "port", rec->port); + iconfig_node_set_str(node, "password", rec->password); + + iconfig_node_set_bool(node, "use_tls", rec->use_tls); + iconfig_node_set_str(node, "tls_cert", rec->tls_cert); + iconfig_node_set_str(node, "tls_pkey", rec->tls_pkey); + iconfig_node_set_str(node, "tls_pass", rec->tls_pass); + iconfig_node_set_bool(node, "tls_verify", rec->tls_verify); + iconfig_node_set_str(node, "tls_cafile", rec->tls_cafile); + iconfig_node_set_str(node, "tls_capath", rec->tls_capath); + iconfig_node_set_str(node, "tls_ciphers", rec->tls_ciphers); + iconfig_node_set_str(node, "tls_pinned_cert", rec->tls_pinned_cert); + iconfig_node_set_str(node, "tls_pinned_pubkey", rec->tls_pinned_pubkey); + + iconfig_node_set_str(node, "own_host", rec->own_host); + + iconfig_node_set_str(node, "family", + rec->family == AF_INET6 ? "inet6" : + rec->family == AF_INET ? "inet" : NULL); + + if (rec->autoconnect) + iconfig_node_set_bool(node, "autoconnect", TRUE); + if (rec->no_proxy) + iconfig_node_set_bool(node, "no_proxy", TRUE); + + signal_emit("server setup saved", 2, rec, node); +} + +static void server_setup_remove_config(SERVER_SETUP_REC *rec) +{ + CONFIG_NODE *parent_node; + GSList *config_node; + + parent_node = iconfig_node_traverse("servers", FALSE); + + if (parent_node == NULL) + return; + + /* Try to find this server in the configuration */ + config_node = g_slist_find_custom(parent_node->value, rec, + (GCompareFunc)compare_server_setup); + + if (config_node != NULL) + /* Delete the server from the configuration */ + iconfig_node_remove(parent_node, config_node->data); +} + +static void server_setup_destroy(SERVER_SETUP_REC *rec) +{ + setupservers = g_slist_remove(setupservers, rec); + signal_emit("server setup destroyed", 1, rec); + + g_free_not_null(rec->own_host); + g_free_not_null(rec->own_ip4); + g_free_not_null(rec->own_ip6); + g_free_not_null(rec->chatnet); + g_free_not_null(rec->password); + g_free_not_null(rec->tls_cert); + g_free_not_null(rec->tls_pkey); + g_free_not_null(rec->tls_pass); + g_free_not_null(rec->tls_cafile); + g_free_not_null(rec->tls_capath); + g_free_not_null(rec->tls_ciphers); + g_free_not_null(rec->tls_pinned_cert); + g_free_not_null(rec->tls_pinned_pubkey); + g_free(rec->address); + g_free(rec); +} + +void server_setup_modify(SERVER_SETUP_REC *rec, int old_port, const char *old_chatnet) +{ + g_return_if_fail(g_slist_find(setupservers, rec) != NULL); + + rec->type = module_get_uniq_id("SERVER SETUP", 0); + server_setup_save(rec, old_port, old_chatnet); + + signal_emit("server setup updated", 1, rec); +} + +void server_setup_add(SERVER_SETUP_REC *rec) +{ + if (g_slist_find(setupservers, rec) == NULL) + setupservers = g_slist_append(setupservers, rec); + server_setup_modify(rec, -1, NULL); +} + +void server_setup_remove_chatnet(const char *chatnet) +{ + GSList *tmp, *next; + + g_return_if_fail(chatnet != NULL); + + for (tmp = setupservers; tmp != NULL; tmp = next) { + SERVER_SETUP_REC *rec = tmp->data; + + next = tmp->next; + if (g_ascii_strcasecmp(rec->chatnet, chatnet) == 0) + server_setup_remove(rec); + } +} + +void server_setup_remove(SERVER_SETUP_REC *rec) +{ + server_setup_remove_config(rec); + server_setup_destroy(rec); +} + +static void read_servers(void) +{ + CONFIG_NODE *node; + GSList *tmp; + + while (setupservers != NULL) + server_setup_destroy(setupservers->data); + + /* Read servers */ + node = iconfig_node_traverse("servers", FALSE); + if (node != NULL) { + int i = 0; + tmp = config_node_first(node->value); + for (; tmp != NULL; tmp = config_node_next(tmp), i++) { + node = tmp->data; + if (node->type != NODE_TYPE_BLOCK) { + g_critical("Expected block node at `servers[%d]' was of %s type. " + "Corrupt config?", + i, node->type == NODE_TYPE_LIST ? "list" : "scalar"); + } else { + server_setup_read(node); + } + } + } +} + +static void read_settings(void) +{ + if (old_source_host == NULL || + g_strcmp0(old_source_host, settings_get_str("hostname")) != 0) { + g_free_not_null(old_source_host); + old_source_host = g_strdup(settings_get_str("hostname")); + + source_host_ok = FALSE; + get_source_host_ip(); + } +} + +void servers_setup_init(void) +{ + settings_add_str("server", "hostname", ""); + + settings_add_str("server", "nick", NULL); + settings_add_str("server", "user_name", NULL); + settings_add_str("server", "real_name", NULL); + + settings_add_bool("proxy", "use_proxy", FALSE); + settings_add_str("proxy", "proxy_address", ""); + settings_add_int("proxy", "proxy_port", 6667); + settings_add_str("proxy", "proxy_string", "CONNECT %s %d"); + settings_add_str("proxy", "proxy_string_after", ""); + settings_add_str("proxy", "proxy_password", ""); + + setupservers = NULL; + source_host_ip4 = source_host_ip6 = NULL; + old_source_host = NULL; + read_settings(); + + signal_add("setup changed", (SIGNAL_FUNC) read_settings); + signal_add("setup reread", (SIGNAL_FUNC) read_servers); + signal_add("irssi init read settings", (SIGNAL_FUNC) read_servers); +} + +void servers_setup_deinit(void) +{ + g_free_not_null(source_host_ip4); + g_free_not_null(source_host_ip6); + g_free_not_null(old_source_host); + + while (setupservers != NULL) + server_setup_destroy(setupservers->data); + + signal_remove("setup changed", (SIGNAL_FUNC) read_settings); + signal_remove("setup reread", (SIGNAL_FUNC) read_servers); + signal_remove("irssi init read settings", (SIGNAL_FUNC) read_servers); + + module_uniq_destroy("SERVER SETUP"); +} |