Created SILC Runtime Toolkit git repository Part I.
[runtime.git] / apps / irssi / src / core / servers.c
diff --git a/apps/irssi/src/core/servers.c b/apps/irssi/src/core/servers.c
deleted file mode 100644 (file)
index ca18914..0000000
+++ /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");
-}