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;
166 conn->use_ssl = sserver->use_ssl;
168 server_setup_fill_reconn(conn, sserver);
170 signal_emit("server setup fill server", 2, conn, sserver);
173 static void server_setup_fill_chatnet(SERVER_CONNECT_REC *conn,
174 CHATNET_REC *chatnet)
176 g_return_if_fail(IS_SERVER_CONNECT(conn));
177 g_return_if_fail(IS_CHATNET(chatnet));
179 if (chatnet->nick != NULL) {
181 conn->nick = g_strdup(chatnet->nick);;
183 if (chatnet->username != NULL) {
184 g_free(conn->username);
185 conn->username = g_strdup(chatnet->username);;
187 if (chatnet->realname != NULL) {
188 g_free(conn->realname);
189 conn->realname = g_strdup(chatnet->realname);;
191 if (chatnet->own_host != NULL) {
192 conn_set_ip(conn, chatnet->own_host,
193 &chatnet->own_ip4, &chatnet->own_ip6);
196 signal_emit("server setup fill chatnet", 2, conn, chatnet);
199 static SERVER_CONNECT_REC *
200 create_addr_conn(int chat_type, const char *address, int port,
201 const char *chatnet, const char *password,
204 CHAT_PROTOCOL_REC *proto;
205 SERVER_CONNECT_REC *conn;
206 SERVER_SETUP_REC *sserver;
207 CHATNET_REC *chatnetrec;
209 g_return_val_if_fail(address != NULL, NULL);
211 sserver = server_setup_find(address, port, chatnet);
212 if (sserver != NULL) {
214 chat_type = sserver->chat_type;
215 else if (chat_type != sserver->chat_type)
219 proto = chat_type >= 0 ? chat_protocol_find_id(chat_type) :
220 chat_protocol_get_default();
222 conn = proto->create_server_connect();
223 server_connect_ref(conn);
225 conn->chat_type = proto->id;
226 if (chatnet != NULL && *chatnet != '\0')
227 conn->chatnet = g_strdup(chatnet);
229 /* fill in the defaults */
230 server_setup_fill(conn, address, port);
232 /* fill the rest from chat network settings */
233 chatnetrec = chatnet != NULL ? chatnet_find(chatnet) :
234 (sserver == NULL || sserver->chatnet == NULL ? NULL :
235 chatnet_find(sserver->chatnet));
236 if (chatnetrec != NULL)
237 server_setup_fill_chatnet(conn, chatnetrec);
239 /* fill the information from setup */
241 server_setup_fill_server(conn, sserver);
243 /* nick / password given in command line overrides all settings */
244 if (password && *password) {
245 g_free_not_null(conn->password);
246 conn->password = g_strdup(password);
249 g_free_not_null(conn->nick);
250 conn->nick = g_strdup(nick);
256 /* Connect to server where last connect succeeded (or we haven't tried to
257 connect yet). If there's no such server, connect to server where we
258 haven't connected for the longest time */
259 static SERVER_CONNECT_REC *
260 create_chatnet_conn(const char *dest, int port,
261 const char *password, const char *nick)
263 SERVER_SETUP_REC *bestrec;
265 time_t now, besttime;
268 bestrec = NULL; besttime = now;
269 for (tmp = setupservers; tmp != NULL; tmp = tmp->next) {
270 SERVER_SETUP_REC *rec = tmp->data;
272 if (rec->chatnet == NULL ||
273 g_strcasecmp(rec->chatnet, dest) != 0)
276 if (!rec->last_failed) {
281 if (bestrec == NULL || besttime > rec->last_connect) {
283 besttime = rec->last_connect;
287 return bestrec == NULL ? NULL :
288 create_addr_conn(bestrec->chat_type, bestrec->address, 0,
292 /* Create server connection record. `dest' is required, rest can be NULL.
293 `dest' is either a server address or chat network */
295 server_create_conn(int chat_type, const char *dest, int port,
296 const char *chatnet, const char *password,
299 SERVER_CONNECT_REC *rec;
300 CHATNET_REC *chatrec;
302 g_return_val_if_fail(dest != NULL, NULL);
304 chatrec = chatnet_find(dest);
305 if (chatrec != NULL) {
306 rec = create_chatnet_conn(chatrec->name, port, password, nick);
311 chatrec = chatnet == NULL ? NULL : chatnet_find(chatnet);
313 chatnet = chatrec->name;
315 return create_addr_conn(chat_type, dest, port,
316 chatnet, password, nick);
319 /* Find matching server from setup. Try to find record with a same port,
320 but fallback to any server with the same address. */
321 SERVER_SETUP_REC *server_setup_find(const char *address, int port,
324 SERVER_SETUP_REC *server;
327 g_return_val_if_fail(address != NULL, NULL);
330 for (tmp = setupservers; tmp != NULL; tmp = tmp->next) {
331 SERVER_SETUP_REC *rec = tmp->data;
333 if (g_strcasecmp(rec->address, address) == 0 &&
334 (chatnet == NULL || rec->chatnet == NULL ||
335 g_strcasecmp(rec->chatnet, chatnet) == 0)) {
337 if (rec->port == port)
345 /* Find matching server from setup. Ports must match or NULL is returned. */
346 SERVER_SETUP_REC *server_setup_find_port(const char *address, int port)
348 SERVER_SETUP_REC *rec;
350 rec = server_setup_find(address, port, NULL);
351 return rec == NULL || rec->port != port ? NULL : rec;
354 static SERVER_SETUP_REC *server_setup_read(CONFIG_NODE *node)
356 SERVER_SETUP_REC *rec;
357 CHATNET_REC *chatnetrec;
358 char *server, *chatnet, *family;
361 g_return_val_if_fail(node != NULL, NULL);
363 server = config_node_get_str(node, "address", NULL);
367 port = config_node_get_int(node, "port", 0);
368 if (server_setup_find_port(server, port) != NULL) {
369 /* already exists - don't let it get there twice or
370 server reconnects will screw up! */
375 chatnet = config_node_get_str(node, "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_strcasecmp(family, "inet6") == 0 ? AF_INET6 :
393 (g_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);
398 rec->autoconnect = config_node_get_bool(node, "autoconnect", FALSE);
399 rec->no_proxy = config_node_get_bool(node, "no_proxy", FALSE);
400 rec->own_host = g_strdup(config_node_get_str(node, "own_host", NULL));
402 signal_emit("server setup read", 2, rec, node);
404 setupservers = g_slist_append(setupservers, rec);
408 static void server_setup_save(SERVER_SETUP_REC *rec)
410 CONFIG_NODE *parentnode, *node;
413 index = g_slist_index(setupservers, rec);
415 parentnode = iconfig_node_traverse("(servers", TRUE);
416 node = config_node_nth(parentnode, index);
418 node = config_node_section(parentnode, NULL, NODE_TYPE_BLOCK);
420 iconfig_node_clear(node);
421 iconfig_node_set_str(node, "address", rec->address);
422 iconfig_node_set_str(node, "chatnet", rec->chatnet);
424 iconfig_node_set_int(node, "port", rec->port);
425 iconfig_node_set_str(node, "password", rec->password);
426 iconfig_node_set_bool(node, "use_ssl", rec->use_ssl);
427 iconfig_node_set_str(node, "own_host", rec->own_host);
429 iconfig_node_set_str(node, "family",
430 rec->family == AF_INET6 ? "inet6" :
431 rec->family == AF_INET ? "inet" : NULL);
433 if (rec->autoconnect)
434 iconfig_node_set_bool(node, "autoconnect", TRUE);
436 iconfig_node_set_bool(node, "no_proxy", TRUE);
438 signal_emit("server setup saved", 2, rec, node);
441 static void server_setup_remove_config(SERVER_SETUP_REC *rec)
446 node = iconfig_node_traverse("servers", FALSE);
448 index = g_slist_index(setupservers, rec);
449 iconfig_node_list_remove(node, index);
453 static void server_setup_destroy(SERVER_SETUP_REC *rec)
455 setupservers = g_slist_remove(setupservers, rec);
456 signal_emit("server setup destroyed", 1, rec);
458 g_free_not_null(rec->own_host);
459 g_free_not_null(rec->own_ip4);
460 g_free_not_null(rec->own_ip6);
461 g_free_not_null(rec->chatnet);
462 g_free_not_null(rec->password);
463 g_free(rec->address);
467 void server_setup_add(SERVER_SETUP_REC *rec)
469 rec->type = module_get_uniq_id("SERVER SETUP", 0);
470 if (g_slist_find(setupservers, rec) == NULL)
471 setupservers = g_slist_append(setupservers, rec);
472 server_setup_save(rec);
474 signal_emit("server setup updated", 1, rec);
477 void server_setup_remove(SERVER_SETUP_REC *rec)
479 server_setup_remove_config(rec);
480 server_setup_destroy(rec);
483 static void read_servers(void)
488 while (setupservers != NULL)
489 server_setup_destroy(setupservers->data);
492 node = iconfig_node_traverse("servers", FALSE);
494 tmp = config_node_first(node->value);
495 for (; tmp != NULL; tmp = config_node_next(tmp))
496 server_setup_read(tmp->data);
500 static void read_settings(void)
502 if (old_source_host == NULL ||
503 strcmp(old_source_host, settings_get_str("hostname")) != 0) {
504 g_free_not_null(old_source_host);
505 old_source_host = g_strdup(settings_get_str("hostname"));
507 source_host_ok = FALSE;
508 get_source_host_ip();
512 void servers_setup_init(void)
514 settings_add_str("server", "hostname", "");
516 settings_add_str("server", "nick", NULL);
517 settings_add_str("server", "user_name", NULL);
518 settings_add_str("server", "real_name", NULL);
520 settings_add_bool("proxy", "use_proxy", FALSE);
521 settings_add_str("proxy", "proxy_address", "");
522 settings_add_int("proxy", "proxy_port", 6667);
523 settings_add_str("proxy", "proxy_string", "CONNECT %s %d");
524 settings_add_str("proxy", "proxy_string_after", "");
525 settings_add_str("proxy", "proxy_password", "");
528 source_host_ip4 = source_host_ip6 = NULL;
529 old_source_host = NULL;
532 signal_add("setup changed", (SIGNAL_FUNC) read_settings);
533 signal_add("setup reread", (SIGNAL_FUNC) read_servers);
534 signal_add("irssi init read settings", (SIGNAL_FUNC) read_servers);
537 void servers_setup_deinit(void)
539 g_free_not_null(source_host_ip4);
540 g_free_not_null(source_host_ip6);
541 g_free_not_null(old_source_host);
543 while (setupservers != NULL)
544 server_setup_destroy(setupservers->data);
546 signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
547 signal_remove("setup reread", (SIGNAL_FUNC) read_servers);
548 signal_remove("irssi init read settings", (SIGNAL_FUNC) read_servers);
550 module_uniq_destroy("SERVER SETUP");