#include "uirc.h"

#define DEFAULTSERVER	"localhost"
#define DEFAULTPORT	6667
#define COMMANDCHAR	'/'
#define TINYSIZE 12322

#ifdef	linux
#define _POSIX_VERSION
#endif

#ifndef _POSIX_VERSION
#include <sgtty.h>
#define	USE_OLD_TTY
#include <sys/ioctl.h>
#undef	USE_OLD_TTY
#ifndef	CBREAK
#define CBREAK RAW
#endif
#if !defined(sun) && !defined(sequent) && !defined(hpux) && \
	!defined(_AIX) && !defined(aix)
#include <strings.h>
#define strchr index
#else
#include <string.h>
#endif
#else
#include <string.h>
#include <termios.h>
#endif

#ifdef	_POSIX_VERSION
struct	termios _tty;
tcflag_t _res_iflg, _res_lflg;
#define cbreak() (_tty.c_lflag&=~ICANON, \
	tcsetattr(_tty_ch, TCSANOW, &_tty))
#define noecho() (_tty.c_lflag &= ~(ECHO|ICRNL), \
	tcsetattr(_tty_ch, TCSADRAIN, &_tty))
#define savetty() ((void) tcgetattr(_tty_ch, &_tty), \
	_res_iflg = _tty.c_iflag, _res_lflg = _tty.c_lflag)
#define resetty() (_tty.c_iflag = _res_iflg, _tty.c_lflag = _res_lflg,\
	(void) tcsetattr(_tty_ch, TCSADRAIN, &_tty))
#define erasechar()	(_tty.c_cc[VERASE])
#else
struct	sgttyb _tty;
int	_res_flg;
#define cbreak() (_tty.sg_flags|=CBREAK, ioctl(_tty_ch, TIOCSETP, &_tty))
#define noecho() (_tty.sg_flags &= ~(ECHO|CRMOD), \
	ioctl(_tty_ch, TIOCSETP, &_tty))
#define savetty() ((void) ioctl(_tty_ch, TIOCGETP, &_tty), \
	_res_flg = _tty.sg_flags)
#define resetty() (_tty.sg_flags = _res_flg, \
	(void) ioctl(_tty_ch, TIOCSETP, &_tty))
#define erasechar()	(_tty.sg_erase)
#endif


#define	tputs_x(s) (tputs(s,0,putchar_x))

fd_set readfs;	/* data type represents file descriptor for select function,
				/* (actually it is a bit array) */
char last_addressed[512];/* the last nick addressed,
							/* like grep in:  grep hi there! */
int color_nick;
char colored_nick[512];
int trace_flag;
int listen_flag;

char ircname[10];
char backup_ircname[10][10];/* well, enough? */
int nick_in_use_flag;
int backup_ircname_ptr;
int nicks;

char hostname[64];
char backup_hostname[64][64];
int server_not_availeble_flag;
int backup_hostname_ptr;
int servers;

u_short ircport;
int backup_ircport[64];

char addressed_channel[512];
char all_channels[512];
int user_ctcp_command_flag;
char received_hostname[512];

int server_id_color;
int server_text_color;
int nick_id_color;
int nick_text_color;
int last_addressed_color;
struct in_addr local_ip_address;
struct in_addr local_ip_address_according_to_server;
struct in_addr ip_address_according_to_server;
int get_local_ip_address_from_server_flag;
int get_nicks_ip_address_flag;
struct passwd *userinfo;
int auto_rejoin_flag;
FILE *setupfile;
FILE *helpfile;
int wait_help_flag;
int global_page_back_flag;
long global_screen_history_position;
char home_dir[512];
int security_flag;
char mynickuserhost[80];
FILE *exec_filefd;
int exec_delay;

/* used for terminal */
char *term;
int backspace;
int delete;
char    termcap[1024], *ti;
int tty_des, CO, LI, _tty_ch, dumb=0;
char *CM, *CS, *CE, *KU, *KD, *KL, *KR, *kD, * BS, *KP, *KN, *K4, *KH;
char  bp[1024], *ptr;
/* buf[512], object[256],localhost[64]; */
struct  termios _tty;
tcflag_t _res_iflg, _res_lflg;

static  int current=0; /* current position in input buffer */
static  int pos=0; /* position on input line */
static  int poslc=0; /* current "page" of 70 columns */

struct timeval timeout;
time_t idletimer; /* idle time for user */
time_t ctcp_ping_timer;/* response time to a ctcp ping request from
								/*  this client */
/* end of terminal */

/* used for mirc colors */
int mirc_colors_flag = 0;


char *expand_mirc_colors(char *text)
{
int a, b, c, d, i, j;
int in_mirc_color_flag;
int fg_flag, bg_flag;
int foreground, background;
char mirc_color_field[512];
int mirc_color_field_ptr;
int outtext_ptr;
char temp[512];
char outtext[1024];
int value;
char *expanded_text;
int digit_cnt;
int fg, bg, fg_intens, bg_intens;

foreground = 0;
background = 0;
outtext_ptr = 0;
fg_flag = 0;
bg_flag = 0;
in_mirc_color_flag = 0;

for(i = 0; i < strlen(text); i++)
	{
	c = text[i];
	if(in_mirc_color_flag)
		{
		if(isdigit(c) ) digit_cnt++;
		else digit_cnt = 0;
		
		if(  (digit_cnt > 2) || ( !isdigit(c) && (c != ',') )  )
			/* after 2 digits in row, or a non digit that is not ',' */
			{
			in_mirc_color_flag = 0;
			mirc_color_field[mirc_color_field_ptr] = 0;
											/* string termination */
			/* parse the color field */
			foreground = 0;
			background = 0;
			bg_flag = 0;
			fg_flag = 0;
			value = 0;
			if( isdigit(mirc_color_field[0]) ) fg_flag = 1; 
			for(j = 0; j < strlen(mirc_color_field); j++)
				{
				d = mirc_color_field[j];
				if(isdigit(d) )
					{
					value = value * 10 + (d - '0');
					continue;
					}
				if(d == ',')
					{
					bg_flag = 1;
					if(fg_flag) foreground = value;
					value = 0;
					continue;
					} 
				}/* end for all characters in mirc_color_field */
			if(! bg_flag) foreground = value;
			if(bg_flag) background = value;
/*						
fprintf(stdout,\
"mirc_color_field=%s (len=%d)foreground=%d background=%d\n",\
mirc_color_field, strlen(mirc_color_field), foreground, background);					
*/

			if(strlen(mirc_color_field) == 0)/* ^C only */
				{
				strcat(outtext, "\33[00m");/* end the color */
				outtext_ptr = strlen(outtext);/* WWWW */
				outtext[outtext_ptr] = c;
				outtext_ptr++;
				outtext[outtext_ptr] = 0;/* string termination */
				continue;
				}
			else
				{
				/* color translation table */
				foreground = foreground % 16;
				background = background % 16;

				mirc_color_to_term_color(foreground, &fg, &fg_intens);
				mirc_color_to_term_color(background, &bg, &bg_intens);
/*
fprintf(stdout,\
"foreground=%d fg_flag=%d a=%d background=%d bg_flag=%d b=%d\n",\
foreground, fg_flag, a, background, bg_flag, b);
fprintf(stdout, "outtext=%s mirc_color_field=%s\n",\
outtext, mirc_color_field);
*/
				/* append the color to outtext */

				if(fg_flag)
					{
					sprintf(temp, "\33[%d;%dm", fg_intens, fg);
					strcat(outtext, temp);
					}
				if(bg_flag)
					{
					sprintf(temp, "\33[%d;%dm", bg_intens, bg + 10);
					strcat(outtext, temp);
					}
				sprintf(temp, "%c", c);
				strcat(outtext, temp);
				outtext_ptr = strlen(outtext);
				}
			continue;
			}/* end end of color field detected */
		else
			{
			mirc_color_field[mirc_color_field_ptr] = c;
			mirc_color_field_ptr++;
			continue;
			}
		}/* end in_mirc_color_flag */
	if(c == 3) /* a mirc color ^C was found, the game begins */
		{
		in_mirc_color_flag = 1;
		mirc_color_field_ptr = 0;
		outtext[outtext_ptr] = 0;/* mark end of string */
		digit_cnt = 0;
		continue;/* scip the ^C */
		}
	outtext[outtext_ptr] = c;
	outtext_ptr++;
	}/* end for all characters in text */

outtext[outtext_ptr] = 0;/* string termination */
strcat(outtext, "\33[00m");/* end the color on the end of line */

expanded_text = (char *)strsave(outtext);
return(expanded_text);
}/* end function expand_mirc_colors */


int putchar_x(int c)
{
putchar(c);
}


void print_at(int hpos, int vpos, char *text)
{
tputs_x( tgoto(CM, hpos, vpos) );
fprintf(stdout, "%s", text);
}


void print_it(char *text)
{
tputs_x( tgoto(CM, 0, LI - 3) );
fprintf(stdout, "%s\n", text);
}


void to_screen(char *text, char *source)
{
char channel[40];
int a, i;
char temp[512];
char arg0[512], arg1[512];
char *mirc_expanded_text;

/* save data for later  page back, or if in page back for later display */
/* window name, vsize, text */
set_screen_history("main", 80, 22, text);

/* if not in page back mode print it */
if(! global_page_back_flag)
	{
	tputs_x( tgoto(CM, 0, LI - 3) );
	fprintf(stdout, "%s\n", text);
	}
/* log it */

/* for now, server messages should always go to the addressed channel */
	/* this keeps the right context for debugging */
if(strcmp(source, "server") == 0) strcpy(channel, addressed_channel);
	/* if error in ctcp dequote, and ctcp to me, log in addressed channel */
else if(strcmp(source, ircname) == 0) strcpy(channel, addressed_channel);
	/* system (uirc) messages should always go to the addressed channel */
else if(source[0] == 0) strcpy(channel, addressed_channel);
else strcpy(channel, source);

/* temp if addresed channel is "" (not on a channel) */ 
if(strlen(channel) == 0) strcpy(channel, "not_on_channel");

for(i = 0; i < 10; i++)
	{
	if(! get_setup("auto_log", temp, i) ) break;
	sscanf(temp, "%s %s", arg0, arg1);
	if(strcmp(arg1, "yes") == 0)
		{
		if(strcmp(channel, "not_on_channel") == 0)
			{
			if(strcmp(arg0, "not_on_channel") == 0)
				{
				log_channel(channel, text);
				}
			}	
		else if( (channel[0] == '#') || (channel[0] == '&') ) /* a channel */
			{
			if(strcmp(arg0, "channels") == 0)
				{
				log_channel(channel, text);
				}
			}
		else /* must be a private message or a dcc chat */
			{
			if(strcmp(arg0, "private_messages") == 0)
				{
				log_channel(channel, text);
				}
			}
		}/* end else if arg2 is 'yes' */
	}/* end for all auto log */
}/* end function to screen */


void usage(char text[])
{
char temp[512];

sprintf(temp, "Usage: %s", text);
to_screen(temp, "");
}


int string_to_color(char *color, int *icolor)
{
char ucolor[40];
int i, a;
char temp[512];
/* convert color to upper case in ucolor */
for(i = 0; i < 40; i++)
	{
	ucolor[i] = toupper(color[i]);
	if(color[i] == 0) break;/* string terminator */
	}
a = 1;
if(strcmp(ucolor, "RED") == 0) *icolor = RED;
else if(strcmp(ucolor, "GREEN") == 0) *icolor = GREEN;
else if(strcmp(ucolor, "BLUE") == 0) *icolor = BLUE;
else if(strcmp(ucolor, "MAGENTA") == 0) *icolor = MAGENTA;
else if(strcmp(ucolor, "YELLOW") == 0) *icolor = YELLOW;
else if(strcmp(ucolor, "CYAN") == 0) *icolor = CYAN;
else if(strcmp(ucolor, "FLASHING") == 0) *icolor = FLASH;
else if(strcmp(ucolor, "INTENSIFIED") == 0) *icolor = INTENSIFIED;
else if(strcmp(ucolor, "BLACK") == 0) *icolor = BLACK;
else if(strcmp(ucolor, "INVERSE") == 0) *icolor = INVERSE;
else if(strcmp(ucolor, "OFF") == 0) *icolor = OFF;
else
	{
	/* do not change color */
	to_screen("Invalid color", "");
	a = 0;
	}
return(a);
}


int mirc_color_to_term_color(int color_in, int *color_out, int *intensity)
{
/* since my xterm (and linux console) has only 8 colors,
/* we have a problem here, anyone ?
*/

switch(color_in)
	{
	case 0:
		*color_out = WHITE; /* mirc: white */
		*intensity = 1;
		break;
	case 1:
		*color_out = BLACK; /* mirc: black */
		*intensity = 1;
		break;
	case 2: 
		*color_out = BLUE; /* mirc: blue (navy) */
		*intensity = 1;
		break;
	case 3:
		*color_out = GREEN;/* mirc: green */
		*intensity = 1;
		break;
	case 4:
		*color_out = RED;/* mirc: red */
		*intensity = 1;
		break;
	case 5:
		*color_out = RED;/* mirc: brown (maroon) */
		*intensity = 0;
		break;
	case 6:
		*color_out = MAGENTA;/* mirc: MAG purple */
		*intensity = 1;
		break;
	case 7:
		*color_out = YELLOW; /* mirc: orange (olive) */
		*intensity = 0;
		break;
	case 8:
		*color_out = YELLOW;/* mirc: yellow */
		*intensity = 1;
		break;
	case 9:
		*color_out = GREEN;/* mirc: lt. green (lime) */
		*intensity = 0;
		break;
	case 10:
		*color_out = BLUE;/* mirc: teal (green-blue cyan)*/
		*intensity = 0;
		break;
	case 11:
		*color_out = CYAN;/* mirc: lt. cyan cyan ? (aqua) */
		*intensity = 0;
		break;
	case 12:
		*color_out = BLUE;/* mirc: ls. blue (royal) */
		*intensity = 0;
		break;
	case 13:
		*color_out = MAGENTA;/* mirc: pink (lt. purple, fuchsia) */
		*intensity = 0;
		break;
	case 14:
		*color_out = BLACK;/* mirc: grey */
		*intensity = 0;
		break;
	case 15:
		*color_out = BLACK;/* mirc: lt. grey (silver) */
		*intensity = 0;
		break;
	}/* end switch color_in */
}/* end function mirc_color_to_term_color */


echo_to_user(char input_buffer[], int pointer, int home_flag)
{
/* echo to user the input_buffer, and print a software (flashing) cursor */
int i, j;
int a;
char c;
char first[512];
char cursor[2];
char color_cursor[100];/* hold ansi sequences, need more space! */
char last[550];
char empty[512];
char temp[512];
char temp2[256];
static int old_i;

first[0] = 0;
last[0] = 0;
empty[0] = 0;

if(home_flag)/* cursor home */
	{
	i = 0;
	old_i = 0;
	}
if(strlen(input_buffer) == 1)/* first or only one character */
	{
	i = 0;
	old_i = 0;
	}
if(strlen(input_buffer) == 0)
	{
	i = 0;
	old_i = 0;
	}
/* cursor is character at cursor position */
/* the cursor is a flashing character, unless pointing to empty space,
/* or at the end of the input line, then it is a flashing '>' */
cursor[0] = input_buffer[pointer];
if(cursor[0] == 0)cursor[0] = '>';/* cursor at end, past last character */
if(cursor[0] == ' ')cursor[0] = '>';/* space between words */
cursor[1] = 0;/* string ternination */

/* give cursor a distinct appearance */
/*color_to_text(cursor, INVERSE, color_cursor);*/
color_to_text(cursor, FLASH, color_cursor, 1);

/* If history, set index i for correct start of window.
/*
/* History access sets pointer to strlen(input_buffer),
/* that is cursor to end of line, a separate
/* history array could be used for the cursor position,
/* but this might be confusing, so doing it this way.
*/
if( pointer == strlen(input_buffer) )
	{
	i = strlen(input_buffer) - (CO - 1);
	if(i < 0) i = 0;
	old_i = i; 
	}

/* first is character up to cursor position */
sprintf(first, "%s", input_buffer);
first[pointer] = 0;
	
/* last is inputbuffer after cursor position */ 
sprintf(last, "%s", &input_buffer[pointer + 1] );
/* overrule this if the cursor was at the end of line */
if(input_buffer[pointer] == 0)last[0] = 0;/* mark empty */

/* print position */
tputs_x( tgoto(CM, 0, LI - 1) );

/* combine */
sprintf(temp, "%s%s%s", first, color_cursor, last);

/* if temp shorter then screen columns, print temp from 0 */
/* else
/* print temp, so that temp is right justified (including the cursor at
/* the most right hand side, if the cursor is at the end).
/* The screen is a window that always has the cursor visible.
/* Trying to move the cursor past the most leftside of the screen will cause 
/* temp to be printed from the cursor position (cutoff at the right).
/* Trying to move the cursor past the most right side of the screen will
/* cause temp to be printed up to and including the cursor (cutoff at the
/* left).
*/

i = old_i;/* keep the window in position, unless following: */
if(pointer < i)/* fell of left side */
	{
	i--;/* shift window left */
	}
if(pointer > i + (CO - 1) )/* fell of right side */
	{
	i++;/* shift window right */
	}

if(i < 0) i = 0;
old_i = i;/* save start window (index in temp) for next time */

/* cut off at end (set end window) */
temp[i + (CO - 1) + strlen(color_cursor)] = 0;
				/* color_cursor has ansi sequences and is 13 bytes long */

/* if cursor at right side of window, and moving back,
/* erase the old characters in window */
/* calculate characters in window to be erased */
a = (CO - 1) - (strlen(temp) - strlen(color_cursor) - i);
for(j = 0; j < a; j++)
	{
	empty[j] = ' ';
	}
empty[j] = 0;

/* combine and print it */
tputs_x( tgoto(CM, 0, LI - 1) );
fprintf(stdout, "%s%s",  &temp[i], empty);

}/* end function echo_to_user */


int copy_down(char string[], int start, int space, int maxlen)
/*copy up string str from start space characters*/
{
int ptr;
char c;
/* first start + space to start, then start + space + 1 to start + 1, etc.*/
if(start < 0)return(0);/*boundary*/
ptr = start;
while(1)
	{
	if( (ptr + space) > maxlen)return(0);/*boundary*/
	c = string[ptr + space];
	string[ptr] = c;/*copy down*/
	if(c == 0)return(1);/*array termination also copied, ready*/
	ptr++;
	}
}/*end function copy_down*/


int copy_up(char string[], int start, int space, int maxlen)
/*copy up string str from start space characters*/
{
int ptr;
char c;
int top;
/*find end of string*/
top = 0;
while(1)
	{
	c = string[top];
	if(c == 0)break;/*found end*/
	top++;
	if(top > maxlen)return(0);/*error, top not found*/
	}
ptr = top;
/* first top to top + space, then top - 1 to top + space - 1, etc. */
while(1)
	{
	/*test for array boundary*/
	if( (ptr < 0) || (ptr > (maxlen - space) ) )return(0);/*error*/
	c = string[ptr];
	string[ptr + space] = c;/* copy up starting at top*/
	if(ptr == start)return(1);/*ready*/
	ptr--;
	}
return(1);/*ok*/
}/*end function copy_up*/


void cleanup()
{
tputs_x ( tgoto(CS, -1, -1) );
tputs_x ( tgoto(CM, 0, LI - 1) );
resetty();
exit(128);
}/* end function cleanup */


int trace(char descriptor[], char contents[])/* for debugging only */
{
char temp[512];
if(! trace_flag)return(1);
sprintf(temp, "%s=%s\n", descriptor, contents);
to_screen(temp, "");
return(1);
}/* end function trace */                 


updatestatus()
{
int i;
time_t now;
char temp1[512];
char temp2[512];
char ignores[512];
char hold[40];
char dcc_send_file_info[80];

/* position cursor */
tputs_x( tgoto(CM, 0, LI - 2) );

/* get the present time */
now = time(NULL);
*(strchr( ti = ctime(&now), '\n') ) = 0;

/* get all joined channels in a string */
all_channels[0] = 0;
get_all_channels(all_channels);

/* dcc_send_file_info in a string */
get_dcc_send_file_info(dcc_send_file_info);

/* get ignores */
get_all_ignore_nick(ignores);

/* print a message if in screen history */
if(global_page_back_flag)
	{
	sprintf(hold, "H I S T O R Y -%ld  ", global_screen_history_position);
	}
else hold[0] = 0;

/* combine the data */
sprintf(temp1, "%s%s to %s  on %s  %s  %s  %s  uirc v%s%s",\
hold, ircname, addressed_channel,  all_channels, ignores, dcc_send_file_info,\
ti, VERSION, CE);

if(strlen(temp1) < CO)
	{
	/* fill the rest of the line up with spaces */
	for(i = strlen(temp1); i < CO; i++)
		{
		strcat(temp1, " ");
		}
	}
else temp1[CO] = 0;/* cut off, prevent the input line from getting messed up */
	
/* invert the characters */
color_to_text(temp1, INVERSE, temp2, 1);

/* print the status line */
fprintf(stdout, "%s", temp2);
}/* end function updatestatus */


int color_to_text(char text[], int color, char outtext[], int rx)
{
char *mirc_expanded_text;
char temp[1024];

if(! color)/* no color, no ANSI escape sequences */
	{
	strcpy(temp, text);
	}
else
	{
	sprintf(temp, "\33[01;%dm%s\33[00m", color, text);/* \33 is escape */
	}
if(rx)
	{
	mirc_expanded_text = (char *) expand_mirc_colors(temp);
	sprintf(outtext, "%s", mirc_expanded_text);
	free(mirc_expanded_text);
	}
else
	{
	strcpy(outtext, temp);
	}	
return(1);
}/* end function color_to_text */


char * read_from_console()
{
static char input_buffer[512];
static int pointer;/* pointer in input_buffer */
static char history[HISTORY_SIZE][512];/* command history */
static int history_write_ptr;/* pointer to store entry in history */
static int history_read_ptr;/* pointer to read entry in history */
static char ansi_sequence[512];
static int ansi_ptr;
static int escape_flag;
static int ansi_flag;
static char first_field[512], second_field[512];
static int tab_cnt;
char temp[512];
int history_flag;
char c;
int a;

/* read a character from console */
c = getc(stdin);
/* handle escape */
if(c == 27)/* escape */
	{
	escape_flag = 1;
	if(wait_help_flag)
		{
		/* close helpfile, no more help display */
		wait_help_flag = -1;
		print_help();
		}
	return(0);/* return line incomplete*/
	}	
/* handle tab, (repeat first field) */
if(c == 9)/* hor tab */
	{
	if(tab_cnt == 0) strcpy(input_buffer, first_field);
	if(tab_cnt == 1) strcat(input_buffer, second_field);
	/* add a space */
	strcat(input_buffer, " ");
	/* calculate new poiner */
	pointer = strlen(input_buffer);
	echo_to_user(input_buffer, pointer, 0);
	tab_cnt++;
	if(tab_cnt == 2) tab_cnt = 0;
	return(0);
	}

/*
tputs_x( tgoto(CM, 0, LI - 3) );
fprintf(stdout, "\n%d", c);
*/

/* set mirc colors flag if ^K */
if(c == 11)
	{
	mirc_colors_flag = 1;
	/* replace with a control c */
	c = 3;
	}
else
	{
	/* leave '\n' and backspace, all other control characters are invalid */
	if( (c != '\n') && (c != 8) ) if(c < ' ') return(0);
	}

if(wait_help_flag)
	{
	print_help();
	/* loose character */
	return(0);
	}

/*
tputs_x( tgoto(CM, 0, LI - 3) );
fprintf(stdout, "\n%d", c);
*/

/* handle start ansi */
if(c == '[')
	{
	if(escape_flag)
		{
		ansi_flag = 1;
		ansi_ptr = 0;
		}
	}

/* reset the escape flag */ 
escape_flag = 0;	

/* store in ansi */
if(ansi_flag)
	{
	ansi_sequence[ansi_ptr] = c;
	ansi_sequence[ansi_ptr + 1] = 0;
	ansi_ptr++;	
	if(ansi_ptr > 1)
		{
		tputs_x( tgoto(CM, 0, LI - 3) );
		/* handle cursor up, the previous entry in history */
		history_flag = 0;/* no history access */
		sprintf(temp, "\33%s", ansi_sequence);/* add leading escape */	
		
		/* delete, delete at cursor (only send by grey delete linux console) */
		if(kD) if(strcmp(temp, kD) == 0)
			{
			ansi_flag = 0;
			/* if cursor is at end of input_buffer,
			/* the terminating 0 is there, do not delete that */
			if(pointer == strlen(input_buffer) )return(0);
			copy_down(input_buffer, pointer, 1, 512);
			/* if(pointer)pointer--; */
			/* echo to user */
			echo_to_user(input_buffer, pointer, 0);
			/* return line not complete */
			return(0);
			}
		/* backspace, delete left of cursor */
		if(BS)if(strcmp(temp, BS) == 0)
			{
			/* empty termcap entry bs: in linux console and color xterm */
			}	
		/* PROBLEM with color xterm, termcap entry shows esc O A
		/* however pressing cursor up (grey) results in esc [ A
		/* now testing for both, this goes for KU, KD, KL, KR
		*/
		/* why the 'a' variable? X gives an exeption if strcmp(temp, 0),
		/* so have to test for zero arguments to strcmp (only in X!)
		*/
		/* cursor home (grey) */
		a = 0;
		if(KH) if(strcmp(temp, KH) == 0) a = 1;
		if(strcmp(temp, "\33[1~") == 0) a = 1;
		if(a)
			{
			pointer = 0;
			ansi_flag = 0;
			echo_to_user(input_buffer, pointer, 1);
			}
		/* cursor end (grey) */
		a = 0;
		if(K4) if(strcmp(temp, K4) == 0) a = 1;
		if(strcmp(temp, "\33[4~") == 0) a = 1;
		if(a)
			{
			pointer = strlen(input_buffer);
			ansi_flag = 0;
			echo_to_user(input_buffer, pointer, 0);
			}
		/* page up (grey) */
		a = 0;
		if(KP) if(strcmp(temp, KP) == 0) a = 1;
		if(strcmp(temp, "\33[5~") == 0) a = 1;
		if(a)	
			{
			get_screen_history("main", -1);
/*			to_screen("PAGE UP GREY", "");*/
			ansi_flag = 0;
/*			echo_to_user(input_buffer, pointer, 0);*/
			}
		/* page down (grey) */
		a = 0;
		if(KN) if(strcmp(temp, KN) == 0) a = 1;
		if(strcmp(temp, "\33[6~") == 0) a = 1;
		if(a)
			{
			get_screen_history("main", +1);
/*			to_screen("PAGE DOWN GREY", "");*/
			ansi_flag = 0;
/*			echo_to_user(input_buffer, pointer, 0);*/
			}
		/* cursor left (grey) */
		a = 0;
		if(KL) if(strcmp(temp, KL) == 0) a = 1;
		if(strcmp(temp, "\33[D") == 0) a = 1;
		if(a)
			{
			if(pointer)pointer--;
			ansi_flag = 0;
			echo_to_user(input_buffer, pointer, 0);
			}
		/* cursor right (grey) */
		a = 0;
		if( KR) if(strcmp(temp, KR) == 0) a = 1;
		if(strcmp(temp, "\33[C") == 0) a = 1;
		if(a)	
			{
			if(pointer < strlen(input_buffer) )pointer++;
			echo_to_user(input_buffer, pointer, 0);
			ansi_flag = 0;
			}
		/* cursor up (grey), read previous entry in history */
		a = 0;
		if(KU) if(strcmp(temp, KU) == 0) a = 1;
		if(strcmp(temp, "\33[A") == 0) a = 1;
		if(a)
			{
			history_flag = 1;
			/* move towards the past */
			if(history_read_ptr > 0)history_read_ptr--;
			else history_read_ptr = HISTORY_SIZE - 1;
			ansi_flag = 0;
			}
		/* cursor down (grey), read next entry in history */
		a = 0;
		if(KD) if(strcmp(temp, KD) == 0) a = 1;
		if(strcmp(temp, "\33[B") == 0) a = 1;
		if(a)	
			{
			history_flag = 1;
			/* move towards most recent entry */
			if(history_read_ptr < HISTORY_SIZE - 1)history_read_ptr++;
			else history_read_ptr = 0;
			ansi_flag = 0;
			}
		
		/* modify the input buffer if a history command was encountered */
		if(history_flag)
			{
			sprintf(input_buffer, "%s", &history[history_read_ptr][0]);
			pointer = strlen(input_buffer);
			echo_to_user(input_buffer, pointer, 0);
			}	
		/* prevent staying in long unknown ansi sequences */
		if(ansi_ptr > 3)ansi_flag = 0;
		}
	return(0);/* return line incomplete */
	}/* end if ansi_flag */

/* backspace, erases character left of cursor */
/* color xterms sends 8, linux console sends 127 */ 
if(c == backspace)
	{
	if(pointer)copy_down(input_buffer, pointer - 1, 1, 512);
	if(pointer)pointer--;
	tputs_x( tgoto(CM, pointer, LI - 1) );
	echo_to_user(input_buffer, pointer, 0);
	/* return line not complete */
	return(0);
	}

/* delete, erases character at cursor */
/* color xterm sends 127, linux console sends esc [3~ */
if(c == delete)
	{
	/* if cursor is at end of input_buffer, the terminating 0 is there,
	/* do not delete that */
	if(pointer == strlen(input_buffer) )return(0);
	copy_down(input_buffer, pointer, 1, 512);
	/* if(pointer)pointer--; */
	/* echo to user */
	echo_to_user(input_buffer, pointer, 0);
	/* return line not complete */
	return(0);
	}

/* handle end of user input */
if(c == '\n')
	{
	/* reset pointer for next time */
	pointer = 0;

	/* store the input buffer in history */
	sprintf(history[history_write_ptr], "%s", input_buffer);
	if(history_write_ptr < HISTORY_SIZE - 1)history_write_ptr++;
	else history_write_ptr = 0; 

	/* set the read pointer for history entries to point to the last entry */
	history_read_ptr = history_write_ptr;

	/* erase history entry ahead of present one (in case history buffer is
	/* full), so an empty field can always be selected */
	history[history_write_ptr][0] = 0;
	
	/* put a cursor in the input line */
	echo_to_user("", 0, 0);

	/* store the first and seconf field for later use */
	sscanf(input_buffer,"%s %s", first_field, second_field);
	
	/* reset the tab_cnt */
	tab_cnt = 0 ;

	/* if screen history active for this window, reset it */
	get_screen_history("main", 0);	

	/* mark input buffer empty (and clear input line) */
	return(input_buffer);
	}

/* make space for the character */
copy_up(input_buffer, pointer, 1, 511);

/* store the character */
input_buffer[pointer] = c;/* store the char */

/* increment pointer */
if(pointer < 400)pointer++;/* prevent input buffer overflow,
							/* leave space for ansi */

/* echo to user,
/* pointer (cursor) points to position next character will be printed */
echo_to_user(input_buffer, pointer, 0);

/* return line not complete */
return(0);
}/* end function read_from_console */



int send_to_server(int socketfd, char txbuf[])/* send data to server */
{
int a;

/*
char temp[512];

for(a = 0; a < strlen(txbuf); a++)
	{
	sprintf(temp, "%d (%c)\n", txbuf[a], txbuf[a]);
	to_screen(temp, " ");
	}
*/

if(socketfd == -1)
	{
	to_screen(\
	"You are not connected to a server, use /server to connect", "");
	return(1);
	}
a = write(socketfd, txbuf, strlen(txbuf) );     
if(a < 0)
	{
	to_screen("\nwrite: failed, error:", "");
	if(errno == EBADF) to_screen("Not a valid file descriptor", "");
	if(errno == EFBIG) to_screen("File to big", "");
	if(errno == EAGAIN) to_screen("O_NONBLOCK flag set", "");
	if(errno == EINTR) to_screen(\
	"Was waiting, but interrupted by signal", "");
	if(errno == EIO) to_screen("Hardware error", "");
	if(errno == ENOSPC) to_screen("no space", "");
	if(errno == EPIPE) to_screen(\
	"Writing to pipe or fifo not open for read", "");
	return(0);
	}
trace("txbuf", txbuf);
return(1);
}/* end function send_to_server */


int display_help_one_screen()
{
int c, i, j;
char temp[80];

/* test if ESCAPE was pressed */
if(wait_help_flag == -1)
	{
	wait_help_flag = 0;
	if(helpfile) fclose(helpfile);
	/* no messages, leave the screen as it is, so helptext stays visible */
	return(0);
	}

wait_help_flag = 0;
j = 0;
while(1)
	{
	temp[0] = 0;/* mark empty string */
	for(i = 0; i < 80; i++)
		{
		c = getc(helpfile);
		if(c == EOF) break;
		if(c == 10)
			{
			temp[i] = 0;
			break;
			}
		temp[i] = c;
		}/* end for all characters in a line */
	to_screen(temp, "");
	if(c == EOF)
		{
		fclose(helpfile);
		to_screen("End of help file", "");
		return(0);
		}
	j++;
	if(j == 20)
		{
		to_screen(\
		"Enter for more, ESC to abort help (and keep this text)", "");
		wait_help_flag = 1;
		return(1);
		}				
	}/* end while lines of text */			
return(1);
}/* end function display_help_one_screen */


int print_help()
{	
char pathfilename[512];
char temp[512];

if(wait_help_flag)
	{
	display_help_one_screen();
	return(1);
	}
sprintf(pathfilename, "%s/.uirc/uirc.help", home_dir);
helpfile = fopen(pathfilename, "r");
if(! helpfile)
	{
	sprintf(temp, "Cannot open file %s for read", pathfilename);
	to_screen(temp, "");
	return(1);
	}
else
	{
	display_help_one_screen();
	return(1);
	}
}/* end function read_help */


server_to_client(int *socketfd)
{
char rxbuf[512];
char user_data[512];
char combined[1024];/* need more space, going to insert ansi sequences */ 
char colored_servername_or_nick[512], colored_combined[1024];
int a, b, i, j;
char c;
char dummy[80];
char ping_src[512];
char temp[512];

char prefix[512];
char command[512];
char params[512];
int command_response;

char servername_or_nick[512];
char user[512];
char host[512];

char middle[512];
char trailing[512];

char text[512];
char channel[512];

char arg0[512], arg1[512], arg2[512], arg3[512];
char arg4[512], arg5[512], arg6[512];
int args;
char params0[512], params1[512], params2[512];
char params3[512], params4[512], params5[512];
int params_cnt;
int from_server_flag;/* server message */
char notice0[512], notice1[512];
char on_action[512];
char no_ctcp[1024];

time_t now;
/* get the present time */
now = time(0);
*(strchr( ti = ctime(&now), '\n') ) = 0;

/* read from socket */
i = 0;
while(1)
	{
	a = read(*socketfd, &c, 1);
	if(a <= 0)
		{
		if(a == 0)
			{
			sprintf(temp,\
	"Connection closed by server (EOF), use /server to connect to a server");
			to_screen(temp, "");
			}
		else
			{
			sprintf(temp, "read: returned %d, connection to server lost", a);
			to_screen(temp, "");
			}
		/* close the server socket */
		close(*socketfd);
		/* mark the server socket invalid */
		*socketfd = -1;
		return(1);/* not fatal error, try another server */
		}
	rxbuf[i] = c;
	if(c == 10)
		{
		break;
		}
	i++;
	if(i > 511)break;
	}
rxbuf[i] = 0;/* string terminator */

trace("rxbuf", rxbuf);

/* now gona split the received data using the protocol described in rfc1459
/*
/* first: 
/* message<message>  ::= [':' <prefix> <SPACE> ] <command> <params> <crlf>
/*
/* later the components are split:
/* <prefix>   ::= <servername> | <nick> [ '!' <user> ] [ '@' <host> ]
/* <command>  ::= <letter> { <letter> } | <number> <number> <number>
/* <SPACE>    ::= ' ' { ' ' }
/* <params>   ::= <SPACE> [ ':' <trailing> | <middle> <params> ]
/*
/* <middle>   ::= <Any *non-empty* sequence of octets not including SPACE
/*               or NUL or CR or LF, the first of which may not be ':'>
/*              <trailing> ::= <Any, possibly *empty*, sequence of octets
/*              not including NUL or CR or LF>
*/

/* mark all empty to start with */
prefix[0] = 0;
command[0] = 0;
params[0] = 0;
servername_or_nick[0] = 0;
user[0] = 0;
host[0] = 0;
middle[0] = 0;
trailing[0] = 0;
arg0[0] = 0;
arg1[0] = 0;
arg2[0] = 0;
arg3[0] = 0;
arg4[0] = 0;
arg5[0] = 0;
params0[0] = 0;
params1[0] = 0;
params2[0] = 0;
params3[0] = 0;
params4[0] = 0;
params5[0] = 0;
from_server_flag = 1;
notice0[0] = 0;
notice1[0] = 0;

/* scan the rxbuf */
args = sscanf(rxbuf, "%s %s %s %s %s %s %s",\
arg0, arg1, arg2, arg3, arg4, arg5, arg6);

i = 0;/* pointer in rxbuf */

/* test for optional prefix */
if(rxbuf[i] == ':')
	{
	/* extract prefix */
	j = 0;
	/* start with i = 1, scip first ':' */
	for(i = 1; i < 512; i++)
		{
		c = rxbuf[i];
		if(c  == ' ')break;/* space is prefix terminator */
		prefix[j] = c;
		j++;
		}
	prefix[j] = 0;/* string terminator */
	i++;/* scip the space, part of prefix, point to first char. command */
	}/* end prefix present */

/* extract command */
j = 0;
for(i = i; i < 512; i++)
	{
	c = rxbuf[i];
	if(c == ' ')break;
	command[j] = c;
	if(c == 0)break;
	j++;
	}
command[j] = 0;/* string terminator */	

/* extract params */
i++;/* scip the space */
j = 0;
for(i = i; i < 512; i++)
	{
	c = rxbuf[i];
	params[j] = c;
	if( (c == 10) || (c == 13) )
		{
		params[j] = 0;/* string terminator */
		break;/* end of line */
		}
	j++;
	}
params[j] = 0;/* string terminator */


/* now we have [prefix], command, params */

/* <prefix>   ::= <servername> | <nick> [ '!' <user> ] [ '@' <host> ]

/* split the prefix */
j = 0;
for(i = 0; i < 512; i++)
	{
	c = prefix[i];
	if(c == '!')break;/* start of user */
	servername_or_nick[j] = c;
	if(c == 0)break;/* end of prefix */
	j++;
	}
servername_or_nick[j] = 0;/* string termination */
if(c == '!')/* user [@host] follows */
	{
	i++;/* scip the '!' */
	j = 0;
	for(i = i; i < 512; i++)
		{
		c = prefix[i]; 	
		if(c == '@')break;/* start of host */
		user[j] = c;
		if(c = 0)break;/* end of prefix */
		j++;
		}
	user[j] = 0;/* string termination */
	}
if(c == '@')/* @host */
	{
	i++;/* scip the '@' */
	j = 0;
	for(i = i; i < 512; i++)
		{
		c = prefix[i];
		host[j] = c;
		if(c == 0)break;/* end of prefix */
		j++;
		}
	host[j] = 0;/* string termination */
	}/* end of host */
/*
printf("\nservername_or_nick=%s user=%s host=%s\n",\
servername_or_nick, user, host);
*/

/* now we have servername_or_nick, user, host */

/* command does not need to be split */

/* split the params */

/* <params>   ::= <SPACE> [ ':' <trailing> | <middle> <params> ]
/*
/* <middle>   ::= <Any *non-empty* sequence of octets not including SPACE
/*               or NUL or CR or LF, the first of which may not be ':'>
/* <trailing> ::= <Any, possibly *empty*, sequence of octets
/*              not including NUL or CR or LF>
*/

params_cnt = sscanf(params, "%s %s %s %s %s %s",\
params0, params1, params2, params3, params4, params5);
j = 0;
for(i = 0; i < 512; i++)
	{
	c = params[i];
	if(c == ':')break;/* start of trailing */
	if(c == ' ')continue;/* go for end or ':' */
	middle[j] = c;
	if(c == 0)break;/* end of params */
	j++;
	}
middle[j] = 0;/* string termination */
if(c == ':')
	{
	i++;/* scip the ':' */
	j = 0;
	for(i = i; i < 512; i++)
		{
		c = params[i];
		trailing[j] = c;
		if(c == 0)break;/* end of params */
		j++;
		}
	trailing[j] = 0;/* string terminator */
	}

/*
printf("\nmiddle=%s trailing=%s\n", middle, trailing);
*/

/* now we have server_name_or_nick, user, host, middle, trailing */

/* set the color of the source */
if(strcmp(servername_or_nick, received_hostname) == 0)/* server id color */
	{
	/* received_hostname may be very long, and different from hostname. */
	color_to_text("***", GREEN, colored_servername_or_nick, 1);
	}
else /* user id color */
	{
	color_to_text(\
	servername_or_nick, nick_id_color , colored_servername_or_nick, 1);
	}

/* command sort */

/* test for ignore all */
if(get_ignore_nick(prefix) & ALL)return(1);

/* 6.2 Command responses. */
if( isdigit(command[0]) && isdigit(command[1]) && isdigit(command[2]) )
	{
	command_response = atoi(command);
	
	/*____REMOVE WHEN ALL CASES DONE_____*/
	sprintf(combined, "%s C %d %s",\
	colored_servername_or_nick, command_response, trailing);
	
	switch(command_response)
		{
		case 004:
			/* rxbuf=:panteltje 004 grep panteltje 2.9.1 oiw biklmnopstva */
			/* this command seems to gib=ve the 'real' hostname */
			sprintf(combined, "%s %s %s %s",\
			params1, params2, params3, params4);
			strcpy(received_hostname, params1);
			break;
		case 300: 
			/* RPL_NONE Dummy reply number. Not used. */
			break;
        case 302:
        	 /* RPL_USERHOST ":[<reply>{<space><reply>}]" 

                - Reply format used by USERHOST to list  replies to
                  the query list.  The reply string is composed as
                  follows:

                  <reply> ::= <nick>['*'] '=' <'+'|'-'><hostname>

                  The '*' indicates whether the client has registered
                  as an Operator.  The '-' or '+' characters represent
                  whether the client has set an AWAY message or not
                  respectively.
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 303:
			/* RPL_ISON
                        ":[<nick> {<space><nick>}]"

                - Reply format used by ISON to list replies to the
                  query list.
             */
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 301:
			/* RPL_AWAY
                        "<nick> :<away message>"
			*/
			sprintf(combined, "%s is away: %s", arg3, trailing);
			break;
		case 305:
			/* RPL_UNAWAY
                        ":You are no longer marked as being away"
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 306:
			/* RPL_NOWAWAY
                        ":You have been marked as being away"

                - These replies are used with the AWAY command (if
                  allowed).  RPL_AWAY is sent to any client sending a
                  PRIVMSG to a client which is away.  RPL_AWAY is only
                  sent by the server to which the client is connected.
                  Replies RPL_UNAWAY and RPL_NOWAWAY are sent when the
                  client removes and sets an AWAY message.
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 311:
			/* RPL_WHOISUSER
			                        "<nick> <user> <host> * :<real name>"
			rxbuf=:panteltje 311 uircold ircii ~root panteltje.255.255 * :root
			*/ 
			host_to_dotted_quad(arg5, temp);
			sprintf(combined, "%s is %s@%s %s IP %s",\
			arg3, arg4, arg5, trailing, temp);
			/* arg5 is host temp is dotted quad */
			break;
		case 312:
			/* RPL_WHOISSERVER
                        "<nick> <server> :<server info>"
			rxbuf=:panteltje 312 uircold ircii panteltje :Panteltje irc chat server
			*/
			sprintf(combined, "%s on server %s", arg3, arg4, trailing);
			break;
		case 313:
			/* RPL_WHOISOPERATOR
                        "<nick> :is an IRC operator"
            */
			sprintf(combined, "%s", trailing);/* text used */
			break;		
		case 317:
			/* RPL_WHOISIDLE
                        "<nick> <integer> :seconds idle"
			
			rxbuf=:panteltje 317 uircold ircii 1118 :seconds idle
			*/
			sprintf(combined, "%s %s %s", arg3, arg4, trailing);
			break;
		case 318:
			/* RPL_ENDOFWHOIS
                        "<nick> :End of /WHOIS list"

			rxbuf=:panteltje 318 uircold ircii :End of /WHOIS list.
			*/
			sprintf(combined, "%s %s", arg3, trailing);
			break;
		case 319:
			/* RPL_WHOISCHANNELS
                        "<nick> :{[@|+]<channel><space>}"

                - Replies 311 - 313, 317 - 319 are all replies
                  generated in response to a WHOIS message.  Given that
                  there are enough parameters present, the answering
                  server must either formulate a reply out of the above
                  numerics (if the query nick is found) or return an
                  error reply.  The '*' in RPL_WHOISUSER is there as
                  the literal character and not as a wild card.  For
                  each reply set, only RPL_WHOISCHANNELS may appear
                  more than once (for long lists of channel names).
                  The '@' and '+' characters next to the channel name
                  indicate whether a client is a channel operator or
                  has been granted permission to speak on a moderated
                  channel.  The RPL_ENDOFWHOIS reply is used to mark
                  the end of processing a WHOIS message.
			
			rxbuf=:panteltje 319 uircold ircii :@#1
			*/
			sprintf(combined, "%s on channel(s) %s", arg3, trailing); 
			break;
		case 314:
			/* RPL_WHOWASUSER
                        "<nick> <user> <host> * :<real name>"
			rxbuf=:panteltje 314 uircold grep root panteltje.255.255 * :(null)
			*/
			sprintf(combined, "%s was %s@%s %s %s",\
			arg3, arg4, arg5, arg6, trailing);
			break;
		case 369:
			/* RPL_ENDOFWHOWAS
                        "<nick> :End of WHOWAS"

                - When replying to a WHOWAS message, a server must use
                  the replies RPL_WHOWASUSER, RPL_WHOISSERVER or
                  ERR_WASNOSUCHNICK for each nickname in the presented
                  list.  At the end of all reply batches, there must
                  be RPL_ENDOFWHOWAS (even if there was only one reply
                  and it was an error).
			rxbuf=:panteltje 369 uircold grep :End of WHOWAS
			*/
			sprintf(combined, "%s %s", trailing, arg3);
			break;
		case 321:
			/* RPL_LISTSTART
                        "Channel :Users  Name"
			*/
			sprintf(combined, "%s %s %s", arg3, arg4, arg5);
			break;
		case 322:
			/* RPL_LIST
                        "<channel> <# visible> :<topic>"
			*/
			/* :server 322 nick          #channel 3        :hi there. */
			sprintf(combined, "%s %s %s", params1, params2, trailing);
			break;
		case 323:
			/* RPL_LISTEND
                        ":End of /LIST"

                - Replies RPL_LISTSTART, RPL_LIST, RPL_LISTEND mark
                  the start, actual replies with data and end of the
                  server's response to a LIST command.  If there are
                  no channels available to return, only the start
                  and end reply must be sent.
			*/
			sprintf(combined, "%s %s %s", arg3, arg4, arg5);
			break;
		case 324:
			/* RPL_CHANNELMODEIS
                        "<channel> <mode> <mode params>"
			rxbuf=:panteltje 324 grep #1 +
			*/
			sprintf(combined, "Mode for channel %s is %s %s", arg3, arg4, arg5); 
			break;
		case 331:
			/* RPL_NOTOPIC
                        "<channel> :No topic is set"	
			rxbuf=:panteltje 331 grep #1 :No topic is set.
			*/
			sprintf(combined, "%s %s", arg3, trailing);
			break;
		case 332:
			/* RPL_TOPIC
                        "<channel> :<topic>"

                - When sending a TOPIC message to determine the
                  channel topic, one of two replies is sent.  If
                  the topic is set, RPL_TOPIC is sent back else
                  RPL_NOTOPIC.
			*/
			sprintf(combined, "The topic for %s is %s", arg3, trailing);
			break;
		case 341:
			/* RPL_INVITING
                        "<channel> <nick>"

                - Returned by the server to indicate that the
                  attempted INVITE message was successful and is
                  being passed onto the end client.
			*/
			sprintf(combined, "%s is invited to %s", arg3, arg4);
			break;
		case 342:
			/* RPL_SUMMONING
                        "<user> :Summoning user to IRC"

                - Returned by a server answering a SUMMON message to
                  indicate that it is summoning that user.
			rxbuf=:panteltje 342 me user :User summoned to irc
			*/
			sprintf(combined, "User %s summoned to irc", arg3);
			break;
		case 351:
			/* RPL_VERSION
                        "<version>.<debuglevel> <server> :<comments>"

                - Reply by the server showing its version details.
                  The <version> is the version of the software being
                  used (including any patchlevel revisions) and the
                  <debuglevel> is used to indicate if the server is
                  running in "debug mode".

                  The "comments" field may contain any comments about
                  the version or further version details.
			*/	
			/* 351 RPL_VERSION "<version>.<debuglevel> <server> :<comments>" */
			/* rxbuf=:server 351 nick 2.9.1.0 panteltje :ACDEHIMSU8 V01 */
			sprintf(combined, "Server: %s %s %s\nClient: uirc %s",\
			params1, params2, trailing, VERSION);
			break;
		case 352:
			/* RPL_WHOREPLY
                        "<channel> <user> <host> <server> <nick> \
                         <H|G>[*][@|+] :<hopcount> <real name>"
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 315:
			/* RPL_ENDOFWHO
                        "<name> :End of /WHO list"

                - The RPL_WHOREPLY and RPL_ENDOFWHO pair are used
                  to answer a WHO message.  The RPL_WHOREPLY is only
                  sent if there is an appropriate match to the WHO
                  query.  If there is a list of parameters supplied
                  with a WHO message, a RPL_ENDOFWHO must be sent
                  after processing each list item with <name> being
                  the item.
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 353:
			/* RPL_NAMREPLY
                        "<channel> :[[@|+]<nick> [[@|+]<nick> [...]]]"
			rxbuf=:panteltje 353 grep = &KILLS :
			*/
			sprintf(combined, "%s %s", arg4, trailing);
			break;
		case 366:
			/* RPL_ENDOFNAMES
                        "<channel> :End of /NAMES list"

                - To reply to a NAMES message, a reply pair consisting
                  of RPL_NAMREPLY and RPL_ENDOFNAMES is sent by the
                  server back to the client.  If there is no channel
                  found as in the query, then only RPL_ENDOFNAMES is
                  returned.  The exception to this is when a NAMES
                  message is sent with no parameters and all visible
                  channels and contents are sent back in a series of
                  RPL_NAMEREPLY messages with a RPL_ENDOFNAMES to mark
                  the end.
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 364:
			/* RPL_LINKS
                        "<mask> <server> :<hopcount> <server info>"c
			*/
			sprintf(combined, "\n%s", trailing);/* text used */
			break;
		case 365:
			/* RPL_ENDOFLINKS
                        "<mask> :End of /LINKS list"

                - In replying to the LINKS message, a server must send
                  replies back using the RPL_LINKS numeric and mark the
                  end of the list using an RPL_ENDOFLINKS reply.
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 367:
			/* RPL_BANLIST
                        "<channel> <banid>"
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 368:
			/*  RPL_ENDOFBANLIST
                        "<channel> :End of channel ban list"

                - When listing the active 'bans' for a given channel,
                  a server is required to send the list back using the
                  RPL_BANLIST and RPL_ENDOFBANLIST messages.  A separate
                  RPL_BANLIST is sent for each active banid.  After the
                  banids have been listed (or if none present) a
                  RPL_ENDOFBANLIST must be sent.
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 371:
			/* RPL_INFO
                        ":<string>"
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 374:
			/* RPL_ENDOFINFO
                        ":End of /INFO list"

                - A server responding to an INFO message is required to
                  send all its 'info' in a series of RPL_INFO messages
                  with a RPL_ENDOFINFO reply to indicate the end of the
                  replies.
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 375:
			/* RPL_MOTDSTART
                        ":- <server> Message of the day - "
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 372:
			/* RPL_MOTD
                        ":- <text>"
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 376:
			/* RPL_ENDOFMOTD
                        ":End of /MOTD command"

                - When responding to the MOTD message and the MOTD file
                  is found, the file is displayed line by line, with
                  each line no longer than 80 characters, using
                  RPL_MOTD format replies.  These should be surrounded
                  by a RPL_MOTDSTART (before the RPL_MOTDs) and an
                  RPL_ENDOFMOTD (after).
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 381:
			/* RPL_YOUREOPER
                        ":You are now an IRC operator"

                - RPL_YOUREOPER is sent back to a client which has
                  just successfully issued an OPER message and gained
                  operator status.
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 382:
			/* RPL_REHASHING
                        "<config file> :Rehashing"

                - If the REHASH option is used and an operator sends
                  a REHASH message, an RPL_REHASHING is sent back to
                  the operator.
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 391:
			/* RPL_TIME
                        "<server> :<string showing server's local time>"

                - When replying to the TIME message, a server must send
                  the reply using the RPL_TIME format above.  The string
                  showing the time need only contain the correct day and
                  time there.  There is no further requirement for the
                  time string.
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 392:
			/* RPL_USERSSTART
                        ":UserID   Terminal  Host"
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 393:
			/* RPL_USERS
                        ":%-8s %-9s %-8s"
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 394:
			/* RPL_ENDOFUSERS
                        ":End of users"
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 395:
			/* RPL_NOUSERS
                        ":Nobody logged in"

                - If the USERS message is handled by a server, the
                  replies RPL_USERSTART, RPL_USERS, RPL_ENDOFUSERS and
                  RPL_NOUSERS are used.  RPL_USERSSTART must be sent
                  first, following by either a sequence of RPL_USERS
                  or a single RPL_NOUSER.  Following this is
                  RPL_ENDOFUSERS.
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 200:
			/* RPL_TRACELINK
                        "Link <version & debug level> <destination> \
                         <next server>"
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 201:
			/* RPL_TRACECONNECTING
                        "Try. <class> <server>"
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 202:
			/* RPL_TRACEHANDSHAKE
                        "H.S. <class> <server>"
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 203:
			/* RPL_TRACEUNKNOWN
                        "???? <class> [<client IP address in dot form>]"
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 204:
			/* RPL_TRACEOPERATOR
                        "Oper <class> <nick>"
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 205:
			/* RPL_TRACEUSER
                        "User <class> <nick>"
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 206:
			/* RPL_TRACESERVER
                        "Serv <class> <int>S <int>C <server> \
                         <nick!user|*!*>@<host|server>"
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 208:
			/* RPL_TRACENEWTYPE
                        "<newtype> 0 <client name>"
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 261:
			/* RPL_TRACELOG
                        "File <logfile> <debug level>"

                - The RPL_TRACE* are all returned by the server in
                  response to the TRACE message.  How many are
                  returned is dependent on the the TRACE message and
                  whether it was sent by an operator or not.  There
                  is no predefined order for which occurs first.
                  Replies RPL_TRACEUNKNOWN, RPL_TRACECONNECTING and
                  RPL_TRACEHANDSHAKE are all used for connections
                  which have not been fully established and are either
                  unknown, still attempting to connect or in the
                  process of completing the 'server handshake'.
                  RPL_TRACELINK is sent by any server which handles
                  a TRACE message and has to pass it on to another
                  server.  The list of RPL_TRACELINKs sent in
                  response to a TRACE command traversing the IRC
                  network should reflect the actual connectivity of
                  the servers themselves along that path.
                  RPL_TRACENEWTYPE is to be used for any connection
                  which does not fit in the other categories but is
                  being displayed anyway.
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 211:
			/* RPL_STATSLINKINFO
                        "<linkname> <sendq> <sent messages> \
                         <sent bytes> <received messages> \
                         <received bytes> <time open>"
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 212:
			/* RPL_STATSCOMMANDS
                        "<command> <count>"
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 213:
			/* RPL_STATSCLINE
                        "C <host> * <name> <port> <class>"
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 214:
			/* RPL_STATSNLINE
                        "N <host> * <name> <port> <class>"
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 215:
			/* RPL_STATSILINE
                        "I <host> * <host> <port> <class>"
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 216:
			/* RPL_STATSKLINE
                        "K <host> * <username> <port> <class>"
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 218:
			/* RPL_STATSYLINE
                        "Y <class> <ping frequency> <connect \
                         frequency> <max sendq>"
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 219:
			/* RPL_ENDOFSTATS
                        "<stats letter> :End of /STATS report"
			*/

			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 241:
			/* RPL_STATSLLINE
                        "L <hostmask> * <servername> <maxdepth>"
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 242:
			/* RPL_STATSUPTIME
                        ":Server Up %d days %d:%02d:%02d"
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 243:
			/* RPL_STATSOLINE
                        "O <hostmask> * <name>"
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 244:
			/* RPL_STATSHLINE
                        "H <hostmask> * <servername>"
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 221:
			/* RPL_UMODEIS
                        "<user mode string>"

                        - To answer a query about a client's own mode,
                          RPL_UMODEIS is sent back.

			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 251:
			/* RPL_LUSERCLIENT
                        ":There are <integer> users and <integer> \
                         invisible on <integer> servers"
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 252:
			/* RPL_LUSEROP
                        "<integer> :operator(s) online"
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 253:
			/* RPL_LUSERUNKNOWN
                        "<integer> :unknown connection(s)"
			*/
			sprintf(combined, "%s %s", arg3, trailing);
			break;
		case 254:
			/* RPL_LUSERCHANNELS
                        "<integer> :channels formed"
			*/
			sprintf(combined, "%s %s", arg3, trailing);
			break;
		case 255:
			/* RPL_LUSERME
                        ":I have <integer> clients and <integer> \
                          servers"

                        - In processing an LUSERS message, the server
                          sends a set of replies from RPL_LUSERCLIENT,
                          RPL_LUSEROP, RPL_USERUNKNOWN,
                          RPL_LUSERCHANNELS and RPL_LUSERME.  When
                          replying, a server must send back
                          RPL_LUSERCLIENT and RPL_LUSERME.  The other
                          replies are only sent back if a non-zero count
                          is found for them.

			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 256:
			/* RPL_ADMINME
                        "<server> :Administrative info"
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 257:
			/* RPL_ADMINLOC1
                        ":<admin info>"
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 258:
			/* RPL_ADMINLOC2
                        ":<admin info>"
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 259:
			/* RPL_ADMINEMAIL
                        ":<admin info>"

                        - When replying to an ADMIN message, a server
                          is expected to use replies RLP_ADMINME
                          through to RPL_ADMINEMAIL and provide a text
                          message with each.  For RPL_ADMINLOC1 a
                          description of what city, state and country
                          the server is in is expected, followed by
                          details of the university and department
                          (RPL_ADMINLOC2) and finally the administrative
                          contact for the server (an email address here
                          is required) in RPL_ADMINEMAIL.
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;	

		/* 6.1 Error Replies. */

		case 401:
        	/*  ERR_NOSUCHNICK
        			"<nickname> :No such nick/channel"
            - Used to indicate the nickname parameter supplied to a
             command is currently unused.
			*/
			/* in case of an attempt to dcc to a non existing nick */
			if( delete_dcc_nick(arg3) )
				{
				sprintf(combined, "DCC open to %s cancelled %s",\
				arg3, trailing); 
				}
			else
				{
				sprintf(combined, "%s %s", arg3, trailing);
				}
			break;
		case 402:
        	/* ERR_NOSUCHSERVER
                        "<server name> :No such server"
                - Used to indicate the server name given currently
                  doesn't exist.
			*/
			sprintf(combined, "'%s' %s", arg3, trailing);
			break;
		case 403:
        	/* ERR_NOSUCHCHANNEL
                        "<channel name> :No such channel"
                - Used to indicate the given channel name is invalid.
			*/
			sprintf(combined, "%s %s", arg3, trailing);
			break;
		case 404:
        	/* ERR_CANNOTSENDTOCHAN
                        "<channel name> :Cannot send to channel"
                - Sent to a user who is either (a) not on a channel
                  which is mode +n or (b) not a chanop (or mode +v) on
                  a channel which has mode +m set and is trying to send
                  a PRIVMSG message to that channel.
			*/
			sprintf(combined, "%s %s", trailing, arg3);
			break;
		case 405:
        	/* ERR_TOOMANYCHANNELS
                        "<channel name> :You have joined too many \
                         channels"
                - Sent to a user when they have joined the maximum
                  number of allowed channels and they try to join
                  another channel.
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 406:
        	/* ERR_WASNOSUCHNICK
                        "<nickname> :There was no such nickname"

                - Returned by WHOWAS to indicate there is no history
                  information for that nickname.
			*/
			sprintf(combined, "%s %s", arg3, trailing);
			break;
		case 407:
			/* ERR_TOOMANYTARGETS
                        "<target> :Duplicate recipients. No message \
                         delivered"

                - Returned to a client which is attempting to send a
                  PRIVMSG/NOTICE using the user@host destination format
                  and for a user@host which has several occurrences.
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 409:
			/* ERR_NOORIGIN
                        ":No origin specified"

                - PING or PONG message missing the originator parameter
                  which is required since these commands must work
                  without valid prefixes.
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;	
		case 411:
			/* ERR_NORECIPIENT
                        ":No recipient given (<command>)"
        	*/
			sprintf(combined, "%s", trailing);/* text used */
        	break;		
		case 412:
			/* ERR_NOTEXTTOSEND
                        ":No text to send"
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 413:
			/* ERR_NOTOPLEVEL
                        "<mask> :No toplevel domain specified"
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 414:
			/* ERR_WILDTOPLEVEL
                        "<mask> :Wildcard in toplevel domain"

                - 412 - 414 are returned by PRIVMSG to indicate that
                  the message wasn't delivered for some reason.
                  ERR_NOTOPLEVEL and ERR_WILDTOPLEVEL are errors that
                  are returned when an invalid use of
                  "PRIVMSG $<server>" or "PRIVMSG #<host>" is attempted.
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 421:
			/* ERR_UNKNOWNCOMMAND
                        "<command> :Unknown command"

                - Returned to a registered client to indicate that the
                  command sent is unknown by the server.
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 422:
			/* ERR_NOMOTD
                        ":MOTD File is missing"

                - Server's MOTD file could not be opened by the server.
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 423:
			/* ERR_NOADMININFO
                        "<server> :No administrative info available"

                - Returned by a server in response to an ADMIN message
                  when there is an error in finding the appropriate
                  information.
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 424:
			/* ERR_FILEERROR
                ":File error doing <file op> on <file>"

                - Generic error message used to report a failed file
                  operation during the processing of a message.
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 431:
			/* ERR_NONICKNAMEGIVEN
                        ":No nickname given"

                - Returned when a nickname parameter expected for a
                  command and isn't found.
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;	
		case 432:
			/* ERR_ERRONEUSNICKNAME
                        "<nick> :Erroneus nickname"

                - Returned after receiving a NICK message which contains
                  characters which do not fall in the defined set.  See
                  section x.x.x for details on valid nicknames.
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 433:
			/* ERR_NICKNAMEINUSE
                        "<nick> :Nickname is already in use"

                - Returned when a NICK message is processed that results
                  in an attempt to change to a currently existing
                  nickname.
			*/
			sprintf(combined, "%s", trailing);/* text used */
			nick_in_use_flag = 1;
			break;
		case 436:
			/* ERR_NICKCOLLISION
                        "<nick> :Nickname collision KILL"

                - Returned by a server to a client when it detects a
                  nickname collision (registered of a NICK that
                  already exists by another server).
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 441:
        	/* ERR_USERNOTINCHANNEL
                        "<nick> <channel> :They aren't on that channel"

                - Returned by the server to indicate that the target
                  user of the command is not on the given channel.
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 442:
			/* ERR_NOTONCHANNEL
                        "<channel> :You're not on that channel"

                - Returned by the server whenever a client tries to
                  perform a channel effecting command for which the
                  client isn't a member.
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 443:
			/* ERR_USERONCHANNEL
                        "<user> <channel> :is already on channel"

                - Returned when a client tries to invite a user to a
                  channel they are already on.
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 444:
			/* ERR_NOLOGIN
                        "<user> :User not logged in"

                - Returned by the summon after a SUMMON command for a
                  user was unable to be performed since they were not
                  logged in.
			*/
			sprintf(combined, "User %s not logged in", arg3);
			break;
		case 445:
			/* ERR_SUMMONDISABLED
                        ":SUMMON has been disabled"

                - Returned as a response to the SUMMON command.  Must be
                  returned by any server which does not implement it.
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 446:
			/* ERR_USERSDISABLED
                        ":USERS has been disabled"

                - Returned as a response to the USERS command.  Must be
                  returned by any server which does not implement it.
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 451:
			/* ERR_NOTREGISTERED
                        ":You have not registered"

                - Returned by the server to indicate that the client
                  must be registered before the server will allow it
                  to be parsed in detail.
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 461:
			/* ERR_NEEDMOREPARAMS
                        "<command> :Not enough parameters"

                - Returned by the server by numerous commands to
                  indicate to the client that it didn't supply enough
                  parameters.
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 462:
			/* ERR_ALREADYREGISTRED
                        ":You may not reregister"

                - Returned by the server to any link which tries to
                  change part of the registered details (such as
                  password or user details from second USER message).
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 463:
			/* ERR_NOPERMFORHOST
                        ":Your host isn't among the privileged"

                - Returned to a client which attempts to register with
                  a server which does not been setup to allow
                  connections from the host the attempted connection
                  is tried.
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 464:
			/* ERR_PASSWDMISMATCH
                       ":Password incorrect"

                - Returned to indicate a failed attempt at registering
                  a connection for which a password was required and
                  was either not given or incorrect.
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 465:
			/* ERR_YOUREBANNEDCREEP
                        ":You are banned from this server"

                - Returned after an attempt to connect and register
                  yourself with a server which has been setup to
                  explicitly deny connections to you.
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 467:
			/* ERR_KEYSET
                        "<channel> :Channel key already set"
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 471:
			/* ERR_CHANNELISFULL
                        "<channel> :Cannot join channel (+l)"
             */
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 472:
			/* ERR_UNKNOWNMODE
                        "<char> :is unknown mode char to me"
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 473:
			/* ERR_INVITEONLYCHAN
                        "<channel> :Cannot join channel (+i)"
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 474:
			/* ERR_BANNEDFROMCHAN
                        "<channel> :Cannot join channel (+b)"
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 475:
			/* ERR_BADCHANNELKEY
                        "<channel> :Cannot join channel (+k)"
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 481:
			/* ERR_NOPRIVILEGES
                        ":Permission Denied- You're not an IRC operator"

                - Any command requiring operator privileges to operate
                  must return this error to indicate the attempt was
                  unsuccessful.
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 482:
			/* ERR_CHANOPRIVSNEEDED
                        "<channel> :You're not channel operator"

                - Any command requiring 'chanop' privileges (such as
                  MODE messages) must return this error if the client
                  making the attempt is not a chanop on the specified
                  channel.
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 483:
			/* ERR_CANTKILLSERVER
                        ":You cant kill a server!"

                - Any attempts to use the KILL command on a server
                  are to be refused and this error returned directly
                  to the client.
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 491:
			/* ERR_NOOPERHOST
                        ":No O-lines for your host"

                - If a client sends an OPER message and the server has
                  not been configured to allow connections from the
                  client's host as an operator, this error must be
                  returned.
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 501:
			/* ERR_UMODEUNKNOWNFLAG
                        ":Unknown MODE flag"

                - Returned by the server to indicate that a MODE
                  message was sent with a nickname parameter and that
                  the a mode flag sent was not recognized.
			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		case 502:
			/* ERR_USERSDONTMATCH
                        ":Cant change mode for other users"

                - Error sent to any user trying to view or change the
                  user mode for a user other than themselves.

			*/
			sprintf(combined, "%s", trailing);/* text used */
			break;
		default:
/*
			sprintf(combined, "\nNumeric command %d not supported (%s)",\
			command_response, trailing);
*/
			sprintf(combined, "*%s", trailing);
			break;
	}/* end switch command response */
}/* end if isdigit command[0] (numeric commands) */
/* reply to a ping */
else if(strcmp(command, "PING") == 0)
	{
	sprintf(temp, "PONG :%s\n", trailing);
	if(! send_to_server(*socketfd, temp) )return(0);
	/* handle any "ON" events */
	get_event(command, "*", servername_or_nick, params, *socketfd);
	return(1);
	}
else if(strcmp(command, "PONG") == 0)
	{
	/* rxbuf=:panteltje PONG panteltje :grep */
	sprintf(combined, "PONG from %s", servername_or_nick);
	/* handle any "ON" events */
	get_event(command, "*", servername_or_nick, params, *socketfd);
	}
else if(strcmp(command, "NICK") == 0)
	{
	/* rxbuf=:uircold!~root@panteltje.255.255 NICK :flup */
	sprintf(combined, "%s is now known as %s",\
	servername_or_nick, trailing);
	nick_in_use_flag = 0;
	/* handle any "ON" events */
	get_event(command, "*", servername_or_nick, params, *socketfd);
	}
else if(strcmp(command, "INVITE") == 0)
	{
	/* rxbuf=:ircii!root@panteltje.255.255 INVITE grep :#1 */

	/* test for any ignore invites */
	if(get_ignore_nick(prefix) & INVITES)return(1);

	sprintf(combined, "* %s invites %s to %s *",\
	servername_or_nick, params0, trailing);
	/* handle any "ON" events */
	get_event(command, "*", servername_or_nick, params, *socketfd);
	}
else if(strcmp(command, "KICK") == 0)
	{
	/* nick!user@host KICK #channel thisnick :text */
	sprintf(combined, "%s has been kicked of channel %s by %s %s",\
	params1, params0, servername_or_nick, trailing); 
	if(strcmp(params1, ircname) == 0)
		{
		/* substract channel name from list of joined channels */
		substract_channel(params0);
		/* no longer addressing this channel if parted from it */
		if(strcmp(addressed_channel, params0) == 0)
			{
			sprintf(addressed_channel, "%s", "");
			}
		}
	/* handle any "ON" events */
	get_event(command, params0, servername_or_nick, params, *socketfd);
	/* if parted successfully, remove this channel from the list of channels */
	if(auto_rejoin_flag)
		{
		sprintf(temp, "JOIN %s\n", params0);
		send_to_server(*socketfd, temp);
		return(1);
		}
	}
else if(strcmp(command, "MODE") == 0)
	{
	/*                      params0	 1  2  
	/* :nick!user@host MODE #channel +o mode_nick */
	/* :nick!user@host MODE #channel +i */
	/* server at startup    rxbuf=:grep MODE grep :+i
	/* MODE #3 +i           rxbuf=:grep!~root@panteltje.255.255 MODE #3 +i
	/* MODE grep +w         rxbuf=:grep MODE grep :+w
	*/
	if( (params0[0] == '#') || (params0[0] == '&') )	
		{
		sprintf(combined, "Mode change %s for channel %s by %s",\
		params1, params0, servername_or_nick); 	
		}
	else
		{	
		sprintf(combined, "Mode change %s for user %s by %s",\
		params1, params0, servername_or_nick); 	
		}
	/* handle any "ON" events */
	get_event(command, params0, servername_or_nick, params, *socketfd);
	}
else if(strcmp(command, "QUIT") == 0)
	{
	/* rxbuf=:ircii!~root@panteltje.255.255 QUIT :ha die pantel */
	sprintf(combined, "%s %s@%s has left irc (%s)",\
	servername_or_nick, user, host, trailing);
	/* handle any "ON" events */
	get_event(command, "*", servername_or_nick, params, *socketfd);
	}
else if(strcmp(command, "JOIN") == 0) 
	{
	/* :nick!user@host JOIN :#channel */
	sprintf(combined, "%s %s@%s has joined channel %s",\
	servername_or_nick, user, host, &params[1]);
	/* if joined successfully, add this channel to the list of channels */
	if(strcmp(servername_or_nick, ircname) == 0)
		{
		add_channel(&params[1]);
		}
	/* handle any "ON" events */
	get_event(command, &params[1], servername_or_nick, params, *socketfd);
	}
else if(strcmp(command, "PART") == 0) 
	{
	/* :nick!user@host PART #channel :nick */
	sprintf(combined, "%s %s@%s has left channel %s",\
	servername_or_nick, user, host, params0);
	/* if parted successfully, remove this channel from the list of channels */
	if(strcmp(servername_or_nick, ircname) == 0)
		{
		/* substract channel name from list of joined channels */
		substract_channel(params0);
		/* no longer addressing this channel if parted from it */
		if(strcmp(addressed_channel, params0) == 0)
			{
			sprintf(addressed_channel, "%s", "");
			}
		}
	/* handle any "ON" events */
	get_event(command, params0, servername_or_nick, params, *socketfd);
	}
else if(strcmp(command, "TOPIC") == 0)
	{
	/* :nick!root@host TOPIC #linux :hi there. */
	sprintf(combined, "%s has set the topic for channel %s to: %s",\
	servername_or_nick, params0, trailing);
	/* handle any "ON" events */
	get_event(command, params0, servername_or_nick, params, *socketfd);
	}
else if(strcmp(command, "NOTICE") == 0)	
	{
	/* in case ctcp ping ircii:
	/* rxbuf=:ircii!root@panteltje.255.255 NOTICE grep :PING */

	/* test for ignore */
	if(get_ignore_nick(prefix) & NOTICES) return(1);

	from_server_flag = 0;
	/* all ctcp is handled here */ 
	extract_and_handle_ctcp(\
	servername_or_nick, params0, trailing, no_ctcp, *socketfd, prefix);
	
	/* no_ctcp now has the non ctcp part of the privmsg, this may be 0 */
	if(no_ctcp[0] == 0)return(1);
	
/*	sprintf(combined, "%s", trailing);*/

	sscanf(no_ctcp, "%s %s", notice0, notice1);
	
	/* set color of text */
	if( get_color_nick(servername_or_nick, &color_nick) )
		{
		color_to_text(combined, color_nick, colored_combined, 1);
		}
	else if(strcmp(servername_or_nick, last_addressed) == 0)/* last addressed*/
		{
		color_to_text(combined, last_addressed_color, colored_combined, 1);
		}
	else /* normal */
		{
		color_to_text(no_ctcp, nick_text_color, colored_combined, 1);
		}

	/* set type of indentifier for message */
	if( (middle[0] != '#') && (middle[0] != '&') )/* one to me */
		{
		sprintf(combined, "-*%s*-%s",\
		colored_servername_or_nick, colored_combined);
		}
	else /* one to channel */
		{
		sprintf(combined, "-<%s>-%s",\
		colored_servername_or_nick, colored_combined);
		}

	/* handle any "ON" events */
	get_event(command, params0, servername_or_nick, params, *socketfd);
	}/* end NOTICE */
else if(strcmp(command, "PRIVMSG") == 0)/* a private message */
	{
	/* :grepgrep!root@panteltje.255.255 PRIVMSG nick :ha die grep. */
	/* :grepgrep!root@panteltje.255.255 PRIVMSG #channel :ha die grep. */
	/* set the color of the message */

	from_server_flag = 0;
	/* all ctcp is handled here */ 
	extract_and_handle_ctcp(\
	servername_or_nick, params0, trailing, no_ctcp, *socketfd, prefix);
	
	/* no_ctcp now has the non ctcp part of the privmsg, this may be 0 */
	if(no_ctcp[0] == 0)return(1);
	
	/* set color of text */	
	if(get_color_nick(servername_or_nick, &color_nick) )
		{
		color_to_text(no_ctcp, color_nick, colored_combined, 1);
		}
	else if(strcmp(servername_or_nick, last_addressed) == 0)/* last addressed*/
		{
		color_to_text(no_ctcp, last_addressed_color, colored_combined, 1);
		}
	else /* normal */
		{
		color_to_text(no_ctcp, nick_text_color, colored_combined, 1);
		}
	
	/* set type of indentifier for message */
	if( (middle[0] != '#') && (middle[0] != '&') )/* one to me */
		{
		/* test for ignore */
		if(get_ignore_nick(prefix) & MESSAGES) return(1);
		sprintf(combined, "*%s*%s",\
		colored_servername_or_nick, colored_combined);
		to_screen(combined, servername_or_nick);/* a private message for me */
		return(1);
		}
	else /* one to channel */
		{
		/* test for ignore */
		if(get_ignore_nick(prefix) & PUBLIC) return(1);
		/* prefix with channel name if destination is not addressed channel */
		if(strcmp(addressed_channel, params0) != 0)
			{
			strcat(colored_servername_or_nick, ":");
			strcat(colored_servername_or_nick, params0); 
			}
		sprintf(combined, "<%s>%s",\
		colored_servername_or_nick, colored_combined);
		to_screen(combined, middle);/* message to this channel */
		return(1);
		}
	/* handle any "ON" events */
	get_event(command, params0, servername_or_nick, params, *socketfd);
	}/* end PRIVMSG */
else /* not any command */
	{
	sprintf(user_data,"COMMAND NOT RECOGNISED");
	/* if not a command */
	sprintf(combined, "%s", trailing);
	to_screen(combined, "");/* message from uirc */
	return(1);
	}

/* set server color */
if(from_server_flag)
	{
	color_to_text(combined, server_text_color, colored_combined, 1); 
/*	sprintf(combined,\
/* "<%s>%s", colored_servername_or_nick, colored_combined);*/
	sprintf(combined, "%s", colored_combined);
	}

/* print it */
to_screen(combined, "server");

/* if nick in use, try backup nick */
if(nick_in_use_flag)
	{
	/* point to the next backup nick, in case this one is also in use */
	backup_ircname_ptr++;
	if(backup_ircname_ptr >= nicks)
		{
		to_screen(\
		"No more nicks specified in file uirc.setup, use /nick", "");
		/* prevent previous message to appear again and again */
		backup_ircname_ptr = 0;
		return(1);
		}
	sprintf(temp, "Changing to nick %s",\
	backup_ircname[backup_ircname_ptr]);
	to_screen(temp, "");
	sprintf(temp, "NICK %s\n", backup_ircname[backup_ircname_ptr]);
	send_to_server(*socketfd, temp);
	strcpy(ircname, backup_ircname[backup_ircname_ptr]);
	/* reset the nick_in_use_flag */
	nick_in_use_flag = 0;
	}

return(1);
}/* end function server_to_client */


int client_to_server(int *socketfd)
{
char bugfix[5000];
int a, b, i, j;
char c;
char txbuf[512];
char user_data[512];
char temp[512];
char temp2[512];
char command[512];
char text[512];
int quit_flag;
char mycolor[512];
int color;
char *aptr;
char arg0[512], arg1[512], arg2[512], arg3[512];
char arg4[512], arg5[512], arg6[512], arg7[512];
char *eptr;

/* set all arguments empty */
arg0[0] = 0;
arg1[0] = 0;
arg2[0] = 0;
arg3[0] = 0;
arg4[0] = 0;
arg5[0] = 0;
arg6[0] = 0;
arg7[0] = 0;

user_ctcp_command_flag = 0;

/* read a char from console and store in user_data,
/* return if line not complete yet
*/
/* read from console */
aptr = read_from_console();
if(!aptr)return(1);/* not enter yet */
else sprintf(user_data, "%s", aptr);
aptr[0] = 0;/* mark empty for next call to read_from_console */

/* user text now complete */

/* handle any aliases */
get_alias(user_data); /* modifies user_data */

tputs_x( tgoto(CM, 0, LI - 3) );

/* mark txbuf empty, will be overruled if valid command or data */
txbuf[0] = 0;

quit_flag = 0;
if(user_data[0] == '/')/* test for command character */
	{
	/* get rid of the leading '/' */
	sprintf(temp, "%s", &user_data[1]);

	/* convert command to upper case  */
	for(i = 0; i < strlen(temp); i++)
		{
		temp[i] = toupper(temp[i]);
		if(temp[i] == ' ')break;/* only to upper command, stop at space */
		}

	/* copy all fields after command to text */ 
	i++;/* scip the space */
	j = 0;
	for(i = i; i < strlen(temp); i++)
		{
		c = temp[i];
		text[j] = c;
		if(c == 0)break; 
		j++;
		}
	text[j] = 0;

	/* command sort */
	/* parse command line */
	a = sscanf(temp, "%s %s %s %s %s %s %s %s",\
	command, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
	if(strcmp(command, "ON") == 0)
		{
		if(a < 3)
			{
			usage("ON <event> <channel> <nick> <serial> <action>");
			return(1);
			}
		else
			{
			if(arg5[0] == 0)/* make it possible to enter an empty definition */
				{
				set_event(arg1, arg2, arg3, atoi(arg4), "");
				}
			else
				{
				set_event(arg1, arg2, arg3, atoi(arg4), strstr(temp, arg5) );
				}
			return(1);
			}
		}/* end ON command */
	if(strcmp(command, "DCC") == 0)
		{
		if(a < 4)
			{
			usage("DCC chat <nick> open");
			usage("DCC chat <nick> accept");
			usage("DCC chat <nick> close");
			usage("DCC send <nick> open <pathfilename>");
			usage("DCC send <nick> accept <filename> [newfilename]");
			usage("DCC send <nick> close <filename>");
			return(1);
			}
		else
			{
			dcc_process(arg1, arg2, arg3, arg4, arg5, *socketfd);
			return(1);
			}
		}
	if(strcmp(command, "CTCP") == 0)
		{
		if(a < 2)
			{
			usage("CTCP [=]<nick> <command> [<args>]");
			return(1);
			}
		else
			{		
		    /* in case ctcp ping from ircii:
       		/* rxbuf=:ircii!root@panteltje.255.255 NOTICE grep :PING
			/* where PING = \1PING\1
			*/
			user_ctcp_command_flag = 1;	
			/* convert command to upper case */
			sprintf(temp, "%s", strstr(text, arg2) );
			for(i = 0; i < strlen(arg2); i++)
				{
				temp[i] = toupper(temp[i] );
				}
			sprintf(txbuf, "PRIVMSG %s :\1%s\1", arg1, temp);
			ctcp_ping_timer = time(0);
			}
		}
	if(strcmp(command, "PING") == 0)
		{
		/* Parameters: <server1> [<server2>] */
		if(a < 2)
			{
			usage("PING <server1> [<server2>]");
			return(1);
			}
		else
			{
			sprintf(txbuf, "PRIVMSG %s :\1PING\1 %s", arg1, arg2);
			ctcp_ping_timer = time(0);
			}
		}
	if(strcmp(command, "NICK") == 0)
		{
		 /* Parameters: <nickname> [ <hopcount> ] */
		if(a < 2)
			{
			usage("NICK <nickname> [ <hopcount> ]");
			return(1);
			}
		else sprintf(txbuf, "NICK %s %s", arg1, arg2);
		strcpy(ircname, arg1);
		nick_in_use_flag = 0;
		}
	if(strcmp(command, "WHOWAS") == 0)
		{
		/* Parameters: <nickname> [<count> [<server>]] */
		if(a < 2)
			{
			usage("WHOWAS <nickname> [<count> [<server>]]");
			return(1);
			}
		else
			{
 			sprintf(txbuf, "WHOWAS %s %s %s", arg1, arg2, arg3);
			}
		}
	if(strcmp(command, "WHOIS") == 0)
		{
		/*  Parameters: [<server>] <nickmask>[,<nickmask>[,...]] */
		if(a < 2)
			{
			usage("WHOIS [<server>] <nickmask>[,<nickmask>[,...]]");
			return(1);
			}
		else
			{
 			sprintf(txbuf, "WHOIS %s %s", arg1, arg2);
			}
		}
	if(strcmp(command, "INVITE") == 0)
		{
		/* Parameters: <nickname> <channel> */
 		if(a < 2)
 			{
 			usage("INVITE <nickname> <channel>");
 			return(1);
 			}
 		else
 			{
 			sprintf(txbuf, "INVITE %s %s", arg1, arg2);
 			}	  
		}
	if(strcmp(command, "KICK") == 0)
		{
		if(a < 3)
			{
			usage("KICK <channel>{,<channel>} <user>{,<user>} [<comment>]");
			return(1);
			}
		else
			{
			/* <channel>{,<channel>} <user>{,<user>} [<comment>] */
			sprintf(txbuf, "KICK %s %s :%s", arg1, arg2, strstr(text, arg3) );
			}
		}		
	if(strcmp(command, "VERSION") == 0)
		{
		/* Parameters: [<server>] */
		sprintf(txbuf, "VERSION %s", arg1);
		}
	if(strcmp(command, "STATS") == 0)
		{
		/* Parameters: [<query> [<server>]] */
		sprintf(txbuf, "STATS %s %s", arg1, arg2);
		}
	if(strcmp(command, "LINKS") == 0)
		{
		if(a > 3)
			{
			usage("LINKS [[<remote server>] <server mask>]");
			return(1);
			}
		else sprintf(txbuf, "LINKS %s %s", arg1, arg2); 
		}
	if(strcmp(command, "TIME") ==0)
		{
		/* Parameters: [<server>] */
		sprintf(txbuf, "TIME %s", arg1);
		}
	if(strcmp(command, "CONNECT") == 0)
		{
		if(a < 2)
			{
			usage("CONNECT <target server> [<port> [<remote server>]]");
			return(1);
			}
		else sprintf(txbuf, "CONNECT %s %s %s", arg1, arg2, arg3); 
		}
	if(strcmp(command, "TRACE") == 0)
		{
		sprintf(txbuf, "TRACE %s", arg1); 
		}
	if(strcmp(command, "INFO") == 0)
		{
		sprintf(txbuf, "INFO %s", arg1); 
		}
	if(strcmp(command, "LIST") == 0)
		{
		if(a > 3)
			{
			usage("[<channel>{,<channel>} [<server>]] (extra ignored)");
			return(1);
			}
		sprintf(txbuf, "LIST %s %s", arg1, arg2); 
		}
	if(strcmp(command, "OPER") == 0)
		{
		if(a == 3)
			{
			sprintf(txbuf, "OPER %s %s", arg1, arg2); 
			}
		else
			{
			usage("OPER <user> <password>");
			return(1);
			}
		}/* end OPER command */
	if(strcmp(command, "MODE") == 0)
		{
		if(a < 2)
			{			
			usage(\
	"MODE <channel> {[+|-]|o|p|s|i|t|n|b|v} [<limit>] [<user>] [<ban mask>]");
			usage("MODE <nickname> {[+|-]|i|w|s|o}");
			return(1);
			}
		else
			{
			sprintf(txbuf, "MODE %s %s %s %s %s",\
			arg1, arg2, arg3, arg4, arg5);
			}
		}/* end MODE command */
	if(strcmp(command, "QUIT") == 0)
		{
		if(a == 1)sprintf(txbuf, "QUIT");
		else /* there was a quit text */
			{
			sprintf(txbuf, "QUIT :%s", strstr(text, arg1) );
			}
		quit_flag = 1;/* send quit command to server, quit after that  */
		}/* end QUIT command */
	if(strcmp(command, "JOIN") == 0)
		{
		if(a < 2)
			{
			usage("join <channel>{,<channel>} [<key>{,<key>}]");
			return(1);
			}
		sprintf(txbuf, "JOIN %s %s", arg1, arg2);
		/* now talking to this channel */
		sprintf(addressed_channel, "%s", arg1);
		}/* end JOIN command */
	if(strcmp(command, "PART") == 0)
		{
		if(a < 2)
			{
			usage("part <channel>{,<channel>}");
			return(1);
			}
		sprintf(txbuf, "PART %s", arg1);
		}/* end PART command */	
	if(strcmp(command, "NAMES") == 0)
		{
		/* Usage: [<channel>{,<channel>}] */
		if(a == 1)sprintf(txbuf, "NAMES");
		if(a == 2)sprintf(txbuf, "NAMES %s", arg1);
		}/* end NAMES command */
	if(strcmp(command, "TOPIC") == 0)
		{
		if(a < 2)
			{
			usage("topic <channel> [topic]");
			return(1);
			}
		if(a == 2)sprintf(txbuf, "TOPIC %s", arg1);
		else
			{
			sprintf(txbuf, "TOPIC %s :%s", arg1, strstr(text, arg1) );
			}
		}/* end TOPIC command */
	if(strcmp(command, "AWAY") == 0)/* optionally, not in spec */
		{
		/* Parameters: [message] */
		sprintf(txbuf, "AWAY :%s", text);
		}
	if(strcmp(command, "SUMMON") == 0)
		{		
		/* Parameters: <user> [<server>] */
		if(a < 2)
			{
			usage("SUMMON <user> [<server>]");
			return(1);
			}
		else sprintf(txbuf, "SUMMON %s %s", arg1, arg2);
		}
	if(strcmp(command, "USERS") == 0)/* optionally, not in spec */
		{
		/* Usage: [<server>] */
		if(a == 1) sprintf(txbuf, "USERS");
		if(a == 2) sprintf(txbuf, "USERS %s", arg1);
		}/* end USERS command */
	/* local executed commands */
	if(strcmp(command, "DELAY") == 0)
		{
		if(a < 2)
			{
			usage("Send delay (after each line of text) for /exec -msg");
			usage("Prevents disconnect for flooding.");
			usage("DELAY <0 to 100>  (time is in seconds).");
			return(1);
			}
		else
			{
			exec_delay = atoi(arg1);
			return(1);
			}
		}
	if(strcmp(command, "EXEC") ==0)
		{
		if(a < 2)
			{
			usage("EXEC [<-MSG> <nick> ] <program> [arguments to program]");
			usage("Examples:");
			usage("EXEC /root/ls -l");
			usage("EXEC -msg flip /root/ls -l");
			usage("EXEC -msg #linux /root/ls -l");
			return(1);
			}
		else
			{
			do_exec(strstr(text, arg1), *socketfd);
			return(1);
			}
		}
	if(strcmp(command, "SECURITY") == 0)
		{
		if(a < 2)
			{
			usage("SECURITY <on | off>");
			return(1);
			}
		else
			{
			if(strcmp(arg0, "on") == 0) security_flag = 1;
			if(strcmp(arg0, "off") == 0) security_flag = 0;
			return(1);
			}
		}
	if(strcmp(command, "SERVER") == 0)
		{
		if( (a == 2) || (a == 3) )
			{
			/* start with most prefered nick */
			strcpy(ircname, backup_ircname[0]);
			backup_ircname_ptr = 0;
			if(! connect_to_server(arg1, atoi(arg2), socketfd) )
				{
				to_screen(\
			"Cannot connect to server, use /server to connect to a server",\
				"");
				}
			return(1);
			}
		else
			{
			usage("SERVER <servername> [port]");
			return(1);
			}	
		}/* end server command */
	if(strcmp(command, "ALIAS") == 0)
		{
		if(a < 3)
			{
			usage("ALIAS <name> <definition>");
			return(1);
			}
		else
			{
			/* remove trailing space */
			set_alias(arg1, strstr(text, arg2) );
			return(1);
			}
		}
	if(strcmp(command, "IGNORE") == 0)
		{
		if(a < 3)
			{
			usage(\
	"IGNORE <nickname!user@host> <none | [-]all | [-]ctcp | [-]public |");
 			usage(\
 			"[-]invites [-]notices | [-]messages | [-]wallops | [-]notes>");
			return(1);
			}
		else
			{
			set_ignore_nick(arg1, arg2);
			return(1);
			}
		}
	if(strcmp(command, "LOAD") == 0)
		{
		if( a < 3)
			{
			usage("load <ignores | events | colors> <filename>");
			return(1);
			}
		else
			{
			if(strcmp(arg1, "ignores") == 0) load_ignores(arg2);
			if(strcmp(arg1, "events") == 0) load_events(arg2);
			if(strcmp(arg1, "colors") == 0) load_colors(arg2);
			if(strcmp(arg1, "aliases") == 0) load_aliases(arg2);
			return(1);
			}
		}
	if(strcmp(command, "SAVE") == 0)
		{
		if( a < 3)
			{
			usage("save <ignores | events | colors> < filename> [filename]");
			return(1);
			}
		else
			{
			if(strcmp(arg1, "ignores") == 0) save_ignores(arg2, arg3);
			if(strcmp(arg1, "events") == 0) save_events(arg2, arg3);
			if(strcmp(arg1, "colors") == 0) save_colors(arg2, arg3);
			return(1);
			}
		}	
	if(strcmp(command, "DELETE") == 0)
		{
		if(a < 2)
			{
			usage("delete <ignores | events | colors> [definition]");
			return(1);
			}
		else
			{
			if(strcmp(arg1, "ignores") == 0) delete_ignores(arg2);
			if(strcmp(arg1, "events") == 0) delete_events(\
			arg3, arg4, arg5, arg6); /* arg2 is '/on' */
			if(strcmp(arg1, "colors") == 0) delete_colors(arg2);
			if(strcmp(arg1, "aliases") == 0) delete_aliases(arg2);
			return(1);
			}
		}	
	if(strcmp(command, "SHOW") == 0)
		{
		if( a < 2)
			{
			usage("show <ignores | events | colors>");
			return(1);
			}
		else
			{
			if(strcmp(arg1, "ignores") == 0) show_ignores();
			if(strcmp(arg1, "events") == 0) show_events();
			if(strcmp(arg1, "colors") == 0) show_colors();
			if(strcmp(arg1, "aliases") == 0) show_aliases();
			return(1);
			}
		}
	if(strcmp(command, "HELP") == 0)
		{
		if( !print_help() )return(1);	
		else return(1);
		}
	if(strcmp(command, "EVENTS") == 0)
		{
		if( a < 2)
			{
			usage("events <on | off>");
			return(1);
			}
		else
			{
			if(strcmp(arg1, "off") == 0)listen_flag = 0;
			if(strcmp(arg1, "on") == 0)listen_flag = 1;
			return(1);
			}
		}
	if(strcmp(command, "COLOR") == 0)
		{
		if(a == 3)
			{
			set_color_nick(arg1, arg2);
			return(1);
			}
		else
			{
			usage("color <nick> <red | green | blue | cyan | yellow | magenta | off |");
			usage("normal | black | flashing | white_i | intensified>");
			
			return(1);
			}
		}/* end COLOR command (interal) */
	if(strcmp(command, "MTRACE") == 0)
		{
		if(strcmp(arg1, "on") == 0)trace_flag = 1;
		if(strcmp(arg1, "off") == 0)trace_flag = 0;
		return(1);
		}/* end TRACE command (internal) */
	if(strcmp(command, "MSG") == 0)
		{
		if(a < 2)
			{
			usage("MSG <receiver>{,<receiver>} <text to be sent>");
			usage("MSG <=receiver> <text to be send (for DCC chat)");
			return(1);
			}
		else
			{
			color = 0;
			get_color_nick(ircname, &color);
			sscanf(arg1, "%s", last_addressed);
			/* add ANSI colors if color not -1 */
			color_to_text(strstr(text, arg2), color, temp, 0);
			if(arg1[0] == '=')/* a dcc chat */
				{
				sprintf(txbuf, "%s\n", temp);
				sprintf(temp2, "%s", &arg1[1]);
				if( dcc_chat_send(temp2, txbuf) )/*dcc chat connection exists*/
					{
					sprintf(temp2, "=> %s= %s", arg1, temp);
					eptr = (char *) expand_mirc_colors(temp2);
					to_screen(eptr, &arg1[1]);/* addressed nick */
					free(eptr);
					}
				return(1);
				}
			else /* a private message */
				{
				/* add ANSII colors if own nick in database */
				/* send the message */
				sprintf(txbuf, "PRIVMSG %s :%s\n", arg1, temp);
				sprintf(temp2, "*%s* %s", arg1, temp); 
				eptr = (char *) expand_mirc_colors(temp2);
				to_screen(eptr, arg1);/* addressed nick */
				free(eptr);
				if(! send_to_server(*socketfd, txbuf) ) return(0);
				return(1);
				}	
			}
		}
	if (strcmp(command, "PRIVMSG") == 0)
		{
		if(a < 2)
			{
			usage("PRIVMSG <receiver>{,<receiver>} <text to be sent>");
			return(1);
			}
		else
			{
			color = 0;
			get_color_nick(ircname, &color);
			sscanf(arg1, "%s", last_addressed);
			/* add ANSI colors */
			color_to_text(strstr(text, arg2), color, temp, 0);
			sprintf(txbuf, "PRIVMSG %s :%s", arg1, temp);
			}
		}
	if(strcmp(command, "NOTICE") == 0)
		{
		if(a <2)
			{
			/* Parameters: <nickname> <text> */
			usage("NOTICE <nickname> <text>");
			return(1);
			}
		else
			{
			sscanf(arg1, "%s", last_addressed);
			/* add ANSI colors if color not -1 */
			color_to_text(strstr(text, arg2), color, temp, 0);
			sprintf(txbuf, "NOTICE %s :%s", arg1, temp);
			}
		}
	if(txbuf[0] == 0) /* no command */
		{
		sprintf(temp, "%s is not a command\n", user_data);
		to_screen(temp, addressed_channel);
		return(1);
		}
	else /* a command */
		{
		/* send the command */
		strcat(txbuf, "\n");
		if(! send_to_server(*socketfd, txbuf) )return(0);	
		}
	}/* end all commands ('/' in first position ) */
else /* a message */
	{
	sscanf(user_data, "%s", last_addressed);
	/* add ANSII colors if own nick in database */
	if( get_color_nick(ircname, &color) )
		{
		color_to_text(user_data, color, temp, 0);
		}
	else
		{
		strcpy(temp, user_data);/* no color */
		}

	/* send the message */
	if(user_data[0])/* some text */
		{
		sprintf(txbuf, "%s %s :%s\n", "PRIVMSG", addressed_channel, temp);
		if(! send_to_server(*socketfd, txbuf) )return(0);	
		}
	else
		{
		return(1);
		}
	}/* end if a message */

/* echo to screen */
sprintf(temp2, ">%s\n", temp);/* temp is user_data with color */
/* QQQQ
*/
eptr = (char *) expand_mirc_colors(temp2);
to_screen(eptr, addressed_channel);
free(eptr);

/* exit orderly if QUIT command */
if(quit_flag) 
	{
	/* save any settings if saving enabled in setupfile */
	for(i = 0; i < 30; i++)
		{
		if(! get_setup("auto_save", temp, i) ) break;
		else
			{
			sscanf(temp, "%s %s %s", arg0, arg1, arg2);
			/* temp: colors filename yes */
			/* Note: save_ignores needs TWO arguments, if filename is to be
			/* overwritten they must be the same.
			*/
			if(strcmp(arg2, "yes") == 0)
				{
				if(strcmp(arg0, "ignores") == 0)
					{
					save_ignores(arg1, arg1);/* do not exit on error,
											/* at least try to save the other
											/* ones */
					}
				if(strcmp(arg0, "colors") == 0)
					{
					save_colors(arg1, arg1);
					}
				if(strcmp(arg0, "events") == 0)
					{
					save_events(arg1, arg1);
					}
				if(strcmp(arg0, "aliases") == 0)
					{
					save_aliases(arg1, arg1);
					}
				}/* end else if arg2 is 'yes' */
			}/* end autosaves */
		}/* end for all auto saves */
	return(0);/* force exit */
	}/* end if quit flag */
return(1);
}/* end function client_to_ server */


int host_to_dotted_quad(char *hostname, char *dotted_quad)
{
struct hostent *hp;
struct in_addr hostaddress;
struct sockaddr_in localaddr;
char temp[512];

if(hp = gethostbyname(hostname) )
	{
	bcopy(hp->h_addr, (char *) &hostaddress, sizeof(hostaddress) );
	}
sprintf(dotted_quad, "%s", (char *)inet_ntoa(hostaddress.s_addr) );

/* save the IP address, used for securety checking in DCC:
/* Want to know if the IP address in a DCC handshake is really the
/* IP address of the other nick. (should not even write this).
/* But anyway they could really have you connect to anything could not they?
/* So we do a whois on the nick in DCC and see if the IP address supplied in
/* the DCC handhake in a DCC offer matches the IP address obtained by doing a
/* whois nick. 
*/
/* gethostbyname leaves address and port in network byte order */

if(get_nicks_ip_address_flag)
	{
	get_nicks_ip_address_flag = 0;
	ip_address_according_to_server.s_addr = hostaddress.s_addr;
	}
/* if my own IP */
if(get_local_ip_address_from_server_flag)
	{
	get_local_ip_address_from_server_flag = 0;
	local_ip_address_according_to_server.s_addr = hostaddress.s_addr;
	sprintf(temp, "My IP according to server= %s",\
	(char *)inet_ntoa(local_ip_address_according_to_server.s_addr) );
	to_screen(temp, "");
	}
return(1);
}/* end function host to dotted quad */


int connect_to_server(char *server, int port, int *socketfd)
{
struct hostent *hp;
struct sockaddr_in sa;
int a;
char txbuf[512];
char temp[80];
char temp1[80];
char localhost [64];
int address_len;
struct sockaddr_in localaddr;
int opt, optlen;
time_t connect_timer;
int connect_to_server_timeout;
int flags;
char server_ip_address[512];

/* reset nick_in_use_flag */
nick_in_use_flag = 0;
backup_ircname_ptr = 0;/* counts backup nicks */

/* set the default port, in case no argument given. */
if(port == 0) port = DEFAULTPORT;

/*
sprintf(temp, "Connecting to server %s port %d", server, port);
to_screen(temp, "");
*/

/* close any old server connection */
FD_CLR(*socketfd, &readfs);
close(*socketfd);

sprintf(temp, "Getting host %s by name", server);
to_screen(temp, ""); 

hp = gethostbyname(server);
if(hp == 0)
	{
	sprintf(temp,\
	"gethostbyname: returned %d  cannot get host %s by name", hp, server);
	to_screen(temp, "");

	/* signal FD_SET (main) that this is no longer a valid filedescriptor */
	*socketfd = -1;
	return(0);
	}

/* gethostbyname() leaves port and host address in network byte order */

bzero(&sa, sizeof(sa) );
bcopy(hp->h_addr, (char *)&sa.sin_addr, hp->h_length);
sa.sin_family = AF_INET;
sa.sin_port = htons( (u_short)port);

/* sa.sin_addr and sa.sin_port now in network byte order */

/* create a socket */
*socketfd = socket(hp->h_addrtype, SOCK_STREAM, 0);
if(*socketfd < 0)
	{
	to_screen("socket failed", "");
	*socketfd = -1;
	return(0);
	}

/* set for nonblocking socket */
if (fcntl(*socketfd, F_SETFL, O_NONBLOCK) < 0)
	{
	return(0);
	}
            
sprintf(server_ip_address, "%s", (char *)inet_ntoa(sa.sin_addr.s_addr) );

/* prevent the program from hanging if connect takes a long time,
/* now a return 0 is forced.
*/
       
if( get_setup("connect_to_server_timeout", temp, 0) )
	{
	sscanf(temp, "%s", temp1);
	connect_to_server_timeout = atoi(temp1);
	}
else connect_to_server_timeout = 60;/* maybe even longer sometimes */

sprintf(temp, "Connecting to %s (%s) port %d timeout %d",\
server, server_ip_address, port, connect_to_server_timeout);
to_screen(temp, "");

/* start the timer */
connect_timer = time(0);

/* keep testing for a connect */
while(1)
	{
	/* connect */
	a = connect(*socketfd, (struct sockaddr*)&sa, sizeof(sa) );
	if(a == 0) break;/* connected */
	if(a < 0)
		{
/*		if( (errno == EINPROGRESS) || (errno ==  EALREADY) )
			{
*/
			/* test for connect time out */
			if( (time(0) - connect_timer) > connect_to_server_timeout)
				{
				/* close the socket */
				close(*socketfd);
			
				/* set socketfd to invalid, it was valid! */
				*socketfd = -1;
				to_screen("Connect timeout", "");
				return(0);
				}
/*			continue;
			}
*/
		continue;/* retry on ALL errors? mmmm,
					/* hopefully timout will save us */
		}/* end connect < 0 */
	}/* end while test for a connect */

/* now set socket blocking */
flags = fcntl(*socketfd, F_GETFL, 0);
flags &= ~O_NONBLOCK;
fcntl(*socketfd, F_SETFL, flags);

sprintf(temp, "connect OK, registering with server");
to_screen(temp, "");

sprintf(txbuf,"NICK %s\n", ircname);

send_to_server(*socketfd, txbuf);

userinfo = getpwuid(getuid() );

gethostname(localhost, 64);
sprintf(txbuf, "USER %s %s %s :%s\n",\
userinfo -> pw_name, localhost, server, ircname);
send_to_server(*socketfd, txbuf);

/* used for dcc chat and send close */
sprintf(mynickuserhost, "%s!%s@%s", ircname, userinfo -> pw_name, localhost);

/* get local ip address from socket */
/* This must be after connect, else always 127.0.0.1 .
/* If not connected it seems to be taken form /etc/hosts for the machine
/* name entry.
*/

/* these addresses are already in network byte order */

address_len = sizeof(struct sockaddr_in);
getsockname(*socketfd, (struct sockaddr *) &localaddr, &address_len);
local_ip_address.s_addr = localaddr.sin_addr.s_addr;

/* Note: This is used by dcc to tell the other client our IP address.
/* The other way to find our own IP address is to do a whois on ourselves.
*/

/* print own (dynamic) ip address) */
sprintf(temp, "Local IP address obtained from socket is %s",\
(char *)inet_ntoa(local_ip_address.s_addr) );
to_screen(temp, "");

/* now also ask the server for our ip address */
/* do a whois */
sprintf(txbuf, "WHOIS %s\n", ircname);
if(! send_to_server(*socketfd, txbuf) )return(1);

/* setting this flag will copy the obatined IP address to a safe place,
/* and disable this flag again in host_to_ip()
*/
get_local_ip_address_from_server_flag = 1;

return(1);
}/* end function connect to server */


main(int argc, char *argv[])
{
int a, b, i, j, s;
int socketfd;
char c;
struct passwd *userinfo;
char sockbuf[512];
char channelname[80];
char temp[512];
char temp2[512];
char arg0[80];
char arg1[80];
char arg2[80];
char pathfilename[512];

char rxbuf[512];
char txbuf[512];
char *cp;

/*trace_flag = 1;*/

/* set speed data is send to nick or channel in /exec -msg command */
exec_delay = 0;

/* security enabled by default, 0 is security_override */
security_flag = 1;

/* reset_global_page_back_flag */
global_page_back_flag = 0;

/* set for no connection yet */
socketfd = -1;

/*select con io 1 byte at the time*/
setbuf(stdout,NULL);
setbuf(stdin,NULL);
 
fprintf(stdout,\
"\nPanteltje (c) uirc internet relay chat client vers. %s 1996\n\n\n",\
VERSION);

/* get user info */
userinfo = getpwuid(getuid() );

/* get home directory */
sprintf(home_dir, "%s", userinfo -> pw_dir);

/* first startup */
sprintf(pathfilename, "%s/.uirc/LICENSE", home_dir);
setupfile = fopen(pathfilename, "r");
if(! setupfile)
	{
	fprintf(stdout, "Cannot open file %s\n", pathfilename);
	exit(1);
	}
else fclose(setupfile);
sprintf(pathfilename, "%s/.uirc/README", home_dir);
setupfile = fopen(pathfilename, "r");
if(! setupfile)
	{
	fprintf(stdout, "Cannot open file %s\n", pathfilename);
	exit(1);
	}	
else fclose(setupfile);
sprintf(pathfilename, "%s/.uirc/.uircf", home_dir);
setupfile = fopen(pathfilename, "r");
if(! setupfile)
	{
	fprintf(stdout,\
	"UIRC IS NOT FREE (GRATIS) SOFTWARE, SEE README FOR PAYMENTS,\n");
	fprintf(stdout, "SEE LICENSE FOR LICENSING.\n");
	fprintf(stdout, \
	"YOU ARE FREE TO EVALUATE THIS SOFTWARE FOR A PERIOD OF 30 DAYS,\n");
	fprintf(stdout, "AFTER THAT PERIOD YOU MUST PAY FOR IT.\n");
	fprintf(stdout, "ACCEPT CONDITIONS? (Y / N) <ENTER>\n");
	fscanf(stdin, "%2s", temp);
	c = toupper(temp[0]);
	if(c != 'Y') exit(1);
	else setupfile = fopen(pathfilename, "w");
	if(setupfile) fclose(setupfile);
	}
else fclose(setupfile);

/* set auto_rejoin_flag */
auto_rejoin_flag = 1;

ircport = DEFAULTPORT;
if( (argc == 3) || (argc == 4) )
	{
	strcpy(ircname, argv[1]);
	strcpy(hostname, argv[2]);
	if(argc == 4)ircport = atoi(argv[3]);
	}
else /* no or incorrect arguments */
	{	
	/* test if a setupfile uirc.setup is present */
	/* combine with home directory */
	sprintf(pathfilename, "%s/.uirc/uirc.setup", home_dir);
	setupfile = fopen(pathfilename, "r");
	if(! setupfile)/* no setup file present */
		{
		fprintf(stdout, "\nCannot open setup file %s\n", pathfilename);
		fprintf(stdout,\
		"If no setup file: usage: uirc <nick> <server> [port]\n");
		exit(-1);
		}
	else /* a setup file present */
		{
		/* read data from uirc.setup setupfile into database */
		while(1)
			{
			/* read a line from the setup file */
			a = readline(setupfile, temp);
			if(a == EOF)break;

			/* lines starting with '#' are scipped */
			if(temp[0] == '#') continue; 

			/* scip comments to end of line */
			cp = strstr(temp, "//");
			/* force a string termination on "//" */
			if(cp) *cp = 0;
			
			/* get the start of the second field */
/*			a = sscanf(temp, "%s %s\n", arg0, arg1);*/
			a = sscanf(temp, "%s %s", arg0, arg1);

			/* scip empty lines */
			if (a == -1) continue;
/*
			fprintf(stdout, "\nInStAl:a=%d temp=%s arg0=%s arg1=%s",\
			a, temp, arg0, arg1);
*/
			/* test if any second field was present,
			/* need at least 2 arguments for a valid entry.
			*/
			if( (a < 2) || (! set_setup(arg0, strstr(temp, arg1) ) ) )
				{
				fprintf(stdout,\
"\nCannot install data from setupfile in database, line reads %s\n", temp);
				if(setupfile) fclose(setupfile);
				exit(-1);
				}
			}/* end while read all lines from setupfile */

		/* read data from setup database into the variables */
		/* get all nicks */
		b = 0;
		for(i = 0; i < 10; i++)
			{
			if(! get_setup("nick", temp, i) ) break;
			sscanf(temp, "%s", backup_ircname[i]);
			b = 1;
			}
		if(! b)	
			{
			fprintf(stdout, "\nCannot read any nick from setupfile\n");
			exit(-1);
			}
		nicks = i;
		strcpy(ircname, backup_ircname[0]);
/*
fprintf(stdout, "ircname=%s backup_ircname[0]=%s", ircname, backup_ircname[0]);
exit(-1);
*/
		/* get all servers */
		b = 0;
		for(i = 0; i < 64; i++)
			{
			if(! get_setup("server", temp, i) ) break;
			b = 1;
			sscanf(temp, "%s port %d",\
			backup_hostname[i], &backup_ircport[i]);
			}/* end for all servers */
		if(! b)
			{
			fprintf(stdout, "\nCannot read any server from setupfile\n");
			exit(-1);
			}
		servers = i;
		strcpy(hostname, backup_hostname[0]);
		ircport = backup_ircport[0];
		
		/* get auto_rejoin_status */
		if( get_setup("auto_rejoin", temp, 0) )
			{
			sscanf(temp, "%s", temp2);
			if(strcmp(temp2, "yes") == 0) auto_rejoin_flag = 1;
			else auto_rejoin_flag = 0;
			}

		/* load any user preference files */
		for(i = 0; i < 30; i++)
			{
			if(! get_setup("auto_load", temp, i) ) break;
			else
				{
				sscanf(temp, "%s %s %s", arg0, arg1, arg2);
				if(strcmp(arg2, "yes") == 0)
					{
					if(strcmp(arg0, "ignores") == 0)
						{
						if(! load_ignores(arg1) ) exit(-1);/*err. msg in ld_i*/
						}
					if(strcmp(arg0, "colors") == 0)
						{
						if(! load_colors(arg1) ) exit(-1);
						}
					if(strcmp(arg0, "events") == 0)
						{
						if(! load_events(arg1) ) exit(-1); 
						}
					if(strcmp(arg0, "aliases") == 0)
						{
						if(! load_aliases(arg1) ) exit(-1);
						}
					}/* end else if arg2 is 'yes' */
				}/* end autoloads */
			}/* end for all auto loads */
		}/* end setup file present */ 
	}/* end no or incorrect arguments */


ptr = termcap;
term = (char *)getenv("TERM");
if(! term)
	{
	fprintf(stderr, "\nTERM not set\n");
	exit(-1);
	} 

/* this will set bp, holding the termcap entry for this terminal (big) */
a = tgetent(bp, term);
if(a < 0)
	{
	fprintf(stderr, "\nNo termcap entry for %s\n", term);
	exit(-1);
	}

/* get the width, if no width use default */
CO = tgetnum("co");
if(CO == -1) CO=80;

/* get the height, if no height use default */
LI = tgetnum("li");
if(LI == -1) LI=24;

/* set delete and backspace for this terminal */
/* normal */
/* defaults */
backspace = 8;
delete = 127;
server_id_color = CYAN;
server_text_color = MAGENTA;
nick_id_color = RED;
nick_text_color = BLUE;
last_addressed_color = RED;
if(strstr(term, "linux") )
	{
/*
	fprintf(stdout, "\nLinux console detected");
*/
	backspace = 127;/* why oh why ? */
	delete = -1;/* escape sequence esc [3~ */

	/* set colors for good visibility on black background */
	server_id_color = CYAN;
	if(get_setup("server_id_color_linux_term", temp, 0) )
		{
		sscanf(temp, "%s", temp2);
		string_to_color(temp2, &server_id_color);
		}
	server_text_color = MAGENTA;
	if(get_setup("server_text_color_linux_term", temp, 0) )
		{
		sscanf(temp, "%s", temp2);
		string_to_color(temp2, &server_text_color);
		}
	nick_id_color = GREEN;
	if(get_setup("nick_id_color_linux_term", temp, 0) )
		{
		sscanf(temp, "%s", temp2);
		string_to_color(temp2, &nick_id_color);
		}
	nick_text_color = YELLOW;
	if(get_setup("nick_text_color_linux_term", temp, 0) )
		{
		sscanf(temp, "%s", temp2);
		string_to_color(temp2, &nick_text_color);
		}
	last_addressed_color = INTENSIFIED;
	if(get_setup("last_addressed_color_linux_term", temp, 0) )
		{
		sscanf(temp, "%s", temp2);
		string_to_color(temp2, &last_addressed_color);
		}
	}
if(strstr(term, "xterm") )
	{
/*
	fprintf(stdout, "\nxtern detected");
*/
	backspace = 8;
	delete = 127;
	
	/* set colors for good visibility on white background */
	server_id_color = CYAN;
	if(get_setup("server_id_color_x_term", temp, 0) )
		{
		sscanf(temp, "%s", temp2);
		string_to_color(temp2, &server_id_color);
		}
	server_text_color = MAGENTA;
	if(get_setup("server_text_color_x_term", temp, 0) )
		{
		sscanf(temp, "%s", temp2);
		string_to_color(temp2, &server_text_color);
		}
	nick_id_color = RED;
	if(get_setup("nick_id_color_x_term", temp, 0) )
		{
		sscanf(temp, "%s", temp2);
		string_to_color(temp2, &nick_id_color);
		}
	nick_text_color = BLUE;
	if(get_setup("nick_text_color_x_term", temp, 0) )
		{
		sscanf(temp, "%s", temp2);
		string_to_color(temp2, &nick_text_color);
		}
	last_addressed_color = RED;
	if(get_setup("last_addressed_color_x_term", temp, 0) )
		{
		sscanf(temp, "%s", temp2);
		string_to_color(temp2, &last_addressed_color);
		}
	}
		
/* bp points to termcap entry for this terminal */
CM = (char *)tgetstr("cm", bp);
CS = (char *)tgetstr("cs", bp);
CE = (char *)tgetstr("ce", bp);
KU = (char *)tgetstr("ku", bp);
KD = (char *)tgetstr("kd", bp);
KL = (char *)tgetstr("kl", bp);
KR = (char *)tgetstr("kr", bp);
kD = (char *)tgetstr("kD", bp);/* linux console delete at cursor,
								/* not specified for color xterm */
BS = (char *)tgetstr("bs", bp);/* not set in linux console and color xterm */

KP = (char *)tgetstr("kP", bp);
KN = (char *)tgetstr("kN", bp);
K4 = (char *)tgetstr("k4", bp);
KH = (char *)tgetstr("kh", bp);

if( (!CM) || (!CS) || (!CE) || (!KU) || (!KD) || (!KL) || (!KR) )
	{
	fprintf(stdout,\
	"\nNo cm, cs, ce, ku, kd, kl, or kr termcap entry\n"); 
	exit(-1);
	}   

/* open the terminal */ 
_tty_ch = open("/dev/tty", O_RDWR, 0);
if(_tty_ch == -1) _tty_ch = 0;/* use stdin if no external ? */

signal(SIGINT, cleanup);
signal(SIGHUP, cleanup);
signal(SIGKILL, cleanup);
savetty();
cbreak();
noecho();/* do not echo to con, will echo in bottom line from function
			/* read_from_console */

/* print the status line */													
updatestatus("");

/* put a cursor in the input line */
echo_to_user("", 0, 0);
tputs_x(tgoto(CS, LI - 3, 0));/* start of scrolling field */

if( (argc == 3) || (argc == 4) )
	{
	/* fill in 1 server database entry */
	strcpy(backup_hostname[0], hostname);
	backup_ircport[0] = ircport;
	servers = 1;
	}
else
	{
	to_screen("Trying all servers in uirc.setup, ESC to abort", "");
	}

/* try all servers in database */
b = 0;
for(i = 0; i < servers; i++)
	{
/*	sleep(1);*/
	FD_ZERO(&readfs);
	FD_SET(fileno(stdin), &readfs);
	timeout.tv_sec = 0;
	timeout.tv_usec = 1000;
	b = select(FD_SETSIZE, &readfs, NULL, NULL, &timeout);
	if(b == -1)
		{
		to_screen("select: servers: returned < 0", "");
		}
	if( FD_ISSET(fileno(stdin), &readfs) )
		{
		c = getc(stdin);
		if(c == 27) /* ESCAPE */
			{
			FD_CLR(fileno(stdin), &readfs);
			to_screen(\
			"Trying servers aborted, use /server to connect to a server",\
			"");
			break;
			}
		}
	if( connect_to_server(backup_hostname[i], backup_ircport[i], &socketfd) )
		{
		b = 1;
		break;
		}
	}/* end for all servers */
if(! b)
	{
	to_screen("Cannot connect to server, use /server to connect to a server",\
	"");
	}
 
/* reset idle timer */
idletimer = time(0);
while(1)/* main communications loop */
	{
	/* this macro initializes the file descriptor readfs to to be the empty
	/* set */
	FD_ZERO(&readfs);

	/* this macro adds socketfd to the file descriptor readfs */
	if(socketfd >= 0)FD_SET(socketfd, &readfs);

	/* this adds any dcc socketfd's to filedescriptor readfs */
	set_all_dcc_filedescriptors();

	/* this adds any exec filefd to readfs */
	set_all_exec_filedescriptors();

	/* this macro adds fileno(stdin) to the file descriptor readfs */
	FD_SET(fileno(stdin), &readfs);
	timeout.tv_sec = 10;/* update the clock every ten seconds */
	timeout.tv_usec = 0;
	/* int FD_SETSIZE  macro is maximum number of filedescriptors that
	/* fd_set can hold */
 	/* function select waits for specified filedescr. to have a signal */
	/* last argument struct timeval *timeout */
	b = select(FD_SETSIZE, &readfs, NULL, NULL, &timeout);
	if(b == -1)/* 0 is timeout, -1 error (in errno) */
		{
		to_screen("select: failed, error:", "");
		if(errno == EBADF) to_screen(\
	"One of the file descriptor sets specified an invalid file descriptor.",\
		"");
		if(errno == EINTR) to_screen(\
		"The operation was interrupted by a signal.", "");
		if(errno == EINVAL)
			{
			to_screen(\
			"The TIMEOUT argument is invalid; one of the components is",\
			"");
			to_screen("negative or too large.", "");
		    }                                                                
		break;
		}

	/* test if socket has data */
	if( FD_ISSET(socketfd, &readfs) )
		{	
		/* read from server, write to console */
		if(! server_to_client(&socketfd) )break;
		}

	/* test for data on other sockets */
	if (! dcc_read_write_all_channels() )break;

	/* test for data on exec filedescriptors */	
	if (! exec_read_write_all_data(socketfd) ) break;

	/* test if user has data */
	if( FD_ISSET(fileno(stdin), &readfs) )
		{
	 	/* read from console, write to server */
		if(! client_to_server(&socketfd) )break;
		
		/* reset idletimer */
		idletimer = time(0);
		}
	updatestatus("");
	}/* end main comminucations loop */
tputs_x( tgoto(CS, -1, -1) );
tputs_x( tgoto(CM, 0, LI - 1));
resetty();
fprintf(stdout, "\n");
exit(1);
}/* end main */
