X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=apps%2Firssi%2Fsrc%2Fcore%2Fservers.c;fp=apps%2Firssi%2Fsrc%2Fcore%2Fservers.c;h=0000000000000000000000000000000000000000;hb=72c2de619079457f7a68100eb13385275a424a23;hp=ca18914ae79259994f62faaf00f3f6e4cab23ee6;hpb=e7b6c157b80152bf9fb9266e6bdd93f9fb0db776;p=runtime.git diff --git a/apps/irssi/src/core/servers.c b/apps/irssi/src/core/servers.c deleted file mode 100644 index ca18914a..00000000 --- a/apps/irssi/src/core/servers.c +++ /dev/null @@ -1,725 +0,0 @@ -/* - server.c : irssi - - Copyright (C) 1999-2000 Timo Sirainen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#include "module.h" -#include "signals.h" -#include "commands.h" -#include "line-split.h" -#include "net-nonblock.h" -#include "net-sendbuffer.h" -#include "misc.h" -#include "rawlog.h" -#include "settings.h" - -#include "chat-protocols.h" -#include "servers.h" -#include "servers-reconnect.h" -#include "servers-setup.h" -#include "channels.h" -#include "queries.h" - -GSList *servers, *lookup_servers; - -/* connection to server failed */ -void server_connect_failed(SERVER_REC *server, const char *msg) -{ - g_return_if_fail(IS_SERVER(server)); - - lookup_servers = g_slist_remove(lookup_servers, server); - - signal_emit("server connect failed", 2, server, msg); - - if (server->connect_tag != -1) { - g_source_remove(server->connect_tag); - server->connect_tag = -1; - } - if (server->handle != NULL) { - net_sendbuffer_destroy(server->handle, TRUE); - server->handle = NULL; - } - - if (server->connect_pipe[0] != NULL) { - g_io_channel_close(server->connect_pipe[0]); - g_io_channel_unref(server->connect_pipe[0]); - g_io_channel_close(server->connect_pipe[1]); - g_io_channel_unref(server->connect_pipe[1]); - server->connect_pipe[0] = NULL; - server->connect_pipe[1] = NULL; - } - - server_unref(server); -} - -/* generate tag from server's address */ -static char *server_create_address_tag(const char *address) -{ - const char *start, *end; - - g_return_val_if_fail(address != NULL, NULL); - - /* try to generate a reasonable server tag */ - if (strchr(address, '.') == NULL) { - start = end = NULL; - } else if (g_strncasecmp(address, "irc", 3) == 0 || - g_strncasecmp(address, "chat", 4) == 0) { - /* irc-2.cs.hut.fi -> hut, chat.bt.net -> bt */ - end = strrchr(address, '.'); - start = end-1; - while (start > address && *start != '.') start--; - } else { - /* efnet.cs.hut.fi -> efnet */ - end = strchr(address, '.'); - start = end; - } - - if (start == end) start = address; else start++; - if (end == NULL) end = address + strlen(address); - - return g_strndup(start, (int) (end-start)); -} - -/* create unique tag for server. prefer ircnet's name or - generate it from server's address */ -static char *server_create_tag(SERVER_CONNECT_REC *conn) -{ - GString *str; - char *tag; - int num; - - g_return_val_if_fail(IS_SERVER_CONNECT(conn), NULL); - - tag = conn->chatnet != NULL && *conn->chatnet != '\0' ? - g_strdup(conn->chatnet) : - server_create_address_tag(conn->address); - - if (conn->tag != NULL && server_find_tag(conn->tag) == NULL && - server_find_lookup_tag(conn->tag) == NULL && - strncmp(conn->tag, tag, strlen(tag)) == 0) { - /* use the existing tag if it begins with the same ID - - this is useful when you have several connections to - same server and you want to keep the same tags with - the servers (or it would cause problems when rejoining - /LAYOUT SAVEd channels). */ - g_free(tag); - return g_strdup(conn->tag); - } - - - /* then just append numbers after tag until unused is found.. */ - str = g_string_new(tag); - - num = 2; - while (server_find_tag(str->str) != NULL || - server_find_lookup_tag(str->str) != NULL) { - g_string_sprintf(str, "%s%d", tag, num); - num++; - } - g_free(tag); - - tag = str->str; - g_string_free(str, FALSE); - return tag; -} - -/* Connection to server finished, fill the rest of the fields */ -void server_connect_finished(SERVER_REC *server) -{ - server->connect_time = time(NULL); - - servers = g_slist_append(servers, server); - signal_emit("server connected", 1, server); -} - -static void server_connect_callback_init(SERVER_REC *server, GIOChannel *handle) -{ - int error; - - g_return_if_fail(IS_SERVER(server)); - - error = net_geterror(handle); - if (error != 0) { - server->connection_lost = TRUE; - server_connect_failed(server, g_strerror(error)); - return; - } - - lookup_servers = g_slist_remove(lookup_servers, server); - g_source_remove(server->connect_tag); - server->connect_tag = -1; - - server_connect_finished(server); -} - -static void server_real_connect(SERVER_REC *server, IPADDR *ip, - const char *unix_socket) -{ - GIOChannel *handle; - IPADDR *own_ip = NULL; - const char *errmsg; - char *errmsg2; - char ipaddr[MAX_IP_LEN]; - int port; - - g_return_if_fail(ip != NULL || unix_socket != NULL); - - signal_emit("server connecting", 2, server, ip); - - if (server->connrec->no_connect) - return; - - if (ip != NULL) { - own_ip = ip == NULL ? NULL : - (IPADDR_IS_V6(ip) ? server->connrec->own_ip6 : - server->connrec->own_ip4); - port = server->connrec->proxy != NULL ? - server->connrec->proxy_port : server->connrec->port; - handle = server->connrec->use_ssl ? - net_connect_ip_ssl(ip, port, own_ip, server->connrec->ssl_cert, server->connrec->ssl_pkey, -server->connrec->ssl_cafile, server->connrec->ssl_capath, server->connrec->ssl_verify) : - net_connect_ip(ip, port, own_ip); - } else { - handle = net_connect_unix(unix_socket); - } - - if (handle == NULL) { - /* failed */ - errmsg = g_strerror(errno); - errmsg2 = NULL; - if (errno == EADDRNOTAVAIL) { - if (own_ip != NULL) { - /* show the IP which is causing the error */ - net_ip2host(own_ip, ipaddr); - errmsg2 = g_strconcat(errmsg, ": ", ipaddr, NULL); - } - server->no_reconnect = TRUE; - } - if (server->connrec->use_ssl && errno == ENOSYS) - server->no_reconnect = TRUE; - - server->connection_lost = TRUE; - server_connect_failed(server, errmsg2 ? errmsg2 : errmsg); - g_free(errmsg2); - } else { - server->handle = net_sendbuffer_create(handle, 0); - server->connect_tag = - g_input_add(handle, G_INPUT_WRITE | G_INPUT_READ, - (GInputFunction) - server_connect_callback_init, - server); - } -} - -static void server_connect_callback_readpipe(SERVER_REC *server) -{ - RESOLVED_IP_REC iprec; - IPADDR *ip; - const char *errormsg; - char *servername = NULL; - - g_source_remove(server->connect_tag); - server->connect_tag = -1; - - net_gethostbyname_return(server->connect_pipe[0], &iprec); - - g_io_channel_close(server->connect_pipe[0]); - g_io_channel_unref(server->connect_pipe[0]); - g_io_channel_close(server->connect_pipe[1]); - g_io_channel_unref(server->connect_pipe[1]); - - server->connect_pipe[0] = NULL; - server->connect_pipe[1] = NULL; - - /* figure out if we should use IPv4 or v6 address */ - if (iprec.error != 0) { - /* error */ - ip = NULL; - } else if (server->connrec->family == AF_INET) { - /* force IPv4 connection */ - ip = iprec.ip4.family == 0 ? NULL : &iprec.ip4; - servername = iprec.host4; - } else if (server->connrec->family == AF_INET6) { - /* force IPv6 connection */ - ip = iprec.ip6.family == 0 ? NULL : &iprec.ip6; - servername = iprec.host6; - } else { - /* pick the one that was found, or if both do it like - /SET resolve_prefer_ipv6 says. */ - if (iprec.ip4.family == 0 || - (iprec.ip6.family != 0 && - settings_get_bool("resolve_prefer_ipv6"))) { - ip = &iprec.ip6; - servername = iprec.host6; - } else { - ip = &iprec.ip4; - servername = iprec.host4; - } - } - - if (ip != NULL) { - /* host lookup ok */ - if (servername) { - g_free(server->connrec->address); - server->connrec->address = g_strdup(servername); - } - server_real_connect(server, ip, NULL); - errormsg = NULL; - } else { - if (iprec.error == 0 || net_hosterror_notfound(iprec.error)) { - /* IP wasn't found for the host, don't try to - reconnect back to this server */ - server->dns_error = TRUE; - } - - if (iprec.error == 0) { - /* forced IPv4 or IPv6 address but it wasn't found */ - errormsg = server->connrec->family == AF_INET ? - "IPv4 address not found for host" : - "IPv6 address not found for host"; - } else { - /* gethostbyname() failed */ - errormsg = iprec.errorstr != NULL ? iprec.errorstr : - "Host lookup failed"; - } - - server->connection_lost = TRUE; - server_connect_failed(server, errormsg); - } - - g_free(iprec.errorstr); - g_free(iprec.host4); - g_free(iprec.host6); -} - -SERVER_REC *server_connect(SERVER_CONNECT_REC *conn) -{ - CHAT_PROTOCOL_REC *proto; - SERVER_REC *server; - - proto = CHAT_PROTOCOL(conn); - server = proto->server_init_connect(conn); - proto->server_connect(server); - - return server; -} - -/* initializes server record but doesn't start connecting */ -void server_connect_init(SERVER_REC *server) -{ - const char *str; - - g_return_if_fail(server != NULL); - - MODULE_DATA_INIT(server); - server->type = module_get_uniq_id("SERVER", 0); - server_ref(server); - - server->nick = g_strdup(server->connrec->nick); - if (server->connrec->username == NULL || *server->connrec->username == '\0') { - g_free_not_null(server->connrec->username); - - str = g_get_user_name(); - if (*str == '\0') str = "unknown"; - server->connrec->username = g_strdup(str); - } - if (server->connrec->realname == NULL || *server->connrec->realname == '\0') { - g_free_not_null(server->connrec->realname); - - str = g_get_real_name(); - if (*str == '\0') str = server->connrec->username; - server->connrec->realname = g_strdup(str); - } - - server->tag = server_create_tag(server->connrec); - server->connect_tag = -1; -} - -/* starts connecting to server */ -int server_start_connect(SERVER_REC *server) -{ - const char *connect_address; - int fd[2]; - - g_return_val_if_fail(server != NULL, FALSE); - if (!server->connrec->unix_socket && server->connrec->port <= 0) - return FALSE; - - server->rawlog = rawlog_create(); - - if (server->connrec->connect_handle != NULL) { - /* already connected */ - GIOChannel *handle = server->connrec->connect_handle; - - server->connrec->connect_handle = NULL; - server->handle = net_sendbuffer_create(handle, 0); - server_connect_finished(server); - } else if (server->connrec->unix_socket) { - /* connect with unix socket */ - server_real_connect(server, NULL, server->connrec->address); - } else { - /* resolve host name */ - if (pipe(fd) != 0) { - g_warning("server_connect(): pipe() failed."); - g_free(server->tag); - g_free(server->nick); - return FALSE; - } - - server->connect_pipe[0] = g_io_channel_unix_new(fd[0]); - server->connect_pipe[1] = g_io_channel_unix_new(fd[1]); - - connect_address = server->connrec->proxy != NULL ? - server->connrec->proxy : server->connrec->address; - server->connect_pid = - net_gethostbyname_nonblock(connect_address, - server->connect_pipe[1], - settings_get_bool("resolve_reverse_lookup")); - server->connect_tag = - g_input_add(server->connect_pipe[0], G_INPUT_READ, - (GInputFunction) - server_connect_callback_readpipe, - server); - - lookup_servers = g_slist_append(lookup_servers, server); - - signal_emit("server looking", 1, server); - } - return TRUE; -} - -static int server_remove_channels(SERVER_REC *server) -{ - GSList *tmp, *next; - int found; - - g_return_val_if_fail(server != NULL, FALSE); - - found = FALSE; - for (tmp = server->channels; tmp != NULL; tmp = next) { - CHANNEL_REC *channel = tmp->data; - - next = tmp->next; - channel_destroy(channel); - found = TRUE; - } - - while (server->queries != NULL) - query_change_server(server->queries->data, NULL); - - g_slist_free(server->channels); - g_slist_free(server->queries); - - return found; -} - -void server_disconnect(SERVER_REC *server) -{ - int chans; - - g_return_if_fail(IS_SERVER(server)); - - if (server->disconnected) - return; - - if (server->connect_tag != -1) { - /* still connecting to server.. */ - if (server->connect_pid != -1) - net_disconnect_nonblock(server->connect_pid); - server_connect_failed(server, NULL); - return; - } - - servers = g_slist_remove(servers, server); - - server->disconnected = TRUE; - signal_emit("server disconnected", 1, server); - - /* close all channels */ - chans = server_remove_channels(server); - - if (server->handle != NULL) { - if (!chans || server->connection_lost) - net_sendbuffer_destroy(server->handle, TRUE); - else { - /* we were on some channels, try to let the server - disconnect so that our quit message is guaranteed - to get displayed */ - net_disconnect_later(net_sendbuffer_handle(server->handle)); - net_sendbuffer_destroy(server->handle, FALSE); - } - server->handle = NULL; - } - - if (server->readtag > 0) { - g_source_remove(server->readtag); - server->readtag = -1; - } - - server_unref(server); -} - -void server_ref(SERVER_REC *server) -{ - g_return_if_fail(IS_SERVER(server)); - - server->refcount++; -} - -int server_unref(SERVER_REC *server) -{ - g_return_val_if_fail(IS_SERVER(server), FALSE); - - if (--server->refcount > 0) - return TRUE; - - if (g_slist_find(servers, server) != NULL) { - g_warning("Non-referenced server wasn't disconnected"); - server_disconnect(server); - return TRUE; - } - - MODULE_DATA_DEINIT(server); - server_connect_unref(server->connrec); - if (server->rawlog != NULL) rawlog_destroy(server->rawlog); - if (server->buffer != NULL) line_split_free(server->buffer); - g_free(server->version); - g_free(server->away_reason); - g_free(server->nick); - g_free(server->tag); - - server->type = 0; - g_free(server); - return FALSE; -} - -SERVER_REC *server_find_tag(const char *tag) -{ - GSList *tmp; - - g_return_val_if_fail(tag != NULL, NULL); - if (*tag == '\0') return NULL; - - for (tmp = servers; tmp != NULL; tmp = tmp->next) { - SERVER_REC *server = tmp->data; - - if (g_strcasecmp(server->tag, tag) == 0) - return server; - } - - return NULL; -} - -SERVER_REC *server_find_lookup_tag(const char *tag) -{ - GSList *tmp; - - g_return_val_if_fail(tag != NULL, NULL); - if (*tag == '\0') return NULL; - - for (tmp = lookup_servers; tmp != NULL; tmp = tmp->next) { - SERVER_REC *server = tmp->data; - - if (g_strcasecmp(server->tag, tag) == 0) - return server; - } - - return NULL; -} - -SERVER_REC *server_find_chatnet(const char *chatnet) -{ - GSList *tmp; - - g_return_val_if_fail(chatnet != NULL, NULL); - if (*chatnet == '\0') return NULL; - - for (tmp = servers; tmp != NULL; tmp = tmp->next) { - SERVER_REC *server = tmp->data; - - if (server->connrec->chatnet != NULL && - g_strcasecmp(server->connrec->chatnet, chatnet) == 0) - return server; - } - - return NULL; -} - -void server_connect_ref(SERVER_CONNECT_REC *conn) -{ - conn->refcount++; -} - -void server_connect_unref(SERVER_CONNECT_REC *conn) -{ - g_return_if_fail(IS_SERVER_CONNECT(conn)); - - if (--conn->refcount > 0) - return; - if (conn->refcount < 0) { - g_warning("Connection '%s' refcount = %d", - conn->tag, conn->refcount); - } - - CHAT_PROTOCOL(conn)->destroy_server_connect(conn); - - if (conn->connect_handle != NULL) - net_disconnect(conn->connect_handle); - - g_free_not_null(conn->proxy); - g_free_not_null(conn->proxy_string); - g_free_not_null(conn->proxy_string_after); - g_free_not_null(conn->proxy_password); - - g_free_not_null(conn->tag); - g_free_not_null(conn->address); - g_free_not_null(conn->chatnet); - - g_free_not_null(conn->own_ip4); - g_free_not_null(conn->own_ip6); - - g_free_not_null(conn->password); - g_free_not_null(conn->nick); - g_free_not_null(conn->username); - g_free_not_null(conn->realname); - - g_free_not_null(conn->ssl_cert); - g_free_not_null(conn->ssl_pkey); - g_free_not_null(conn->ssl_cafile); - g_free_not_null(conn->ssl_capath); - - g_free_not_null(conn->channels); - g_free_not_null(conn->away_reason); - - conn->type = 0; - g_free(conn); -} - -void server_change_nick(SERVER_REC *server, const char *nick) -{ - g_free(server->nick); - server->nick = g_strdup(nick); - - signal_emit("server nick changed", 1, server); -} - -/* Update own IPv4 and IPv6 records */ -void server_connect_own_ip_save(SERVER_CONNECT_REC *conn, - IPADDR *ip4, IPADDR *ip6) -{ - if (ip4 == NULL || ip4->family == 0) - g_free_and_null(conn->own_ip4); - if (ip6 == NULL || ip6->family == 0) - g_free_and_null(conn->own_ip6); - - if (ip4 != NULL && ip4->family != 0) { - /* IPv4 address was found */ - if (conn->own_ip4 == NULL) - conn->own_ip4 = g_new0(IPADDR, 1); - memcpy(conn->own_ip4, ip4, sizeof(IPADDR)); - } - - if (ip6 != NULL && ip6->family != 0) { - /* IPv6 address was found */ - if (conn->own_ip6 == NULL) - conn->own_ip6 = g_new0(IPADDR, 1); - memcpy(conn->own_ip6, ip6, sizeof(IPADDR)); - } -} - -/* `optlist' should contain only one unknown key - the server tag. - returns NULL if there was unknown -option */ -SERVER_REC *cmd_options_get_server(const char *cmd, - GHashTable *optlist, - SERVER_REC *defserver) -{ - SERVER_REC *server; - GSList *list, *tmp, *next; - - /* get all the options, then remove the known ones. there should - be only one left - the server tag. */ - list = hashtable_get_keys(optlist); - if (cmd != NULL) { - for (tmp = list; tmp != NULL; tmp = next) { - char *option = tmp->data; - next = tmp->next; - - if (command_have_option(cmd, option)) - list = g_slist_remove(list, option); - } - } - - if (list == NULL) - return defserver; - - server = server_find_tag(list->data); - if (server == NULL || list->next != NULL) { - /* unknown option (not server tag) */ - signal_emit("error command", 2, - GINT_TO_POINTER(CMDERR_OPTION_UNKNOWN), - server == NULL ? list->data : list->next->data); - signal_stop(); - - server = NULL; - } - - g_slist_free(list); - return server; -} - -static void disconnect_servers(GSList *servers, int chat_type) -{ - GSList *tmp, *next; - - for (tmp = servers; tmp != NULL; tmp = next) { - SERVER_REC *rec = tmp->data; - - next = tmp->next; - if (rec->chat_type == chat_type) - server_disconnect(rec); - } -} - -static void sig_chat_protocol_deinit(CHAT_PROTOCOL_REC *proto) -{ - disconnect_servers(servers, proto->id); - disconnect_servers(lookup_servers, proto->id); -} - -void servers_init(void) -{ - settings_add_bool("server", "resolve_prefer_ipv6", FALSE); - settings_add_bool("server", "resolve_reverse_lookup", FALSE); - lookup_servers = servers = NULL; - - signal_add("chat protocol deinit", (SIGNAL_FUNC) sig_chat_protocol_deinit); - - servers_reconnect_init(); - servers_setup_init(); -} - -void servers_deinit(void) -{ - signal_remove("chat protocol deinit", (SIGNAL_FUNC) sig_chat_protocol_deinit); - - servers_setup_deinit(); - servers_reconnect_deinit(); - - module_uniq_destroy("SERVER"); - module_uniq_destroy("SERVER CONNECT"); -}