diff options
Diffstat (limited to 'src/core/server.c')
-rw-r--r-- | src/core/server.c | 273 |
1 files changed, 273 insertions, 0 deletions
diff --git a/src/core/server.c b/src/core/server.c new file mode 100644 index 00000000..dcfefc5a --- /dev/null +++ b/src/core/server.c @@ -0,0 +1,273 @@ +/* + 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 "modules.h" +#include "signals.h" +#include "line-split.h" +#include "net-nonblock.h" +#include "rawlog.h" +#include "misc.h" +#include "server.h" +#include "server-redirect.h" +#include "settings.h" + +GSList *servers, *lookup_servers; + +/* connection to server failed */ +static void server_cant_connect(SERVER_REC *server, const char *msg) +{ + g_return_if_fail(server != NULL); + + 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); + + if (server->connect_pipe[0] != -1) { + close(server->connect_pipe[0]); + close(server->connect_pipe[1]); + } + + MODULE_DATA_DEINIT(server); + g_free(server->tag); + g_free(server->nick); + g_free(server); +} + +/* generate tag from server's address */ +static char *server_create_address_tag(const char *address) +{ + const char *start, *end; + + /* try to generate a reasonable server tag */ + 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; + + tag = conn->ircnet != NULL ? g_strdup(conn->ircnet) : + server_create_address_tag(conn->address); + + /* 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++) + g_string_sprintf(str, "%s%d", tag, num); + g_free(tag); + + tag = str->str; + g_string_free(str, FALSE); + return tag; +} + +static void server_connect_callback_init(SERVER_REC *server, int handle) +{ + int error; + + error = net_geterror(handle); + if (error != 0) { + server->connection_lost = TRUE; + server_cant_connect(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_time = time(NULL); + server->rawlog = rawlog_create(); + servers = g_slist_append(servers, server); + + signal_emit("server connected", 1, server); +} + +static void server_connect_callback_readpipe(SERVER_REC *server, int handle) +{ + SERVER_CONNECT_REC *conn; + RESOLVED_IP_REC iprec; + + g_source_remove(server->connect_tag); + server->connect_tag = -1; + + net_gethostbyname_return(handle, &iprec); + + close(server->connect_pipe[0]); + close(server->connect_pipe[1]); + + server->connect_pipe[0] = -1; + server->connect_pipe[1] = -1; + + conn = server->connrec; + server->handle = iprec.error == -1 ? -1 : + net_connect_ip(&iprec.ip, conn->proxy != NULL ? + conn->proxy_port : conn->port, + conn->own_ip != NULL ? conn->own_ip : NULL); + if (server->handle == -1) { + /* failed */ + server->connection_lost = TRUE; + server_cant_connect(server, + iprec.error != -1 ? g_strerror(errno) : /* connect() failed */ + (iprec.errorstr != NULL ? iprec.errorstr : "Host lookup failed")); /* gethostbyname() failed */ + g_free_not_null(iprec.errorstr); + return; + } + + server->connect_tag = g_input_add(server->handle, G_INPUT_WRITE|G_INPUT_READ, + (GInputFunction) server_connect_callback_init, server); + signal_emit("server connecting", 2, server, &iprec.ip); +} + +int server_connect(SERVER_REC *server) +{ + g_return_val_if_fail(server != NULL, FALSE); + + MODULE_DATA_INIT(server); + + if (pipe(server->connect_pipe) != 0) { + g_warning("server_connect(): pipe() failed."); + return FALSE; + } + + server->tag = server_create_tag(server->connrec); + server->handle = -1; + + server->connect_pid = + net_gethostname_nonblock(server->connrec->proxy != NULL ? + server->connrec->proxy : server->connrec->address, + server->connect_pipe[1]); + + 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; +} + +void server_disconnect(SERVER_REC *server) +{ + g_return_if_fail(server != NULL); + + if (server->connect_tag != -1) { + /* still connecting to server.. */ + if (server->connect_pid != -1) + net_disconnect_nonblock(server->connect_pid); + server_cant_connect(server, NULL); + return; + } + + servers = g_slist_remove(servers, server); + + signal_emit("server disconnected", 1, server); + + if (server->handle != -1) + net_disconnect(server->handle); + + MODULE_DATA_DEINIT(server); + rawlog_destroy(server->rawlog); + line_split_free(server->buffer); + g_free(server->tag); + g_free(server->nick); + g_free(server); +} + +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 (strcmp(server->tag, tag) == 0) + return server; + } + + for (tmp = lookup_servers; tmp != NULL; tmp = tmp->next) { + SERVER_REC *server = tmp->data; + + if (strcmp(server->tag, tag) == 0) + return server; + } + + return NULL; +} + +SERVER_REC *server_find_ircnet(const char *ircnet) +{ + GSList *tmp; + + g_return_val_if_fail(ircnet != NULL, NULL); + if (*ircnet == '\0') return NULL; + + for (tmp = servers; tmp != NULL; tmp = tmp->next) { + SERVER_REC *server = tmp->data; + + if (server->connrec->ircnet != NULL && + strcmp(server->connrec->ircnet, ircnet) == 0) return server; + } + + return NULL; +} + +void servers_init(void) +{ + lookup_servers = servers = NULL; + + servers_redirect_init(); +} + +void servers_deinit(void) +{ + while (servers != NULL) + server_disconnect(servers->data); + while (lookup_servers != NULL) + server_cant_connect(lookup_servers->data, NULL); + + servers_redirect_deinit(); +} |