Merged from silc_1_0_branch.
[silc.git] / apps / irssi / src / core / servers.c
index a5a8c701703005397fb2d62c5ca2451d85169420..f9ab791aabb1f6e1666c1584aa1dcf47dc5d2691 100644 (file)
@@ -110,6 +110,7 @@ static char *server_create_tag(SERVER_CONNECT_REC *conn)
                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
@@ -123,8 +124,13 @@ static char *server_create_tag(SERVER_CONNECT_REC *conn)
 
        /* then just append numbers after tag until unused is found.. */
        str = g_string_new(tag);
-       for (num = 2; server_find_tag(str->str) != NULL; num++)
+
+       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;
@@ -161,16 +167,53 @@ static void server_connect_callback_init(SERVER_REC *server, GIOChannel *handle)
        server_connect_finished(server);
 }
 
-static void server_connect_callback_readpipe(SERVER_REC *server)
+static void server_real_connect(SERVER_REC *server, IPADDR *ip,
+                               const char *unix_socket)
 {
-       SERVER_CONNECT_REC *conn;
-       RESOLVED_IP_REC iprec;
        GIOChannel *handle;
-        IPADDR *ip, *own_ip;
-       const char *errormsg;
+        IPADDR *own_ip;
         int port;
 
-       g_return_if_fail(IS_SERVER(server));
+       g_return_if_fail(ip != NULL || unix_socket != NULL);
+
+       signal_emit("server connecting", 2, server, ip);
+
+       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) :
+                       net_connect_ip(ip, port, own_ip);
+       } else {
+               handle = net_connect_unix(unix_socket);
+       }
+
+       if (handle == NULL) {
+               /* failed */
+               if (server->connrec->use_ssl && errno == ENOSYS)
+                       server->no_reconnect = TRUE;
+
+               server->connection_lost = TRUE;
+               server_connect_failed(server, g_strerror(errno));
+       } 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;
@@ -192,45 +235,41 @@ static void server_connect_callback_readpipe(SERVER_REC *server)
        } 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. */
-               ip = iprec.ip4.family == 0 ||
-                       (iprec.ip6.family != 0 &&
-                        settings_get_bool("resolve_prefer_ipv6")) ?
-                       &iprec.ip6 : &iprec.ip4;
+               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;
+               }
        }
 
-        conn = server->connrec;
-       port = conn->proxy != NULL ? conn->proxy_port : conn->port;
-       own_ip = ip == NULL ? NULL :
-               (IPADDR_IS_V6(ip) ? conn->own_ip6 : conn->own_ip4);
-
-       handle = NULL;
        if (ip != NULL) {
-               signal_emit("server connecting", 2, server, ip);
-                if (server->handle == NULL)
-                       handle = net_connect_ip(ip, port, own_ip);
-               else
-                        handle = net_sendbuffer_handle(server->handle);
-       }
-
-       if (handle == NULL) {
-               /* failed */
-               if (ip == NULL && (iprec.error == 0 ||
-                                  net_hosterror_notfound(iprec.error))) {
-                       /* IP wasn't found for the host, don't try to reconnect
-                          back to this server */
+               /* 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 (ip != NULL) {
-                       /* connect() failed */
-                       errormsg = g_strerror(errno);
-               } else if (iprec.error == 0) {
+               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" :
@@ -240,23 +279,33 @@ static void server_connect_callback_readpipe(SERVER_REC *server)
                        errormsg = iprec.errorstr != NULL ? iprec.errorstr :
                                "Host lookup failed";
                }
+
                server->connection_lost = TRUE;
                server_connect_failed(server, errormsg);
-               g_free_not_null(iprec.errorstr);
-               return;
        }
 
-        if (server->handle == NULL)
-               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);
+       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);
@@ -267,19 +316,20 @@ void server_connect_init(SERVER_REC *server)
        if (server->connrec->username == NULL || *server->connrec->username == '\0') {
                g_free_not_null(server->connrec->username);
 
-               server->connrec->username = g_get_user_name();
-               if (*server->connrec->username == '\0') server->connrec->username = "-";
-               server->connrec->username = g_strdup(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);
 
-               server->connrec->realname = g_get_real_name();
-               if (*server->connrec->realname == '\0') server->connrec->realname = "-";
-               server->connrec->realname = g_strdup(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 */
@@ -289,49 +339,64 @@ int server_start_connect(SERVER_REC *server)
         int fd[2];
 
        g_return_val_if_fail(server != NULL, FALSE);
-       if (server->connrec->port <= 0) return FALSE;
-
-       server_connect_init(server);
-
-       if (pipe(fd) != 0) {
-               g_warning("server_connect(): pipe() failed.");
-                g_free(server->tag);
-               g_free(server->nick);
+       if (!server->connrec->unix_socket && server->connrec->port <= 0)
                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]);
-       server->connect_tag =
-               g_input_add(server->connect_pipe[0], G_INPUT_READ,
-                           (GInputFunction) server_connect_callback_readpipe,
-                           server);
        server->rawlog = rawlog_create();
 
-       lookup_servers = g_slist_append(lookup_servers, server);
+       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);
 
-       signal_emit("server looking", 1, 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;
+       GSList *tmp, *next;
        int found;
 
        g_return_val_if_fail(server != NULL, FALSE);
 
        found = FALSE;
-       for (tmp = server->channels; tmp != NULL; tmp = tmp->next) {
+       for (tmp = server->channels; tmp != NULL; tmp = next) {
                CHANNEL_REC *channel = tmp->data;
 
-               channel->server = NULL;
+               next = tmp->next;
                channel_destroy(channel);
                found = TRUE;
        }
@@ -439,6 +504,16 @@ SERVER_REC *server_find_tag(const char *tag)
                        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;
 
@@ -485,6 +560,9 @@ void server_connect_unref(SERVER_CONNECT_REC *conn)
 
         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);
@@ -603,6 +681,7 @@ static void sig_chat_protocol_deinit(CHAT_PROTOCOL_REC *proto)
 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);