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_password = g_strdup(settings_get_str("proxy_password"));
138 if (source_host_ip4 != NULL) {
139 conn->own_ip4 = g_new(IPADDR, 1);
140 memcpy(conn->own_ip4, source_host_ip4, sizeof(IPADDR));
142 if (source_host_ip6 != NULL) {
143 conn->own_ip6 = g_new(IPADDR, 1);
144 memcpy(conn->own_ip6, source_host_ip6, sizeof(IPADDR));
148 static void server_setup_fill_server(SERVER_CONNECT_REC *conn,
149 SERVER_SETUP_REC *sserver)
151 g_return_if_fail(IS_SERVER_CONNECT(conn));
152 g_return_if_fail(IS_SERVER_SETUP(sserver));
154 sserver->last_connect = time(NULL);
156 if (sserver->family != 0 && conn->family == 0)
157 conn->family = sserver->family;
158 if (sserver->port > 0 && conn->port <= 0)
159 conn->port = sserver->port;
160 server_setup_fill_reconn(conn, sserver);
162 signal_emit("server setup fill server", 2, conn, sserver);
165 static void server_setup_fill_chatnet(SERVER_CONNECT_REC *conn,
166 CHATNET_REC *chatnet)
168 g_return_if_fail(IS_SERVER_CONNECT(conn));
169 g_return_if_fail(IS_CHATNET(chatnet));
173 conn->nick = g_strdup(chatnet->nick);;
175 if (chatnet->username) {
176 g_free(conn->username);
177 conn->username = g_strdup(chatnet->username);;
179 if (chatnet->realname) {
180 g_free(conn->realname);
181 conn->realname = g_strdup(chatnet->realname);;
183 if (chatnet->own_host != NULL) {
184 conn_set_ip(conn, chatnet->own_host,
185 &chatnet->own_ip4, &chatnet->own_ip6);
188 signal_emit("server setup fill chatnet", 2, conn, chatnet);
191 static SERVER_CONNECT_REC *
192 create_addr_conn(int chat_type, const char *address, int port,
193 const char *chatnet, const char *password,
196 CHAT_PROTOCOL_REC *proto;
197 SERVER_CONNECT_REC *conn;
198 SERVER_SETUP_REC *sserver;
199 CHATNET_REC *chatnetrec;
201 g_return_val_if_fail(address != NULL, NULL);
203 sserver = server_setup_find(address, port);
204 if (sserver != NULL) {
206 chat_type = sserver->chat_type;
207 else if (chat_type != sserver->chat_type)
211 proto = chat_type >= 0 ? chat_protocol_find_id(chat_type) :
212 chat_protocol_get_default();
214 conn = proto->create_server_connect();
215 conn->chat_type = proto->id;
216 if (chatnet != NULL && *chatnet != '\0')
217 conn->chatnet = g_strdup(chatnet);
219 /* fill in the defaults */
220 server_setup_fill(conn, address, port);
222 /* fill the rest from chat network settings */
223 chatnetrec = chatnet != NULL ? chatnet_find(chatnet) :
224 (sserver == NULL || sserver->chatnet == NULL ? NULL :
225 chatnet_find(sserver->chatnet));
226 if (chatnetrec != NULL)
227 server_setup_fill_chatnet(conn, chatnetrec);
229 /* fill the information from setup */
231 server_setup_fill_server(conn, sserver);
233 /* nick / password given in command line overrides all settings */
234 if (password && *password) {
235 g_free_not_null(conn->password);
236 conn->password = g_strdup(password);
239 g_free_not_null(conn->nick);
240 conn->nick = g_strdup(nick);
243 signal_emit("server setup fill connect", 1, conn);
247 /* Connect to server where last connect succeeded (or we haven't tried to
248 connect yet). If there's no such server, connect to server where we
249 haven't connected for the longest time */
250 static SERVER_CONNECT_REC *
251 create_chatnet_conn(const char *dest, int port,
252 const char *password, const char *nick)
254 SERVER_SETUP_REC *bestrec;
256 time_t now, besttime;
259 bestrec = NULL; besttime = now;
260 for (tmp = setupservers; tmp != NULL; tmp = tmp->next) {
261 SERVER_SETUP_REC *rec = tmp->data;
263 if (rec->chatnet == NULL ||
264 g_strcasecmp(rec->chatnet, dest) != 0)
267 if (!rec->last_failed) {
272 if (bestrec == NULL || besttime > rec->last_connect) {
274 besttime = rec->last_connect;
278 return bestrec == NULL ? NULL :
279 create_addr_conn(bestrec->chat_type, bestrec->address, 0,
283 /* Create server connection record. `dest' is required, rest can be NULL.
284 `dest' is either a server address or chat network */
286 server_create_conn(int chat_type, const char *dest, int port,
287 const char *chatnet, const char *password,
290 SERVER_CONNECT_REC *rec;
292 g_return_val_if_fail(dest != NULL, NULL);
294 if (chatnet_find(dest) != NULL) {
295 rec = create_chatnet_conn(dest, port, password, nick);
300 return create_addr_conn(chat_type, dest, port,
301 chatnet, password, nick);
304 /* Find matching server from setup. Try to find record with a same port,
305 but fallback to any server with the same address. */
306 SERVER_SETUP_REC *server_setup_find(const char *address, int port)
308 SERVER_SETUP_REC *server;
311 g_return_val_if_fail(address != NULL, NULL);
314 for (tmp = setupservers; tmp != NULL; tmp = tmp->next) {
315 SERVER_SETUP_REC *rec = tmp->data;
317 if (g_strcasecmp(rec->address, address) == 0) {
319 if (rec->port == port)
327 /* Find matching server from setup. Ports must match or NULL is returned. */
328 SERVER_SETUP_REC *server_setup_find_port(const char *address, int port)
330 SERVER_SETUP_REC *rec;
332 rec = server_setup_find(address, port);
333 return rec == NULL || rec->port != port ? NULL : rec;
336 static SERVER_SETUP_REC *server_setup_read(CONFIG_NODE *node)
338 SERVER_SETUP_REC *rec;
339 CHATNET_REC *chatnetrec;
340 char *server, *chatnet, *family;
343 g_return_val_if_fail(node != NULL, NULL);
345 server = config_node_get_str(node, "address", NULL);
349 port = config_node_get_int(node, "port", 0);
350 if (server_setup_find_port(server, port) != NULL) {
351 /* already exists - don't let it get there twice or
352 server reconnects will screw up! */
357 chatnet = config_node_get_str(node, "chatnet", NULL);
358 if (chatnet == NULL) /* FIXME: remove this after .98... */ {
359 chatnet = config_node_get_str(node, "ircnet", NULL);
360 if (chatnet != NULL) {
361 iconfig_node_set_str(node, "chatnet", chatnet);
362 iconfig_node_set_str(node, "ircnet", NULL);
363 chatnet = config_node_get_str(node, "chatnet", NULL);
367 chatnetrec = chatnet == NULL ? NULL : chatnet_find(chatnet);
368 if (chatnetrec == NULL && chatnet != NULL) {
369 /* chat network not found, create it. */
370 chatnetrec = chat_protocol_get_default()->create_chatnet();
371 chatnetrec->chat_type = chat_protocol_get_default()->id;
372 chatnetrec->name = g_strdup(chatnet);
373 chatnet_create(chatnetrec);
376 family = config_node_get_str(node, "family", "");
378 rec = CHAT_PROTOCOL(chatnetrec)->create_server_setup();
379 rec->type = module_get_uniq_id("SERVER SETUP", 0);
380 rec->chat_type = CHAT_PROTOCOL(chatnetrec)->id;
381 rec->chatnet = chatnetrec == NULL ? NULL : g_strdup(chatnetrec->name);
382 rec->family = g_strcasecmp(family, "inet6") == 0 ? AF_INET6 :
383 (g_strcasecmp(family, "inet") == 0 ? AF_INET : 0);
384 rec->address = g_strdup(server);
385 rec->password = g_strdup(config_node_get_str(node, "password", NULL));
387 rec->autoconnect = config_node_get_bool(node, "autoconnect", FALSE);
388 rec->own_host = g_strdup(config_node_get_str(node, "own_host", NULL));
390 signal_emit("server setup read", 2, rec, node);
392 setupservers = g_slist_append(setupservers, rec);
396 static void server_setup_save(SERVER_SETUP_REC *rec)
398 CONFIG_NODE *parentnode, *node;
401 index = g_slist_index(setupservers, rec);
403 parentnode = iconfig_node_traverse("(servers", TRUE);
404 node = config_node_index(parentnode, index);
406 node = config_node_section(parentnode, NULL, NODE_TYPE_BLOCK);
408 iconfig_node_clear(node);
409 iconfig_node_set_str(node, "address", rec->address);
410 iconfig_node_set_str(node, "chatnet", rec->chatnet);
412 iconfig_node_set_int(node, "port", rec->port);
413 iconfig_node_set_str(node, "password", rec->password);
414 iconfig_node_set_str(node, "own_host", rec->own_host);
416 iconfig_node_set_str(node, "family",
417 rec->family == AF_INET6 ? "inet6" :
418 rec->family == AF_INET ? "inet" : NULL);
420 if (rec->autoconnect)
421 iconfig_node_set_bool(node, "autoconnect", TRUE);
423 signal_emit("server setup saved", 2, rec, node);
426 static void server_setup_remove_config(SERVER_SETUP_REC *rec)
431 node = iconfig_node_traverse("servers", FALSE);
433 index = g_slist_index(setupservers, rec);
434 iconfig_node_list_remove(node, index);
438 static void server_setup_destroy(SERVER_SETUP_REC *rec)
440 setupservers = g_slist_remove(setupservers, rec);
441 signal_emit("server setup destroyed", 1, rec);
443 g_free_not_null(rec->own_host);
444 g_free_not_null(rec->own_ip4);
445 g_free_not_null(rec->own_ip6);
446 g_free_not_null(rec->chatnet);
447 g_free_not_null(rec->password);
448 g_free(rec->address);
452 void server_setup_add(SERVER_SETUP_REC *rec)
454 rec->type = module_get_uniq_id("SERVER SETUP", 0);
455 if (g_slist_find(setupservers, rec) == NULL)
456 setupservers = g_slist_append(setupservers, rec);
457 server_setup_save(rec);
460 void server_setup_remove(SERVER_SETUP_REC *rec)
462 server_setup_remove_config(rec);
463 server_setup_destroy(rec);
466 static void read_servers(void)
471 while (setupservers != NULL)
472 server_setup_destroy(setupservers->data);
475 node = iconfig_node_traverse("servers", FALSE);
477 for (tmp = node->value; tmp != NULL; tmp = tmp->next)
478 server_setup_read(tmp->data);
482 static void read_settings(void)
484 if (old_source_host == NULL ||
485 strcmp(old_source_host, settings_get_str("hostname")) != 0) {
486 g_free_not_null(old_source_host);
487 old_source_host = g_strdup(settings_get_str("hostname"));
489 source_host_ok = FALSE;
490 get_source_host_ip();
494 void servers_setup_init(void)
496 settings_add_str("server", "hostname", "");
498 settings_add_str("server", "nick", NULL);
499 settings_add_str("server", "user_name", NULL);
500 settings_add_str("server", "real_name", NULL);
502 settings_add_bool("proxy", "use_proxy", FALSE);
503 settings_add_str("proxy", "proxy_address", "");
504 settings_add_int("proxy", "proxy_port", 6667);
505 settings_add_str("proxy", "proxy_string", "CONNECT %s %d");
506 settings_add_str("proxy", "proxy_password", "");
509 source_host_ip4 = source_host_ip6 = NULL;
510 old_source_host = NULL;
513 signal_add("setup changed", (SIGNAL_FUNC) read_settings);
514 signal_add("setup reread", (SIGNAL_FUNC) read_servers);
515 signal_add("irssi init read settings", (SIGNAL_FUNC) read_servers);
518 void servers_setup_deinit(void)
520 g_free_not_null(source_host_ip4);
521 g_free_not_null(source_host_ip6);
522 g_free_not_null(old_source_host);
524 while (setupservers != NULL)
525 server_setup_destroy(setupservers->data);
527 signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
528 signal_remove("setup reread", (SIGNAL_FUNC) read_servers);
529 signal_remove("irssi init read settings", (SIGNAL_FUNC) read_servers);
531 module_uniq_destroy("SERVER SETUP");