summaryrefslogtreecommitdiff
path: root/src/core/servers-setup.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/servers-setup.c')
-rw-r--r--src/core/servers-setup.c456
1 files changed, 456 insertions, 0 deletions
diff --git a/src/core/servers-setup.c b/src/core/servers-setup.c
new file mode 100644
index 00000000..b314ca95
--- /dev/null
+++ b/src/core/servers-setup.c
@@ -0,0 +1,456 @@
+/*
+ servers-setup.c : irssi
+
+ Copyright (C) 1999-2000 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "module.h"
+#include "signals.h"
+#include "network.h"
+#include "lib-config/iconfig.h"
+#include "settings.h"
+
+#include "servers.h"
+#include "servers-setup.h"
+#include "chatnets.h"
+
+GSList *setupservers;
+
+int source_host_ok; /* Use source_host_ip .. */
+IPADDR *source_host_ip; /* Resolved address */
+
+static void get_source_host_ip(void)
+{
+ IPADDR ip;
+
+ if (source_host_ok)
+ return;
+
+ /* FIXME: This will block! */
+ source_host_ok = *settings_get_str("hostname") != '\0' &&
+ net_gethostbyname(settings_get_str("hostname"), &ip) == 0;
+ if (source_host_ok) {
+ if (source_host_ip == NULL)
+ source_host_ip = g_new(IPADDR, 1);
+ memcpy(source_host_ip, &ip, sizeof(IPADDR));
+ }
+}
+
+static void conn_set_ip(SERVER_CONNECT_REC *conn,
+ IPADDR **own_ip, const char *own_host)
+{
+ IPADDR ip;
+
+ if (*own_ip != NULL) {
+ /* use already resolved IP */
+ if (conn->own_ip == NULL)
+ conn->own_ip = g_new(IPADDR, 1);
+ memcpy(conn->own_ip, *own_ip, sizeof(IPADDR));
+ return;
+ }
+
+
+ /* resolve the IP and use it */
+ if (net_gethostbyname(own_host, &ip) == 0) {
+ if (conn->own_ip == NULL)
+ conn->own_ip = g_new(IPADDR, 1);
+ memcpy(conn->own_ip, &ip, sizeof(IPADDR));
+
+ *own_ip = g_new(IPADDR, 1);
+ memcpy(*own_ip, &ip, sizeof(IPADDR));
+ }
+}
+
+/* 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_ip, sserver->own_host);
+
+ 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);
+
+ signal_emit("server setup fill reconn", 2, conn, sserver);
+}
+
+static void server_setup_fill(SERVER_CONNECT_REC *conn,
+ const char *address, int port)
+{
+ 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);
+ conn->port = port > 0 ? port : 6667;
+
+ if (!conn->nick) conn->nick = g_strdup(settings_get_str("default_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"));
+ }
+
+ /* source IP */
+ get_source_host_ip();
+ if (source_host_ok) {
+ conn->own_ip = g_new(IPADDR, 1);
+ memcpy(conn->own_ip, source_host_ip, sizeof(IPADDR));
+ }
+}
+
+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);
+
+ if (sserver->port > 0) conn->port = sserver->port;
+ 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) {
+ g_free(conn->nick);
+ conn->nick = g_strdup(chatnet->nick);;
+ }
+ if (chatnet->username) {
+ g_free(conn->username);
+ conn->username = g_strdup(chatnet->username);;
+ }
+ if (chatnet->realname) {
+ g_free(conn->realname);
+ conn->realname = g_strdup(chatnet->realname);;
+ }
+ if (chatnet->own_host != NULL)
+ conn_set_ip(conn, &chatnet->own_ip, chatnet->own_host);
+
+ signal_emit("server setup fill chatnet", 2, conn, chatnet);
+}
+
+static SERVER_CONNECT_REC *
+create_addr_conn(const char *address, int port,
+ const char *password, const char *nick)
+{
+ SERVER_CONNECT_REC *conn;
+ SERVER_SETUP_REC *sserver;
+ CHATNET_REC *chatnet;
+
+ g_return_val_if_fail(address != NULL, NULL);
+
+ sserver = server_setup_find(address, port);
+ chatnet = sserver->chatnet == NULL ? NULL :
+ chatnet_find(sserver->chatnet);
+ conn = NULL;
+ signal_emit("server setup connect", 2, &conn, chatnet);
+ if (conn == NULL) {
+ /* no chat protocol wanted this server? */
+ return NULL;
+ }
+
+ /* fill in the defaults */
+ server_setup_fill(conn, address, port);
+
+ /* fill the rest from chat network settings */
+ if (chatnet != NULL)
+ server_setup_fill_chatnet(conn, chatnet);
+
+ /* fill the information from setup */
+ if (sserver != NULL)
+ server_setup_fill_server(conn, sserver);
+
+ /* 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)
+{
+ 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_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->address, 0, NULL, nick);
+}
+
+/* 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(const char *dest, int port,
+ const char *password, const char *nick)
+{
+ SERVER_CONNECT_REC *rec;
+
+ g_return_val_if_fail(dest != NULL, NULL);
+
+ if (chatnet_find(dest)) {
+ rec = create_chatnet_conn(dest, port, password, nick);
+ if (rec != NULL)
+ return rec;
+ }
+
+ return create_addr_conn(dest, port, password, nick);
+}
+
+/* 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)
+{
+ 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_strcasecmp(rec->address, address) == 0) {
+ server = rec;
+ if (rec->port == port)
+ break;
+ }
+ }
+
+ return server;
+}
+
+/* Find matching server from setup. Ports must match or NULL is returned. */
+SERVER_SETUP_REC *server_setup_find_port(const char *address, int port)
+{
+ SERVER_SETUP_REC *rec;
+
+ rec = server_setup_find(address, port);
+ return rec == NULL || rec->port != port ? NULL : rec;
+}
+
+static SERVER_SETUP_REC *server_setup_read(CONFIG_NODE *node)
+{
+ SERVER_SETUP_REC *rec;
+ char *server, *chatnet;
+ int port;
+
+ 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", 6667);
+ if (server_setup_find_port(server, port) != NULL) {
+ /* already exists - don't let it get there twice or
+ server reconnects will screw up! */
+ return NULL;
+ }
+
+ rec = NULL;
+ chatnet = config_node_get_str(node, "chatnet", NULL);
+ signal_emit("server setup read", 3, &rec, node,
+ chatnet == NULL ? NULL : chatnet_find(chatnet));
+ if (rec == NULL) {
+ /* no chat protocol wanted this server? */
+ return NULL;
+ }
+
+ rec->type = module_get_uniq_id("SERVER SETUP", 0);
+ rec->chatnet = g_strdup(chatnet);
+ rec->address = g_strdup(server);
+ rec->password = g_strdup(config_node_get_str(node, "password", NULL));
+ rec->port = port;
+ rec->autoconnect = config_node_get_bool(node, "autoconnect", FALSE);
+ rec->own_host = g_strdup(config_node_get_str(node, "own_host", 0));
+
+ setupservers = g_slist_append(setupservers, rec);
+ return rec;
+}
+
+static void server_setup_save(SERVER_SETUP_REC *rec)
+{
+ CONFIG_NODE *parentnode, *node;
+ int index;
+
+ index = g_slist_index(setupservers, rec);
+
+ parentnode = iconfig_node_traverse("(servers", TRUE);
+ node = config_node_index(parentnode, index);
+ if (node == NULL)
+ node = config_node_section(parentnode, NULL, NODE_TYPE_BLOCK);
+
+ iconfig_node_clear(node);
+ iconfig_node_set_str(node, "address", rec->address);
+ iconfig_node_set_str(node, "chatnet", rec->chatnet);
+
+ config_node_set_int(node, "port", rec->port);
+ iconfig_node_set_str(node, "password", rec->password);
+ iconfig_node_set_str(node, "own_host", rec->own_host);
+
+ if (rec->autoconnect)
+ config_node_set_bool(node, "autoconnect", TRUE);
+
+ signal_emit("server setup saved", 2, rec, node);
+}
+
+static void server_setup_remove_config(SERVER_SETUP_REC *rec)
+{
+ CONFIG_NODE *node;
+ int index;
+
+ node = iconfig_node_traverse("servers", FALSE);
+ if (node != NULL) {
+ index = g_slist_index(setupservers, rec);
+ iconfig_node_list_remove(node, index);
+ }
+}
+
+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_ip);
+ g_free_not_null(rec->chatnet);
+ g_free(rec->address);
+ g_free_not_null(rec->password);
+ g_free(rec);
+}
+
+void server_setup_add(SERVER_SETUP_REC *rec)
+{
+ if (g_slist_find(setupservers, rec) == NULL)
+ setupservers = g_slist_append(setupservers, rec);
+ server_setup_save(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) {
+ for (tmp = node->value; tmp != NULL; tmp = tmp->next)
+ server_setup_read(tmp->data);
+ }
+}
+
+static void read_settings(void)
+{
+ g_free_and_null(source_host_ip);
+
+ source_host_ok = FALSE;
+ get_source_host_ip();
+}
+
+void servers_setup_init(void)
+{
+ settings_add_str("server", "hostname", "");
+
+ settings_add_str("server", "default_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");
+
+ source_host_ip = 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_ip);
+
+ 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");
+}