2 servers-setup.c : irssi
4 Copyright (C) 1999-2001 Timo Sirainen
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 #include "lib-config/iconfig.h"
27 #include "chat-protocols.h"
30 #include "servers-setup.h"
34 static char *old_source_host;
35 int source_host_ok; /* Use source_host_ip .. */
36 IPADDR *source_host_ip4, *source_host_ip6; /* Resolved address */
38 static void save_ips(IPADDR *ip4, IPADDR *ip6,
39 IPADDR **save_ip4, IPADDR **save_ip6)
42 g_free_and_null(*save_ip4);
44 if (*save_ip4 == NULL)
45 *save_ip4 = g_new(IPADDR, 1);
46 memcpy(*save_ip4, ip4, sizeof(IPADDR));
50 g_free_and_null(*save_ip6);
52 if (*save_ip6 == NULL)
53 *save_ip6 = g_new(IPADDR, 1);
54 memcpy(*save_ip6, ip6, sizeof(IPADDR));
58 static void get_source_host_ip(void)
66 /* FIXME: This will block! */
67 hostname = settings_get_str("hostname");
68 source_host_ok = *hostname != '\0' &&
69 net_gethostbyname(hostname, &ip4, &ip6) == 0;
72 save_ips(&ip4, &ip6, &source_host_ip4, &source_host_ip6);
74 g_free_and_null(source_host_ip4);
75 g_free_and_null(source_host_ip6);
79 static void conn_set_ip(SERVER_CONNECT_REC *conn, const char *own_host,
80 IPADDR **own_ip4, IPADDR **own_ip6)
84 if (*own_ip4 == NULL && *own_ip6 == NULL) {
86 if (net_gethostbyname(own_host, &ip4, &ip6) == 0)
87 save_ips(&ip4, &ip6, own_ip4, own_ip6);
90 server_connect_own_ip_save(conn, *own_ip4, *own_ip6);
93 /* Fill information to connection from server setup record */
94 void server_setup_fill_reconn(SERVER_CONNECT_REC *conn,
95 SERVER_SETUP_REC *sserver)
97 g_return_if_fail(IS_SERVER_CONNECT(conn));
98 g_return_if_fail(IS_SERVER_SETUP(sserver));
100 if (sserver->own_host != NULL) {
101 conn_set_ip(conn, sserver->own_host,
102 &sserver->own_ip4, &sserver->own_ip6);
105 if (sserver->chatnet != NULL && conn->chatnet == NULL)
106 conn->chatnet = g_strdup(sserver->chatnet);
108 if (sserver->password != NULL && conn->password == NULL)
109 conn->password = g_strdup(sserver->password);
111 signal_emit("server setup fill reconn", 2, conn, sserver);
114 static void server_setup_fill(SERVER_CONNECT_REC *conn,
115 const char *address, int port)
117 g_return_if_fail(conn != NULL);
118 g_return_if_fail(address != NULL);
120 conn->type = module_get_uniq_id("SERVER CONNECT", 0);
122 conn->address = g_strdup(address);
123 if (port > 0) conn->port = port;
125 if (!conn->nick) conn->nick = g_strdup(settings_get_str("nick"));
126 conn->username = g_strdup(settings_get_str("user_name"));
127 conn->realname = g_strdup(settings_get_str("real_name"));
130 if (settings_get_bool("use_proxy")) {
131 conn->proxy = g_strdup(settings_get_str("proxy_address"));
132 conn->proxy_port = settings_get_int("proxy_port");
133 conn->proxy_string = g_strdup(settings_get_str("proxy_string"));
134 conn->proxy_string_after = g_strdup(settings_get_str("proxy_string_after"));
135 conn->proxy_password = g_strdup(settings_get_str("proxy_password"));
139 if (source_host_ip4 != NULL) {
140 conn->own_ip4 = g_new(IPADDR, 1);
141 memcpy(conn->own_ip4, source_host_ip4, sizeof(IPADDR));
143 if (source_host_ip6 != NULL) {
144 conn->own_ip6 = g_new(IPADDR, 1);
145 memcpy(conn->own_ip6, source_host_ip6, sizeof(IPADDR));
148 signal_emit("server setup fill connect", 1, conn);
151 static void server_setup_fill_server(SERVER_CONNECT_REC *conn,
152 SERVER_SETUP_REC *sserver)
154 g_return_if_fail(IS_SERVER_CONNECT(conn));
155 g_return_if_fail(IS_SERVER_SETUP(sserver));
157 sserver->last_connect = time(NULL);
159 if (sserver->no_proxy)
160 g_free_and_null(conn->proxy);
162 if (sserver->family != 0 && conn->family == 0)
163 conn->family = sserver->family;
164 if (sserver->port > 0 && conn->port <= 0)
165 conn->port = sserver->port;
167 conn->use_ssl = sserver->use_ssl;
168 if (conn->ssl_cert == NULL && sserver->ssl_cert != NULL && sserver->ssl_cert[0] != '\0')
169 conn->ssl_cert = g_strdup(sserver->ssl_cert);
170 if (conn->ssl_pkey == NULL && sserver->ssl_pkey != NULL && sserver->ssl_pkey[0] != '\0')
171 conn->ssl_pkey = g_strdup(sserver->ssl_pkey);
172 conn->ssl_verify = sserver->ssl_verify;
173 if (conn->ssl_cafile == NULL && sserver->ssl_cafile != NULL && sserver->ssl_cafile[0] != '\0')
174 conn->ssl_cafile = g_strdup(sserver->ssl_cafile);
175 if (conn->ssl_capath == NULL && sserver->ssl_capath != NULL && sserver->ssl_capath[0] != '\0')
176 conn->ssl_capath = g_strdup(sserver->ssl_capath);
178 server_setup_fill_reconn(conn, sserver);
180 signal_emit("server setup fill server", 2, conn, sserver);
183 static void server_setup_fill_chatnet(SERVER_CONNECT_REC *conn,
184 CHATNET_REC *chatnet)
186 g_return_if_fail(IS_SERVER_CONNECT(conn));
187 g_return_if_fail(IS_CHATNET(chatnet));
189 if (chatnet->nick != NULL) {
191 conn->nick = g_strdup(chatnet->nick);;
193 if (chatnet->username != NULL) {
194 g_free(conn->username);
195 conn->username = g_strdup(chatnet->username);;
197 if (chatnet->realname != NULL) {
198 g_free(conn->realname);
199 conn->realname = g_strdup(chatnet->realname);;
201 if (chatnet->own_host != NULL) {
202 conn_set_ip(conn, chatnet->own_host,
203 &chatnet->own_ip4, &chatnet->own_ip6);
206 signal_emit("server setup fill chatnet", 2, conn, chatnet);
209 static SERVER_CONNECT_REC *
210 create_addr_conn(int chat_type, const char *address, int port,
211 const char *chatnet, const char *password,
214 CHAT_PROTOCOL_REC *proto;
215 SERVER_CONNECT_REC *conn;
216 SERVER_SETUP_REC *sserver;
217 CHATNET_REC *chatnetrec;
219 g_return_val_if_fail(address != NULL, NULL);
221 sserver = server_setup_find(address, port, chatnet);
222 if (sserver != NULL) {
224 chat_type = sserver->chat_type;
225 else if (chat_type != sserver->chat_type)
229 proto = chat_type >= 0 ? chat_protocol_find_id(chat_type) :
230 chat_protocol_get_default();
232 conn = proto->create_server_connect();
233 server_connect_ref(conn);
235 conn->chat_type = proto->id;
236 if (chatnet != NULL && *chatnet != '\0')
237 conn->chatnet = g_strdup(chatnet);
239 /* fill in the defaults */
240 server_setup_fill(conn, address, port);
242 /* fill the rest from chat network settings */
243 chatnetrec = chatnet != NULL ? chatnet_find(chatnet) :
244 (sserver == NULL || sserver->chatnet == NULL ? NULL :
245 chatnet_find(sserver->chatnet));
246 if (chatnetrec != NULL)
247 server_setup_fill_chatnet(conn, chatnetrec);
249 /* fill the information from setup */
251 server_setup_fill_server(conn, sserver);
253 /* nick / password given in command line overrides all settings */
254 if (password && *password) {
255 g_free_not_null(conn->password);
256 conn->password = g_strdup(password);
259 g_free_not_null(conn->nick);
260 conn->nick = g_strdup(nick);
266 /* Connect to server where last connect succeeded (or we haven't tried to
267 connect yet). If there's no such server, connect to server where we
268 haven't connected for the longest time */
269 static SERVER_CONNECT_REC *
270 create_chatnet_conn(const char *dest, int port,
271 const char *password, const char *nick)
273 SERVER_SETUP_REC *bestrec;
275 time_t now, besttime;
278 bestrec = NULL; besttime = now;
279 for (tmp = setupservers; tmp != NULL; tmp = tmp->next) {
280 SERVER_SETUP_REC *rec = tmp->data;
282 if (rec->chatnet == NULL ||
283 g_strcasecmp(rec->chatnet, dest) != 0)
286 if (!rec->last_failed) {
291 if (bestrec == NULL || besttime > rec->last_connect) {
293 besttime = rec->last_connect;
297 return bestrec == NULL ? NULL :
298 create_addr_conn(bestrec->chat_type, bestrec->address, 0,
302 /* Create server connection record. `dest' is required, rest can be NULL.
303 `dest' is either a server address or chat network */
305 server_create_conn(int chat_type, const char *dest, int port,
306 const char *chatnet, const char *password,
309 SERVER_CONNECT_REC *rec;
310 CHATNET_REC *chatrec;
312 g_return_val_if_fail(dest != NULL, NULL);
314 chatrec = chatnet_find(dest);
315 if (chatrec != NULL) {
316 rec = create_chatnet_conn(chatrec->name, port, password, nick);
321 chatrec = chatnet == NULL ? NULL : chatnet_find(chatnet);
323 chatnet = chatrec->name;
325 return create_addr_conn(chat_type, dest, port,
326 chatnet, password, nick);
329 /* Find matching server from setup. Try to find record with a same port,
330 but fallback to any server with the same address. */
331 SERVER_SETUP_REC *server_setup_find(const char *address, int port,
334 SERVER_SETUP_REC *server;
337 g_return_val_if_fail(address != NULL, NULL);
340 for (tmp = setupservers; tmp != NULL; tmp = tmp->next) {
341 SERVER_SETUP_REC *rec = tmp->data;
343 if (g_strcasecmp(rec->address, address) == 0 &&
344 (chatnet == NULL || rec->chatnet == NULL ||
345 g_strcasecmp(rec->chatnet, chatnet) == 0)) {
347 if (rec->port == port)
355 static SERVER_SETUP_REC *server_setup_read(CONFIG_NODE *node)
357 SERVER_SETUP_REC *rec;
358 CHATNET_REC *chatnetrec;
359 char *server, *chatnet, *family;
362 g_return_val_if_fail(node != NULL, NULL);
364 server = config_node_get_str(node, "address", NULL);
368 port = config_node_get_int(node, "port", 0);
369 chatnet = config_node_get_str(node, "chatnet", NULL);
371 if (server_setup_find(server, port, chatnet) != NULL) {
377 chatnetrec = chatnet == NULL ? NULL : chatnet_find(chatnet);
378 if (chatnetrec == NULL && chatnet != NULL) {
379 /* chat network not found, create it. */
380 chatnetrec = chat_protocol_get_default()->create_chatnet();
381 chatnetrec->chat_type = chat_protocol_get_default()->id;
382 chatnetrec->name = g_strdup(chatnet);
383 chatnet_create(chatnetrec);
386 family = config_node_get_str(node, "family", "");
388 rec = CHAT_PROTOCOL(chatnetrec)->create_server_setup();
389 rec->type = module_get_uniq_id("SERVER SETUP", 0);
390 rec->chat_type = CHAT_PROTOCOL(chatnetrec)->id;
391 rec->chatnet = chatnetrec == NULL ? NULL : g_strdup(chatnetrec->name);
392 rec->family = g_ascii_strcasecmp(family, "inet6") == 0 ? AF_INET6 :
393 (g_ascii_strcasecmp(family, "inet") == 0 ? AF_INET : 0);
394 rec->address = g_strdup(server);
395 rec->password = g_strdup(config_node_get_str(node, "password", NULL));
396 rec->use_ssl = config_node_get_bool(node, "use_ssl", FALSE);
397 rec->ssl_cert = g_strdup(config_node_get_str(node, "ssl_cert", NULL));
398 rec->ssl_pkey = g_strdup(config_node_get_str(node, "ssl_pkey", NULL));
399 rec->ssl_verify = config_node_get_bool(node, "ssl_verify", FALSE);
400 rec->ssl_cafile = g_strdup(config_node_get_str(node, "ssl_cafile", NULL));
401 rec->ssl_capath = g_strdup(config_node_get_str(node, "ssl_capath", NULL));
402 if (rec->ssl_cafile || rec->ssl_capath)
403 rec->ssl_verify = TRUE;
404 if (rec->ssl_cert != NULL || rec->ssl_verify)
407 rec->autoconnect = config_node_get_bool(node, "autoconnect", FALSE);
408 rec->no_proxy = config_node_get_bool(node, "no_proxy", FALSE);
409 rec->own_host = g_strdup(config_node_get_str(node, "own_host", NULL));
411 signal_emit("server setup read", 2, rec, node);
413 setupservers = g_slist_append(setupservers, rec);
417 static void server_setup_save(SERVER_SETUP_REC *rec)
419 CONFIG_NODE *parentnode, *node;
422 index = g_slist_index(setupservers, rec);
424 parentnode = iconfig_node_traverse("(servers", TRUE);
425 node = config_node_nth(parentnode, index);
427 node = config_node_section(parentnode, NULL, NODE_TYPE_BLOCK);
429 iconfig_node_clear(node);
430 iconfig_node_set_str(node, "address", rec->address);
431 iconfig_node_set_str(node, "chatnet", rec->chatnet);
433 iconfig_node_set_int(node, "port", rec->port);
434 iconfig_node_set_str(node, "password", rec->password);
435 iconfig_node_set_bool(node, "use_ssl", rec->use_ssl);
436 iconfig_node_set_str(node, "ssl_cert", rec->ssl_cert);
437 iconfig_node_set_str(node, "ssl_pkey", rec->ssl_pkey);
438 iconfig_node_set_bool(node, "ssl_verify", rec->ssl_verify);
439 iconfig_node_set_str(node, "ssl_cafile", rec->ssl_cafile);
440 iconfig_node_set_str(node, "ssl_capath", rec->ssl_capath);
441 iconfig_node_set_str(node, "own_host", rec->own_host);
443 iconfig_node_set_str(node, "family",
444 rec->family == AF_INET6 ? "inet6" :
445 rec->family == AF_INET ? "inet" : NULL);
447 if (rec->autoconnect)
448 iconfig_node_set_bool(node, "autoconnect", TRUE);
450 iconfig_node_set_bool(node, "no_proxy", TRUE);
452 signal_emit("server setup saved", 2, rec, node);
455 static void server_setup_remove_config(SERVER_SETUP_REC *rec)
460 node = iconfig_node_traverse("servers", FALSE);
462 index = g_slist_index(setupservers, rec);
463 iconfig_node_list_remove(node, index);
467 static void server_setup_destroy(SERVER_SETUP_REC *rec)
469 setupservers = g_slist_remove(setupservers, rec);
470 signal_emit("server setup destroyed", 1, rec);
472 g_free_not_null(rec->own_host);
473 g_free_not_null(rec->own_ip4);
474 g_free_not_null(rec->own_ip6);
475 g_free_not_null(rec->chatnet);
476 g_free_not_null(rec->password);
477 g_free_not_null(rec->ssl_cert);
478 g_free_not_null(rec->ssl_pkey);
479 g_free_not_null(rec->ssl_cafile);
480 g_free_not_null(rec->ssl_capath);
481 g_free(rec->address);
485 void server_setup_add(SERVER_SETUP_REC *rec)
487 rec->type = module_get_uniq_id("SERVER SETUP", 0);
488 if (g_slist_find(setupservers, rec) == NULL)
489 setupservers = g_slist_append(setupservers, rec);
490 server_setup_save(rec);
492 signal_emit("server setup updated", 1, rec);
495 void server_setup_remove(SERVER_SETUP_REC *rec)
497 server_setup_remove_config(rec);
498 server_setup_destroy(rec);
501 static void read_servers(void)
506 while (setupservers != NULL)
507 server_setup_destroy(setupservers->data);
510 node = iconfig_node_traverse("servers", FALSE);
512 tmp = config_node_first(node->value);
513 for (; tmp != NULL; tmp = config_node_next(tmp))
514 server_setup_read(tmp->data);
518 static void read_settings(void)
520 if (old_source_host == NULL ||
521 strcmp(old_source_host, settings_get_str("hostname")) != 0) {
522 g_free_not_null(old_source_host);
523 old_source_host = g_strdup(settings_get_str("hostname"));
525 source_host_ok = FALSE;
526 get_source_host_ip();
530 void servers_setup_init(void)
532 settings_add_str("server", "hostname", "");
534 settings_add_str("server", "nick", NULL);
535 settings_add_str("server", "user_name", NULL);
536 settings_add_str("server", "real_name", NULL);
538 settings_add_bool("proxy", "use_proxy", FALSE);
539 settings_add_str("proxy", "proxy_address", "");
540 settings_add_int("proxy", "proxy_port", 6667);
541 settings_add_str("proxy", "proxy_string", "CONNECT %s %d");
542 settings_add_str("proxy", "proxy_string_after", "");
543 settings_add_str("proxy", "proxy_password", "");
546 source_host_ip4 = source_host_ip6 = NULL;
547 old_source_host = NULL;
550 signal_add("setup changed", (SIGNAL_FUNC) read_settings);
551 signal_add("setup reread", (SIGNAL_FUNC) read_servers);
552 signal_add("irssi init read settings", (SIGNAL_FUNC) read_servers);
555 void servers_setup_deinit(void)
557 g_free_not_null(source_host_ip4);
558 g_free_not_null(source_host_ip6);
559 g_free_not_null(old_source_host);
561 while (setupservers != NULL)
562 server_setup_destroy(setupservers->data);
564 signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
565 signal_remove("setup reread", (SIGNAL_FUNC) read_servers);
566 signal_remove("irssi init read settings", (SIGNAL_FUNC) read_servers);
568 module_uniq_destroy("SERVER SETUP");