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 server_setup_fill_reconn(conn, sserver);
168 signal_emit("server setup fill server", 2, conn, sserver);
171 static void server_setup_fill_chatnet(SERVER_CONNECT_REC *conn,
172 CHATNET_REC *chatnet)
174 g_return_if_fail(IS_SERVER_CONNECT(conn));
175 g_return_if_fail(IS_CHATNET(chatnet));
177 if (chatnet->nick != NULL) {
179 conn->nick = g_strdup(chatnet->nick);;
181 if (chatnet->username != NULL) {
182 g_free(conn->username);
183 conn->username = g_strdup(chatnet->username);;
185 if (chatnet->realname != NULL) {
186 g_free(conn->realname);
187 conn->realname = g_strdup(chatnet->realname);;
189 if (chatnet->own_host != NULL) {
190 conn_set_ip(conn, chatnet->own_host,
191 &chatnet->own_ip4, &chatnet->own_ip6);
194 signal_emit("server setup fill chatnet", 2, conn, chatnet);
197 static SERVER_CONNECT_REC *
198 create_addr_conn(int chat_type, const char *address, int port,
199 const char *chatnet, const char *password,
202 CHAT_PROTOCOL_REC *proto;
203 SERVER_CONNECT_REC *conn;
204 SERVER_SETUP_REC *sserver;
205 CHATNET_REC *chatnetrec;
207 g_return_val_if_fail(address != NULL, NULL);
209 sserver = server_setup_find(address, port, chatnet);
210 if (sserver != NULL) {
212 chat_type = sserver->chat_type;
213 else if (chat_type != sserver->chat_type)
217 proto = chat_type >= 0 ? chat_protocol_find_id(chat_type) :
218 chat_protocol_get_default();
220 conn = proto->create_server_connect();
221 server_connect_ref(conn);
223 conn->chat_type = proto->id;
224 if (chatnet != NULL && *chatnet != '\0')
225 conn->chatnet = g_strdup(chatnet);
227 /* fill in the defaults */
228 server_setup_fill(conn, address, port);
230 /* fill the rest from chat network settings */
231 chatnetrec = chatnet != NULL ? chatnet_find(chatnet) :
232 (sserver == NULL || sserver->chatnet == NULL ? NULL :
233 chatnet_find(sserver->chatnet));
234 if (chatnetrec != NULL)
235 server_setup_fill_chatnet(conn, chatnetrec);
237 /* fill the information from setup */
239 server_setup_fill_server(conn, sserver);
241 /* nick / password given in command line overrides all settings */
242 if (password && *password) {
243 g_free_not_null(conn->password);
244 conn->password = g_strdup(password);
247 g_free_not_null(conn->nick);
248 conn->nick = g_strdup(nick);
254 /* Connect to server where last connect succeeded (or we haven't tried to
255 connect yet). If there's no such server, connect to server where we
256 haven't connected for the longest time */
257 static SERVER_CONNECT_REC *
258 create_chatnet_conn(const char *dest, int port,
259 const char *password, const char *nick)
261 SERVER_SETUP_REC *bestrec;
263 time_t now, besttime;
266 bestrec = NULL; besttime = now;
267 for (tmp = setupservers; tmp != NULL; tmp = tmp->next) {
268 SERVER_SETUP_REC *rec = tmp->data;
270 if (rec->chatnet == NULL ||
271 g_strcasecmp(rec->chatnet, dest) != 0)
274 if (!rec->last_failed) {
279 if (bestrec == NULL || besttime > rec->last_connect) {
281 besttime = rec->last_connect;
285 return bestrec == NULL ? NULL :
286 create_addr_conn(bestrec->chat_type, bestrec->address, 0,
290 /* Create server connection record. `dest' is required, rest can be NULL.
291 `dest' is either a server address or chat network */
293 server_create_conn(int chat_type, const char *dest, int port,
294 const char *chatnet, const char *password,
297 SERVER_CONNECT_REC *rec;
298 CHATNET_REC *chatrec;
300 g_return_val_if_fail(dest != NULL, NULL);
302 chatrec = chatnet_find(dest);
303 if (chatrec != NULL) {
304 rec = create_chatnet_conn(chatrec->name, port, password, nick);
309 chatrec = chatnet == NULL ? NULL : chatnet_find(chatnet);
311 chatnet = chatrec->name;
313 return create_addr_conn(chat_type, dest, port,
314 chatnet, password, nick);
317 /* Find matching server from setup. Try to find record with a same port,
318 but fallback to any server with the same address. */
319 SERVER_SETUP_REC *server_setup_find(const char *address, int port,
322 SERVER_SETUP_REC *server;
325 g_return_val_if_fail(address != NULL, NULL);
328 for (tmp = setupservers; tmp != NULL; tmp = tmp->next) {
329 SERVER_SETUP_REC *rec = tmp->data;
331 if (g_strcasecmp(rec->address, address) == 0 &&
332 (chatnet == NULL || rec->chatnet == NULL ||
333 g_strcasecmp(rec->chatnet, chatnet) == 0)) {
335 if (rec->port == port)
343 /* Find matching server from setup. Ports must match or NULL is returned. */
344 SERVER_SETUP_REC *server_setup_find_port(const char *address, int port)
346 SERVER_SETUP_REC *rec;
348 rec = server_setup_find(address, port, NULL);
349 return rec == NULL || rec->port != port ? NULL : rec;
352 static SERVER_SETUP_REC *server_setup_read(CONFIG_NODE *node)
354 SERVER_SETUP_REC *rec;
355 CHATNET_REC *chatnetrec;
356 char *server, *chatnet, *family;
359 g_return_val_if_fail(node != NULL, NULL);
361 server = config_node_get_str(node, "address", NULL);
365 port = config_node_get_int(node, "port", 0);
366 if (server_setup_find_port(server, port) != NULL) {
367 /* already exists - don't let it get there twice or
368 server reconnects will screw up! */
373 chatnet = config_node_get_str(node, "chatnet", NULL);
375 chatnetrec = chatnet == NULL ? NULL : chatnet_find(chatnet);
376 if (chatnetrec == NULL && chatnet != NULL) {
377 /* chat network not found, create it. */
378 chatnetrec = chat_protocol_get_default()->create_chatnet();
379 chatnetrec->chat_type = chat_protocol_get_default()->id;
380 chatnetrec->name = g_strdup(chatnet);
381 chatnet_create(chatnetrec);
384 family = config_node_get_str(node, "family", "");
386 rec = CHAT_PROTOCOL(chatnetrec)->create_server_setup();
387 rec->type = module_get_uniq_id("SERVER SETUP", 0);
388 rec->chat_type = CHAT_PROTOCOL(chatnetrec)->id;
389 rec->chatnet = chatnetrec == NULL ? NULL : g_strdup(chatnetrec->name);
390 rec->family = g_strcasecmp(family, "inet6") == 0 ? AF_INET6 :
391 (g_strcasecmp(family, "inet") == 0 ? AF_INET : 0);
392 rec->address = g_strdup(server);
393 rec->password = g_strdup(config_node_get_str(node, "password", NULL));
395 rec->autoconnect = config_node_get_bool(node, "autoconnect", FALSE);
396 rec->no_proxy = config_node_get_bool(node, "no_proxy", FALSE);
397 rec->own_host = g_strdup(config_node_get_str(node, "own_host", NULL));
399 signal_emit("server setup read", 2, rec, node);
401 setupservers = g_slist_append(setupservers, rec);
405 static void server_setup_save(SERVER_SETUP_REC *rec)
407 CONFIG_NODE *parentnode, *node;
410 index = g_slist_index(setupservers, rec);
412 parentnode = iconfig_node_traverse("(servers", TRUE);
413 node = config_node_index(parentnode, index);
415 node = config_node_section(parentnode, NULL, NODE_TYPE_BLOCK);
417 iconfig_node_clear(node);
418 iconfig_node_set_str(node, "address", rec->address);
419 iconfig_node_set_str(node, "chatnet", rec->chatnet);
421 iconfig_node_set_int(node, "port", rec->port);
422 iconfig_node_set_str(node, "password", rec->password);
423 iconfig_node_set_str(node, "own_host", rec->own_host);
425 iconfig_node_set_str(node, "family",
426 rec->family == AF_INET6 ? "inet6" :
427 rec->family == AF_INET ? "inet" : NULL);
429 if (rec->autoconnect)
430 iconfig_node_set_bool(node, "autoconnect", TRUE);
432 iconfig_node_set_bool(node, "no_proxy", TRUE);
434 signal_emit("server setup saved", 2, rec, node);
437 static void server_setup_remove_config(SERVER_SETUP_REC *rec)
442 node = iconfig_node_traverse("servers", FALSE);
444 index = g_slist_index(setupservers, rec);
445 iconfig_node_list_remove(node, index);
449 static void server_setup_destroy(SERVER_SETUP_REC *rec)
451 setupservers = g_slist_remove(setupservers, rec);
452 signal_emit("server setup destroyed", 1, rec);
454 g_free_not_null(rec->own_host);
455 g_free_not_null(rec->own_ip4);
456 g_free_not_null(rec->own_ip6);
457 g_free_not_null(rec->chatnet);
458 g_free_not_null(rec->password);
459 g_free(rec->address);
463 void server_setup_add(SERVER_SETUP_REC *rec)
465 rec->type = module_get_uniq_id("SERVER SETUP", 0);
466 if (g_slist_find(setupservers, rec) == NULL)
467 setupservers = g_slist_append(setupservers, rec);
468 server_setup_save(rec);
471 void server_setup_remove(SERVER_SETUP_REC *rec)
473 server_setup_remove_config(rec);
474 server_setup_destroy(rec);
477 static void read_servers(void)
482 while (setupservers != NULL)
483 server_setup_destroy(setupservers->data);
486 node = iconfig_node_traverse("servers", FALSE);
488 tmp = config_node_first(node->value);
489 for (; tmp != NULL; tmp = config_node_next(tmp))
490 server_setup_read(tmp->data);
494 static void read_settings(void)
496 if (old_source_host == NULL ||
497 strcmp(old_source_host, settings_get_str("hostname")) != 0) {
498 g_free_not_null(old_source_host);
499 old_source_host = g_strdup(settings_get_str("hostname"));
501 source_host_ok = FALSE;
502 get_source_host_ip();
506 void servers_setup_init(void)
508 settings_add_str("server", "hostname", "");
510 settings_add_str("server", "nick", NULL);
511 settings_add_str("server", "user_name", NULL);
512 settings_add_str("server", "real_name", NULL);
514 settings_add_bool("proxy", "use_proxy", FALSE);
515 settings_add_str("proxy", "proxy_address", "");
516 settings_add_int("proxy", "proxy_port", 6667);
517 settings_add_str("proxy", "proxy_string", "CONNECT %s %d");
518 settings_add_str("proxy", "proxy_string_after", "");
519 settings_add_str("proxy", "proxy_password", "");
522 source_host_ip4 = source_host_ip6 = NULL;
523 old_source_host = NULL;
526 signal_add("setup changed", (SIGNAL_FUNC) read_settings);
527 signal_add("setup reread", (SIGNAL_FUNC) read_servers);
528 signal_add("irssi init read settings", (SIGNAL_FUNC) read_servers);
531 void servers_setup_deinit(void)
533 g_free_not_null(source_host_ip4);
534 g_free_not_null(source_host_ip6);
535 g_free_not_null(old_source_host);
537 while (setupservers != NULL)
538 server_setup_destroy(setupservers->data);
540 signal_remove("setup changed", (SIGNAL_FUNC) read_settings);
541 signal_remove("setup reread", (SIGNAL_FUNC) read_servers);
542 signal_remove("irssi init read settings", (SIGNAL_FUNC) read_servers);
544 module_uniq_destroy("SERVER SETUP");