diff -Naupr BitchX.orig/include/ctcp.h BitchX/include/ctcp.h --- BitchX.orig/include/ctcp.h 2003-04-11 03:09:07.000000000 +0200 +++ BitchX/include/ctcp.h 2006-10-03 11:08:57.000000000 +0200 @@ -56,7 +56,6 @@ extern CtcpEntryDll *dll_ctcp; -extern char *ctcp_type[]; extern int sed; extern int in_ctcp_flag; diff -Naupr BitchX.orig/include/struct.h BitchX/include/struct.h --- BitchX.orig/include/struct.h 2003-04-11 03:09:07.000000000 +0200 +++ BitchX/include/struct.h 2006-10-03 11:09:13.000000000 +0200 @@ -1064,7 +1064,6 @@ struct timeval time; int delete; } TimerList; -extern TimerList *PendingTimers; typedef struct nicktab_stru { struct nicktab_stru *next; diff -Naupr BitchX.orig/source/funny.c BitchX/source/funny.c --- BitchX.orig/source/funny.c 2003-04-11 03:09:07.000000000 +0200 +++ BitchX/source/funny.c 2006-10-03 11:08:45.000000000 +0200 @@ -265,6 +265,11 @@ int user_count = 0; if (!channel || !line) return; + if (channel == NULL || line == NULL) { + bitchsay("Invalid number of arguments for %s", __FUNCTION__); + return; + } + ptr = line; while (*ptr) { diff -Naupr BitchX.orig/source/funny.c.orig BitchX/source/funny.c.orig --- BitchX.orig/source/funny.c.orig 1970-01-01 01:00:00.000000000 +0100 +++ BitchX/source/funny.c.orig 2003-04-11 03:09:07.000000000 +0200 @@ -0,0 +1,435 @@ +/* + * funny.c: Well, I put some stuff here and called it funny. So sue me. + * + * written by michael sandrof + * + * copyright(c) 1990 + * + * see the copyright file, or do a help ircii copyright + */ + + +#include "irc.h" +static char cvsrevision[] = "$Id: funny.c,v 1.1.1.1 2003/04/11 01:09:07 dan Exp $"; +CVS_REVISION(funny_c) +#include "struct.h" + +#include "ircaux.h" +#include "hook.h" +#include "vars.h" +#include "funny.h" +#include "names.h" +#include "server.h" +#include "lastlog.h" +#include "ircterm.h" +#include "output.h" +#include "numbers.h" +#include "parse.h" +#include "status.h" +#include "misc.h" +#include "screen.h" +#define MAIN_SOURCE +#include "modval.h" + +static char *match_str = NULL; + +static int funny_min; +static int funny_max; +static int funny_flags; + +void funny_match(char *stuff) +{ + malloc_strcpy(&match_str, stuff); +} + +void set_funny_flags(int min, int max, int flags) +{ + funny_min = min; + funny_max = max; + funny_flags = flags; +} + +struct WideListInfoStru +{ + char *channel; + int users; +}; + +typedef struct WideListInfoStru WideList; + +static WideList **wide_list = NULL; +static int wl_size = 0; +static int wl_elements = 0; + +static int funny_widelist_users (WideList **, WideList **); +static int funny_widelist_names (WideList **, WideList **); + +static int funny_widelist_users(WideList **left, WideList **right) +{ + if ((**left).users > (**right).users) + return -1; + else if ((**right).users > (**left).users) + return 1; + else + return my_stricmp((**left).channel, (**right).channel); +} + +static int funny_widelist_names(WideList **left, WideList **right) +{ + int comp; + + if (!(comp = my_stricmp((**left).channel, (**right).channel))) + return comp; + else if ((**left).users > (**right).users) + return -1; + else if ((**right).users > (**left).users) + return 1; + else + return 0; +} + + +void funny_print_widelist(void) +{ + int i; + char buffer1[BIG_BUFFER_SIZE]; + char buffer2[BIG_BUFFER_SIZE]; + char *ptr; + + if (!wide_list) + return; + + if (funny_flags & FUNNY_NAME) + qsort((void *) wide_list, wl_elements, sizeof(WideList *), + (int (*) (const void *, const void *)) funny_widelist_names); + else if (funny_flags & FUNNY_USERS) + qsort((void *) wide_list, wl_elements, sizeof(WideList *), + (int (*) (const void *, const void *)) funny_widelist_users); + + set_display_target(NULL, LOG_CRAP); + *buffer1 = '\0'; + for (i = 1; i < wl_elements; i++) + { + sprintf(buffer2, "%s(%d) ", wide_list[i]->channel, + wide_list[i]->users); + ptr = strchr(buffer1, '\0'); + if (strlen(buffer1) + strlen(buffer2) > current_term->TI_cols - 5) + { + if (do_hook(WIDELIST_LIST, "%s", buffer1)) + put_it("%s", convert_output_format(fget_string_var(FORMAT_WIDELIST_FSET), "%s %s", update_clock(GET_TIME), buffer1)); + *buffer1 = 0; + strcat(buffer1, buffer2); + } + else + strcpy(ptr, buffer2); + } + if (*buffer1 && do_hook(WIDELIST_LIST, "%s", buffer1)) + put_it("%s", convert_output_format(fget_string_var(FORMAT_WIDELIST_FSET), "%s %s", update_clock(GET_TIME), buffer1)); + + reset_display_target(); + for (i = 0; i < wl_elements; i++) + { + new_free(&wide_list[i]->channel); + new_free((char **)&wide_list[i]); + } + new_free((char **)&wide_list); + wl_elements = wl_size = 0; +} + +void funny_list(char *from, char **ArgList) +{ + char *channel, + *user_cnt, + *line; + WideList **new_list; + int cnt; + static char format[30]; + static int last_width = -1; + + if (last_width != get_int_var(CHANNEL_NAME_WIDTH_VAR)) + { + if ((last_width = get_int_var(CHANNEL_NAME_WIDTH_VAR)) != 0) + snprintf(format, 25, "%%s %%-%u.%us %%-5s %%s", /*thing_ansi,*/ + (unsigned char) last_width, + (unsigned char) last_width); + else + snprintf(format, 25, "%%s %%s %%-5s %%s"/*, thing_ansi*/); + } + channel = ArgList[0]; + user_cnt = ArgList[1]; + line = PasteArgs(ArgList, 2); + if (funny_flags & FUNNY_TOPIC && !(line && *line)) + return; + cnt = my_atol(user_cnt); + if (funny_min && (cnt < funny_min)) + return; + if (funny_max && (cnt > funny_max)) + return; + if ((funny_flags & FUNNY_PRIVATE) && (*channel != '*')) + return; + if ((funny_flags & FUNNY_PUBLIC) && ((*channel == '*') || (*channel == '@'))) + return; + if (match_str) + { + if (wild_match(match_str, channel) == 0) + return; + } + if (funny_flags & FUNNY_WIDE) + { + if (wl_elements >= wl_size) + { + new_list = (WideList **) new_malloc(sizeof(WideList *) * + (wl_size + 50)); + memset(new_list, 0, sizeof(WideList *) * (wl_size + 50)); + if (wl_size) + memcpy(new_list, wide_list, sizeof(WideList *) * wl_size); + wl_size += 50; + new_free((char **)&wide_list); + wide_list = new_list; + } + wide_list[wl_elements] = (WideList *) + new_malloc(sizeof(WideList)); + wide_list[wl_elements]->channel = NULL; + wide_list[wl_elements]->users = cnt; + malloc_strcpy(&wide_list[wl_elements]->channel, + (*channel != '*') ? channel : "Prv"); + wl_elements++; + return; + } + set_display_target(channel, LOG_CRAP); + if (do_hook(current_numeric, "%s %s %s %s", from, channel, user_cnt, + line) && do_hook(LIST_LIST, "%s %s %s", channel, user_cnt, line)) + { + if (channel && user_cnt) + put_it("%s", convert_output_format(fget_string_var(FORMAT_LIST_FSET),"%s %s %s %s", update_clock(GET_TIME), *channel == '*'?"Prv":channel, user_cnt, line)); + } + reset_display_target(); +} + +void print_funny_names(char *line) +{ +register char *t; +int count = 0; +char buffer[BIG_BUFFER_SIZE+1]; +char special = '\0'; +int cols = get_int_var(NAMES_COLUMNS_VAR); + if (!cols) + cols = 1; + if (line && *line) + { + *buffer = 0; + t = next_arg(line, &line); + do { + if (!count && fget_string_var(FORMAT_NAMES_BANNER_FSET)) + strcpy(buffer, convert_output_format(fget_string_var(FORMAT_NAMES_BANNER_FSET), NULL, NULL)); + if (*t == '@' || *t == '+' || *t == '~' || *t == '-') + { + special = *t; + if (special == '+') + strcat(buffer, convert_output_format(fget_string_var(FORMAT_NAMES_VOICECOLOR_FSET),"%c %s", special, ++t)); + else + strcat(buffer, convert_output_format(fget_string_var(FORMAT_NAMES_OPCOLOR_FSET),"%c %s", special, ++t)); + } + else + strcat(buffer, convert_output_format(fget_string_var(FORMAT_NAMES_NICKCOLOR_FSET), "$ %s", t)); + strcat(buffer, space); + if (count++ >= (cols - 1)) + { + put_it("%s", buffer); + *buffer = 0; + count = 0; + } + } while ((t = next_arg(line, &line))); + + if (buffer) + put_it("%s", buffer); + } +} + +void funny_namreply(char *from, char **Args) +{ +char *type, + *channel; +static char format[40]; +static int last_width = -1; +register char *ptr; +register char *line; +int user_count = 0; + + PasteArgs(Args, 2); + type = Args[0]; + channel = Args[1]; + line = Args[2]; + + /* protocol violation by server */ + if (!channel || !line) + return; + + ptr = line; + while (*ptr) + { + while (*ptr && (*ptr != ' ')) + ptr++; + user_count++; + while (*ptr && (*ptr == ' ')) + ptr++; + } + + if (in_join_list(channel, from_server)) + { + set_display_target(channel, LOG_CRAP); + if (do_hook(current_numeric, "%s %s %s %s", from, type, channel,line) + && do_hook(NAMES_LIST, "%s %s", channel, line) + && get_int_var(SHOW_CHANNEL_NAMES_VAR)) + { + put_it("%s", convert_output_format(fget_string_var(FORMAT_NAMES_FSET), "%s %s %d",update_clock(GET_TIME), channel, user_count)); + print_funny_names(line); + } + if ((user_count == 1) && (*line == '@')) + { + ChannelList *chan; + if ((chan = lookup_channel(channel, from_server, CHAN_NOUNLINK))) + if ((ptr = get_cset_str_var(chan->csets, CHANMODE_CSET))) + my_send_to_server(from_server, "MODE %s %s", channel, ptr); + } + got_info(channel, from_server, GOTNAMES); + reset_display_target(); + return; + } + if (last_width != get_int_var(CHANNEL_NAME_WIDTH_VAR)) + { + if ((last_width = get_int_var(CHANNEL_NAME_WIDTH_VAR)) != 0) + sprintf(format, "%%s: %%-%u.%us %%s", + (unsigned char) last_width, + (unsigned char) last_width); + else + strcpy(format, "%s: %s\t%s"); + } + if (funny_min && (user_count < funny_min)) + return; + else if (funny_max && (user_count > funny_max)) + return; + if ((funny_flags & FUNNY_PRIVATE) && (*type == '=')) + return; + if ((funny_flags & FUNNY_PUBLIC) && ((*type == '*') || (*type == '@'))) + return; + if (type && channel) + { + if (match_str) + { + if (wild_match(match_str, channel) == 0) + return; + } + if (do_hook(current_numeric, "%s %s %s %s", from, type, channel, line) && do_hook(NAMES_LIST, "%s %s", channel, line)) + { + set_display_target(channel, LOG_CRAP); + if (fget_string_var(FORMAT_NAMES_FSET)) + { + put_it("%s", convert_output_format(fget_string_var(FORMAT_NAMES_FSET), "%s %s %d", update_clock(GET_TIME), channel, user_count)); + print_funny_names(line); + } + else + { + switch (*type) + { + case '=': + if (last_width &&(strlen(channel) > last_width)) + { + channel[last_width-1] = '>'; + channel[last_width] = (char) 0; + } + put_it(format, "Pub", channel, line); + break; + case '*': + put_it(format, "Prv", channel, line); + break; + case '@': + put_it(format, "Sec", channel, line); + break; + } + } + reset_display_target(); + } + } +} + +void funny_mode(char *from, char **ArgList) +{ + char *mode, *channel; + ChannelList *chan = NULL; + + if (!ArgList[0]) return; + + channel = ArgList[0]; + mode = ArgList[1]; + PasteArgs(ArgList, 1); + + if((channel && in_join_list(channel, from_server)) || get_chan_from_join_list(from_server)) + { + if (!channel) + channel = get_chan_from_join_list(from_server); + update_channel_mode(from, channel, from_server, mode, chan); + update_all_status(current_window, NULL, 0); + got_info(channel, from_server, GOTMODE); + } + else + { + if (channel) + { + set_display_target(channel, LOG_CRAP); + if (do_hook(current_numeric, "%s %s %s", from, channel, mode)) + put_it("%s", convert_output_format(fget_string_var(FORMAT_MODE_CHANNEL_FSET), "%s %s %s %s %s", update_clock(GET_TIME), from, *FromUserHost ? FromUserHost:"ÿ", channel, mode)); + reset_display_target(); + } + else + { + if (do_hook(current_numeric, "%s %s", from, mode)) + put_it("%s", convert_output_format(fget_string_var(FORMAT_MODE_CHANNEL_FSET), "%s %s %s %s", update_clock(GET_TIME), from, *FromUserHost ? FromUserHost:"ÿ", mode)); + } + } +} + +void update_user_mode(char *modes) +{ + int onoff = 1; + char *p_umodes = get_possible_umodes(from_server); + + for (; *modes; modes++) + { + if (*modes == '-') + onoff = 0; + else if (*modes == '+') + onoff = 1; + + else if ((*modes >= 'a' && *modes <= 'z') + || (*modes >= 'A' && *modes <= 'Z')) + { + size_t idx; + int c = *modes; + + idx = ccspan(p_umodes, c); + if (p_umodes[idx] == 0) + ircpanic("Invalid user mode referenced"); + set_server_flag(from_server, idx, onoff); + + if (c == 'o' || c == 'O') + set_server_operator(from_server, onoff); +#if 0 + char c = tolower(*modes); + size_t idx = (size_t) (strchr(umodes, c) - umodes); + + set_server_flag(from_server, USER_MODE << idx, onoff); + + if (c == 'o' || c == 'O') + set_server_operator(from_server, onoff); +#endif + } + } +} + +void reinstate_user_modes (void) +{ + char *modes = get_umode(from_server); + if (modes && *modes) + send_to_server("MODE %s +%s", get_server_nickname(from_server), modes); +} diff -Naupr BitchX.orig/source/Makefile.in BitchX/source/Makefile.in --- BitchX.orig/source/Makefile.in 2003-04-11 03:09:07.000000000 +0200 +++ BitchX/source/Makefile.in 2006-10-03 11:08:45.000000000 +0200 @@ -37,7 +37,7 @@ INSTALL_IRC = @INSTALL_IRC@ IRCLIB = @IRCLIB@ CC = @CC@ -DEFS = @INCLUDES@ +DEFS = @INCLUDES@ @CPPFLAGS@ LIBS = @LIBS@ # Tcl library. @@ -51,6 +51,7 @@ TCL_SRCS = @TCL_SRCS@ # Set this to -g if you want to be able to debug the client, otherwise # use -O to have the compiler do some optimization instead. CFLAGS = @CFLAGS@ +CPPFLAGS= @CPPFLAGS@ # Set this to -s if you want the binary to be stripped. LDFLAGS = @LDFLAGS@ diff -Naupr BitchX.orig/source/server.c BitchX/source/server.c --- BitchX.orig/source/server.c 2003-06-11 09:00:43.000000000 +0200 +++ BitchX/source/server.c 2006-10-03 11:08:45.000000000 +0200 @@ -151,7 +151,7 @@ void BX_close_server (int cs_index, char 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); + snprintf(buffer, sizeof buffer, "QUIT :%s\n", message); #ifdef HAVE_SSL if (get_server_ssl(cs_index)) SSL_write(server_list[cs_index].ssl_fd, buffer, strlen(buffer)); diff -Naupr BitchX.orig/source/server.c.orig BitchX/source/server.c.orig --- BitchX.orig/source/server.c.orig 1970-01-01 01:00:00.000000000 +0100 +++ BitchX/source/server.c.orig 2003-06-11 09:00:43.000000000 +0200 @@ -0,0 +1,3736 @@ +/* + * 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; +} diff -Naupr BitchX.orig/source/term.c BitchX/source/term.c --- BitchX.orig/source/term.c 2003-04-11 03:09:07.000000000 +0200 +++ BitchX/source/term.c 2006-10-03 11:08:45.000000000 +0200 @@ -92,7 +92,6 @@ extern int tgetflag(); #endif extern char *getenv(); -extern char *tparm(); /* * The old code assumed termcap. termcap is almost always present, but on