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
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "lib-config/iconfig.h"
27 #include "chat-protocols.h"
30 #include "servers-setup.h"
34 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 /* Find matching server from setup. Ports must match or NULL is returned. */
356 SERVER_SETUP_REC *server_setup_find_port(const char *address, int port)
358 SERVER_SETUP_REC *rec;
360 rec = server_setup_find(address, port, NULL);
361 return rec == NULL || rec->port != port ? NULL : rec;
364 static SERVER_SETUP_REC *server_setup_read(CONFIG_NODE *node)
366 SERVER_SETUP_REC *rec;
367 CHATNET_REC *chatnetrec;
368 char *server, *chatnet, *family;
371 g_return_val_if_fail(node != NULL, NULL);
373 server = config_node_get_str(node, "address", NULL);
377 port = config_node_get_int(node, "port", 0);
378 if (server_setup_find_port(server, port) != NULL) {
379 /* already exists - don't let it get there twice or
380 server reconnects will screw up! */
385 chatnet = config_node_get_str(node, "chatnet", NULL);
387 chatnetrec = chatnet == NULL ? NULL : chatnet_find(chatnet);
388 if (chatnetrec == NULL && chatnet != NULL) {
389 /* chat network not found, create it. */
390 chatnetrec = chat_protocol_get_default()->create_chatnet();
391 chatnetrec->chat_type = chat_protocol_get_default()->id;
392 chatnetrec->name = g_strdup(chatnet);
393 chatnet_create(chatnetrec);
396 family = config_node_get_str(node, "family", "");
398 rec = CHAT_PROTOCOL(chatnetrec)->create_server_setup();
399 rec->type = module_get_uniq_id("SERVER SETUP", 0);
400 rec->chat_type = CHAT_PROTOCOL(chatnetrec)->id;
401 rec->chatnet = chatnetrec == NULL ? NULL : g_strdup(chatnetrec->name);
402 rec->family = g_strcasecmp(family, "inet6") == 0 ? AF_INET6 :
403 (g_strcasecmp(family, "inet") == 0 ? AF_INET : 0);
404 rec->address = g_strdup(server);
405 rec->password = g_strdup(config_node_get_str(node, "password", NULL));
406 rec->use_ssl = config_node_get_bool(node, "use_ssl", FALSE);
407 rec->ssl_cert = g_strdup(config_node_get_str(node, "ssl_cert", NULL));
408 rec->ssl_pkey = g_strdup(config_node_get_str(node, "ssl_pkey", NULL));
409 rec->ssl_verify = config_node_get_bool(node, "ssl_verify", FALSE);
410 rec->ssl_cafile = g_strdup(config_node_get_str(node, "ssl_cafile", NULL));
411 rec->ssl_capath = g_strdup(config_node_get_str(node, "ssl_capath", NULL));
412 if (rec->ssl_cafile || rec->ssl_capath)
413 rec->ssl_verify = TRUE;
414 if (rec->ssl_cert != NULL || rec->ssl_verify)
417 rec->autoconnect = config_node_get_bool(node, "autoconnect", FALSE);
418 rec->no_proxy = config_node_get_bool(node, "no_proxy", FALSE);
419 rec->own_host = g_strdup(config_node_get_str(node, "own_host", NULL));
421 signal_emit("server setup read", 2, rec, node);
423 setupservers = g_slist_append(setupservers, rec);
427 static void server_setup_save(SERVER_SETUP_REC *rec)
429 CONFIG_NODE *parentnode, *node;
432 index = g_slist_index(setupservers, rec);
434 parentnode = iconfig_node_traverse("(servers", TRUE);
435 node = config_node_nth(parentnode, index);
437 node = config_node_section(parentnode, NULL, NODE_TYPE_BLOCK);
439 iconfig_node_clear(node);
440 iconfig_node_set_str(node, "address", rec->address);
441 iconfig_node_set_str(node, "chatnet", rec->chatnet);
443 iconfig_node_set_int(node, "port", rec->port);
444 iconfig_node_set_str(node, "password", rec->password);
445 iconfig_node_set_bool(node, "use_ssl", rec->use_ssl);
446 iconfig_node_set_str(node, "ssl_cert", rec->ssl_cert);
447 iconfig_node_set_str(node, "ssl_pkey", rec->ssl_pkey);
448 iconfig_node_set_bool(node, "ssl_verify", rec->ssl_verify);
449 iconfig_node_set_str(node, "ssl_cafile", rec->ssl_cafile);
450 iconfig_node_set_str(node, "ssl_capath", rec->ssl_capath);
451 iconfig_node_set_str(node, "own_host", rec->own_host);
453 iconfig_node_set_str(node, "family",
454 rec->family == AF_INET6 ? "inet6" :
455 rec->family == AF_INET ? "inet" : NULL);
457 if (rec->autoconnect)
458 iconfig_node_set_bool(node, "autoconnect", TRUE);
460 iconfig_node_set_bool(node, "no_proxy", TRUE);
462 signal_emit("server setup saved", 2, rec, node);
465 static void server_setup_remove_config(SERVER_SETUP_REC *rec)
470 node = iconfig_node_traverse("servers", FALSE);
472 index = g_slist_index(setupservers, rec);
473 iconfig_node_list_remove(node, index);
477 static void server_setup_destroy(SERVER_SETUP_REC *rec)
479 setupservers = g_slist_remove(setupservers, rec);
480 signal_emit("server setup destroyed", 1, rec);
482 g_free_not_null(rec->own_host);
483 g_free_not_null(rec->own_ip4);
484 g_free_not_null(rec->own_ip6);
485 g_free_not_null(rec->chatnet);
486 g_free_not_null(rec->password);
487 g_free_not_null(rec->ssl_cert);
488 g_free_not_null(rec->ssl_pkey);
489 g_free_not_null(rec->ssl_cafile);
490 g_free_not_null(rec->ssl_capath);
491 g_free(rec->address);
495 void server_setup_add(SERVER_SETUP_REC *rec)
497 rec->type = module_get_uniq_id("SERVER SETUP", 0);
498 if (g_slist_find(setupservers, rec) == NULL)
499 setupservers = g_slist_append(setupservers, rec);
500 server_setup_save(rec);
502 signal_emit("server setup updated", 1, rec);
505 void server_setup_remove(SERVER_SETUP_REC *rec)
507 server_setup_remove_config(rec);
508 server_setup_destroy(rec);
511 static void read_servers(void)
516 while (setupservers != NULL)
517 server_setup_destroy(setupservers->data);
520 node = iconfig_node_traverse("servers", FALSE);
522 tmp = config_node_first(node->value);
523 for (; tmp != NULL; tmp = config_node_next(tmp))
524 server_setup_read(tmp->data);
528 static void read_settings(void)
530 if (old_source_host == NULL ||
531 strcmp(old_source_host, settings_get_str("hostname")) != 0) {
532 g_free_not_null(old_source_host);
533 old_source_host = g_strdup(settings_get_str("hostname"));
535 source_host_ok = FALSE;
536 get_source_host_ip();
540 void servers_setup_init(void)
542 settings_add_str("server", "hostname", "");
544 settings_add_str("server", "nick", NULL);
545 settings_add_str("server", "user_name", NULL);
546 settings_add_str("server", "real_name", NULL);
548 settings_add_bool("server", "use_ssl", FALSE);
549 settings_add_str("server", "ssl_cert", NULL);
550 settings_add_str("server", "ssl_pkey", NULL);
551 settings_add_bool("server", "ssl_verify", FALSE);
552 settings_add_str("server", "ssl_cafile", NULL);
553 settings_add_str("server", "ssl_cacert", NULL);
555 settings_add_bool("proxy", "use_proxy", FALSE);
556 settings_add_str("proxy", "proxy_address", "");
557 settings_add_int("proxy", "proxy_port", 6667);
558 settings_add_str("proxy", "proxy_string", "CONNECT %s %d");
559 settings_add_str("proxy", "proxy_string_after", "");
560 settings_add_str("proxy", "proxy_password", "");
563 source_host_ip4 = source_host_ip6 = NULL;
564 old_source_host = NULL;
567 signal_add("setup changed", (SIGNAL_FUNC) read_settings);
568 signal_add("setup reread", (SIGNAL_FUNC) read_servers);
569 signal_add("irssi init read settings", (SIGNAL_FUNC) read_servers);
572 void servers_setup_deinit(void)
574 g_free_not_null(source_host_ip4);
575 g_free_not_null(source_host_ip6);
576 g_free_not_null(old_source_host);
578 while (setupservers != NULL)
579 server_setup_destroy(setupservers->data);
581 signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
582 signal_remove("setup reread", (SIGNAL_FUNC) read_servers);
583 signal_remove("irssi init read settings", (SIGNAL_FUNC) read_servers);
585 module_uniq_destroy("SERVER SETUP");