#ident "@(#)irc.c 1.21"
/*
 * Original from ircII: a new irc client.  I like it.  I hope you will too!
 * Written By Michael Sandrof
 * Copyright(c) 1990 
 * 
 * Modified by Rex Feany <laeos@laeos.net> for Xaric
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <sys/stat.h>
#include <sys/types.h>

#ifdef USING_CURSES
# include <curses.h>
#endif

#include "irc.h"
#include "log.h"
#include "dcc.h"
#include "misc.h"
#include "hook.h"
#include "keys.h"
#include "exec.h"
#include "vars.h"
#include "names.h"
#include "build.h"
#include "debug.h"
#include "newio.h"
#include "flood.h"
#include "input.h"
#include "timer.h"
#include "output.h"
#include "status.h"
#include "screen.h"
#include "server.h"
#include "window.h"
#include "notify.h"
#include "whowas.h"
#include "ircaux.h"
#include "history.h"
#include "numbers.h"
#include "ircterm.h"
#include "commands.h"
#include "tcommand.h"
#include "xaric_version.h"


/** Global Variables **/

/* These are all just "handy" variables. */
char zero[] = "0", 
     one[] = "1", 
     space[] = " ", 
     on[] = "ON", 
     off[] = "OFF",
     empty_string[] = "";

char *invite_channel = NULL,	/* last channel of an INVITE */
 *ircrc_file = NULL,		/* full path .ircrc file */
 *my_path = NULL,		/* path to users home dir */
 *ircservers_file = NULL,	/* name of server file */
  nickname[NICKNAME_LEN + 1],	/* users nickname */
  hostname[NAME_LEN + 1],	/* name of current host */
  realname[REALNAME_LEN + 1],	/* real name of user */
  username[NAME_LEN + 1],	/* usernameof user */
 *send_umode = NULL,		/* sent umode */
 *who_name = NULL,		/* extra /who switch info */
 *who_file = NULL,		/* extra /who switch info */
 *who_server = NULL,		/* extra /who switch info */
 *who_host = NULL,		/* extra /who switch info */
 *who_nick = NULL,		/* extra /who switch info */
 *who_real = NULL,		/* extra /who switch info */
 *cut_buffer = NULL,		/* global cut_buffer */
 *prog_name = NULL, 		/* argv[0] */
 *line_thing = NULL,		/* show_numeric_str, say( ), put at begin of line */
  oper_command = 0,		/* true just after an oper() command is
				 * given.  Used to tell the difference
				 * between an incorrect password generated by
				 * an oper() command and one generated when
				 * connecting to a new server */
 *LocalHostName = NULL;		/* What our local hostname is, for vhost stuff. */

int irc_port = IRC_PORT,	/* port of ircd */
  strip_ansi_in_echo, 		/* used in the send_text() */
  current_on_hook = -1,		
  current_numeric,		/* this is negative of the
				 * current numeric! */
  key_pressed = 0, 
  waiting_out = 0,		/* used by /WAIT command */
  waiting_in = 0,		/* used by /WAIT command */
  who_mask = 0,			/* keeps track of which /who
				 * switchs are set */
  away_set = 0,			/* set if there is an away
				 * message anywhere */
  need_redraw = 0;		/* set whenever the terminal is reset */

static int
  load_ircrc = 1,		/* load ircrc file? */
#ifdef SERVERS_FILE
  load_g_ircservers = 1,	/* load global servers file? */
#endif
  load_ircservers = 1;		/* load servers file? */




struct in_addr MyHostAddr;	/* The local machine address */
struct in_addr LocalHostAddr;

time_t idle_time = 0, start_time;
fd_set readables, writables;


/* Display the startup message */
static void 
startup_message (void)
{
	int old = strip_ansi_in_echo; strip_ansi_in_echo = 0;

	/* black magic. leave me alone. */
	put_it (empty_string);

	put_fmt_str("%g***%n", NULL);
	put_fmt_str("%g***%C $0-", "%s", xversion.v_tex);
	put_fmt_str("%g***%n", NULL);
	put_fmt_str("%g***%n Xaric is free software, covered by the GNU General Public License,", NULL);
	put_fmt_str("%g***%n and you are welcome to change it and/or distribute copies of it", NULL);
	put_fmt_str("%g***%n under certain conditions.", NULL);
	put_fmt_str("%g***%n Type \"/help copying\" to see the conditions.", NULL);
	put_fmt_str("%g***%n", NULL);
	put_fmt_str("%g***%n There is absolutely no warranty for Xaric.", NULL);
	put_fmt_str("%g***%n Type \"/help warranty\" for details.", NULL);
	put_fmt_str("%g***%n", NULL);

	strip_ansi_in_echo = old;
}

static void usage (void) __attribute__ ((noreturn));

/* Print out the usage message, and die */
static void
usage (void)
{
	static char help[] = 

	"Usage: %s [OPTION]... [nick [server list]...]\n"
	"   -n               do not load your " IRCRC_NAME " file.\n"
	"   -s               do not load the global server file.\n"
	"   -S               do not load your " IRCSERVERS_NAME " file.\n"
	"   -h               this help text.\n"
	"   -v               display xaric version and exit.\n"
	"   -f               your terminal users flow control (^s/^q), so xaric shouldn't.\n"
	"   -F               your terminal does not use flow control.\n"
	"   -H <hostname>    uses the virtual hostname if possible.\n"
	"   -d <string>      set debug options (see documentation).\n"
	"   -p <port>        set default port to use (normally 6667).\n"
	"   -l <file>        loads file instead of " IRCRC_NAME ".\n"
	"   -r <file>        loads file as list of servers, instead of " IRCSERVERS_NAME ".\n\n"

	"Xaric uses the values in IRCSERVER, IRCPORT, IRCRC, IRCNICK, IRCNAME\n"
	"IRCHOST, IRCUMODE, IRCSERVERS\n\n"

	"Command line arguments override environment variables.\n\n"
	"Report bugs to bugs@xaric.org\n";

	fprintf(stderr, help, prog_name);

	exit(EXIT_FAILURE);
}

/* Parse command line arguments. */
static void
parse_args (int argc, char *argv[])
{
	static const char optstr[] = "vhH:p:fFl:r:nsSd:";
 
	while (1) {
		int c = getopt (argc, argv, optstr);

		if (-1 == c)
			break;

		switch(c) {
			case 'v': /* print version */
				puts(xversion.v_tex);
				putchar('\n');
				exit (0);

			case 'H': /* Set local hostname, for vhost stuff */
				malloc_strcpy(&LocalHostName, optarg);
				break;

			case 'p': /* Default port to use */
				irc_port = my_atol (optarg);
				break;

			case 'f': /* Use flow control */
				term_set_flow_control(ON);
				break;

			case 'F': /* dont use flow control */
				term_set_flow_control(OFF);
				break;

			case 'l': /* Load some file instead of ~/.ircrc */
				malloc_strcpy (&ircrc_file, optarg);
				break;

			case 'r': /* Load list of servers from this file */
				malloc_strcpy (&ircservers_file, optarg);

			case 'n': /* do not load ircrc */
				load_ircrc = 0;
				break;

			case 's': /* do not load global server file */
#ifdef SERVERS_FILE
				load_g_ircservers = 0;
#else
				fprintf(stderr, "No global servers file!\n");
#endif
				break;

			case 'S': /* do not load .ircservers file */
				load_ircservers = 0;
				break;



			case 'd': /* set server debug */
#ifdef XARIC_DEBUG
				if (xd_parse(optarg)) {
					fprintf(stderr, "Bad arguments to -d\n");
					exit (1);
				}
#else
				fprintf(stderr, "Debug fluf not compiled in!\n");
#endif /* XARIC_DEBUG */
				break;


			case '?':  /* unknown option */
			case ':':  /* missing argument */
			case 'h':  /* help */
			default:
				usage(); /*does not return*/
		}
	}

	/* first non-option argument is a nickname */
	if (optind < argc)
		strmcpy(nickname, argv[optind++], NICKNAME_LEN);

	/* the rest are servers */
	while (optind < argc)
		build_server_list (argv[optind++]);

}

/* sniff out user information from passwd file */
static void 
get_user_info (void)
{
	struct passwd *entry;
	char *ptr;


	if (! (entry = getpwuid (getuid ())))
		return;

	if (!*realname && entry->pw_gecos && *(entry->pw_gecos)) {
#ifdef GECOS_DELIMITER
		if ((ptr = index (entry->pw_gecos, GECOS_DELIMITER)))
			*ptr = (char) 0;
#endif
		if ((ptr = strchr (entry->pw_gecos, '&')) == NULL)
			strmcpy (realname, entry->pw_gecos, REALNAME_LEN);
		else {
			int len = ptr - entry->pw_gecos;

			if (len < REALNAME_LEN && *(entry->pw_name)) {
				char *q = realname + len;

				strmcpy (realname, entry->pw_gecos, len);
				strmcat (realname, entry->pw_name, REALNAME_LEN);
				strmcat (realname, ptr + 1, REALNAME_LEN);
				if (islower (*q) && (q == realname || isspace (*(q - 1))))
					*q = toupper (*q);
			} else
				strmcpy (realname, entry->pw_gecos, REALNAME_LEN);
		}
	}

	if (entry->pw_name && *(entry->pw_name) && !*username)
		strmcpy (username, entry->pw_name, NAME_LEN);
	if (entry->pw_dir && *(entry->pw_dir))
		malloc_strcpy (&my_path, entry->pw_dir);
}

/* Load data in from environment variables. */
/* We expect this to initilize most globals. */
static void
load_xaric_environment (void)
{
	char *ptr; 

	if ((ptr = getenv ("IRCNICK")))
		strmcpy (nickname, ptr, NICKNAME_LEN);

	if ((ptr = getenv ("IRCUMODE")))
		malloc_strcpy (&send_umode, ptr);

	if ((ptr = getenv ("HOME")))
		malloc_strcpy (&my_path, ptr);

	if ((ptr = getenv ("IRCRC")))
		malloc_strcpy (&ircrc_file, ptr);

	if ((ptr = getenv ("IRCSERVERS")))
		malloc_strcpy (&ircservers_file, ptr);

	if ((ptr = getenv ("IRCNAME")) || (ptr = getenv ("NAME")))
		strmcpy (realname, ptr, REALNAME_LEN);

	if ((ptr = getenv ("IRCUSER")) || (ptr = getenv ("USER")))
		strmcpy (username, ptr, NAME_LEN);

	if ((ptr = getenv ("IRCHOST")))
		LocalHostName = m_strdup (ptr);

	if ((ptr = getenv ("IRCPORT")))
		irc_port = my_atol (ptr);

	if ((ptr = getenv ("IRCSERVER")))
		build_server_list (ptr);
}

/* Make sure all the global variables are initilized. */
static void
load_xaric_finish (void)
{
	if (! nickname || !*nickname)
		strmcpy (nickname, username, sizeof (nickname));

	if (!check_nickname (nickname)) {
		fprintf (stderr, "Illegal nickname %s\n", nickname);
		fprintf (stderr, "Please restart IRC II with a valid nickname\n");
		exit (1);
	}

	if (!*realname)
		strmcpy (realname, "*Unknown*", REALNAME_LEN);

	if (!*username)
		strmcpy (username, "*Unknown*", NAME_LEN);

	if (!my_path || !*my_path)
		malloc_strcpy (&my_path, "/");

	if (! ircservers_file)
		malloc_strcpy (&ircservers_file, IRCSERVERS_NAME);

	if (! ircrc_file)
		malloc_strcpy(&ircrc_file, IRCRC_NAME);
}

/* load irc servers file */
static void
load_xaric_servers (void)
{
	/* load server files here */
#ifdef SERVERS_FILE
	if (load_g_ircservers)
		read_server_file (SERVERS_FILE);
#endif

	if (load_ircservers)
		read_server_file (ircservers_file);

#ifdef DEFAULT_SERVER
	if (server_list_size () == 0) {
		char *ptr = m_strdup(DEFAULT_SERVER);
		build_server_list (ptr);
		new_free (&ptr);
		/* XXX build_server_list should take const */
	}
#endif

	if (server_list_size () == 0)
		ircpanic ("I have know no servers!");
}

/* initilize the network bits */
/* XXX Belongs in network code? */
static void
load_xaric_network (void)
{
	struct hostent *hp;

	if ((gethostname (hostname, sizeof (hostname)))) {
		if (! LocalHostName) {
			fprintf(stderr, "%s: Could not figure out my hostname! Try -H\n", prog_name);
			exit (1);
		}
	}

	if (LocalHostName) {
		printf ("Your hostname appears to be [%s]\n", LocalHostName);
		memset ((void *) &LocalHostAddr, 0, sizeof (LocalHostAddr));
		if ((hp = gethostbyname (LocalHostName)))
			memcpy ((void *) &LocalHostAddr, hp->h_addr, sizeof (LocalHostAddr));
	} else {
		if ((hp = gethostbyname (hostname)))
			memcpy ((char *) &MyHostAddr, hp->h_addr, sizeof (MyHostAddr));
	}
}

/* irc_exit: cleans up and leaves */
void
irc_exit (char *reason, char *formated)
{
	int old_window_display = window_display;

	do_hook (EXIT_LIST, "%s", reason);
	close_server (-1, reason);
	put_it (formated ? formated : reason);
	logger (curr_scr_win, NULL, 0);
	if (get_int_var (MSGLOG_VAR))
		log_toggle (0, NULL);

	clean_up_processes ();
	cursor_to_input ();	/* Needed so that ircII doesn't gobble
				 * the last line of the kill. */
	term_cr ();
	term_clear_to_eol ();
	term_reset ();

	/* Debugging sanity. */
	window_display = 0;
	set_lastlog_size (curr_scr_win, NULL, 0);
	set_history_size (curr_scr_win, NULL, 0);
	remove_channel (NULL, 0);
	window_display = old_window_display;
	clear_bindings ();
	clear_sets ();

	fprintf (stdout, "\r");
	fflush (stdout);
	exit (0);
}

/* initilize global variables, parse command line, etc */
static void
xaric_init (int argc, char *argv[])
{
	get_user_info ();

	load_xaric_environment ();

	parse_args (argc, argv);

	load_xaric_network ();

	load_xaric_finish ();

	load_xaric_servers ();

	if (init_screen ()) {
		fprintf (stderr, "%s: Woops! Couldn't init the terminal!\n", prog_name);
		exit (1);
	}

	signals_init();
	init_variables ();
	init_keys_1 ();
	init_commands ();
	build_status (curr_scr_win, NULL, 0);
	update_input (UPDATE_ALL);

	startup_message();
}


/* new irc_io modularized stuff */

/* 
 * GetLineStruct is what is "under" your current input line, and the function
 * we're supposed to call when you press return.  This is different from
 * AddWaitPrompt which does functionally the same thing but doesnt cause
 * recursive calls to io.
 */
struct GetLineStruct
{
	int done;
	void (*func) (char, char *);
	char *saved_input;
	char *saved_prompt;
	int recursive_call;
	struct GetLineStruct *prev;
	struct GetLineStruct *next;
};
typedef struct GetLineStruct GetLine;
GetLine *GetLineStack = NULL;

/* when you press return, you call this. */
extern void 
get_line_return (char unused, char *not_used)
{
	GetLine *stuff;

	/* get the last item on the stack */
	if ((stuff = GetLineStack) == NULL)
		return;

	/* 
	   If we're NOT the main() call, then undo all that we 
	   messed up coming in. 
	   If stuff->done gets set to 1 when recursive_call is 
	   zero, then something is VERY wrong.
	   We can set stuff->prev->next to null because the call
	   to get_line() holds a pointer to stuff, so when it
	   unrecurses, it will free it.
	 */
	if (stuff->func)
	{
		not_used = NULL;
		(stuff->func) (unused, not_used);
	}
	if (stuff->recursive_call)
	{
		stuff->done = 1;
		set_input (stuff->saved_input);
		set_input_prompt (curr_scr_win, stuff->saved_prompt, 0);
		new_free (&(stuff->saved_input));
		new_free (&(stuff->saved_prompt));
		stuff->next->prev = NULL;
		GetLineStack = stuff->next;
	}

	update_input (UPDATE_ALL);

	/* We cant delete stuff here becuase the get_line function
	 * still needs to look at stuff->done.  So we let it delete
	 * the items off the list.  But we removed it from the list,
	 * so we wont accidentally use it later.
	 */
	return;
}

/* This is a wrapper for io().  Only two functions at any time are allowed
 * to call it, and main() is one of those two.  When you call it, you have
 * the option to change the input prompt and the input buffer.  You also
 * give it a function to call when it gets a return.  Only main() is 
 * allowed to call it with an new_input of -1, which tells it that it is
 * at the lowest level of parsing, by which i mean that noone is waiting
 * for anything, since there is no recursion going on.
 */
void 
get_line (char *prompt, int new_input, void (*func) (char, char *))
{
	GetLine *stuff;

	if (GetLineStack && new_input == -1)
		ircpanic ("Illegal call to get_line\n");

	/* initialize the new item. */
	stuff = (GetLine *) new_malloc (sizeof (GetLine));
	stuff->done = 0;
	stuff->func = func;
	stuff->recursive_call = (new_input == -1) ? 0 : 1;
	stuff->saved_input = NULL;
	stuff->saved_prompt = NULL;
	stuff->prev = NULL;
	stuff->next = NULL;
	malloc_strcpy (&(stuff->saved_input), get_input ());
	malloc_strcpy (&(stuff->saved_prompt), get_input_prompt ());

	/* put it on the stack */
	if (GetLineStack)
	{
		stuff->next = GetLineStack;
		GetLineStack->prev = stuff;
	}
	GetLineStack = stuff;

	/* if its a global call, get the input prompt */
	if (new_input == -1)
		set_input_prompt (curr_scr_win, get_string_var (INPUT_PROMPT_VAR), 0);
	else
		set_input_prompt (curr_scr_win, prompt, 0);
	set_input (empty_string);

	/* ok.  we call io() until the user presses return, ending 
	 * the input line.  get_line_return will then set get_line_done
	 * to one, and we will stop getting characters and drop out.
	 * get_line_done NEVER sets this to one if we are in our call
	 * from main().  NEVER.
	 */
	while (!stuff->done)
		io ("get line");

	if (new_input == -1)
		ircpanic ("get_line: input == -1 is illegal value");

	/* By the time we get here, stuff->done has been set to 1,
	 * which means that get_line_return has already freed the
	 * interesting items in stuff and removed it from the list.
	 * Noone but us has a pointer to it, so we free it here.
	 */
	new_free (&stuff->saved_input);
	new_free (&stuff->saved_prompt);
	new_free ((char **) &stuff);
}

/* This simply waits for a key to be pressed before it unrecurses.
 * It doesnt do anyting in particular with that key (it will go to 
 * the input buffer, actually)
 */
char 
get_a_char (void)
{
	key_pressed = 0;
	while (!key_pressed)
		io ("get a char");
	update_input (UPDATE_ALL);
	return key_pressed;
}

/* 
 * io() is a ONE TIME THROUGH loop!  It simply does ONE check on the
 * file descriptors, and if there is nothing waiting, it will time
 * out and drop out.  It does everything as far as checking for exec,
 * dcc, ttys, notify, the whole ball o wax, but it does NOT iterate!
 * 
 * You should usually NOT call io() unless you are specifically waiting
 * for something from a file descriptor.  It doesnt look like bad things
 * will happen if you call this elsewhere, but its long time behavior has
 * not been observed.  It *does* however, appear to be much more reliable
 * then the old irc_io, and i even know how this works. >;-)
 */
extern void set_screens (fd_set *, fd_set *);

void 
io (const char *what)
{
	static int first_time = 1, level = 0;
	static struct timeval cursor_timeout, clock_timeout, right_away,
	  timer, *timeptr = NULL;
	int hold_over;
	fd_set rd, wd;
	static int old_level = 0;
	Screen *screen, *old_current_screen = current_screen;
	static const char *caller[51] =
	{NULL};			/* XXXX */
	static int last_warn = 0;
	time_t now = time (NULL);

	level++;



	if (level != old_level) {
		DEBUG(XD_COMM, 5, "Moving from io level [%d] to level [%d] from\
				[%s]", old_level, level, what);
		old_level = level;
	}


	if (level && (level - last_warn == 5))
	{
		last_warn = level;
		yell ("io's nesting level is [%d],  [%s]<-[%s]<-[%s]<-[%s]<-[%s]<-[%s]", level, what, caller[level - 1], caller[level - 2], caller[level - 3], caller[level - 4]);
		if (level % 50 == 0)
			ircpanic ("Ahoy there matey!  Abandon ship!");
		return;
	}
	else if (level && (last_warn - level == 5))
		last_warn -= 5;

	caller[level] = what;

	/* first time we run this function, set up the timeouts */
	if (first_time)
	{
		first_time = 0;

		/* time before cursor jumps from display area to input line */
		cursor_timeout.tv_usec = 0L;
		cursor_timeout.tv_sec = 1L;

		/*
		 * time delay for updating of internal clock
		 *
		 * Instead of looking every 15 seconds and seeing if
		 * the clock has changed, we now figure out how much
		 * time there is to the next clock change and then wait
		 * until then.  There is a small performance penalty 
		 * in actually calculating when the next minute will tick, 
		 * but that will be offset by the fact that we will only
		 * call select() once a minute instead of 4 times.
		 */
		clock_timeout.tv_usec = 0L;

		right_away.tv_usec = 0L;
		right_away.tv_sec = 0L;

		timer.tv_usec = 0L;
	}

	/* SET UP TIMEOUTS USED IN SELECTING */
/*      clock_timeout.tv_sec = time_to_next_minute(); */

	rd = readables;
	wd = writables;

	FD_ZERO (&wd);
	FD_ZERO (&rd);

	set_screens (&rd, &wd);
	set_dcc_bits (&rd, &wd);
	set_server_bits (&rd, &wd);
	set_process_bits (&rd);

	clock_timeout.tv_sec = (60 - now % 60);

	/* if the time changes, now - idle_time can be negative,
	 * and cause all kinds of problems */
	if (now > idle_time)
		clock_timeout.tv_sec += now - idle_time;

	if (!timeptr)
		timeptr = &clock_timeout;
	timer.tv_sec = TimerTimeout ();
	if (timer.tv_sec <= timeptr->tv_sec)
		timeptr = &timer;
#if 0
	if ((hold_over = unhold_windows ()) != 0)
		timeptr = &right_away;
#else
	hold_over = 0;
#endif

	/* go ahead and wait for some data to come in */
	switch (new_select (&rd, &wd, timeptr))
	{
	case 0:
		break;
	case -1:
		{
			/* if we just got a sigint */
			if (cntl_c_hit)
			{
				key_pressed = 3;
				edit_char ('\003');
				cntl_c_hit = 0;
			}
			else if (errno != EINTR && errno > 0)
				yell ("Select failed with [%s]", strerror (errno));
			break;

		}

		/* we got something on one of the descriptors */
	default:
		{
			set_current_screen (last_input_screen);
			dcc_check (&rd, &wd);
			do_server (&rd, &wd);
			do_processes (&rd);
			do_screens (&rd);
			dcc_check_idle ();
			set_current_screen (old_current_screen);
			break;
		}
	}
	ExecuteTimers ();
	while (got_sigchild)
	{
		check_wait_status (-1);
		got_sigchild--;
	}

	if (!hold_over)
		cursor_to_input ();
	timeptr = &clock_timeout;

	for (screen = screen_list; screen; screen = screen->next)
		if (screen->alive && is_cursor_in_display (screen))
			timeptr = &cursor_timeout;

	if (get_int_var (LLOOK_VAR) && from_server > -1 && !server_list[from_server].link_look)
	{
		if (time (NULL) - server_list[from_server].link_look_time > get_int_var (LLOOK_DELAY_VAR))
		{
			server_list[from_server].link_look++;
			my_send_to_server (from_server, "LINKS");
			server_list[from_server].link_look_time = time (NULL);
		}
	}
	if (update_clock (0))
	{
		do_notify ();
		clean_whowas_chan_list ();
		clean_whowas_list ();
		clean_flood_list ();
		if (get_int_var (CLOCK_VAR))
		{
			update_all_status (curr_scr_win, NULL, 0);
			cursor_to_input ();
		}
		check_server_connect (from_server);
	}

	/* (set in term.c) -- we should redraw the screen here */
	if (need_redraw)
		refresh_screen (0, NULL);

	caller[level] = NULL;
	level--;
	return;
}


/* This is the main xaric "loop" */
static void
xaric_main (void)
{
	if (load_ircrc)
		load_scripts ();

	get_connected (0);

	set_input (empty_string);
	get_line (NULL, -1, send_line);

	ircpanic ("get_line() returned");
}

int 
main (int argc, char *argv[], char *envp[])
{
	int retval = EXIT_FAILURE;

	srand ((unsigned) time (NULL));
	time (&start_time);
	time (&idle_time);
	prog_name = argv[0];

	if (! isatty (0)) {
		fprintf (stderr, "Woops I need a tty!\n");
		exit (1);
	}

	FD_ZERO (&readables);
	FD_ZERO (&writables);

	xaric_init (argc, argv);

	xaric_main ();

	return retval;
}
