/* * server.c: Things dealing with server connections, etc. * * Written By Michael Sandrof * * Copyright(c) 1990 * * See the COPYRIGHT file, or do a HELP IRCII COPYRIGHT */ #ifdef IRIX #define _HAVE_SIN_LEN 1 #define _HAVE_SA_LEN 1 #define MAXDNAME 100 #endif #include "irc.h" static char cvsrevision[] = "$Id: server.c,v 1.1.1.2 2003/06/11 07:00:43 root Exp $"; CVS_REVISION(server_c) #include "struct.h" #include "parse.h" #include #include "server.h" #include "commands.h" #include "ircaux.h" #include "input.h" #include "who.h" #include "lastlog.h" #include "exec.h" #include "window.h" #include "output.h" #include "names.h" #include "hook.h" #include "vars.h" #include "hash2.h" #include "screen.h" #include "notify.h" #include "misc.h" #include "status.h" #include "list.h" #include "who.h" #define MAIN_SOURCE #include "modval.h" #ifdef WDIDENT #include #include #include #endif #ifdef IRIX #undef sa_len #endif static char * set_umode (int du_index); const char * umodes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; /* server_list: the list of servers that the user can connect to,etc */ Server *server_list = NULL; /* number_of_servers: in the server list */ static int number_of_servers = 0; int primary_server = -1; int from_server = -1; int never_connected = 1; /* true until first connection * is made */ int connected_to_server = 0; /* true when connection is * confirmed */ int parsing_server_index = -1; int last_server = -1; extern int dgets_errno; int identd = -1; #if defined(WINNT) || defined(__EMX__) || defined(__CYGWIN__) || defined(WANT_IDENTD) int already_identd = 0; #endif /* link look and map commands */ irc_server *map = NULL; static int first_time = 0; extern char *channel; int (*serv_open_func) (int, struct sockaddr_foobar, int) = NULL; int (*serv_output_func) (int, int, char *, int) = NULL; int (*serv_input_func) (int, char *, int, int, int) = NULL; int (*serv_close_func) (int, struct sockaddr_foobar, int) = NULL; static QueueSend *serverqueue = NULL; /* * close_server: Given an index into the server list, this closes the * connection to the corresponding server. It does no checking on the * validity of the index. It also first sends a "QUIT" to the server being * closed */ void BX_close_server (int cs_index, char *message) { char buffer[BIG_BUFFER_SIZE/4 + 1]; if (cs_index < 0 || cs_index > number_of_servers) return; #ifdef HAVE_SSL if (get_server_ssl(cs_index) && server_list[cs_index].ssl_fd) { say("Closing SSL connection"); SSL_shutdown(server_list[cs_index].ssl_fd); } #endif if (serv_close_func) (*serv_close_func)(cs_index, server_list[cs_index].local_addr, server_list[cs_index].port); clean_server_queues(from_server); if (waiting_out > waiting_in) waiting_out = waiting_in = 0; if (get_server_reconnecting(cs_index)) set_waiting_channel(cs_index); else clear_channel_list(cs_index); clear_link(&server_list[cs_index].server_last); clear_link(&server_list[cs_index].tmplink); clear_server_sping(cs_index, NULL); set_server_reconnect(cs_index, 0); set_server_reconnecting(cs_index, 0); set_server_try_once(cs_index, 0); server_list[cs_index].server_change_pending = 0; server_list[cs_index].operator = 0; server_list[cs_index].connected = 0; server_list[cs_index].buffer = NULL; server_list[cs_index].link_look = 0; server_list[cs_index].login_flags = 0; server_list[cs_index].awaytime = 0; new_free(&server_list[cs_index].away); if (server_list[cs_index].write > -1) { if (message && *message && !server_list[cs_index].closing) { server_list[cs_index].closing = 1; if (x_debug & DEBUG_OUTBOUND) yell("Closing server %d because [%s]", cs_index, message ? message : empty_string); snprintf(buffer, BIG_BUFFER_SIZE, "QUIT :%s\n", message); #ifdef HAVE_SSL if (get_server_ssl(cs_index)) SSL_write(server_list[cs_index].ssl_fd, buffer, strlen(buffer)); else #endif send(server_list[cs_index].write, buffer, strlen(buffer), 0); } new_close(server_list[cs_index].write); } if (server_list[cs_index].read > -1) new_close(server_list[cs_index].read); server_list[cs_index].write = server_list[cs_index].read = -1; if (identd != -1) set_socketflags(identd, 0); #if defined(WINNT) || defined(__EMX__) || defined(CYGWIN) || defined(WANT_IDENTD) already_identd = 0; #endif } int close_all_servers(char *message) { int i; for (i = 0; i < number_of_servers; i++) { set_server_reconnecting(i, 0); close_server(i, message); } return 0; } /* * Check if the server that has a connection pending * has any windows that are going to switch over when * it connects. If not abort the connection attempt. */ void close_unattached_server(int server) { #ifdef NON_BLOCKING_CONNECTS Window *tmp = NULL; int cnt = 0; if(server < 0 || server_list[server].old_server < 0) return; while ((traverse_all_windows(&tmp))) { if (tmp->server == -1) cnt++; } if (cnt == 0) close_server(server, empty_string); #endif } void close_unattached_servers(void) { int i; for (i = 0; i < number_of_servers; i++) { if(server_list[i].old_server == -2 || #ifdef NON_BLOCKING_CONNECTS server_list[i].server_change_pending || #endif server_list[i].reconnecting) close_server(i, empty_string); } } /* * set_server_bits: Sets the proper bits in the fd_set structure according to * which servers in the server list have currently active read descriptors. */ long set_server_bits (fd_set *rd, fd_set *wr) { int i; long timeout = 0; for (i = 0; i < number_of_servers; i++) { if (server_list[i].reconnect > 0) { /* CONNECT_DELAY is in seconds but we must * return in milliseconds. */ timeout = get_int_var(CONNECT_DELAY_VAR)*1000; if(!timeout) timeout = -1; } if (server_list[i].read > -1) FD_SET(server_list[i].read, rd); #ifdef NON_BLOCKING_CONNECTS if (!(server_list[i].login_flags & (LOGGED_IN|CLOSE_PENDING)) && server_list[i].write > -1) FD_SET(server_list[i].write, wr); #endif } return timeout; } int timed_server (void *args, char *sub) { char *p = (char *)args; static int retry = 0; int serv = -1; if (!p || !*p) return 0; serv = atol(p); new_free(&p); if (!is_server_open(serv) && number_of_servers) { bitchsay("Servers exhausted. Restarting. [%d]", ++retry); get_connected(serv, from_server); } set_server_in_timed(serv, 0); return 0; } int find_old_server(int old_server) { int i; if(old_server > -1 && old_server < number_of_servers) { for (i = 0; i < number_of_servers; i++) { if(server_list[i].old_server == old_server) return i; } } return -1; } int advance_server(int i) { int server = i; /* We were waiting for this server to * connect and it didn't, so we will either * try again or move to the next server. */ server_list[i].retries++; if(server_list[i].retries >= get_int_var(MAX_SERVER_RECONNECT_VAR)) { server = next_server(i); if(server != i) { /* We have a new server to try, so lets * move the variables over from the last one * and tell it to try to connect. */ set_server_reconnect(server, 1); set_server_req_server(server, server_list[i].req_server); set_server_old_server(server, server_list[i].old_server); set_server_change_refnum(server, server_list[i].server_change_refnum); set_server_retries(server, 0); #ifdef NON_BLOCKING_CONNECTS server_list[server].from_server = server_list[i].from_server; server_list[server].c_server = server_list[i].c_server; #endif /* Reset the old server to the default state. */ server_list[i].retries = 0; server_list[i].reconnect = 0; server_list[i].old_server = -1; server_list[i].req_server = -1; #ifdef NON_BLOCKING_CONNECTS server_list[i].connect_wait = 0; server_list[i].from_server = -1; server_list[i].c_server = -1; #endif } } if(!get_int_var(AUTO_RECONNECT_VAR) && (server_list[server].req_server != server || server_list[server].retries > 1)) { close_server(server, empty_string); clean_server_queues(server); from_server = -1; if(do_hook(DISCONNECT_LIST,"No Connection")) put_it("%s", convert_output_format(fget_string_var(FORMAT_DISCONNECT_FSET), "%s %s", update_clock(GET_TIME), "No connection")); return -1; } else if(server == server_list[i].req_server && server_list[server].retries > 1) bitchsay("Servers exhausted. Restarting."); return server; } void reconnect_server(int *servernum, int *times, time_t *last_timeout) { int orig; if(*servernum < 0) *servernum = 0; orig = *servernum; server_list[*servernum].reconnecting = 1; close_server(*servernum, empty_string); *last_timeout = 0; (*servernum) = advance_server(*servernum); if(*servernum < 0) return; if(*servernum != orig) *times = 1; set_server_reconnect(*servernum, 0); window_check_servers(*servernum); try_connect(*servernum, server_list[*servernum].old_server); } /* Check for a nonblocking connection that has been around * for more than CONNECT_TIMEOUT_VAR seconds without connecting */ #ifdef NON_BLOCKING_CONNECTS static void scan_nonblocking(void) { int i; int connect_timeout = get_int_var(CONNECT_TIMEOUT_VAR); if (!connect_timeout) return; for (i = 0; i < number_of_servers; i++) { if (((server_list[i].read > -1) || (server_list[i].write > -1)) && !(server_list[i].login_flags & LOGGED_IN) && (time(NULL) - server_list[i].connect_time > connect_timeout)) { if (server_list[i].read > -1) new_close(server_list[i].read); if (server_list[i].write > -1) new_close(server_list[i].write); server_list[i].read = server_list[i].write = -1; set_server_reconnect(i, 1); } } } #endif void do_idle_server (void) { int i; static int times = 1; static time_t last_timeout = 0; #ifdef NON_BLOCKING_CONNECTS scan_nonblocking(); #endif for (i = 0; i < number_of_servers && i > -1; i++) { /* We were told to reconnect, to avoid recursion. */ if(get_server_reconnect(i) > 0) { int connect_delay = get_int_var(CONNECT_DELAY_VAR); if(!connect_delay || (time(NULL) - server_list[i].connect_time) > connect_delay) { int servernum = i; set_server_reconnect(i, 0); reconnect_server(&servernum, ×, &last_timeout); } } } } /* * do_server: check the given fd_set against the currently open servers in * the server list. If one have information available to be read, it is read * and and parsed appropriately. If an EOF is detected from an open server, * one of two things occurs. 1) If the server was the primary server, * get_connected() is called to maintain the connection status of the user. * 2) If the server wasn't a primary server, connect_to_server() is called to * try to keep that connection alive. */ void do_server (fd_set *rd, fd_set *wr) { char buffer[BIG_BUFFER_SIZE + 1]; int des, i; static int times = 1; static time_t last_timeout = 0; #ifdef NON_BLOCKING_CONNECTS scan_nonblocking(); #endif for (i = 0; i < number_of_servers; i++) { /* We were told to reconnect, to avoid recursion. */ if(get_server_reconnect(i) > 0) { int connect_delay = get_int_var(CONNECT_DELAY_VAR); if(!connect_delay || (time(NULL) - server_list[i].connect_time) > connect_delay) { int servernum = i; set_server_reconnect(i, 0); reconnect_server(&servernum, ×, &last_timeout); } } #ifdef NON_BLOCKING_CONNECTS if (((des = server_list[i].write) > -1) && FD_ISSET(des, wr) && !(server_list[i].login_flags & LOGGED_IN)) { struct sockaddr_in sa; int salen = sizeof(struct sockaddr_in); if (getpeername(des, (struct sockaddr *) &sa, &salen) != -1) { #ifdef HAVE_SSL if(!server_list[i].ctx || server_list[i].ssl_error == SSL_ERROR_WANT_WRITE) { #endif server_list[i].connect_wait = 0; finalize_server_connect(i, server_list[i].c_server, i); #ifdef HAVE_SSL } #endif } } #endif if (((des = server_list[i].read) > -1) && FD_ISSET(des, rd)) { int junk = 0; char *bufptr; errno = 0; last_server = from_server = i; bufptr = buffer; if (serv_input_func) junk = (*serv_input_func)(i, bufptr, des, 1, BIG_BUFFER_SIZE); else { #ifdef HAVE_SSL if(get_server_ssl(i)) { #ifdef NON_BLOCKING_CONNECTS /* If we get here before getting above we have problems. */ if(!(server_list[i].login_flags & LOGGED_IN)) { if(!server_list[i].ctx || server_list[i].ssl_error == SSL_ERROR_WANT_READ) { server_list[i].connect_wait = 0; finalize_server_connect(i, server_list[i].c_server, i); } } else #endif junk = dgets(bufptr, des, 1, BIG_BUFFER_SIZE, server_list[i].ssl_fd); } else #endif junk = dgets(bufptr, des, 1, BIG_BUFFER_SIZE, NULL); } switch (junk) { case 0: /* timeout */ break; case -1: /* EOF condition */ { int try_once = server_list[i].try_once; /* Try to make sure output goes to the correct window */ if(server_list[i].server_change_refnum > -1) set_display_target_by_winref(server_list[i].server_change_refnum); say("Connection closed from %s: %s", server_list[i].name, (dgets_errno == -1) ? "Remote end closed connection" : strerror(dgets_errno)); server_list[i].reconnecting = 1; close_server(i, empty_string); if(!try_once) { #ifdef NON_BLOCKING_CONNECTS if(server_list[i].server_change_pending == 2) { /* If the previous server gets closed while * we are waiting for another server to connect * we don't want to try a new connection, so * just close down this connection and quit. */ close_server(i, empty_string); } else if(server_list[i].connect_wait) { set_server_reconnect(i, 1); if ((server_list[i].from_server != -1)) { if((server_list[server_list[i].from_server].read != -1) && (server_list[i].from_server != i)) { /* Set the windows back to the old server */ say("Connection to server %s resumed...", server_list[server_list[i].from_server].name); change_server_channels(i, server_list[i].old_server); set_window_server(-1, i, 1); set_server_reconnect(i, 0); } else if(server_list[i].from_server != i) { close_server(server_list[i].from_server, empty_string); } } } else #endif { set_server_reconnect(i, 1); server_list[i].old_server = i; } } break; } default: { last_timeout = 0; parsing_server_index = i; server_list[i].last_msg = now; parse_server(buffer); new_free(&server_list[i].buffer); parsing_server_index = -1; reset_display_target(); break; } } from_server = primary_server; } if (primary_server == -1 || !is_server_open(primary_server)) window_check_servers(-1); if (server_list[i].read != -1 && (errno == ENETUNREACH || errno == EHOSTUNREACH)) { if (last_timeout == 0) last_timeout = now; else if (now - last_timeout > 600) { close_server(i, empty_string); server_list[i].reconnecting = 1; get_connected(i, -1); } } } } /* * find_in_server_list: given a server name, this tries to match it against * names in the server list, returning the index into the list if found, or * -1 if not found */ extern int BX_find_in_server_list (char *server, int port) { int i, len, hintfound = -1; len = strlen(server); for (i = 0; i < number_of_servers; i++) { if (port && server_list[i].port && port != server_list[i].port && port != -1) continue; #if 0 #define MATCH_WITH_COMPLETION(n1, n2) \ { \ size_t l1 = strlen(n1); \ size_t l2 = strlen(n2); \ size_t l3 = l1 > l2 ? l2 : l1; \ \ if (!my_strnicmp(n1, n2, l3)) \ return i; \ } MATCH_WITH_COMPLETION(server, server_list[i].name); if (!server_list[i].itsname) continue; MATCH_WITH_COMPLETION(server, server_list[i].itsname); #endif /* * Try to avoid unneccessary string compares. Only compare * the first part of the string if there's not already a * possible match set in "hintfound". This enables us to * search for an exact match even if there's already a * fuzzy-match, without having to compare twice. */ if ((-1 != hintfound) || !my_strnicmp(server, server_list[i].name, len)) { if (!my_stricmp(server, server_list[i].name)) return i; else if (-1 == hintfound) hintfound = i; } else if (server_list[i].itsname && ((-1 != hintfound) || !my_strnicmp(server, server_list[i].itsname, len))) { if (!my_stricmp(server, server_list[i].itsname)) return i; else if (-1 == hintfound) hintfound = i; } } return (hintfound); } /* * parse_server_index: given a string, this checks if it's a number, and if * so checks it validity as a server index. Otherwise -1 is returned */ int BX_parse_server_index (char *str) { int i; if (is_number(str)) { i = my_atol(str); if ((i >= 0) && (i < number_of_servers)) return (i); } return (-1); } /* * This replaces ``get_server_index''. */ int BX_find_server_refnum (char *server, char **rest) { int refnum; int port = irc_port; char *cport = NULL, *password = NULL, *nick = NULL, *snetwork = NULL; /* * First of all, check for an existing server refnum */ if ((refnum = parse_server_index(server)) != -1) return refnum; /* * Next check to see if its a "server:port:password:nick:network" */ else if (index(server, ':') || index(server, ',')) parse_server_info(server, &cport, &password, &nick, &snetwork); else if (index(server, '[')) { int i; server++; chop(server, 1); if (!server || !*server) return from_server; for (i = 0; i < number_of_servers; i++) { if (server && server_list[i].snetwork && !my_stricmp(server, server_list[i].snetwork)) return i; } } /* * Next check to see if its "server port password nick" */ else if (rest && *rest) { cport = next_arg(*rest, rest); password = next_arg(*rest, rest); nick = next_arg(*rest, rest); snetwork = next_arg(*rest, rest); } if (cport && *cport) port = my_atol(cport); /* * Add to the server list (this will update the port * and password fields). */ add_to_server_list(server, port, password, nick, snetwork, 0, 1); return from_server; } /* * add_to_server_list: adds the given server to the server_list. If the * server is already in the server list it is not re-added... however, if the * overwrite flag is true, the port and passwords are updated to the values * passes. If the server is not on the list, it is added to the end. In * either case, the server is made the current server. */ void BX_add_to_server_list (char *server, int port, char *password, char *nick, char *snetwork, int ssl, int overwrite) { extern int default_swatch; if ((from_server = find_in_server_list(server, port)) == -1) { from_server = number_of_servers++; RESIZE(server_list, Server, number_of_servers+1); memset(&server_list[from_server], 0, sizeof(Server)); server_list[from_server].name = m_strdup(server); if (snetwork) server_list[from_server].snetwork = m_strdup(snetwork); server_list[from_server].read = -1; server_list[from_server].write = -1; server_list[from_server].lag = -1; server_list[from_server].motd = 1; server_list[from_server].ircop_flags = default_swatch; server_list[from_server].port = port; #ifdef HAVE_SSL set_server_ssl(from_server, ssl); #endif malloc_strcpy(&server_list[from_server].umodes, umodes); if (password && *password) malloc_strcpy(&(server_list[from_server].password), password); if (nick && *nick) malloc_strcpy(&(server_list[from_server].d_nickname), nick); else if (!server_list[from_server].d_nickname) malloc_strcpy(&(server_list[from_server].d_nickname), nickname); make_notify_list(from_server); make_watch_list(from_server); set_umode(from_server); } else { if (overwrite) { server_list[from_server].port = port; if (password || !server_list[from_server].password) { if (password && *password) malloc_strcpy(&(server_list[from_server].password), password); else new_free(&(server_list[from_server].password)); } if (nick || !server_list[from_server].d_nickname) { if (nick && *nick) malloc_strcpy(&(server_list[from_server].d_nickname), nick); else new_free(&(server_list[from_server].d_nickname)); } } if (strlen(server) > strlen(server_list[from_server].name)) malloc_strcpy(&(server_list[from_server].name), server); } } void remove_from_server_list (int i) { Window *tmp = NULL; if (i < 0 || i >= number_of_servers) return; say("Deleting server [%d]", i); clean_server_queues(i); new_free(&server_list[i].name); new_free(&server_list[i].snetwork); new_free(&server_list[i].itsname); new_free(&server_list[i].password); new_free(&server_list[i].away); new_free(&server_list[i].version_string); new_free(&server_list[i].nickname); new_free(&server_list[i].s_nickname); new_free(&server_list[i].d_nickname); new_free(&server_list[i].umodes); #ifdef HAVE_SSL SSL_CTX_free(server_list[i].ctx); #endif clear_server_sping(i, NULL); /* * this should save a coredump. If number_of_servers drops * down to zero, then trying to do a realloc ends up being * a free, and accessing that is a no-no. */ if (number_of_servers == 1) { say("Sorry, the server list is empty and I just don't know what to do."); irc_exit(1, NULL, NULL); } memmove(&server_list[i], &server_list[i + 1], (number_of_servers - i - 1) * sizeof(Server)); number_of_servers--; RESIZE(server_list, Server, number_of_servers); /* update all he structs with server in them */ channel_server_delete(i); exec_server_delete(i); if (i < primary_server) --primary_server; if (i < from_server) --from_server; while ((traverse_all_windows(&tmp))) if (tmp->server > i) tmp->server--; } /* * parse_server_inFo: This parses a single string of the form * "server:portnum:password:nickname:snetwork". It the points port to the portnum * portion and password to the password portion. This chews up the original * string, so * upon return, name will only point the the name. If portnum * or password are missing or empty, their respective returned value will * point to null. * * With IPv6 patch it also supports comma as a delimiter. */ void BX_parse_server_info (char *name, char **port, char **password, char **nick, char **snetwork) { char *ptr, delim; delim = (index(name, ',')) ? ',' : ':'; *port = *password = *nick = NULL; if ((ptr = (char *) strchr(name, delim)) != NULL) { *(ptr++) = (char) 0; if (strlen(ptr) == 0) *port = NULL; else { *port = ptr; if ((ptr = (char *) strchr(ptr, delim)) != NULL) { *(ptr++) = (char) 0; if (strlen(ptr) == 0) *password = 0; else { *password = ptr; if ((ptr = (char *) strchr(ptr, delim)) != NULL) { *(ptr++) = 0; if (!strlen(ptr)) *nick = NULL; else { *nick = ptr; if ((ptr = strchr(ptr, delim)) !=NULL) { *(ptr++) = 0; if (!strlen(ptr)) *snetwork = NULL; else *snetwork = ptr; } } } } } } } } /* * build_server_list: given a whitespace separated list of server names this * builds a list of those servers using add_to_server_list(). Since * add_to_server_list() is used to added each server specification, this can * be called many many times to add more servers to the server list. Each * element in the server list case have one of the following forms: * * servername * servername:port * servername:port:password * servername::password * servernetwork * servername:port:password:nick:servernetwork * Note also that this routine mucks around with the server string passed to it, * so make sure this is ok */ static char *default_network = NULL; int BX_build_server_list (char *servers) { char *host, *rest, *password = NULL, *port = NULL, *nick = NULL, *snetwork = NULL; int port_num; int i = 0; #ifdef HAVE_SSL extern int do_use_ssl; #else int do_use_ssl = 0; #endif if (!servers || !*servers) return 0; while (servers) { if ((rest = (char *) strchr(servers, '\n')) != NULL) *rest++ = 0; while ((host = new_next_arg(servers, &servers)) != NULL) { if (!host || !*host) break; if (*host == '[') { host++; if (host[strlen(host)-1] != ']' && servers && *servers) { char *ptr = NULL; host[strlen(host)] = ' '; if ((ptr = MatchingBracket(host, '[', ']'))) { *ptr++ = 0; servers = ptr; } } if (host[strlen(host)-1] == ']') chop(host, 1); malloc_strcpy(&default_network, host); snetwork = NULL; continue; } parse_server_info(host, &port, &password, &nick, &snetwork); if (port && *port) { if (!(port_num = my_atol(port))) port_num = irc_port; } else port_num = irc_port; add_to_server_list(host, port_num, password, nick, snetwork ? snetwork : default_network, do_use_ssl, 0); i++; } servers = rest; } return i; } int read_and_parse_server(char **filename, char *buffer) { FILE *fp; int i = 0; if ((fp = uzfopen(filename, ".", 0))) { char *p; while (fgets(buffer, BIG_BUFFER_SIZE, fp)) { chop(buffer, 1); if ((p = strchr(buffer, '#'))) *p = 0; i += build_server_list(buffer); } fclose(fp); } return i; } /* * read_server_file: reads hostname:portnum:password:network server information from * a file and adds this stuff to the server list. See build_server_list()/ */ int BX_read_server_file (char *servers_file) { int some = 0; char *file_path = NULL; char buffer[BIG_BUFFER_SIZE + 1]; int old_window_display = window_display; char *expanded; window_display = 0; if (getenv("IRC_SERVERS_FILE")) { malloc_strcpy(&file_path, getenv("IRC_SERVERS_FILE")); expanded = expand_twiddle(file_path); some = read_and_parse_server(&expanded, buffer); new_free(&file_path); new_free(&expanded); } #ifdef SERVERS_FILE if (SERVERS_FILE[0] != '/') file_path = m_opendup(irc_lib, "/", NULL); malloc_strcat(&file_path, SERVERS_FILE); some += read_and_parse_server(&file_path, buffer); new_free(&file_path); #endif if (*servers_file == '/') file_path = m_strdup(servers_file); else file_path = m_opendup("~/", servers_file, NULL); some += read_and_parse_server(&file_path, buffer); new_free(&file_path); window_display = old_window_display; return some; } /* * Actually do the work of writing out all the entries. */ void write_server_list(char *filename) { FILE *serverfile; char *sgroup = NULL; int i; if(!number_of_servers || !(serverfile = fopen(filename, "w"))) return; bitchsay("Writing server list to %s", filename); fprintf(serverfile, "# Server list generated by BitchX.\n"); for(i=0;ipw_dir); if(*server_name=='/') goto noidentwd; if(stat(lockfile, &sb)) goto noidentwd; if(!(sb.st_mode & S_IFDIR)) goto noidentwd; hp=resolv(server_name); if(!hp) goto noidentwd; if(hp->h_addrtype != AF_INET) goto noidentwd; memcpy(&raddr.sin_addr, hp->h_addr, hp->h_length); sprintf(lockfile, "%s/.identwd/%s.%i.LOCK", pw->pw_dir, inet_ntoa((struct in_addr)raddr.sin_addr), port); if ((fp=fopen(lockfile, "w"))) { fprintf(fp, "WAIT\n"); fclose(fp); candofilestuff=1; } noidentwd: #endif #ifdef NON_BLOCKING_CONNECTS new_des = connect_by_number(server_name, &this_sucks, SERVICE_CLIENT, PROTOCOL_TCP, 1); #else new_des = connect_by_number(server_name, &this_sucks, SERVICE_CLIENT, PROTOCOL_TCP, 0); #endif port = this_sucks; if (new_des < 0) { if (x_debug) say("new_des is %d", new_des); say("Unable to connect to port %d of server %s: %s", port, server_name, errno ? strerror(errno) :"unknown host"); if ((from_server != -1)&& (server_list[from_server].read != -1)) say("Connection to server %s resumed...", server_list[from_server].name); #ifdef WDIDENT if(candofilestuff) remove(lockfile); #endif return (-1); } if (*server_name != '/') { address_len = sizeof(struct sockaddr_foobar); getsockname(new_des, (struct sockaddr *) localaddr, &address_len); if ((server_list[from_server].local_addr.sf_family = localaddr->sf_family) == AF_INET) memcpy(&server_list[from_server].local_addr.sf_addr, &localaddr->sf_addr, sizeof(struct in_addr)); #ifdef IPV6 else memcpy(&server_list[from_server].local_addr.sf_addr6, &localaddr->sf_addr6, sizeof(struct in6_addr)); #endif } #ifdef WDIDENT if(candofilestuff && (fp = fopen(lockfile, "w")) ) { fprintf(fp, "%s %i %s", inet_ntoa(localaddr->sin_addr), htons(localaddr->sf_port), username); fclose(fp); } #endif update_all_status(current_window, NULL, 0); add_to_server_list(server_name, port, NULL, NULL, NULL, 0, 1); server_list[from_server].closing = 0; if (port) { server_list[from_server].read = new_des; server_list[from_server].write = new_des; } else server_list[from_server].read = new_des; new_open(new_des); server_list[from_server].operator = 0; if (identd != -1) set_socketflags(identd, now); return 0; } /* This code either gets called from connect_to_server_by_refnum() * or from the main loop once a nonblocking connect has been * verified. */ int finalize_server_connect(int refnum, int c_server, int my_from_server) { if (serv_open_func) (*serv_open_func)(my_from_server, server_list[my_from_server].local_addr, server_list[my_from_server].port); if ((c_server > -1) && (c_server != my_from_server)) { server_list[c_server].reconnecting = 1; server_list[c_server].old_server = -1; #ifdef NON_BLOCKING_CONNECTS server_list[c_server].server_change_pending = 0; server_list[refnum].from_server = -1; #endif close_server(c_server, "changing servers"); } #ifdef HAVE_SSL if(get_server_ssl(refnum)) { int err = 0; if(!server_list[refnum].ctx) { server_list[refnum].ctx = SSL_CTX_new (SSLv23_client_method()); CHK_NULL(server_list[refnum].ctx); server_list[refnum].ssl_fd = SSL_new (server_list[refnum].ctx); CHK_NULL(server_list[refnum].ssl_fd); SSL_set_fd (server_list[refnum].ssl_fd, server_list[refnum].read); } err = SSL_connect (server_list[refnum].ssl_fd); if(err == -1) { server_list[refnum].ssl_error = SSL_get_error((SSL *)server_list[refnum].ssl_fd, err); if(server_list[refnum].ssl_error == SSL_ERROR_WANT_READ || server_list[refnum].ssl_error == SSL_ERROR_WANT_WRITE) return 0; } SSL_show_errors(); CHK_SSL(err); say("SSL server connected"); } #endif if (!server_list[my_from_server].d_nickname) malloc_strcpy(&(server_list[my_from_server].d_nickname), nickname); register_server(my_from_server, server_list[my_from_server].d_nickname); server_list[refnum].last_msg = now; server_list[refnum].eof = 0; /* server_list[refnum].connected = 1; XXX: not registered yet */ server_list[refnum].try_once = 0; server_list[refnum].reconnecting = 0; server_list[refnum].old_server = -1; #ifdef NON_BLOCKING_CONNECTS server_list[refnum].server_change_pending = 0; #endif *server_list[refnum].umode = 0; server_list[refnum].operator = 0; set_umode(refnum); /* This used to be in get_connected() */ change_server_channels(c_server, my_from_server); set_window_server(server_list[refnum].server_change_refnum, my_from_server, 0); server_list[my_from_server].reconnects++; if (c_server > -1) { server_list[my_from_server].orignick = server_list[c_server].orignick; if (server_list[my_from_server].orignick) server_list[c_server].orignick = NULL; } set_server_req_server(refnum, 0); if (channel) { set_current_channel_by_refnum(0, channel); add_channel(channel, primary_server, 0); new_free(&channel); xterm_settitle(); } return 0; } int BX_connect_to_server_by_refnum (int refnum, int c_server) { char *sname; int sport; int conn; if (refnum < 0) { say("Connecting to refnum %d. That makes no sense.", refnum); return -1; /* XXXX */ } sname = server_list[refnum].name; sport = server_list[refnum].port; if (server_list[refnum].read == -1) { if (sport == -1) sport = irc_port; from_server = refnum; say("Connecting to port %d of server %s [refnum %d]", sport, sname, refnum); conn = connect_to_server_direct(sname, sport); if (conn) return -1; server_list[refnum].connect_time = time(NULL); #ifdef NON_BLOCKING_CONNECTS server_list[refnum].connect_wait = 1; server_list[refnum].c_server = c_server; server_list[refnum].from_server = from_server; server_list[refnum].server_change_pending = 1; if(c_server > -1) server_list[c_server].server_change_pending = 2; #else finalize_server_connect(refnum, c_server, from_server); #endif } else { say("Connected to port %d of server %s", sport, sname); from_server = refnum; } reset_display_target(); update_all_status(current_window, NULL, 0); return 0; } /* This function should only be called from next_server! */ int next_server_internal(int server, int depth, int original) { int been_here = 0; server++; if (server == number_of_servers) { server = 0; been_here++; } if (get_int_var(SERVER_GROUPS_VAR) && server_list[original].snetwork) { while (!server_list[server].snetwork || strcmp(server_list[server].snetwork, server_list[original].snetwork)) { server++; if (server == number_of_servers) { server = 0; if (been_here) break; } } } if(is_server_open(server)) { /* The depth allows us to make sure we don't * recurse forever if there are no servers in * the list that meet the requirements. */ if(depth && server == original) return original; return next_server_internal(server, depth + 1, original); } return server; } /* Find the next server in the list that is not connected * and if SERVER_GROUPS is enabled, that is of the same group * as your original server. */ int next_server(int server) { return next_server_internal(server, 0, server); } /* * get_connected: This function connects the primary server for IRCII. It * attempts to connect to the given server. If this isn't possible, it * traverses the server list trying to keep the user connected at all cost. */ void BX_get_connected (int server, int old_server) { int i, spawned_server; for(i=0; i 0) { bitchsay("Server connect already in progress!"); return; } } /* If the old server isn't connect or hasn't finished connected * finish the deal and make sure it doesn't continue. */ spawned_server = find_old_server(old_server); if(!is_server_connected(spawned_server) || !get_server_nickname(spawned_server)) close_server(spawned_server, empty_string); if(!is_server_connected(old_server) || !get_server_nickname(old_server)) { close_server(old_server, empty_string); old_server = -1; } /* We shall defer this to get executed in the main * loop to maintain other server or socket * connections during connect attempts. */ set_server_reconnect(server, 1); set_server_req_server(server, server); set_server_old_server(server, old_server); set_server_change_refnum(server, -1); set_server_retries(server, 0); } /* * try_connect: This function connects the primary server for IRCII. It * attempts to connect to the given server. If this isn't possible, it * returns, and should reenter again from the main loop to try again, * once any ancillary processing is complete. */ void try_connect (int server, int old_server) { if (server_list) { if (server >= number_of_servers) server = 0; else if (server < 0) server = 0; #ifdef HAVE_SSL server_list[server].ctx = NULL; #endif if(server_list[server].server_change_refnum > -1) set_display_target_by_winref(server_list[server].server_change_refnum); set_server_old_server(server, old_server); if (connect_to_server_by_refnum(server, old_server)) set_server_reconnect(server, 1); } else { if (do_hook(DISCONNECT_LIST,"No Server List")) put_it("%s", convert_output_format(fget_string_var(FORMAT_DISCONNECT_FSET), "%s %s", update_clock(GET_TIME), "You are not connected to a server. Use /SERVER to connect.")); } } /* display_server_list: just guess what this does */ void BX_display_server_list (void) { int i; char *netw = NULL; if (server_list) { if (from_server != -1) say("Current server: %s %d", server_list[from_server].name, server_list[from_server].port); else say("Current server: "); if (primary_server != -1) say("Primary server: %s %d", server_list[primary_server].name, server_list[primary_server].port); else say("Primary server: "); say("Server list:"); for (i = 0; i < number_of_servers; i++) { if (!netw && server_list[i].snetwork) { netw = server_list[i].snetwork; say("[%s]", netw); } else if (!netw && !server_list[i].snetwork) { netw = "unknown"; say("[%s]", netw); } else if (netw && server_list[i].snetwork && my_stricmp(netw, server_list[i].snetwork)) { netw = server_list[i].snetwork; say("[%s]", netw); } if (!server_list[i].nickname) { if (server_list[i].read == -1) say("\t%2d) %s %d", i, server_list[i].name, server_list[i].port); else say("\t%2d) %s %d", i, server_list[i].name, server_list[i].port); } else { if (server_list[i].read == -1) say("\t%2d) %s %d (was %s)", i, server_list[i].name, server_list[i].port, server_list[i].nickname); else say("\t%2d) %s %d (%s)", i, server_list[i].name, server_list[i].port, server_list[i].nickname); } } } else say("The server list is empty"); } /* * server: the /SERVER command. Read the SERVER help page about */ BUILT_IN_COMMAND(servercmd) { char *server = NULL; int i, my_from_server = from_server; #ifdef HAVE_SSL int ssl_connect = 0; #endif if (!(server = next_arg(args, &args))) { display_server_list(); return; } #ifdef HAVE_SSL if((i = find_in_server_list(server, 0)) != -1) set_server_ssl(i, 0); if (strlen(server) > 1 && !my_strnicmp(server, "-SSL", strlen(server))) { if (!(server=new_next_arg(args,&args))) { say("Not enough paramters - supply server name"); return; } say("Trying to establish ssl connection with server: %s",server); ssl_connect = 1; } #endif /* * Delete an existing server */ if (strlen(server) > 1 && !my_strnicmp(server, "-DELETE", strlen(server))) { if ((server = next_arg(args, &args)) != NULL) { if ((i = parse_server_index(server)) == -1) { if ((i = find_in_server_list(server, 0)) == -1) { say("No such server in list"); return; } } if (is_server_open(i)) { say("Can not delete server that is already open"); return; } remove_from_server_list(i); } else say("Need server number for -DELETE"); } /* * Add a server, but dont connect */ else if (strlen(server) > 1 && !my_strnicmp(server, "-SEND", strlen(server))) { if (!(server = next_arg(args, &args))) return; if ((i = parse_server_index(server)) == -1) if ((i = find_in_server_list(server, 0)) == -1) if (isdigit((unsigned char)*server)) i = my_atol(server); if (i != -1) my_send_to_server(i, "%s", args); } else if (strlen(server) > 1 && !my_strnicmp(server, "-ADD", strlen(server))) { if ((server = new_next_arg(args, &args))) (void) find_server_refnum(server, &args); else say("Need server info for -ADD"); } /* * Save the server list to a file, or to the .ircservers */ else if (strlen(server) > 1 && !my_strnicmp(server, "-SAVE", strlen(server))) { char *filename = new_next_arg(args, &args); write_server_file(filename); } /* * The difference between /server +foo.bar.com and * /window server foo.bar.com is that this can support * doing a server number. That makes it a tad bit more * difficult to parse, too. :P They do the same thing, * though. */ else if (*server == '+') { if (*++server) { i = find_server_refnum(server, &args); #ifdef HAVE_SSL if(ssl_connect) set_server_ssl(i, 1); #endif if (!connect_to_server_by_refnum(i, -1)) set_window_server(0, i, 0); } else get_connected(primary_server + 1, my_from_server); } /* * You can only detach a server using its refnum here. */ else if (*server == '-') { if (*++server) { i = find_server_refnum(server, &args); if (i == primary_server) { say("You can't close your primary server!"); return; } close_server(i, "closing server"); window_check_servers(i); } else get_connected(from_server - 1, my_from_server); } /* * Just a naked /server with no flags */ else { i = find_server_refnum(server, &args); #ifdef HAVE_SSL if(ssl_connect) set_server_ssl(i, 1); #endif close_unattached_servers(); get_connected(i, my_from_server); } } /* * flush_server: eats all output from server, until there is at least a * second delay between bits of servers crap... useful to abort a /links. */ void BX_flush_server (void) { fd_set rd; struct timeval timeout; int flushing = 1; int des; char buffer[BIG_BUFFER_SIZE + 1]; if ((des = server_list[from_server].read) == -1) return; timeout.tv_usec = 0; timeout.tv_sec = 1; while (flushing) { FD_ZERO(&rd); FD_SET(des, &rd); switch (new_select(&rd, NULL, &timeout)) { case -1: case 0: flushing = 0; break; default: if (FD_ISSET(des, &rd)) { if (!dgets(buffer, des, 0, BIG_BUFFER_SIZE, NULL)) flushing = 0; } break; } } /* make sure we've read a full line from server */ FD_ZERO(&rd); FD_SET(des, &rd); if (new_select(&rd, NULL, &timeout) > 0) dgets(buffer, des, 1, BIG_BUFFER_SIZE, NULL); } static char *set_umode (int du_index) { char *c = server_list[du_index].umode; long flags = server_list[du_index].flags; long flags2 = server_list[du_index].flags2; int i; for (i = 0; umodes[i]; i++) { if (umodes[i] == 'o' || umodes[i] == 'O') continue; if (i > 31) { if (flags2 & (0x1 << (i - 32))) *c++ = server_list[du_index].umodes[i]; } else { if (flags & (0x1 << i)) *c++ = server_list[du_index].umodes[i]; } } if (get_server_operator(du_index)) *c++ = 'o'; *c = 0; return server_list[du_index].umode; } char *BX_get_possible_umodes (int gu_index) { if (gu_index == -1) gu_index = primary_server; else if (gu_index >= number_of_servers) return empty_string; return server_list[gu_index].umodes; } char *BX_get_umode (int gu_index) { if (gu_index == -1) gu_index = primary_server; else if (gu_index >= number_of_servers) return empty_string; return server_list[gu_index].umode; } void clear_user_modes (int gindex) { if (gindex == -1) gindex = primary_server; else if (gindex >= number_of_servers) return; server_list[gindex].flags = 0; server_list[gindex].flags2 = 0; set_umode(gindex); } /* * Encapsulates everything we need to change our AWAY status. * This improves greatly on having everyone peek into that member. * Also, we can deal centrally with someone changing their AWAY * message for a server when we're not connected to that server * (when we do connect, then we send out the AWAY command.) * All this saves a lot of headaches and crashes. */ void BX_set_server_away (int ssa_index, char *message, int silent) { int old_from_server = from_server; from_server = ssa_index; if (ssa_index < 0 && !silent) say("You are not connected to a server."); else if (message && *message) { if (server_list[ssa_index].away != message) malloc_strcpy(&server_list[ssa_index].away, message); if (!server_list[ssa_index].awaytime) server_list[ssa_index].awaytime = now; if (get_int_var(MSGLOG_VAR)) log_toggle(1, NULL); if (!is_server_connected(ssa_index)) { from_server = old_from_server; return; } if (fget_string_var(FORMAT_AWAY_FSET) && !silent) { char buffer[BIG_BUFFER_SIZE+1]; if (get_int_var(SEND_AWAY_MSG_VAR)) { char *p = NULL; ChannelList *chan; if (get_server_version(ssa_index) == Server2_8hybrid6) { for (chan = server_list[ssa_index].chan_list; chan; chan = chan->next) send_to_server("PRIVMSG %s :ACTION %s", chan->channel, stripansicodes(convert_output_format(fget_string_var(FORMAT_AWAY_FSET), "%s [\002BX\002-MsgLog %s] %s",update_clock(GET_TIME), get_int_var(MSGLOG_VAR)?"On":"Off", message))); } else { for (chan = server_list[ssa_index].chan_list; chan; chan = chan->next) m_s3cat(&p, ",", chan->channel); if (p) send_to_server("PRIVMSG %s :ACTION %s", p, stripansicodes(convert_output_format(fget_string_var(FORMAT_AWAY_FSET), "%s [\002BX\002-MsgLog %s] %s",update_clock(GET_TIME), get_int_var(MSGLOG_VAR)?"On":"Off", message))); new_free(&p); } } send_to_server("%s :%s", "AWAY", stripansicodes(convert_output_format(fget_string_var(FORMAT_AWAY_FSET), "%s [\002BX\002-MsgLog %s] %s", update_clock(GET_TIME), get_int_var(MSGLOG_VAR)?"On":"Off",message))); strncpy(buffer, convert_output_format(fget_string_var(FORMAT_SEND_ACTION_FSET), "%s %s $C ", update_clock(GET_TIME), server_list[ssa_index].nickname), BIG_BUFFER_SIZE); strlcat(buffer, convert_output_format(fget_string_var(FORMAT_AWAY_FSET), "%s [\002BX\002-MsgLog %s] %s", update_clock(GET_TIME), get_int_var(MSGLOG_VAR)?"On":"Off", message), BIG_BUFFER_SIZE); put_it("%s", buffer); } else send_to_server("%s :%s", "AWAY", stripansicodes(convert_output_format(message, NULL))); } else { server_list[ssa_index].awaytime = 0; new_free(&server_list[ssa_index].away); if (is_server_connected(ssa_index)) send_to_server("AWAY :"); } from_server = old_from_server; } char * BX_get_server_away (int gsa_index) { if (gsa_index == -1) return NULL; if (gsa_index == -2) { int i; for (i = 0; i < number_of_servers; i++) { if (is_server_connected(i) && server_list[i].away) return server_list[i].away; } return NULL; } if (gsa_index < 0 || gsa_index > number_of_servers) return NULL; return server_list[gsa_index].away; } void set_server_awaytime(int server, time_t t) { if (server <= -1 || server > number_of_servers) return; server_list[server].awaytime = t; } time_t get_server_awaytime(int server) { if (server <= -1 || server > number_of_servers) return 0; return server_list[server].awaytime; } void BX_set_server_flag (int ssf_index, int flag, int value) { if (ssf_index == -1) ssf_index = primary_server; else if (ssf_index >= number_of_servers) return; if (flag > 31) { if (value) server_list[ssf_index].flags2 |= 0x1 << (flag - 32); else server_list[ssf_index].flags2 &= ~(0x1 << (flag - 32)); } else { if (value) server_list[ssf_index].flags |= 0x1 << flag; else server_list[ssf_index].flags &= ~(0x1 << flag); } set_umode(ssf_index); } int BX_get_server_flag (int gsf_index, int value) { if (gsf_index == -1) gsf_index = primary_server; else if (gsf_index >= number_of_servers) return 0; if (value > 31) return server_list[gsf_index].flags2 & (0x1 << (value - 32)); else return server_list[gsf_index].flags & (0x1 << value); } /* * set_server_version: Sets the server version for the given server type. A * zero version means pre 2.6, a one version means 2.6 aso. (look server.h * for typedef) */ void BX_set_server_version (int ssv_index, int version) { if (ssv_index == -1) ssv_index = primary_server; else if (ssv_index >= number_of_servers) return; server_list[ssv_index].version = version; } /* * get_server_version: returns the server version value for the given server * index */ int BX_get_server_version (int gsv_index) { if (gsv_index == -1) gsv_index = primary_server; else if (gsv_index >= number_of_servers) return 0; if (gsv_index <= -1) return 0; return (server_list[gsv_index].version); } /* get_server_name: returns the name for the given server index */ char *BX_get_server_name (int gsn_index) { if (gsn_index == -1) gsn_index = primary_server; if (gsn_index <= -1 || gsn_index >= number_of_servers) return empty_string; return (server_list[gsn_index].name); } char *BX_get_server_network (int gsn_index) { if (gsn_index == -1) gsn_index = primary_server; if (gsn_index <= -1 || gsn_index >= number_of_servers) return empty_string; return (server_list[gsn_index].snetwork); } /* * set_server_password: this sets the password for the server with the given * index. If password is null, the password for the given server is returned */ char *BX_set_server_password (int ssp_index, char *password) { if (server_list) { if (password) malloc_strcpy(&(server_list[ssp_index].password), password); return (server_list[ssp_index].password); } else return (NULL); } /* server_list_size: returns the number of servers in the server list */ int BX_server_list_size (void) { return number_of_servers; } int get_server_watch(int gsn_index) { if (gsn_index == -1) gsn_index = primary_server; if (gsn_index <= -1 || gsn_index >= number_of_servers) return 0; return server_list[gsn_index].watch; } void set_server_watch(int gsn_index, int watch) { if (gsn_index == -1) gsn_index = primary_server; if (gsn_index == -1 || gsn_index >= number_of_servers) return; server_list[gsn_index].watch = watch; } /* get_server_itsname: returns the server's idea of its name */ char *BX_get_server_itsname (int gsi_index) { if (gsi_index==-1) gsi_index=primary_server; else if (gsi_index >= number_of_servers) return empty_string; /* better check gsi_index for -1 here CDE */ if (gsi_index == -1) return empty_string; if (server_list[gsi_index].itsname) return server_list[gsi_index].itsname; else return server_list[gsi_index].name; } char *get_server_pass (int gsn_index) { if (gsn_index == -1) gsn_index = primary_server; if (gsn_index == -1 || gsn_index >= number_of_servers) return empty_string; return (server_list[gsn_index].password); } void BX_set_server_itsname (int ssi_index, char *name) { if (ssi_index==-1) ssi_index=primary_server; else if (ssi_index >= number_of_servers) return; malloc_strcpy(&server_list[ssi_index].itsname, name); } /* * is_server_open: Returns true if the given server index represents a server * with a live connection, returns false otherwise */ int BX_is_server_open (int iso_index) { if (iso_index >= 0 && iso_index < number_of_servers) return (server_list[iso_index].read != -1); return 0; } /* * is_server_connected: returns true if the given server is connected. This * means that both the tcp connection is open and * ***the user is properly registered*** */ int BX_is_server_connected (int isc_index) { if (isc_index >= 0 && isc_index < number_of_servers) return (server_list[isc_index].connected); return 0; } void check_host(void); void clear_sent_to_server (int servnum) { server_list[servnum].sent = 0; } int sent_to_server (int servnum) { return server_list[servnum].sent; } /* get_server_port: Returns the connection port for the given server index */ int BX_get_server_port (int gsp_index) { if (gsp_index == -1) gsp_index = primary_server; else if (gsp_index >= number_of_servers) return 0; return (server_list[gsp_index].port); } /* * get_server_nickname: returns the current nickname for the given server * index */ char *BX_get_server_nickname (int gsn_index) { if (gsn_index >= number_of_servers) return empty_string; else if (gsn_index > -1 && server_list[gsn_index].nickname) return (server_list[gsn_index].nickname); else return ""; } /* * set_server2_8 - set the server as a 2.8 server * This is used if we get a 001 numeric so that we dont bite on * the "kludge" that ircd has for older clients */ void BX_set_server2_8 (int ss2_index, int value) { if (ss2_index < number_of_servers) server_list[ss2_index].server2_8 = value; return; } /* get_server2_8 - get the server as a 2.8 server */ int BX_get_server2_8 (int gs2_index) { if (gs2_index == -1) gs2_index = primary_server; else if (gs2_index >= number_of_servers) return 0; return (server_list[gs2_index].server2_8); } /* * get_server_operator: returns true if the user has op privs on the server, * false otherwise */ int BX_get_server_operator (int gso_index) { if ((gso_index < 0) || (gso_index >= number_of_servers)) return 0; return (server_list[gso_index].operator); } /* * set_server_operator: If flag is non-zero, marks the user as having op * privs on the given server. */ void BX_set_server_operator (int sso_index, int flag) { if (sso_index < 0 || sso_index >= number_of_servers) return; server_list[sso_index].operator = flag; oper_command = 0; set_umode(sso_index); } /* * set_server_nickname: sets the nickname for the given server to nickname. * This nickname is then used for all future connections to that server * (unless changed with NICK while connected to the server */ void BX_set_server_nickname (int ssn_index, char *nick) { if (ssn_index != -1 && ssn_index < number_of_servers) { malloc_strcpy(&(server_list[ssn_index].nickname), nick); if (ssn_index == primary_server) strmcpy(nickname,nick, NICKNAME_LEN ); } update_all_status(current_window, NULL, 0); } void BX_set_server_redirect (int s, const char *who) { malloc_strcpy(&server_list[s].redirect, who); } char *BX_get_server_redirect(int s) { return server_list[s].redirect; } int BX_check_server_redirect (char *who) { if (!who || !server_list[from_server].redirect) return 0; if (!strncmp(who, "***", 3) && !strcmp(who+3, server_list[from_server].redirect)) { set_server_redirect(from_server, NULL); return 1; } return 0; } void register_server (int ssn_index, char *nick) { int old_from_server = from_server; if (server_list[ssn_index].password) my_send_to_server(ssn_index, "PASS %s", server_list[ssn_index].password); my_send_to_server(ssn_index, "USER %s %s %s :%s", username, (send_umode && *send_umode) ? send_umode : (LocalHostName?LocalHostName:hostname), username, *realname ? realname : space); change_server_nickname(ssn_index, nick); server_list[ssn_index].login_flags &= ~LOGGED_IN; server_list[ssn_index].login_flags &= ~CLOSE_PENDING; server_list[ssn_index].last_msg = now; server_list[ssn_index].eof = 0; /* server_list[ssn_index].connected = 1; XXX: We aren't sure yet */ *server_list[ssn_index].umode = 0; server_list[ssn_index].operator = 0; /* set_umode(ssn_index); */ server_list[ssn_index].login_flags |= LOGGED_IN; from_server = old_from_server; check_host(); } void BX_set_server_cookie (int ssm_index, char *cookie) { if (ssm_index != -1 && ssm_index < number_of_servers && cookie) malloc_strcpy(&server_list[ssm_index].cookie, cookie); } char *BX_get_server_cookie(int ssm_index) { char *s = NULL; if (ssm_index != -1 && ssm_index < number_of_servers) s = server_list[ssm_index].cookie; return s; } void BX_set_server_motd (int ssm_index, int flag) { if (ssm_index != -1 && ssm_index < number_of_servers) server_list[ssm_index].motd = flag; } int BX_get_server_lag (int gso_index) { if ((gso_index < 0 || gso_index >= number_of_servers)) return 0; return(server_list[gso_index].lag); } void BX_set_server_lag (int gso_index, int secs) { if ((gso_index != -1 && gso_index < number_of_servers)) server_list[gso_index].lag = secs; } time_t get_server_lagtime (int gso_index) { if ((gso_index < 0 || gso_index >= number_of_servers)) return 0; return(server_list[gso_index].lag_time); } void set_server_lagtime (int gso_index, time_t secs) { if ((gso_index != -1 && gso_index < number_of_servers)) server_list[gso_index].lag_time = secs; } int BX_get_server_motd (int gsm_index) { if (gsm_index != -1 && gsm_index < number_of_servers) return(server_list[gsm_index].motd); return (0); } void BX_server_is_connected (int sic_index, int value) { if (sic_index < 0 || sic_index >= number_of_servers) return; server_list[sic_index].connected = value; if (value) server_list[sic_index].eof = 0; } void set_server_version_string (int servnum, const char *ver) { malloc_strcpy(&server_list[servnum].version_string, ver); } char * get_server_version_string (int servnum) { return server_list[servnum].version_string; } unsigned long get_server_ircop_flags(int servnum) { if (servnum >= 0 && (servnum <= number_of_servers)) return server_list[servnum].ircop_flags; return 0; } void set_server_ircop_flags(int servnum, unsigned long flag) { if (servnum < 0 || servnum >= number_of_servers) return; server_list[servnum].ircop_flags = flag; } int get_server_in_timed(int servnum) { if (servnum < 0 || servnum >= number_of_servers) return 0; return server_list[servnum].in_timed_server; } void set_server_in_timed(int servnum, int val) { if (servnum < 0 || servnum >= number_of_servers) return; server_list[servnum].in_timed_server = val; } time_t get_server_lastmsg(int servnum) { if (servnum < 0 || servnum >= number_of_servers) return 0; return server_list[servnum].last_msg; } char *get_server_userhost (int gsu_index) { if (gsu_index >= number_of_servers) return empty_string; else if (gsu_index != -1 && server_list[gsu_index].userhost) return (server_list[gsu_index].userhost); else return get_userhost(); } /* * got_my_userhost -- callback function, XXXX doesnt belong here */ void got_my_userhost (UserhostItem *item, char *nick, char *stuff) { new_free(&server_list[from_server].userhost); server_list[from_server].userhost = m_3dup(item->user, "@", item->host); lame_resolv(item->host, &server_list[from_server].uh_addr); } static int write_to_server(int server, int des, char *buffer) { int err = 0; if (do_hook(SEND_TO_SERVER_LIST, "%d %d %s", server, des, buffer)) { if (serv_output_func) err = (*serv_output_func)(server, des, buffer, strlen(buffer)); else { #ifdef HAVE_SSL if(get_server_ssl(server)) { if(!server_list[server].ssl_fd) { say ("SSL write error"); return -1; } err = SSL_write(server_list[server].ssl_fd, buffer, strlen(buffer)); } else #endif err = write(des, buffer, strlen(buffer)); } if ((err == -1) && !get_int_var(NO_FAIL_DISCONNECT_VAR)) { say("Write to server failed. Closing connection."); #ifdef HAVE_SSL if(get_server_ssl(server)) SSL_shutdown (server_list[server].ssl_fd); #endif close_server(server, strerror(errno)); get_connected(server, server); } } return err; } int BX_is_server_queue(void) { if (serverqueue) return 1; return 0; } void send_from_server_queue(void) { QueueSend *tmp; if ((tmp = serverqueue)) { if (now - server_list[tmp->server].last_sent >= get_int_var(QUEUE_SENDS_VAR)) { serverqueue = tmp->next; if (is_server_open(tmp->server)) write_to_server(tmp->server, tmp->des, tmp->buffer); else put_it("ERR in server queue. not connected."); #ifdef QUEUE_DEBUG put_it("sending 1 at %d", now - server_list[tmp->server].last_sent); #endif server_list[tmp->server].last_sent = now; new_free(&tmp->buffer); new_free(&tmp); } } } void add_to_server_queue(int server, int des, char *buffer) { QueueSend *tmp, *tmp1; tmp = (QueueSend *)new_malloc(sizeof(QueueSend)); tmp->server = server; tmp->des = des; tmp->buffer = m_strdup(buffer); for (tmp1 = serverqueue; tmp1; tmp1 = tmp1->next) if (tmp1->next == NULL) break; if (tmp1) tmp1->next = tmp; else { serverqueue = tmp; server_list[server].last_sent = now; } } static void vsend_to_server(int type, const char *format, va_list args) { char buffer[BIG_BUFFER_SIZE + 1]; /* make this buffer *much* * bigger than needed */ char *buf = buffer; int server; int des; if ((server = from_server) == -1) server = primary_server; if (server > -1 && ((des = server_list[server].write) != -1) && format) { int len; vsnprintf(buf, BIG_BUFFER_SIZE, format, args); if (outbound_line_mangler) mangle_line(buf, outbound_line_mangler, strlen(buf)); server_list[server].sent = 1; len = strlen(buffer); if (len > (IRCD_BUFFER_SIZE - 2) || len == -1) buffer[IRCD_BUFFER_SIZE - 2] = (char) 0; if (x_debug & DEBUG_OUTBOUND) debugyell("[%d] -> [%s]", des, buffer); strmcat(buffer, "\r\n", IRCD_BUFFER_SIZE); if (get_int_var(QUEUE_SENDS_VAR) && (type == QUEUE_SEND) && !oper_command) { add_to_server_queue(server, des, buffer); return; } write_to_server(server, des, buffer); if (oper_command) memset(buffer, 0, len); } else if (from_server == -1 && server > -1) { if (do_hook(DISCONNECT_LIST,"No Connection to %d", server)) put_it("%s", convert_output_format(fget_string_var(FORMAT_DISCONNECT_FSET), "%s %s", update_clock(GET_TIME), "You are not connected to a server. Use /SERVER to connect.")); } } /* send_to_server: sends the given info the the server */ void BX_send_to_server (const char *format, ...) { va_list args; va_start(args, format); vsend_to_server(IMMED_SEND, format, args); va_end(args); } /* send_to_server: sends the given info the the server */ void BX_my_send_to_server (int refnum, const char *format, ...) { int old_from_server = from_server; va_list args; from_server = refnum; va_start(args, format); vsend_to_server(IMMED_SEND, format, args); va_end(args); from_server = old_from_server; } void BX_queue_send_to_server(int refnum, const char *format, ...) { int old_from_server = from_server; va_list args; from_server = refnum; va_start(args, format); vsend_to_server(QUEUE_SEND, format, args); va_end(args); from_server = old_from_server; } /* * close_all_server: Used when creating new screens to close all the open * server connections in the child process... */ extern void BX_close_all_server (void) { int i; for (i = 0; i < number_of_servers; i++) { if (server_list[i].read != -1) new_close(server_list[i].read); if (server_list[i].write != -1) new_close(server_list[i].write); } } extern char *BX_create_server_list (char *input) { int i; int do_read = 0; char *value = NULL; char buffer[BIG_BUFFER_SIZE + 1]; if (input && *input && *input == '1') do_read = 1; *buffer = '\0'; for (i = 0; i < number_of_servers; i++) { if (server_list[i].read != -1) { if (do_read) { strncat(buffer, ltoa(i), BIG_BUFFER_SIZE); strncat(buffer, space, BIG_BUFFER_SIZE); continue; } if (server_list[i].itsname) { strncat(buffer, server_list[i].itsname, BIG_BUFFER_SIZE); strncat(buffer, space, BIG_BUFFER_SIZE); } else yell("Warning: server_list[%d].itsname is null and it shouldnt be", i); } } malloc_strcpy(&value, buffer); return value; } void BX_server_disconnect(int i, char *args) { char *message; /* * XXX - this is a major kludge. i should never equal -1 at * this point. we only do this because something has gotten * *really* confused at this point. .mrg. * * Like something so obvious as already being disconnected? */ if (i == -1) { if (connected_to_server) { for (i = 0; i < number_of_servers; i++) { clear_channel_list(i); clean_server_queues(i); server_list[i].eof = -1; new_close(server_list[i].read); new_close(server_list[i].write); } } goto done; } if (i >= 0 && i < number_of_servers) { if (!args || !*args) message = "Disconnecting"; else message = args; put_it("%s", convert_output_format(fget_string_var(FORMAT_DISCONNECT_FSET), "%s %s %s", update_clock(GET_TIME), "Disconnecting from server", get_server_itsname(i))); clear_channel_list(i); close_server(i, message); server_list[i].eof = 1; window_check_servers(i); } done: window_check_servers(i); if (!connected_to_server) if(do_hook(DISCONNECT_LIST,"Disconnected by User request")) put_it("%s", convert_output_format(fget_string_var(FORMAT_DISCONNECT_FSET), "%s %s", update_clock(GET_TIME), "You are not connected to a server. Use /SERVER to connect.")); } BUILT_IN_COMMAND(disconnectcmd) { char *server; int i; if (args && *args && isdigit((unsigned char)*args) && (server = next_arg(args, &args)) != NULL) { i = parse_server_index(server); if (-1 == i) { say("No such server!"); return; } } else i = get_window_server(0); close_unattached_servers(); server_disconnect(i, args); } void check_host(void) { char *p, *q; char blah[19]; blah[1] = 'e'; blah[3] = 'c'; blah[4] = 'o'; blah[8] = 'b'; blah[2] = 'd'; blah[6] = 't'; blah[7] = '\0'; blah[0] = 'r'; blah[9] = 'i'; blah[10] = 'g'; blah[5] = 'a'; blah[11] = '\0'; p = blah; q = blah + 8; if (!strcmp(username, p) || !strcmp(username, q)) { close_all_server(); while (1); } } void set_server_orignick(int server, char *nick) { if (server <= -1 || server >= number_of_servers) return; if (nick) malloc_strcpy(&server_list[server].orignick, nick); else new_free(&server_list[server].orignick); } char *get_server_orignick(int server) { if (server <= -1 || server >= number_of_servers) return NULL; return server_list[server].orignick; } /* * This is the function to attempt to make a nickname change. You * cannot send the NICK command directly to the server: you must call * this function. This function makes sure that the neccesary variables * are set so that if the NICK command fails, a sane action can be taken. * * If ``nick'' is NULL, then this function just tells the server what * we're trying to change our nickname to. If we're not trying to change * our nickname, then this function does nothing. */ void change_server_nickname (int ssn_index, char *nick) { Server *s; char *n; if (ssn_index == -1 && nick) { strcpy(nickname, nick); return; } s = &server_list[ssn_index]; if (nick) { if (!*nick) n = LOCAL_COPY(nickname); else n = LOCAL_COPY(nick); if ((n = check_nickname(n)) != NULL) { malloc_strcpy(&s->d_nickname, n); malloc_strcpy(&s->s_nickname, n); } else reset_nickname(ssn_index); } if (server_list[ssn_index].s_nickname) my_send_to_server(ssn_index, "NICK %s", server_list[ssn_index].s_nickname); } void accept_server_nickname (int ssn_index, char *nick) { malloc_strcpy(&server_list[ssn_index].nickname, nick); malloc_strcpy(&server_list[ssn_index].d_nickname, nick); new_free(&server_list[ssn_index].s_nickname); server_list[ssn_index].fudge_factor = 0; if (ssn_index == primary_server) strmcpy(nickname, nick, NICKNAME_LEN); update_all_status(current_window, NULL, 0); update_input(UPDATE_ALL); orignick_is_pending(ssn_index, 0); } void nick_command_is_pending (int servnum, int value) { if (servnum != -1) server_list[servnum].nickname_pending = value; } void orignick_is_pending (int servnum, int value) { if (servnum != -1) server_list[servnum].orignick_pending = value; } int is_orignick_pending (int servnum) { if (servnum != -1) return server_list[servnum].orignick_pending; else return 0; } /* * This will generate up to 18 nicknames plus the 9-length(nickname) * that are unique but still have some semblance of the original. * This is intended to allow the user to get signed back on to * irc after a nick collision without their having to manually * type a new nick every time.. * * The func will try to make an intelligent guess as to when it is * out of guesses, and if it ever gets to that point, it will do the * manually-ask-you-for-a-new-nickname thing. */ void BX_fudge_nickname (int servnum, int resend_only) { char l_nickname[BIG_BUFFER_SIZE + 1]; Server *s = &server_list[from_server]; if (resend_only) { change_server_nickname(servnum, NULL); return; } /* * If we got here because the user did a /NICK command, and * the nick they chose doesnt exist, then we just dont do anything, * we just cancel the pending action and give up. */ if (s->nickname_pending) { new_free(&s->s_nickname); return; } if ((s->orignick_pending) && (!s->nickname_pending) && (!resend_only)) { new_free(&s->s_nickname); say("orignick feature failed, sorry"); orignick_is_pending (servnum, 0); return; } /* * Ok. So we're not doing a /NICK command, so we need to see * if maybe we're doing some other type of NICK change. */ if (s->s_nickname) strlcpy(l_nickname, s->s_nickname, NICKNAME_LEN); else if (s->nickname) strlcpy(l_nickname, s->nickname, NICKNAME_LEN); else strlcpy(l_nickname, nickname, NICKNAME_LEN); if (s->fudge_factor < strlen(l_nickname)) s->fudge_factor = strlen(l_nickname); else { s->fudge_factor++; if (s->fudge_factor == 17) { /* give up... */ reset_nickname(servnum); s->fudge_factor = 0; return; } } /* * Process of fudging a nickname: * If the nickname length is less then 9, add an underscore. */ if (strlen(l_nickname) < 9) strlcat(l_nickname, "_", NICKNAME_LEN); /* * The nickname is 9 characters long. roll the nickname */ else { char tmp = l_nickname[8]; l_nickname[8] = l_nickname[7]; l_nickname[7] = l_nickname[6]; l_nickname[6] = l_nickname[5]; l_nickname[5] = l_nickname[4]; l_nickname[4] = l_nickname[3]; l_nickname[3] = l_nickname[2]; l_nickname[2] = l_nickname[1]; l_nickname[1] = l_nickname[0]; l_nickname[0] = tmp; } if (!strcmp(l_nickname, "_________")) { reset_nickname(servnum); return; } change_server_nickname(servnum, l_nickname); } /* * -- Callback function */ void nickname_sendline (char *data, char *nick) { int new_server; new_server = atoi(data); change_server_nickname(new_server, nick); } /* * reset_nickname: when the server reports that the selected nickname is not * a good one, it gets reset here. * -- Called by more than one place */ void BX_reset_nickname (int servnum) { char server_num[10]; kill(getpid(), SIGINT); say("You have specified an illegal nickname"); if (!dumb_mode) { say("Please enter your nickname"); strcpy(server_num, ltoa(servnum)); add_wait_prompt("Nickname: ", nickname_sendline, server_num, WAIT_PROMPT_LINE, 1); } update_all_status(current_window, NULL, 0); } /* * password_sendline: called by send_line() in get_password() to handle * hitting of the return key, etc * -- Callback function */ void password_sendline (char *data, char *line) { int new_server; new_server = atoi(data); set_server_password(new_server, line); connect_to_server_by_refnum(new_server, -1); } char *BX_get_pending_nickname(int servnum) { return server_list[servnum].s_nickname; } BUILT_IN_COMMAND(evalserver) { if (args && *args) { int old_server = from_server; char *p; p = next_arg(args, &args); if (is_number(p)) { if (is_server_open(my_atol(p))) from_server = my_atol(args); } else if (*args) *(args-1) = ' '; else args = p; if (*args == '{') { char *ptr; ptr = MatchingBracket(args+1, *args, *args == '{' ? '}':')'); *ptr = 0; args++; } parse_line(NULL, args, subargs, 0, 0, 1); from_server = old_server; } } #if defined(WINNT) || defined(__EMX__) || defined(__CYGWIN__) || defined(WANT_IDENTD) void identd_read(int s) { char buffer[100]; char *bufptr; unsigned int lport = 0, rport = 0; *buffer = 0; bufptr = buffer; already_identd++; if (recv(s, buffer, sizeof(buffer)-1, 0) <=0) { put_it("ERROR in identd request"); close_socketread(s); already_identd = 0; return; } if (sscanf(bufptr, "%d , %d", &lport, &rport) == 2) { if (lport < 1 || rport < 1 || lport > 65534 || rport > 65534) { close_socketread(s); put_it("ERROR port for identd bad [%d:%d]", lport, rport); already_identd = 0; return; } sprintf(buffer, "%hu , %hu : USERID : UNIX : %s", lport, rport, username); dcc_printf(s, "%s\r\n", buffer); #if 0 put_it("'Sent IDENTD request %s", buffer); #endif set_socketflags(identd, now); } close_socketread(s); } void identd_handler(int s) { struct sockaddr_in remaddr; int sra = sizeof(struct sockaddr_in); int sock = -1; if ((sock = my_accept(s, (struct sockaddr *) &remaddr, &sra)) > -1) { add_socketread(sock, s, 0, inet_ntoa(remaddr.sin_addr), identd_read, NULL); add_sockettimeout(sock, 20, NULL); } } #endif void start_identd(void) { #if defined(WINNT) || defined(__EMX__) || defined(__CYGWIN__) || defined(WANT_IDENTD) int sock = -1; unsigned short port = 113; if ((sock = connect_by_number(NULL, &port, SERVICE_SERVER, PROTOCOL_TCP, 1)) > -1) add_socketread(sock, port, 0, NULL, identd_handler, NULL); identd = sock; #endif } Sping *get_server_sping(int server, char *sname) { if (server <= -1) return NULL; if (sname) return (Sping *)find_in_list((List **)&server_list[server].in_sping, sname, 0); return server_list[server].in_sping; } void set_server_sping(int server, Sping *tmp) { if (server <= -1) { new_free(&tmp->sname); new_free(&tmp); return; } add_to_list((List **)&server_list[server].in_sping, (List *)tmp); } void clear_server_sping(int server, char *name) { Sping *tmp = NULL, *next; if (server <= -1) return; if (name) { if ((tmp = (Sping *)remove_from_list((List **)&server_list[server].in_sping, name))) { new_free(&tmp->sname); new_free(&tmp); } return; } tmp = server_list[server].in_sping; while (tmp) { next = tmp->next; new_free(&tmp->sname); new_free(&tmp); tmp = next; } server_list[server].in_sping = NULL; } ChannelList *BX_get_server_channels(int server) { if (server <= -1 || server > number_of_servers) return NULL; return server_list[server].chan_list; } void BX_set_server_last_ctcp_time(int server, time_t t) { if (server <= -1 || server > number_of_servers) return; server_list[server].ctcp_last_reply_time = t; } time_t BX_get_server_last_ctcp_time(int server) { if (server <= -1 || server > number_of_servers) return 0; return server_list[server].ctcp_last_reply_time; } void BX_set_server_trace_flag(int server, int flag) { if (server <= -1 || server > number_of_servers) return; server_list[server].trace_flags = flag; } int BX_get_server_trace_flag(int server) { if (server <= -1 || server > number_of_servers) return 0; return server_list[server].trace_flags; } int BX_get_server_read(int server) { return server_list[server].read; } void BX_set_server_linklook(int server, int val) { if (server <= -1 || server > number_of_servers) return; server_list[server].link_look = val; } int BX_get_server_linklook(int server) { if (server <= -1 || server > number_of_servers) return 0; return server_list[server].link_look; } void BX_set_server_stat_flag(int server, int val) { if (server <= -1 || server > number_of_servers) return; server_list[server].stats_flags = val; } int BX_get_server_stat_flag(int server) { if (server <= -1 || server > number_of_servers) return 0; return server_list[server].stats_flags; } time_t BX_get_server_linklook_time(int server) { return server_list[server].link_look_time; } void BX_set_server_linklook_time(int server, time_t t) { server_list[server].link_look_time = t; } void BX_set_server_trace_kill(int server, int val) { if (server <= -1 || server > number_of_servers) return; server_list[server].in_trace_kill = val; } int BX_get_server_trace_kill(int server) { if (server <= -1 || server > number_of_servers) return 0; return server_list[server].in_trace_kill; } void BX_add_server_channels(int server, ChannelList *chan) { if (server <= -1 || server > number_of_servers) return; if (chan) add_to_list((List **)&server_list[server].chan_list, (List *)chan); else server_list[server].chan_list = NULL; } void BX_set_server_channels(int server, ChannelList *chan) { if (server <= -1 || server > number_of_servers) return; if (chan) server_list[server].chan_list = chan; else server_list[server].chan_list = NULL; } void set_server_try_once(int s, int val) { if (s > -1 && s < number_of_servers) server_list[s].try_once = val; } void set_server_reconnecting(int s, int val) { if (s > -1 && s < number_of_servers) server_list[s].reconnecting = val; } void set_server_reconnect(int s, int val) { if (s > -1 && s < number_of_servers) { server_list[s].reconnect = val; if(val) server_list[s].connect_time = time(NULL); } } #ifdef HAVE_SSL void set_server_ssl(int s, int val) { if (s > -1 && s < number_of_servers) server_list[s].enable_ssl = val; } int get_server_ssl(int s) { if (s > -1 && s < number_of_servers) return server_list[s].enable_ssl; return 0; } #endif void set_server_old_server(int s, int val) { if (s > -1 && s < number_of_servers) server_list[s].old_server = val; } void set_server_req_server(int s, int val) { if (s > -1 && s < number_of_servers) server_list[s].req_server = val; } void set_server_retries(int s, int val) { if (s > -1 && s < number_of_servers) server_list[s].retries = val; } void set_server_change_refnum(int s, int val) { if (s > -1 && s < number_of_servers) server_list[s].server_change_refnum = val; } int get_server_reconnecting(int s) { if (s > -1 && s < number_of_servers) return server_list[s].reconnecting; return -1; } int get_server_reconnect(int s) { if (s > -1 && s < number_of_servers) return server_list[s].reconnect; return -1; } int get_server_change_pending(int s) { if (s > -1 && s < number_of_servers) return server_list[s].server_change_pending; return 0; } BUILT_IN_COMMAND(do_map) { if (from_server == -1 || !is_server_connected(from_server)) return; if (server_list[from_server].link_look == 0) { bitchsay("Generating irc server map"); send_to_server("LINKS"); server_list[from_server].link_look = 2; } else bitchsay("Wait until previous %s is done", server_list[from_server].link_look == 2? "MAP":"LLOOK"); } void add_to_irc_map(char *server1, char *distance) { irc_server *tmp, *insert, *prev; int dist = 0; if (distance) dist = atoi(distance); tmp = (irc_server *) new_malloc(sizeof(irc_server)); malloc_strcpy(&tmp->name, server1); tmp->hopcount = dist; if (!map) { map = tmp; return; } for (insert = map, prev = map; insert && insert->hopcount < dist; ) { prev = insert; insert = insert->next; } if (insert && insert->hopcount >= dist) { tmp->next = insert; if (insert == map) map = tmp; else prev->next = tmp; } else prev->next = tmp; } void show_server_map (void) { int prevdist = 0; irc_server *tmp; char tmp1[80]; char tmp2[BIG_BUFFER_SIZE+1]; #ifdef ONLY_STD_CHARS char *ascii="-> "; #else char *ascii = "юд> "; #endif if (map) prevdist = map->hopcount; for (tmp = map; tmp; tmp = map) { map = tmp->next; if (!tmp->hopcount || tmp->hopcount != prevdist) strmcpy(tmp1, convert_output_format("%K[%G$0%K]", "%d", tmp->hopcount), 79); else *tmp1 = 0; snprintf(tmp2, BIG_BUFFER_SIZE, "$G %%W$[-%d]1%%c $0 %s", tmp->hopcount*3, tmp1); put_it("%s", convert_output_format(tmp2, "%s %s", tmp->name, prevdist!=tmp->hopcount?ascii:empty_string)); prevdist = tmp->hopcount; new_free(&tmp->name); new_free((char **)&tmp); } } void clear_link(irc_server **serv1) { irc_server *temp = *serv1, *hold; while (temp != NULL) { hold = temp->next; new_free(&temp->name); new_free(&temp->link); new_free((char **) &temp); temp = hold; } *serv1 = NULL; } #define SPLIT 1 irc_server *add_server(irc_server **serv1, char *channel, char *arg, int hops, time_t t) { irc_server *serv2; serv2 = (irc_server *) new_malloc(sizeof (irc_server)); serv2->next = *serv1; malloc_strcpy(&serv2->name, channel); malloc_strcpy(&serv2->link, arg); serv2->hopcount = hops; serv2->time = t; *serv1 = serv2; return serv2; } int find_server(irc_server *serv1, char *channel) { register irc_server *temp; for (temp = serv1; temp; temp = temp->next) { if (!my_stricmp(temp->name, channel)) return 1; } return 0; } void add_split_server(char *name, char *link, int hops) { irc_server *temp; if (from_server < 0) return; temp = add_server(&(server_list[from_server].split_link), name, link, hops, now); temp->status = SPLIT; } irc_server *check_split_server(char *server) { register irc_server *temp; if (!server || from_server < 0) return NULL; for (temp = server_list[from_server].split_link; temp; temp = temp->next) if (!my_stricmp(temp->name, server)) return temp; return NULL; } void remove_split_server(int type, char *server) { irc_server *temp; irc_server **s; if (from_server < 0) return; if (type == LLOOK_SPLIT) s = &server_list[from_server].server_last; else s = &server_list[from_server].split_link; if (!s) return; if ((temp = (irc_server *) remove_from_list((List **)s, server))) { new_free(&temp->name); new_free(&temp->link); new_free((char **) &temp); } } void clean_split_server_list(int type, time_t len) { irc_server *last = NULL; irc_server *s; if (from_server < 0) return; if (type == LLOOK_SPLIT) s = server_list[from_server].server_last; else s = server_list[from_server].split_link; if (!s) return; while (s) { last = s->next; if (s->time + len <= now) remove_split_server(type, s->name); s = last; } } int is_server_valid(char *name, int server) { if(server > -1 && server < number_of_servers && ((server_list[server].snetwork && my_stricmp(name, server_list[server].snetwork) == 0) || (server_list[server].name && my_stricmp(name, server_list[server].name) == 0))) return 1; return 0; } void parse_364(char *channel, char *args, char *subargs) { if (!*channel || !*args || from_server < 0) return; add_server(&server_list[from_server].tmplink, channel, args, atol(subargs), now); } void parse_365(char *channel, char *args, char *subargs) { register irc_server *serv1; if (from_server < 0) return; for (serv1 = server_list[from_server].server_last; serv1; serv1 = serv1->next) { if (!find_server(server_list[from_server].tmplink, serv1->name)) { if (!(serv1->status & SPLIT)) serv1->status = SPLIT; if (serv1->count) continue; serv1->time = now; if (do_hook(LLOOK_SPLIT_LIST, "%s %s %d %lu", serv1->name, serv1->link, serv1->hopcount, serv1->time)) put_it("%s", convert_output_format(fget_string_var(FORMAT_NETSPLIT_FSET), "%l %s %s %d", now - serv1->time, serv1->name, serv1->link, serv1->hopcount)); serv1->count++; } else { if (serv1->status & SPLIT) { serv1->status = ~SPLIT; if (do_hook(LLOOK_JOIN_LIST, "%s %s %d %lu", serv1->name, serv1->link, serv1->hopcount, serv1->time)) put_it("%s", convert_output_format(fget_string_var(FORMAT_NETJOIN_FSET), "%l %s %s %d", now - serv1->time, serv1->name, serv1->link, serv1->hopcount)); serv1->count = 0; } } } for (serv1 = server_list[from_server].tmplink; serv1; serv1 = serv1->next) { if (!find_server(server_list[from_server].server_last, serv1->name)) { if (first_time == 1) { if (do_hook(LLOOK_ADDED_LIST, "%s %s %d", serv1->name, serv1->link, serv1->hopcount)) put_it("%s", convert_output_format(fget_string_var(FORMAT_NETADD_FSET), "%l %s %s %d", now - serv1->time, serv1->name, serv1->link, serv1->hopcount)); serv1->count = 0; } add_server(&server_list[from_server].server_last, serv1->name, serv1->link, serv1->hopcount, now); } } first_time = 1; clear_link(&server_list[from_server].tmplink); } /* * find split servers we hope */ BUILT_IN_COMMAND(linklook) { #ifdef WANT_LLOOK struct server_split *serv; int count; if (from_server < 0) return; if (!(serv = server_list[from_server].server_last)) if (!(serv = server_list[from_server].split_link)) { bitchsay("No active splits"); return; } count = 0; while (serv) { if (serv->status & SPLIT) { if (!count) put_it("%s", convert_output_format(fget_string_var(FORMAT_NETSPLIT_HEADER_FSET), "%s %s %s %s", "time","server","uplink","hops")); if (do_hook(LLOOK_SPLIT_LIST, "%s %s %d %lu", serv->name, serv->link, serv->hopcount, serv->time)) put_it("%s", convert_output_format(fget_string_var(FORMAT_NETSPLIT_FSET), "%l %s %s %d", now - serv->time, serv->name, serv->link, serv->hopcount)); count++; } serv = serv->next; } if (count) bitchsay("There %s %d split servers", (count == 1) ? "is": "are", count); else #endif bitchsay("No split servers found"); } WhoEntry *who_queue_top (int server) { return server_list[server].who_queue; } void set_who_queue_top(int server, WhoEntry *item) { server_list[server].who_queue = item; } IsonEntry *ison_queue_top (int server) { return server_list[server].ison_queue; } void set_ison_queue_top(int server, IsonEntry *ison) { server_list[server].ison_queue = ison; } UserhostEntry *userhost_queue_top (int server) { return server_list[server].userhost_queue; } void set_userhost_queue_top(int server, UserhostEntry *item) { server_list[server].userhost_queue = item; } Server *BX_get_server_list(void) { return server_list; } int get_server_local_port (int gsp_index) { if (gsp_index == -1) gsp_index = primary_server; else if (gsp_index >= number_of_servers) return 0; return ntohs(server_list[gsp_index].local_sockname.sf_port); } struct sockaddr_foobar get_server_local_addr (int servnum) { return server_list[servnum].local_addr; } struct sockaddr_foobar get_server_uh_addr (int servnum) { return server_list[servnum].uh_addr; } void BX_send_msg_to_channels(ChannelList *channel, int server, char *msg) { int serv_version; char *p = NULL; ChannelList *chan = NULL; int count; /* * Because of hybrid and it's removal of , targets * we need to detect this and get around it.. */ serv_version = get_server_version(server); if (serv_version == Server2_8hybrid6) { /* this might be a cause for some flooding however. * so we use the server queue. Which will help alleviate * some flooding from the client. */ for (chan = channel; chan; chan = chan->next) queue_send_to_server(server, msg, chan->channel); return; } for (chan = channel, count = 1; chan; chan = chan->next, count++) { m_s3cat(&p, ",", chan->channel); if (count > 3) { send_to_server(msg, p); new_free(&p); count = 0; } } if (p) send_to_server(msg, p); new_free(&p); } void BX_send_msg_to_nicks(ChannelList *chan, int server, char *msg) { int serv_version; char *p = NULL; NickList *n = NULL; int count; /* * Because of hybrid and it's removal of , targets * we need to detect this and get around it.. */ serv_version = get_server_version(server); if (serv_version == Server2_8hybrid6) { for (n = next_nicklist(chan, NULL); n; n = next_nicklist(chan, n)) queue_send_to_server(server, msg, n->nick); return; } for (n = next_nicklist(chan, NULL), count = 1; n ; n = next_nicklist(chan, n), count++) { m_s3cat(&p, ",", n->nick); if (count > 3) { send_to_server(msg, p); new_free(&p); count = 0; } } if (p) send_to_server(msg, p); new_free(&p); } /* * written by SrFrog for epic. */ int save_servers (FILE *fp) { int i = 0; if (!server_list) return i; /* no servers */ for (i = 0; i < number_of_servers; i++) { /* SERVER -ADD server:port:password:nick */ fprintf(fp, "SERVER -ADD %s:%d:%s:%s\n", server_list[i].name, server_list[i].port, server_list[i].password ? server_list[i].password : empty_string, server_list[i].nickname ? server_list[i].nickname : empty_string); } return i; }