/*
 * screen.c
 *
 * Written By Matthew Green, based on portions of window.c
 * by Michael Sandrof.
 *
 * Copyright(c) 1993, 1994.
 *
 * See the COPYRIGHT file, or do a HELP IRCII COPYRIGHT 
 */


#include "irc.h"
#include "commands.h"
#include "screen.h"
#include "status.h"
#include "window.h"
#include "output.h"
#include "vars.h"
#include "server.h"
#include "list.h"
#include "ircterm.h"
#include "names.h"
#include "ircaux.h"
#include "input.h"
#include "log.h"
#include "hook.h"
#include "dcc.h"
#include "exec.h"
#include "newio.h"
#include "misc.h"
#include "cset.h"
#include "tcl_bx.h"
#ifdef TRANSLATE
#include "translat.h"
#endif
#ifdef WANT_HEBREW
#include "hebrew.h"
#endif

#ifdef WINNT
extern	int	reverse_ch;
#endif


	Window	*to_window;
	Screen	*main_screen;
	Screen	*last_input_screen;
	Screen	*output_screen;
	
	int	extended_handled = 0;
extern	int	in_add_to_tcl;
extern	int	foreground;
	
/* Our list of screens */
Screen	*screen_list = NULL;

static int 	add_to_display_list (Window *, const unsigned char *);
Display *new_display_line (Display *);
void add_to_window (Window *window, const unsigned char *str);
static char display_highlight (int flag);
static char display_bold (int flag);
static char display_blink (int flag);
static char display_underline (int flag);
static void display_color (long color1, long color2);


/*
 * add_to_screen: This adds the given null terminated buffer to the screen.
 * That is, it determines which window the information should go to, which
 * lastlog the information should be added to, which log the information
 * should be sent to, etc 
 */
void add_to_screen(unsigned char *buffer)
{
	Window	*tmp = NULL;


	if (!get_int_var(DISPLAY_ANSI_VAR))
		strcpy(buffer, stripansicodes(buffer));

	if (!current_window)
	{
		puts(buffer);
		return;
	}
#ifdef WANT_TCL
	if (in_add_to_tcl)
	{
		add_to_tcl(current_window, buffer);
		return;
	}
#endif
	if (dumb_mode)
	{
		add_to_lastlog(current_window, buffer);
		if (do_hook(WINDOW_LIST, "%u %s", current_window->refnum, buffer))
			puts(buffer);
		fflush(stdout);
		return;
	}

	if (in_window_command)
	{
		in_window_command = 0;
		update_all_windows();
	}

	if (to_window)
	{
		add_to_window(to_window, buffer);
		return;
	}
	else if ((who_level == LOG_CURRENT) && (current_window->server == from_server))
	{
		add_to_window(current_window, buffer);
		return;
	}
	else if (who_from && *who_from)
	{
		tmp = NULL;
		while ((traverse_all_windows(&tmp)))
		{
			if (tmp->current_channel)
			{
				if (!my_stricmp(who_from, tmp->current_channel) && 
					tmp->server == from_server)
				{
					add_to_window(tmp, buffer);
					return;
				}
			} 
			if (tmp->query_nick &&
				(((who_level == LOG_MSG || who_level == LOG_NOTICE)
				&& !my_stricmp(who_from, tmp->query_nick) &&
				from_server == tmp->server) ||
				(who_level == LOG_DCC &&
				(*tmp->query_nick == '=' || *tmp->query_nick == '-') &&
				!my_stricmp(who_from, tmp->query_nick + 1))))
			{
				add_to_window(tmp, buffer);
				return;
			}
		}
		
		if (is_channel(who_from) && from_server != -1)
		{
			ChannelList *chan;
			if ((chan = (ChannelList *)find_in_list((List **)&(server_list[from_server].chan_list), 
				who_from, !USE_WILDCARDS)))
			{
				tmp = NULL;
				while ((traverse_all_windows(&tmp)))
				{
					if (chan->window && chan->window == tmp && from_server == chan->window->server)
					{
						add_to_window(tmp, buffer);
						return;
					}
				}
			}
		}
		tmp = NULL;
		while ((traverse_all_windows(&tmp)))
		{
			if (from_server == tmp->server)
			{
				if (find_in_list((List **)&(tmp->nicks), who_from, !USE_WILDCARDS))
				{
					add_to_window(tmp, buffer);
					return;
				}
			}
		}
	}
	tmp = NULL;
	while ((traverse_all_windows(&tmp)))
	{
		if (((from_server == tmp->server) || (from_server == -1)) &&
		    (who_level & tmp->window_level))
		{
			add_to_window(tmp, buffer);
			return;
		}
	}
	if (from_server == current_window->server)
	{
		add_to_window(current_window, buffer);
		return;
	}
	tmp = NULL;
	while ((traverse_all_windows(&tmp)))
	{
		if (tmp->server == from_server)
		{
			add_to_window(tmp, buffer);
			return;
		}
	}
	add_to_window(current_window, buffer);
}

/*
 * This puts the given string into a scratch window.  It ALWAYS suppresses
 * any further action (by returning a FAIL, so rite() is not called).
 */
static	int	add_to_scratch_window_display_list (Window *window, const unsigned char *str)
{
	Display *my_line, *my_line_prev;
	int cnt;

	if (window->scratch_line == -1)
		ircpanic("This is not a scratch window.");

	if (window->scratch_line > window->display_size)
		ircpanic("scratch_line is too big.");

	my_line = window->top_of_display;
	my_line_prev = NULL;

	for (cnt = 0; cnt < window->scratch_line; cnt++)
	{
		if (my_line == window->display_ip)
		{
			if (my_line_prev)
			{
				my_line_prev->next = new_display_line(my_line_prev);
				my_line = my_line_prev->next;
				my_line->next = window->display_ip;
				window->display_ip->prev = my_line;
			}
			else
			{
				window->top_of_display = new_display_line(my_line_prev);
				my_line = window->top_of_display;
				my_line->next = window->display_ip;
				window->display_ip->prev = my_line;
			}
			window->display_buffer_size++;
		}

		my_line_prev = my_line;
		my_line = my_line->next;
	}
	/* XXXX DO this right!!!! XXXX */
	if (my_line == window->display_ip)
	{
		my_line = new_display_line(window->display_ip->prev);
		if (window->display_ip->prev)
			window->display_ip->prev->next = my_line;
		my_line->next = window->display_ip;
		window->display_ip->prev = my_line;
		window->display_buffer_size++;
	}

	malloc_strcpy(&my_line->line, str);
	window->cursor = window->scratch_line;

	/*
	 * Make sure the cursor ends up in the right spot
	 */
	if (window->visible)
	{
		window->cursor = window->scratch_line;
		window->screen->cursor_window = window;
		term_move_cursor(0, window->top + window->cursor);
		term_clear_to_eol();
		output_line((char *)str);
		display_highlight(OFF);
	}

	window->scratch_line++;
	if (window->scratch_line >= window->display_size)
		window->scratch_line = 0;	/* Just go back to top */
	window->cursor = window->scratch_line;
	return 0;		/* Express a failure */
}

/*
 * add_to_window: adds the given string to the display.  No kidding. This
 * routine handles the whole ball of wax.  It keeps track of what's on the
 * screen, does the scrolling, everything... well, not quite everything...
 * The CONTINUED_LINE idea thanks to Jan L. Peterson (jlp@hamblin.byu.edu)  
 *
 * At least it used to. Now most of this is done by split_up_line, and this
 * function just dumps it onto the screen. This is because the scrollback
 * functions need to be able to figure out how to split things up too.
 */
void add_to_window(Window *window, const unsigned char *str)
{

	if (window->server >= 0 && server_list[window->server].redirect)
		redirect_text(window->server, 
			        server_list[window->server].redirect,
				str, NULL, 0, 0);
	if (do_hook(WINDOW_LIST, "%u %s", window->refnum, str))
	{
		unsigned char   **lines;
		int	cols;
		                                                
		add_to_log(window->log_fp, 0, str);
		add_to_lastlog(window, str);
		display_highlight(OFF);
		display_bold(OFF);

		if (window->screen)
			cols = window->screen->co;
		else
			cols = window->columns;

		for (lines = split_up_line(str, cols); *lines; lines++)
		{
			if (add_to_display_list(window, *lines))
				rite(window, *lines);
		}
		/*
		 * This used to be in rite(), but since rite() is a general
		 * purpose function, and this stuff really is only intended
		 * to hook on "new" output, it really makes more sense to do
		 * this here.  This also avoids the terrible problem of 
		 * recursive calls to split_up_line, which are bad.
		 */
		if (!window->visible)
		{
			/*
			 * This is for archon -- he wanted a way to have 
			 * a hidden window always beep, even if BEEP is off.
			 */
			if (window->beep_always && strchr(str, '\007'))
			{
				Window *old_to_window;
				term_beep();
				old_to_window = to_window;
				to_window = current_window;
				say("Beep in window %d", window->refnum);
				to_window = old_to_window;
			}

			/*
			 * Tell some visible window about our problems 
			 * if the user wants us to.
			 */
			if (!(window->miscflags & WINDOW_NOTIFIED) &&
				who_level & window->notify_level)
			{
				window->miscflags |= WINDOW_NOTIFIED;
				if (window->miscflags & WINDOW_NOTIFY)
				{
					Window	*old_to_window;
					int	lastlog_level;

					lastlog_level = set_lastlog_msg_level(LOG_CRAP);
					old_to_window = to_window;
					to_window = current_window;
					say("Activity in window %d", 
						window->refnum);
					to_window = old_to_window;
					set_lastlog_msg_level(lastlog_level);
				}
				update_all_status(current_window, NULL, 0);
			}
		}

		cursor_in_display();
	}
}


/*
 * split_up_line -- converts a logical line into one or more physical lines
 * accounting for special characters, unprintables, etc.  This function
 * is large and obtuse, so itll take a bit of explaining.
 *
 * Essentialy two copies of the string are made: The original string (str)
 * is walked and is copied byte for byte into "buffer", with extra characters
 * being inserted for the sake of special control characters (like beeps or
 * tabs or whatever).  As each line in "buffer" is created, it is malloc-
 * copied off into "output" which holds the final broken result.  When the
 * entire input has been converted into "buffer" and then copied off into
 * "output", the "output" is returned, and passed off to output_line.
 *
 * As much as possible, i have had tried to avoid extraneous malloc() and
 * free calls which are essentially a waste of CPU time.  Note that this
 * means that an exceptionally long line will not have all of its lines
 * free()d until another line of such length is processed.  That can mean
 * a small amount of space that is not "lost" but will not be reclaimed, 
 * which should not be terribly significant, since it saves a tremendous
 * amount of CPU.
 *
 * Note that there are no limiations on the put any longer.  Neither the
 * size of "buffer" (2048 characters) nor the size of "output" (40 lines)
 * are completely inflexible any longer.  The only true limitation now is
 * a screen width of 2048 characters (absurdly large).
 *
 * XXXX -- If it werent for scrollback, you could roll output_line into this
 * function and simplify the output chain greatly, without having to place
 * arbitrary limits on the output.
 */
#define	MAXIMUM_SPLITS	40
#define MAX_SCREEN_BUFFER (BIG_BUFFER_SIZE * 2)
unsigned char **split_up_line (const unsigned char *str, int max_cols)
{
static	unsigned char	**output = NULL;
static	int		output_size = 0;
	unsigned char	buffer[2 * BIG_BUFFER_SIZE + 1];
const	unsigned char	*ptr;
	unsigned char	*cont_ptr,
			*cont = empty_string,
			c;
register int		pos = 0,		/* Current pos in "buffer" */
			col = 0,		/* Current col on display */
			word_break = 0,		/* Last end of word */
			i;			/* Generic counter */
	int		indent = 0,		/* Start of 2nd word */
			beep_cnt = 0,		/* Controls number of beeps */
			beep_max,		/* what od you think? */
			tab_cnt = 0,
			tab_max,
			line = 0;		/* Current pos in "output" */
	int		len;			/* Used for counting tabs */
	unsigned char	*pos_copy;		/* Used for reconstruction */
	int		do_indent;
	int		newline = 0;
static	int		recursion = 0;

	if (recursion)
		abort();
	recursion++;
	
	/* XXXXX BOGUS! XXXXX */
	if (!output_size)
	{
		int new = MAXIMUM_SPLITS;
		RESIZE(output, char *, new);
		output_size = new;
	}

	*buffer = 0;

	/* Especially handle blank lines */
	if (!*str)
		str = " ";


	beep_max = get_int_var(BEEP_VAR) ? get_int_var(BEEP_MAX_VAR) > 5 ? 5 :get_int_var(BEEP_MAX_VAR) : -1;
	tab_max = get_int_var(TAB_VAR) ? get_int_var(TAB_MAX_VAR) : -1;
	do_indent = get_int_var(INDENT_VAR);

	if (!(cont_ptr = get_string_var(CONTINUED_LINE_VAR)))
		cont_ptr = empty_string;


	/*
	 * Walk the entire input string and convert it as neccesary.
	 * Intermediate results go into 'buffer', and the final destination
	 * is 'output'.
	 */
#ifdef WANT_HEBREW
	/*
	 * crisk: Hebrew processing the line.
	 * 
	 */
	if (get_int_var(HEBREW_TOGGLE_VAR))
		hebrew_process(str);
#endif

	for (ptr = str; *ptr && (pos < 2 * BIG_BUFFER_SIZE - 20); ptr++)
	{
#ifdef TRANSLATE
		if (translation)
			*ptr = transToClient[*ptr];
#endif
		switch (*ptr)
		{
			case '\007':	/* bell */
			{
				beep_cnt++;
				if (beep_max == -1 || beep_cnt > beep_max)
				{
					buffer[pos++] = REV_TOG;
					buffer[pos++] = ((*ptr) & 127) | 64;
					buffer[pos++] = REV_TOG;
					col++;
				}
				else 
					buffer[pos++] = *ptr;
				break;
			}
			case '\011':	/* tab */
			{
				tab_cnt++;
				if (tab_max > 0 && tab_cnt > tab_max)
				{
					buffer[pos++] = REV_TOG;
					buffer[pos++] = ((*ptr) & 127) | 64;
					buffer[pos++] = REV_TOG;
					col++;
				}
				else
				{
					if (indent == 0)
						indent = -1;
					word_break = pos;

					/*
					 * Tabs only go as far as the right
					 * edge of the screen -- no farther
					 */
					len = 8 - (col % 8);
					for (i = 0; i < len; i++)
					{
						buffer[pos++] = ' ';
						if (col++ >= max_cols)
							break;
					}
				}
				break;
			}
			case '\n':	/* Forced newline */
			{
				newline = 1;
				if (indent == 0)
					indent = -1;
				word_break = pos;
				break;
			}
			case ',':
			case ' ':	/* word break */
			{
				if (indent == 0)
					indent = -1;
				if (*ptr == ',')
					word_break = pos + 1;
				else
					word_break = pos;
				buffer[pos++] = *ptr;
				col++;
				break;
			}
			case UND_TOG:
			case ALL_OFF:
			case REV_TOG:
			case BOLD_TOG:
			case BLINK_TOG:
			{
				buffer[pos++] = *ptr;
				break;
			}
			case '\003':	/* ^C colors */
			{
				int c1, c2;

				/* Copy the \003. */
				buffer[pos++] = *ptr++;

				/* If the first char after the \003 is digit */
				if (isdigit(*ptr))
				{
					/* Then grab its value */
					c1 = *ptr - '0';

					/* And put that char in the buffer */
					buffer[pos++] = *ptr++;

					/* 
					 * Check to see if a 2nd digit is
					 * needed to get value 0 < x <= 15
					 */
					if (c1 == 0 && isdigit(*ptr))
						buffer[pos++] = *ptr++;

					if (c1 == 1 && isdigit(*ptr) && 
					    (*ptr - '0' < 6))
						buffer[pos++] = *ptr++;
				}

				/* 
				 * Now ptr is pointing at first char after
				 * the previous number.  If it isnt a comma,
				 * then we need to back up so that the ptr++
				 * at the top of the loop makes sure to handle
				 * this character.
				 */
				if (*ptr == ',' && isdigit(ptr[1]))
				{
					/* Copy the comma */
					buffer[pos++] = *ptr++;

					/* Then grab its value */
					c2 = *ptr - '0';

					/* Put the first digit in buffer */
					buffer[pos++] = *ptr++;

					/* 
					 * Check to see if a 2nd digit is
					 * needed to get value 0 < x <= 15
					 */
					if (c2 == 0 && isdigit(*ptr))
						buffer[pos++] = *ptr++;

					if (c2 == 1 && isdigit(*ptr) && 
					    (*ptr - '0' < 6))
						buffer[pos++] = *ptr++;
				}

				/*
				 * We know that the 'ptr' points at the next
				 * char to be handled, so back up and jam
				 * (itll be ptr++'d at the top)
				 */
				ptr--;
				break;
			}
			case '\033':	/* ESCape */
			{
				/* 
				 * This is the only character that
				 * term_putchar lets go by unchecked.
				 * so we check it here.  Everything
				 * else doesnt need to be filtered.
				 */
				if (!get_int_var(DISPLAY_ANSI_VAR))
				{
					buffer[pos++] = REV_TOG;
					buffer[pos++] = '[';
					buffer[pos++] = REV_TOG;
					col++;
					break;
				}
				/* ELSE FALLTHROUGH */
			}

			/* Everything else including unfiltered ESCapes */
			default:
			{
				/* Check if printable... */
				if (!vt100_decode(*ptr))
				{
					if (indent == -1)
						indent = col;
					col++;
				}

				buffer[pos++] = *ptr;
				break;
			}
		}


		/*
		 * Ok.  This test is to see if we've reached the right side
		 * of the display.  If we do, then we have three tasks:
		 *  1. Break off the current line at the end of the last word
		 *  2. Start the new line with the "continued line" string
		 *  3. Put back the stuff already parsed after the break.
		 */
		if (col >= max_cols || newline)
		{
			/* one big long line, no word breaks */
			if (word_break == 0)
				word_break = max_cols - 1; /*
						      * MHacker came up with a
						      *	possible solution here
						      */

			/*
			 * Resize output if neccesary.
			 * XXX Note that this uses -3, so that there are
			 * always at least two lines available when we
			 * exit the for loop -- one for the last line,
			 * and one for the 
			 */
			if (line >= output_size - 3)
			{
				int new = output_size + MAXIMUM_SPLITS + 1;
				RESIZE(output, char *, new);
				output_size = new;
			}

			/* 1. Break off the current line at the end */
			/*
			 * Copy the current line into the return values.
			 */
			c = buffer[word_break];
			buffer[word_break] = '\0';
			malloc_strcpy((char **)&(output[line++]), buffer);
			buffer[word_break] = c;

		


			/* 2. Calculate the "continued line" string */

			/*
			 * If the 'continued line' string has not yet
			 * been set, we need to set it here (since at
			 * this point the first line is done, and we cant
			 * do the /SET INDENT until we know how the first
			 * line is layed out.
			 */
			if (!*cont && do_indent && (indent < max_cols / 3) && (strlen(cont_ptr) < indent))
			{
				cont = alloca(indent + 10);
				sprintf(cont, "%-*s", indent, cont_ptr);
			}
			/*
			 * If cont_ptr has not been initialize, do so.
			 * Otherwise we dont do anything.
			 */
			else if (!*cont && *cont_ptr)
				cont = cont_ptr;


			/* 3. Paste the new line back together again. */

			/*
			 * Skip over the spaces that comprised the break
			 * between the lines.
			 */
			while (buffer[word_break] == ' ' && word_break < pos)
				word_break++;

			/*
			 * Now re-create the new line
			 * and figure out where we are.
			 */
			buffer[pos] = 0;
			pos_copy = alloca(strlen(buffer + word_break) + strlen(cont) + 2);
			strcpy(pos_copy, buffer + word_break);

			strcpy(buffer, cont);
			strcat(buffer, pos_copy);
			col = pos = strlen(buffer);
			word_break = 0;
			newline = 0;

			if (get_int_var(DISPLAY_ANSI_VAR))
				col -= count_ansi(buffer, -1);
		}
	}

	/*
	 * At this point we've completely walked the input source, so we 
	 * clean up anything left in the intermediate buffer.  This is the 
	 * "typical" case, since most output is only one line long.
	 */
	buffer[pos++] = ALL_OFF;
	buffer[pos] = '\0';
	if (*buffer)
		malloc_strcpy((char **)&(output[line++]), buffer);

	new_free(&output[line]);
	recursion--;
	return output;
}
 
/*
 * This function adds an item to the window's display list.  If the item
 * should be displayed on the screen, then 1 is returned.  If the item is
 * not to be displayed, then 0 is returned.  This function handles all
 * the hold_mode stuff.
 */
static int 	add_to_display_list (Window *window, const unsigned char *str)
{
	if (window->scratch_line != -1)
		return add_to_scratch_window_display_list(window, str);

	if (!window->display_ip)
		return 1;
	/* Add to the display list */
	window->display_ip->next = new_display_line(window->display_ip);
	malloc_strcpy(&window->display_ip->line, str);
	window->display_ip = window->display_ip->next;
	window->display_buffer_size++;
	window->distance_from_display++;
	
	/*
	 * Only output the line if hold mode isnt activated
	 */
	if (((window->distance_from_display > window->display_size) &&
						window->scrollback_point) ||
		(window->hold_mode &&
  			(++window->held_displayed >= window->display_size)) ||
  		(window->holding_something && window->lines_held))
	{
		if (!window->holding_something)
			window->holding_something = 1;
			
		window->lines_held++;
		if (window->lines_held >= window->last_lines_held + 10)
		{
			update_window_status(window, 0);
			window->last_lines_held = window->lines_held;
		}
		return 0;
	}


	/*
	 * Before outputting the line, we snip back the top of the
	 * display buffer.  (The fact that we do this only when we get
	 * to here is what keeps whats currently on the window always
	 * active -- once we get out of hold mode or scrollback mode, then
	 * we truncate the display buffer at that point.)
	 */
	while (window->display_buffer_size > window->display_buffer_max)
	{
		Display *next = window->top_of_scrollback->next;
		delete_display_line(window->top_of_scrollback);
		window->top_of_scrollback = next;
		window->display_buffer_size--;
	}

	/*
	 * And tell them its ok to output this line.
	 */
	return 1;
}



/*
 * rite: this routine displays a line to the screen adding bold facing when
 * specified by ^Bs, etc.  It also does handle scrolling and paging, if
 * SCROLL is on, and HOLD_MODE is on, etc.  This routine assumes that str
 * already fits on one screen line.  If show is true, str is displayed
 * regardless of the hold mode state.  If redraw is true, it is assumed we a
 * redrawing the screen from the display_ip list, and we should not add what
 * we are displaying back to the display_ip list again. 
 *
 * Note that rite sets display_highlight() to what it was at then end of the
 * last rite().  Also, before returning, it sets display_highlight() to OFF.
 * This way, between susequent rites(), you can be assured that the state of
 * bold face will remain the same and the it won't interfere with anything
 * else (i.e. status line, input line). 
 */
int rite(Window *window, const unsigned char *str)
{
static	int		high = OFF;

	output_screen = window->screen;
	scroll_window(window);

	if (window->visible && foreground)
	{
		display_highlight(high);
		output_line((char *)str);
		high = display_highlight(OFF);
#ifdef WINNT
		NT_MoveToLineOrChar(output_screen->hStdout, 1, 1);
		NT_MoveToLineOrCharAbs(output_screen->hStdout, 0, 0);
#else
		term_cr();
		term_newline();
#endif
		term_flush();
	}
	window->cursor++;
	return 0;
}

/*
 * This actually outputs a string to the screen.  Youll notice this function
 * is a lot simpler than it was before, because all of that busiwork it did
 * before was completely bogus.  What happens now is:
 *
 * Any time we get a recognized highlight character, we handle it by 
 * toggling the appropriate setting.  This might waste a few function calls
 * if people have two of the same highlight char next to each other, but
 * that savings isnt worth the maintainance nightmare of the previous code.
 *
 * Any other character that isnt a recognized highlight character is 
 * dispatched to the screen.  Since we use term_putchar(), any special
 * handling of ansi sequences is filtered there.  We do not know, and we
 * do not care about what is actually in the string.  We can (and do) assume
 * that the string passed to us in "str" will fit on the screen at whatever
 * position the cursor is at.
 *
 * Unless the last character on the line is an ALL_OFF character, output_line
 * will *NOT* reset any attributes that may be set during the source of the
 * output.  This is so you can output one or more lines that constitute part
 * of a "logical" line, and any highlights or colors will "bleed" onto the
 * next physical line.  The last such physical line in a logical line without
 * exception MUST end with the ALL_OFF character, or everything will go all
 * higgledy-piggledy.  As long as you do that, everything will look ok.
 */
int output_line (register unsigned char *str)
{
unsigned char	*ptr = str;
	int	beep = 0;
#ifdef WINNT
	int	len;
	if (!ptr)
		return;
	len = strlen(str);
#endif
	if (!foreground)
		return 0;

	/* Walk the string looking for special chars. */
#ifdef WINNT
	nt_write(current_window->screen->hStdout,str, len);
#else

	while (ptr && *ptr)
	{
		switch (*ptr)
		{
			case REV_TOG:
			{
				display_highlight(TOGGLE);
				break;
			}
			case UND_TOG:
			{
				display_underline(TOGGLE);
				break;
			}
			case BOLD_TOG:
			{
				display_bold(TOGGLE);
				break;
			}
			case BLINK_TOG:
			{
				display_blink(TOGGLE);
				break;
			}
			case ALL_OFF:
			{
				display_underline(OFF);
				display_highlight(OFF);
				display_bold(OFF); /* This turns it all off */
				display_blink(OFF);
				if (!ptr[1])	/* We're the end of line */
					term_bold_off();
				break;
			}
			case '\003':  /* ^C colors */
			{
				long c1 = -1, c2 = -1;

				ptr++;
				if (isdigit(*ptr))
				{
					c1 = (*ptr++ - '0');
					if (c1 == 0 || c1 == 1)
					{
						if (isdigit(*ptr) &&
						   (c1 == 0 || 
							(*ptr - '0' < 6)))
						{
							c1 *= 10;
							c1 += (*ptr++ - '0');
						}
					}
				}
				if (*ptr == ',' && isdigit(ptr[1]))
				{
					ptr++;
					c2 = (*ptr++ - '0');
					if (c2 == 0 || c2 == 1)
					{
						if (isdigit(*ptr) &&
						   (c2 == 0 || 
							(*ptr - '0' < 6)))
						{
							c2 *= 10;
							c2 += (*ptr++ - '0');
						}
					}
				}

				ptr--;
				display_color(c1, c2);
				break;
			}
			case '\007':
			{
				beep++;
				break;
			}
			case '\r':
			case '\n':
				break;
			default:
			{
				term_putchar(*ptr);
				break;
			}
		}
		ptr++;
	}


	if (beep)
		term_beep();
#endif
	term_clear_to_eol();
	return 0;
}

/*
 * scroll_window: Given a pointer to a window, this determines if that window
 * should be scrolled, or the cursor moved to the top of the screen again, or
 * if it should be left alone. 
 */
void scroll_window(Window *window)
{
	if (dumb_mode)
		return;


	if (window->cursor == window->display_size)
	{
		int	scroll,	i;

		if (window->holding_something || window->scrollback_point)
			ircpanic("Cant scroll this window!");

		if ((scroll = get_int_var(SCROLL_LINES_VAR)) <= 0)
			scroll = 1;


		for (i = 0; i < scroll; i++)
		{
			window->top_of_display = window->top_of_display->next;
			window->distance_from_display--;
		}


		if (window->visible && foreground)
		{
			if (window->status_split)
				term_scroll(window->top+window->menu.lines,
					window->top + window->menu.lines +
					window->cursor-1, scroll);
			else
				term_scroll(window->top,
					window->top - window->menu.lines +
					window->cursor, scroll);
		}
		window->cursor -= scroll;
	}
	if (window->visible)
	{
		window->screen->cursor_window = window;
		if (window->status_split)
			term_move_cursor(0, window->top + window->menu.lines + window->cursor);
		else
			term_move_cursor(0, window->top + window->cursor);
		term_clear_to_eol();
	}
}

#ifdef WINNT
/* display_highlight: turns off and on the display highlight.  */
static	char display_highlight(int flag)
{
	if (flag == reverse_ch)
		return (flag);
	switch (flag)
	{
		case ON:
		{
			if (get_int_var(INVERSE_VIDEO_VAR))
                        	reverse_ch = 1;
			flag = OFF;
                	break;
		}
		case OFF:
		{
			if (get_int_var(INVERSE_VIDEO_VAR))
                        	reverse_ch = 0;
			flag = ON;
                	break;
		}
		case TOGGLE:
		{
			if (reverse_ch)
			{
				if (get_int_var(INVERSE_VIDEO_VAR))
					reverse_ch = 0;
				flag = ON;
			}
			else
			{
				if (get_int_var(INVERSE_VIDEO_VAR))
					reverse_ch = 1;
				flag = OFF;
			}
		}
	}
	set_term_inverse(reverse_ch);
	return flag;
}

/* display_bold: turns off and on the display bolding.  */
static	char display_bold(int flag)
{
	if (flag == intensity)
		return (flag);
	switch (flag)
	{
	case ON:
		if (get_int_var(BOLD_VIDEO_VAR))
			intensity = 1;
		flag = OFF;
        	break;
	case OFF:
		if (get_int_var(BOLD_VIDEO_VAR))
			intensity = 0;
               	break;
		flag = ON;
	case TOGGLE:
		if (intensity)
		{
			if (get_int_var(BOLD_VIDEO_VAR))
				intensity = 0;
			flag = ON;
		}
		else
		{
			if (get_int_var(BOLD_VIDEO_VAR))
				intensity = 1;
			flag = OFF;
		}
	}
	set_term_intensity(intensity);
	return flag;
}

/* display_bold: turns off and on the display bolding.  */
static char display_underline (int flag)
{
	if (flag == underline)
		return (flag);

	switch (flag)
	{
		case ON:
		{
			if (get_int_var(UNDERLINE_VIDEO_VAR))
				underline = 1;
			flag = OFF;
	               	break;
		}
		case OFF:
		{
			if (get_int_var(UNDERLINE_VIDEO_VAR))
				underline = 0;
			flag = ON;
	               	break;
		}
		case TOGGLE:
		{
			if (underline)
			{
				if (get_int_var(UNDERLINE_VIDEO_VAR))
					underline = 0;
				flag = ON;
			}
			else
			{
				if (get_int_var(UNDERLINE_VIDEO_VAR))
					underline = 1;
				flag = OFF;
			}
		}
	}
	set_term_underline(underline);
	return flag;
}

static char	display_blink(int flag)
{
	/* THIS function needs to be filled out for NT */
	return OFF;
}

#else
/* display_blink: turns on and off the annoying flashing text */
static char 	display_blink (int flag)
{
	static	int	blink = OFF;

	if (flag == blink)
		return (flag);

	switch (flag)
	{
		case ON:
			blink = ON;
			if (get_int_var(BLINK_VIDEO_VAR))
				term_blink_on();
			return (OFF);
		case OFF:
			blink = OFF;
			if (get_int_var(BLINK_VIDEO_VAR))
				term_bold_off();
			return (ON);
		case TOGGLE:
			if (blink == ON)
			{
				blink = OFF;
				if (get_int_var(BLINK_VIDEO_VAR))
					term_bold_off();
				return (ON);
			}
			else
			{
				blink = ON;
				if (get_int_var(BLINK_VIDEO_VAR))
					term_blink_on();
				return (OFF);
			}
	}
	return OFF;
}

/* display_highlight: turns off and on the display highlight.  */
static	char display_highlight(int flag)
{
	static	int	highlight = OFF;

	if (flag == highlight)
		return (flag);
	switch (flag)
	{
		case ON:
		{
			highlight = ON;
			if (get_int_var(INVERSE_VIDEO_VAR))
				term_standout_on();
			return (OFF);
		}
		case OFF:
		{
			highlight = OFF;
			if (get_int_var(INVERSE_VIDEO_VAR))
				term_standout_off();
			return (ON);
		}
		case TOGGLE:
		{
			if (highlight == ON)
			{
				highlight = OFF;
				if (get_int_var(INVERSE_VIDEO_VAR))
					term_standout_off();
				return (ON);
			}
			else
			{
				highlight = ON;
				if (get_int_var(INVERSE_VIDEO_VAR))
					term_standout_on();
				return (OFF);
			}
		}
	}
	return flag;
}
 
/* display_bold: turns off and on the display bolding.  */
static	char display_bold(int flag)
{
	static	int	bold = OFF;

	if (flag == bold)
		return (flag);
	switch (flag)
	{
	case ON:
		bold = ON;
		if (get_int_var(BOLD_VIDEO_VAR))
			term_bold_on();
		return (OFF);
	case OFF:
		bold = OFF;
		if (get_int_var(BOLD_VIDEO_VAR))
			term_bold_off();
		return (ON);
	case TOGGLE:
		if (bold == ON)
		{
			bold = OFF;
			if (get_int_var(BOLD_VIDEO_VAR))
				term_bold_off();
			return (ON);
		}
		else
		{
			bold = ON;
			if (get_int_var(BOLD_VIDEO_VAR))
				term_bold_on();
			return (OFF);
		}
	}
	return OFF;
}

/* display_bold: turns off and on the display bolding.  */
static char display_underline (int flag)
{
	static	int	underline = OFF;

	if (flag == underline)
		return (flag);

	switch (flag)
	{
		case ON:
		{
			underline = ON;
			if (get_int_var(UNDERLINE_VIDEO_VAR))
				term_underline_on();
			return (OFF);
		}
		case OFF:
		{
			underline = OFF;
			if (get_int_var(UNDERLINE_VIDEO_VAR))
				term_underline_off();
			return (ON);
		}
		case TOGGLE:
		{
			if (underline == ON)
			{
				underline = OFF;
				if (get_int_var(UNDERLINE_VIDEO_VAR))
					term_underline_off();
				return (ON);
			}
			else
			{
				underline = ON;
				if (get_int_var(UNDERLINE_VIDEO_VAR))
					term_underline_on();
				return (OFF);
			}
		}
	}
	return OFF;
}
#endif

static void display_color (long color1, long color2)
{
	char seq[32];

	if (!get_int_var(MIRCS_VAR))
		return;

	if (color1 > 7)
	{
		term_bold_on();
		color1 -= 8;
	}
	if (color2 > 7)
	{
/*		term_blink_on();*/
		color2 -= 8;
	}

	if (color1 != -1)
	{
		sprintf(seq, "\033[%ldm", color1 + 30);
#ifdef WINNT
		nt_write(output_screen->hStdout,seq, 6);
#else
		tputs_x(seq);
#endif
	}
	if (color2 != -1)
	{
		sprintf(seq, "\033[%ldm", color2 + 40);
#ifdef WINNT
		nt_write(output_screen->hStdout,seq, 6);
#else
		tputs_x(seq);
#endif
	}
	if (color1 == -1 && color2 == -1)
	{
		sprintf(seq, "\033[%d;%dm", 39, 49);
#ifdef WINNT
		nt_write(output_screen->hStdout,seq, 6);
#else
		tputs_x(seq);
#endif
		term_bold_off();
	}
}

/*
 * cursor_not_in_display: This forces the cursor out of the display by
 * setting the cursor window to null.  This doesn't actually change the
 * physical position of the cursor, but it will force rite() to reset the
 * cursor upon its next call 
 */
void cursor_not_in_display _((void))
{
	if (current_window && current_window->screen)
		current_window->screen->cursor_window = NULL;
}

/*
 * cursor_in_display: this forces the cursor_window to be the
 * output_screen->current_window. 
 * It is actually only used in hold.c to trick the system into thinking the
 * cursor is in a window, thus letting the input updating routines move the
 * cursor down to the input line.  Dumb dumb dumb 
 */
void cursor_in_display _((void))
{
	if (current_window->screen)
		current_window->screen->cursor_window = current_window;
}

/*
 * is_cursor_in_display: returns true if the cursor is in one of the windows
 * (cursor_window is not null), false otherwise 
 */
int is_cursor_in_display(Screen *screen)
{
	if (!screen && current_window->screen)
		screen = current_window->screen;
	return (screen->cursor_window ? 1 : 0);
}

/* * * * * * * SCREEN UDPATING AND RESIZING * * * * * * * * */
/*
 * repaint_window: redraw the "m"th through the "n"th part of the window.
 * If end_line is -1, then that means clear the display if any of it appears
 * after the end of the scrollback buffer.
 */
void 	repaint_window (Window *w, int start_line, int end_line)
{
	Window *window = (Window *)w;
	Display *curr_line;
	int count;
	int clean_display = 0;

	if (dumb_mode || !window->visible)
		return;

	if (!window)
		window = current_window;

	if (end_line == -1)
	{
		end_line = window->display_size;/* - 1; CDE this fixes a small flash problem */
		clean_display = 1;
	}

	curr_line = window->top_of_display;
	window->cursor = start_line;
	for (count = start_line; count < end_line; count++)
	{
		rite(window, curr_line->line);

		if (curr_line == window->display_ip)
			break;

		curr_line = curr_line->next;
	}

	/*
	 * If "end_line" is -1, then we're supposed to clear off the rest
	 * of the display, if possible.  Do that here.
	 */
	if (clean_display)
	{
		for (; count < end_line; count++)
		{
#ifdef WINNT
			NT_MoveToLineOrChar(output_screen->hStdout, 1, 1);
			NT_MoveToLineOrCharAbs(output_screen->hStdout, 0, 0);
#else
			term_clear_to_eol();
			term_newline();
#endif
		}
		update_window_status(window, 1);
	}

	recalculate_window_cursor(window);	/* XXXX */
}

/*
 * create_new_screen creates a new screen structure. with the help of
 * this structure we maintain ircII windows that cross screen window
 * boundaries.
 */
Screen	* create_new_screen(void)
{
	Screen	*new = NULL, *list;
	static	int	refnumber = 0;
	
	for (list = screen_list; list; list = list->next)
	{
		if (!list->alive)
		{
			new = list;
			break;
		}

		if (!list->next)
			break;
	}

	if (!new)
	{
		new = (Screen *) new_malloc(sizeof(Screen));
		new->screennum = ++refnumber;
		new->next = NULL;
		if (list)
			list->next = new;
		else
			screen_list = new;
	}
	new->last_window_refnum = 1;
	new->fdout = 1;
	new->fpout = stdout;
#ifdef WINNT
	new->hStdin = GetStdHandle(STD_INPUT_HANDLE);
	new->hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
#endif
	if (use_input)
		new_open(0);
	new->fpin = stdin;
	new->alive = 1;
	new->li = LI;
	new->co = CO;
	new->old_li = 0;
	new->old_co = 0;
	new->buffer_pos = new->buffer_min_pos = 0;
	new->input_buffer[0] = '\0';
	new->input_cursor = 0;
	new->input_visible = 0;
	new->input_start_zone = 0;
	new->input_end_zone = 0;
	new->input_prompt = NULL;
	new->input_prompt_len = 0;
	new->input_prompt_malloc = 0;
	new->input_line = 23;

	new->redirect_server = -1;
	last_input_screen = new;

	if (!main_screen)
		main_screen = new;
	init_input();
	return new;
}

#if defined(WINDOW_CREATE) && !defined(WINNT)

void setup_additional_screen (int screen_type, unsigned short port, int s)
{
	char *opts, *of;
	char *xterm;
	char *args[64], **args_ptr = args;
	char geom[32];
	int i;
			
	setuid(getuid());
	setgid(getgid());
	setsid();
	for (i = 0; i < 256; i++)
		close(i);
	my_signal(SIGINT,  SIG_IGN, 0);
	my_signal(SIGSEGV, SIG_DFL, 0);
	my_signal(SIGBUS,  SIG_DFL, 0);
	my_signal(SIGABRT, SIG_DFL, 0);

	if (screen_type == ST_SCREEN)
	{
		of = opts = m_strdup(get_string_var(SCREEN_OPTIONS_VAR));
			*args_ptr++ = "screen";
		while (opts && *opts)
			*args_ptr++ = new_next_arg(opts, &opts);
	}
	else if (screen_type == ST_XTERM)
	{
		snprintf(geom, 31, "%dx%d", CO+1, LI);
		of = opts = m_strdup(get_string_var(XTERM_OPTIONS_VAR));
		if (!(xterm = getenv("XTERM")))
			if (!(xterm = get_string_var(XTERM_VAR)))
				xterm = "rxvt";

		*args_ptr++ = xterm;
		*args_ptr++ = "-geometry";
		*args_ptr++ = geom;
		while (opts && *opts)
			*args_ptr++ = new_next_arg(opts, &opts);
		*args_ptr++ = "-e";
	}

	*args_ptr++ = WSERV_PATH;
	*args_ptr++ = "localhost";
	*args_ptr++ = ltoa((long)port);
	*args_ptr++ = NULL;
	new_free(&of);
	s = execvp(args[0], args);
	_exit(0);
}

extern	Window	*create_additional_screen _((void))
{
        Window  *win;
        Screen  *oldscreen, *new;
        char    *displayvar,
                *termvar;
        int     screen_type = ST_NOTHING;
        struct  sockaddr_in NewSock;
        int     NsZ;
        int     s;
	fd_set	fd_read;
	struct	timeval	timeout;
	pid_t	child;
	unsigned short port;
	char buffer[BIG_BUFFER_SIZE + 1];


	if (!use_input)
		return NULL;


	/* Check for X first. */
	if ((displayvar = getenv("DISPLAY")))
	{
		if (!(termvar = getenv("TERM")))
			say("I don't know how to create new windows for this terminal");
		else
			screen_type = ST_XTERM;
	}
	/*
	 * Environment variable STY has to be set for screen to work..  so it is
	 * the best way to check screen..  regardless of what TERM is, the 
	 * execpl() for screen won't just open a new window if STY isn't set,
	 * it will open a new screen process, and run the wserv in its first
	 * window, not what we want...  -phone
	 */
	if (screen_type == ST_NOTHING && getenv("STY"))
		screen_type = ST_SCREEN;


	if (screen_type == ST_NOTHING)
	{
		say("I don't know how to create new windows for this terminal");
		return NULL;
	}

        say("Opening new %s...",
                screen_type == ST_XTERM ?  "window" :
                screen_type == ST_SCREEN ? "screen" :
                                           "wound" );
	port = 0;
	s = connect_by_number(NULL, &port, SERVICE_SERVER, PROTOCOL_TCP, 0);
	if (s < 0)
	{
		yell("Couldnt establish server side -- error [%d]", s);
		return NULL;
	}

	oldscreen = current_window->screen;
	new = create_new_screen();

	switch ((child = fork()))
	{
		case -1:
		{
			kill_screen(new);
			say("I couldnt fire up a new wserv process");
			break;
		}

		case 0:
		{
			setup_additional_screen(screen_type, port, s);
		}
	}

	/* All the rest of this is the parent.... */
	NsZ = sizeof(NewSock);
	FD_ZERO(&fd_read);
	FD_SET(s, &fd_read);
	timeout.tv_sec = (time_t) 10;
	timeout.tv_usec = 0;
	/* using say(), yell() can be bad in this next section of code. */

	switch (select(NFDBITS , &fd_read, NULL, NULL, &timeout))
	{
		case -1:
		case 0:
		{
			int errnod = get_child_exit (child);
			close(s);
			kill_screen(new);
			kill(child, SIGKILL);
        	        yell("child %s with %d", (errnod < 1) ? "signaled" : "exited",
                	                         (errnod < 1) ? -errnod : errnod);
			yell("Errno is %d", errno);
			return NULL;
		}
		default:
		{
			new->fdin = new->fdout = accept(s, (struct sockaddr *) &NewSock, &NsZ);
			if (new->fdin < 0)
			{
				kill_screen(new);
				return NULL;
			}
			new_open(new->fdin);
			new->fpin = new->fpout = fdopen(new->fdin, "r+");
			close(s);

			FD_ZERO(&fd_read);
			FD_SET(new->fdin, &fd_read);
			select(NFDBITS, &fd_read, NULL, NULL, &timeout);

			if (dgets(buffer, new->fdin, 0) < 1)
			{
				new->fdin = new_close(new->fdin);
				kill_screen(new);
				kill(child, SIGKILL);
				return NULL;
			}
			else
				malloc_strcpy(&new->tty_name, buffer);

			win = new_window(new);
			refresh_screen(0, NULL);
			return win;
		}
	}
	return NULL;
}

void kill_screen(Screen *screen)
{
	Window	*window;

	if (main_screen == screen)
	{
		say("You may not kill the main screen");
		return;
	}
	if (screen->fdin)
	{
		if (use_input)
			screen->fdin = new_close(screen->fdin);
		close(screen->fdout);
		close(screen->fdin);
	}
	while ((window = screen->window_list))
	{
		screen->window_list = window->next;
		add_to_invisible_list(window);
	}


	if (last_input_screen == screen)
		last_input_screen = main_screen;

	say("The screen is now dead.");
	screen->alive = 0;
	make_window_current(NULL);
}

#endif /* WINDOW_CREATE */

void set_screens _((fd_set *rd, fd_set *wd))
{
Screen *screen;
	if (use_input)
		for (screen = screen_list; screen; screen = screen->next)
			if (screen->alive)
				FD_SET(screen->fdin, rd);
}



/* cough cough */
extern int key_pressed;

void do_screens _((fd_set *rd))
{
	Screen *screen;
	char buffer[BIG_BUFFER_SIZE + 1];

	if (!use_input)
		return;
	for (screen = screen_list; screen; screen = screen->next)
	{
		if (!screen->alive)
			continue;
		if (FD_ISSET(screen->fdin, rd))
		{
			/*
			 * This section of code handles all in put from the terminal(s).
			 * connected to ircII.  Perhaps the idle time *shouldn't* be 
			 * reset unless its not a screen-fd that was closed..
			 */
			time(&idle_time);
			if (cpu_saver)
			{
				cpu_saver = 0;
				update_all_status(current_window, NULL, 0);
			}

			if (dumb_mode)
			{
				if (dgets(buffer, screen->fdin, 0))
				{
					*(buffer + strlen(buffer) - 1) = '\0';
					if (get_int_var(INPUT_ALIASES_VAR))
						parse_line(NULL, buffer, empty_string, 1, 0);
					else
						parse_line(NULL, buffer, NULL, 1, 0);
				}
				else
				{
					bitchsay("BitchX exiting on EOF from stdin");
					irc_exit(1, "BitchX - EOF from stdin", NULL);
				}
				key_pressed = 13; /* *cough* *cough* */
			}
			else
			{
				int server;
				char	loc_buffer[BIG_BUFFER_SIZE + 1];
				int	n, i;

				server = from_server;
				last_input_screen = screen;
				output_screen = screen;
				make_window_current(screen->current_window);
				from_server = current_window->server;
				
				if ((n = read(screen->fdin, loc_buffer, BIG_BUFFER_SIZE)) > 0)
				{
					extended_handled = 0;
					for (i = 0; i < n; i++)
						if (!extended_handled)
							edit_char(loc_buffer[i]);
					key_pressed = loc_buffer[0];
				}
#ifdef WINDOW_CREATE
				else if (screen != main_screen)
					kill_screen(screen);
#endif /* WINDOW_CREATE */
				else
					irc_exit(1, "Hey!  Where'd my controlling terminal go?", NULL);
				from_server = server;
			} 
		}
	} 
} 


/*
 * Change xterm's title to reflect current connection status.
 */
void xterm_settitle(void)
{
	char titlestring[BIG_BUFFER_SIZE+1];
#ifdef __EMX__
 
    HSWITCH hswitch;        /* task-list entry handle               */
    SWCNTRL swctl = {0};          /* switch-control data                  */
    HWND hwndFrame = 0;         /* frame handle                         */
#if 0
    hab = WinQueryAnchorBlock(hwndFrame);      /* gets anchor block */
 /* initialize switch structure */
    swctl.hwnd = hwndFrame;                   /* window handle      */
    swctl.hwndIcon = NULLHANDLE;              /* icon handle        */
    swctl.hprog = NULLHANDLE;                 /* program handle     */
    swctl.idProcess = 0;                    /* process identifier */
    swctl.idSession = 0;                      /* session identifier */
    swctl.uchVisibility = SWL_VISIBLE;        /* visibility         */
    swctl.fbJump = SWL_JUMPABLE;              /* jump indicator     */
    swctl.szSwtitle[0]= 0;                    /* program name       */
 
    hswitch = WinCreateSwitchEntry(hab, &swctl);
#endif
    hswitch = WinQuerySwitchHandle(hwndFrame, 0);
    WinQuerySwitchEntry(hswitch, &swctl);
    /* set application name */
    snprintf(titlestring, BIG_BUFFER_SIZE, "BitchX:%s:%s:%s", nickname, is_server_connected(from_server) ?get_server_itsname(from_server):"<not connected>", get_current_channel_by_refnum(0));
    strncpy(swctl.szSwtitle, titlestring, 60);
    hwndFrame = WinQueryWindow(swctl.hwnd, QW_PARENT);
    WinSetWindowText(hwndFrame, swctl.szSwtitle);
    WinChangeSwitchEntry(hswitch, &swctl);

#else
#ifdef WINNT            
	snprintf(titlestring, BIG_BUFFER_SIZE, "BitchX:  %s on %s:%s", nickname, is_server_connected(from_server) ?get_server_itsname(from_server):"<not connected>", get_current_channel_by_refnum(0));
       	SetConsoleTitle(titlestring);
#else
	if (get_int_var(XTERM_TITLE_VAR) && (getenv("STY") || getenv("DISPLAY")))
	{
		snprintf(titlestring, BIG_BUFFER_SIZE, "\033]2;BitchX:  %s on %s:%s", nickname, is_server_connected(from_server) ?get_server_itsname(from_server):"<not connected>", get_current_channel_by_refnum(0));
        	tputs_x(titlestring);
		term_flush();
	}
#endif
#endif
}

/* 
 * add_wait_prompt:  Given a prompt string, a function to call when
 * the prompt is entered.. some other data to pass to the function,
 * and the type of prompt..  either for a line, or a key, we add 
 * this to the prompt_list for the current screen..  and set the
 * input prompt accordingly.
 */
void add_wait_prompt(char *prompt, void (*func)(char *, char *), char *data, int type, int echo)
{
	WaitPrompt **AddLoc,
		   *New;

	New = (WaitPrompt *) new_malloc(sizeof(WaitPrompt));
	New->prompt = m_strdup(prompt);
	New->data = m_strdup(data);
	New->type = type;
	New->func = func;
	New->next = NULL;
	New->echo = echo;
	for (AddLoc = &current_window->screen->promptlist; *AddLoc;
			AddLoc = &(*AddLoc)->next);
	*AddLoc = New;
	if (AddLoc == &current_window->screen->promptlist)
		change_input_prompt(1);
}

