/*
 * ircII: a new irc client.  I like it.  I hope you will too!
 *
 * Written By Michael Sandrof
 * Copyright(c) 1990 
 * See the COPYRIGHT file, or do a HELP IRCII COPYRIGHT 
 *
 * Reformatted by Matthew Green, November 1992.
 */
#define IRCII_VERSION   "2.2.4.term"

/*
 * INTERNAL_VERSION is the number that the special alias $V returns.
 * Make sure you are prepared for floods, pestilence, hordes of locusts, 
 * and all sorts of HELL to break loose if you change this number.
 * Its format is actually YYYYMMDD, for the _release_ date of the
 * client..
 */
#define INTERNAL_VERSION	"19930426"

#ifdef HPUX
# include <curses.h>
#endif /* HPUX */
#ifdef SVR4
# include <fcntl.h>
#endif
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/time.h>
#ifdef XD88
# include <sys/fcntl.h>
#endif
#include <signal.h>
#ifdef sgi
# include <stdio.h>
#endif /* sgi*/
#include <pwd.h>
#ifdef ISC22
# include <sys/bsdtypes.h>
# include <unistd.h>
#endif /* ISC22 */
#ifdef ESIX
# include <lan/net_types.h>
# include <unistd.h>
#endif /* ESIX */
#ifdef POSIX
# include <curses.h>
# ifndef _IBMR2
#  include <sys/fcntl.h>
# endif
# include <sys/select.h>
#endif /* POSIX */
#include <netinet/in.h>
#if DO_USER2
#include <setjmp.h>
#endif
#include <netdb.h>
#include "irc.h"
#include "status.h"
#include "dcc.h"
#include "names.h"
#include "vars.h"
#include "input.h"
#include "alias.h"
#include "output.h"
#include "term.h"
#include "exec.h"
#include "screen.h"
#include "log.h"
#include "server.h"
#include "hook.h"
#include "keys.h"
#include "ircaux.h"
#include "edit.h"
#include "window.h"
#include "history.h"
#include "exec.h"
#include "notify.h"
#include "mail.h"

int	irc_port = IRC_PORT,			/* port of ircd */
	send_text_flag = -1,			/* used in the send_text()
						 * routine */
	use_flow_control = USE_FLOW_CONTROL,	/* true: ^Q/^S used for flow
						 * cntl */
	irc_io_loop = 1,			/* see irc_io below */
	break_io_processing = 0,		/* more forceful than
						 * irc_io_loop */
	current_numeric,			/* this is negative of the
						 * current numeric! */
	dumb = 0,				/* if true, IRCII is put in
						 * "dumb" mode */
	no_fork = 0,				/* if true, IRCII won't with
						 * -b or -e */
	use_input = 1,				/* if 0, stdin is never
						 * checked */
	waiting = 0,				/* used by /WAIT command */
	who_mask = 0,				/* keeps track of which /who
						 * switchs are set */
	background = 0;				/* if in the back ground */

char	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 */
char	global_all_off[2];		/* lame kludge to get around lameness */
char	MyHostName[80];			/* The local machine name. Used by
					 * DCC TALK */
struct	in_addr	MyHostAddr;		/* The local machine address */
extern	unsigned Long local_ip_address; /* Sometimes the same, sometimes not */
extern	char	*last_away_nick;

char	*invite_channel = null(char *),		/* last channel of an INVITE */
	buffer[BIG_BUFFER_SIZE + 1],		/* multipurpose buffer */
	*ircrc_file = null(char *),		/* full path .ircrc file */
	*my_path = null(char *),		/* path to users home dir */
	*irc_path = null(char *),		/* paths used by /load */
	*irc_lib = null(char *),		/* path to the ircII library */
	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 */
	*args_str = null(char *),		/* list of command line args */
	*last_notify_nick = null(char *),	/* last detected nickname */
	empty_string[] = "",			/* just an empty string */
	*who_name = null(char *),		/* extra /who switch info */
	*who_file = null(char *),		/* extra /who switch info */
	*who_server = null(char *),		/* extra /who switch info */
	*who_host = null(char *),		/* extra /who switch info */
	*who_nick = null(char *),		/* extra /who switch info */
	*who_real = null(char *),		/* extra /who switch info */
	*cannot_open = null(char *),		/* extra /who switch info */
	*cut_buffer = null(char *);		/* global cut_buffer */
	int away_set = 0;			/* set if there is an away
						 * message anywhere */
Long	idle_time = 0;

static	int	cntl_c_hit = 0;
#if DO_USER2
jmp_buf	outta_here;
#endif

char	irc_version[] = IRCII_VERSION;
char	internal_version[] = INTERNAL_VERSION;

static	char	switch_help[] =
"Usage: irc [switches] [nickname] [server list] \n\
  The [nickname] can be at most 9 characters long\n\
  The [server list] is a whitespace separate list of server name\n\
  The [switches] may be any or all of the following\n\
   -c <channel>\tjoins <channel> o startup\n\
   -p <port>\tdefault server connection port (usually 6667)\n\
   -f\t\tyour terminal uses flow controls (^S/^Q), so IRCII shouldn't\n\
   -F\t\tyour terminal doesn't use flow control (default)\n\
   -s\t\tdon't use separate server processes (ircserv)\n\
   -S\t\tuse separate server processes (ircserv)\n\
   -d\t\truns IRCII in \"dumb\" terminal mode\n\
   -a\t\tadds default servers and command line servers to server list\n";

static	char	switch_help_l[] =
#ifdef COMMAND_LINE_L
"   -l <file>\tloads <file> in place of your .ircrc\n\
   -L <file>\tloads <file> in place of your .ircrc and expands $ expandos\n";
#else
"";
#endif

static	char	switch_help_b[] =
#ifdef COMMAND_LINE_B
"   -b\t\truns IRCII in the background (it accepts no user input)\n";
#else
"";
#endif

static	char	switch_help_n[] =
#if defined(COMMAND_LINE_E) && defined (COMMAND_LINE_B)
"   -n\t\tIRCII automatically run in background with -b and -e\n";
#else
"";
#endif

static	char	switch_help_e[] = 
#ifdef COMMAND_LINE_E
"   -e <process arg list>  runs IRCII by reading stdin from <process> and\n\
      sending stdout to <process>.  All other args are passed to <process>,\n\
      so this must be the last switch\n";
#else
"";
#endif

/* irc_exit: cleans up and leaves */
void	irc_exit()
{
	close_server(-1);
	logger(0);
	set_history_file(null(char *));
	clean_up_processes();
	if (!dumb)
	{
		cursor_to_input();	/* Needed so that ircII doesn't gobble
					 * the last line of the kill. */
		term_cr();
		if (term_clear_to_eol())
			term_space_erase(0);
		term_reset();
#if defined(HPUX) || defined(ESIX)
		endwin();		/* Added for curses */
#ifdef ESIX
		system("tput reset");
		new_stty("sane");
#else
		system("tset -Q");
		system("reset");
#endif /* ESIX */
#endif /* defined(HPUX) || defined(ESIX) */
	}
	exit(0);
}

#ifdef CORECATCH
/* sigsegv: something to handle segfaults in a nice way */
SIGTYP	coredump(sig)
int	sig;
{
	printf("IRCII has been terminated by a SIG%s\n\r", signals[sig]);
	printf("Please inform phone (phone@coombs.anu.edu.au) of this\n\r");
	printf("with as much detail as possible about what you were doing when it happened.\n\r");
	printf("Please include the version of IRCII (%s) and type of system in the report.\n\r", irc_version);
	fflush(stdout);
	irc_exit();
}
#endif

/*
 * quit_response: Used by irc_io when called from irc_quit to see if we got
 * the right response to our question.  If the response was affirmative, the
 * user gets booted from irc.  Otherwise, life goes on. 
 */
static	void	quit_response(dummy, ptr)
char	*dummy;
char	*ptr;
{
	int	len,
		old_irc_io_loop;

	old_irc_io_loop = irc_io_loop;
	irc_io_loop = 0;
	if (len = strlen(ptr))
	{
		if (!strnicmp(ptr, "yes", len))
		{
			send_to_server("QUIT");
			irc_exit();
		}
	}
	irc_io_loop = old_irc_io_loop;
}

/* irc_quit: prompts the user if they wish to exit, then does the right thing */
void	irc_quit()
{
	static	int in_it = 0;

	if (in_it)
		return;
	in_it = 1;
	add_wait_prompt("Do you really want to quit? ", quit_response,
		empty_string, WAIT_PROMPT_LINE);
	in_it = 0;
}

/*
 * cntl_c: emergency exit.... if somehow everything else freezes up, hitting
 * ^C five times should kill the program. 
 */
SIGTYP	cntl_c()
{
#ifdef MUNIX
	signal(SIGINT, cntl_c);		/* sysV reissue.. */
#endif
	if (cntl_c_hit++ >= 4)
		irc_exit();
}

SIGTYP	sig_user1()
{
#ifdef MUNIX
	signal(SIGUSR1, sig_user1);
#endif
	say("Got SIGUSR1, closing DCC connections and EXECed processes");
	close_all_dcc();
	close_all_exec();
}

#if DO_USER2
SIGTYP	sig_user2()
{
#ifdef MUNIX
	signal(SIGUSR2, sig_user2);
#endif
	say("Got SIGUSR2, jumping to normal loop");
	longjmp(outta_here);
}
#endif 

#ifdef MUNIX
/* A characteristic of PCS MUNIX - Ctrl-Y produces a SIGQUIT */
SIGTYP	cntl_y()
{
	signal(SIGQUIT, cntl_y);
	edit_char( (char)25 ); /* Ctrl-Y */
}
#endif

#ifdef COMMAND_LINE_E
/*
 * start_process: using the given args list, this execvps the process,
 * setting stdout of the process to IRCII stdin, and stdin of the process to
 * IRCII stdout.  Stderr of both still go to the tty.  This is used by the -e
 * switch of IRCII to allow a automotons to be written to control IRCII 
 */
static	void	start_process(args)
char	**args;
{
	int	p1[2],
		p2[2],
		pid;

	if (pipe(p1) || pipe(p2))
	{
		fprintf(stderr, "irc: couldn't start new process: %s\n",
			sys_errlist[errno]);
		_exit(1);
	}
	switch (pid = fork())
	{
	case -1:
		fprintf(stderr, "irc: couldn't start new process: %s\n",
			sys_errlist[errno]);
		_exit(1);
		break;
	case 0:
		signal(SIGINT, SIG_IGN);
		dup2(p1[1], 1);
		dup2(p2[0], 0);
		close(p1[0]);
		close(p2[1]);
		setuid(getuid());
		setgid(getgid());
		execvp(args[0], args);
		fprintf(stderr, "irc: error starting process: %s\n",
			sys_errlist[errno]);
		_exit(1);
		break;
	default:
		printf("%d\n", pid);
		fflush(stdout);
		dup2(p1[0], 0);
		dup2(p2[1], 1);
		close(p1[1]);
		close(p2[0]);
		if (! no_fork)
		{
			if (fork())
			_exit(1);
		}
		break;
	}
}
#endif /* COMMAND_LINE_E */

/* shows the version of irc */
static	void	show_version()
{
	printf("ircII version %s - %s\n\r", irc_version, internal_version);
	exit (0);
}

/* get_arg: used by parse_args() to get an argument after a switch */
static	char	*get_arg(arg, next_arg, ac)
char	*arg;
char	*next_arg;
int	*ac;
{
	(*ac)++;
	if (*arg)
		return (arg);
	else
	{
		if (next_arg)
			return (next_arg);
		fprintf(stderr, "irc: missing parameter\n");
		exit(1);
	}
}

/*
 * parse_args: parse command line arguments for irc, and sets all initial
 * flags, etc. 
 */
static	char	*parse_args(argv, argc)
char	*argv[];
int	argc;
{
	char	*arg,
		*ptr;
	int	ac;
	int	add_servers = 0;
	char	*channel = null(char *);
	struct	passwd	*entry;
	struct	hostent	*hp;

    /*
     * Note that this uses the global buffer to build the args_str list,
     * which is a whitespace separated list of the arguments used when
     * loading the .ircrc and GLOBAL_IRCRC files.
     */
	*nickname = null(char);
	*realname = null(char);
	ac = 1;
	strmcpy(buffer,argv[0],BIG_BUFFER_SIZE);
	strmcat(buffer," ",BIG_BUFFER_SIZE);
	while (arg = argv[ac++])
	{
		strmcat(buffer,argv[ac-1],BIG_BUFFER_SIZE);
		strmcat(buffer," ",BIG_BUFFER_SIZE);
		if (*arg == '-')
		{
			++arg;
			while (*arg)
			{
				switch (*(arg++))
				{
				case 'v':
					show_version();
					break;
				case 'c':
					malloc_strcpy(&channel, get_arg(arg,
							argv[ac], &ac));
					break;
				case 'p':
					irc_port = atoi(get_arg(arg, argv[ac],
							&ac));
					break;
				case 'f':
					use_flow_control = 1;
					break;
				case 'F':
					use_flow_control = 0;
					break;
				case 'd':
					dumb = 1;
					break;
#ifdef COMMAND_LINE_L
				case 'l':
					malloc_strcpy(&ircrc_file, get_arg(arg,
							argv[ac], &ac));
					break;
				case 'L':
					malloc_strcpy(&ircrc_file, get_arg(arg,
							argv[ac], &ac));
					malloc_strcat(&ircrc_file," -");
					break;
#endif /* COMMAND_LINE_L */
				case 'a':
					add_servers = 1;
					break;
#ifdef COMMAND_LINE_E
				case 'e':
					dumb = 1;
					start_process(&(argv[ac]));
					ac = argc;
					background = 1;
					break;
#endif /* COMMAND_LINE_E */
				case 'n':
					no_fork = 1;
					break;
				case 's':
					using_server_process = 0;
					break;
				case 'S':
					using_server_process = 1;
					break;
#ifdef COMMAND_LINE_B
				case 'b':
					dumb = 1;
					use_input = 0;
					background = 1;
					break;
#endif /* COMMAND_LINE_B */
				case '-':
					while (arg=argv[ac++])
					{
						strmcat(command_line, arg,
							BIG_BUFFER_SIZE);
						strmcat(command_line, " ",
							BIG_BUFFER_SIZE);
					}
					if (*command_line)
				command_line[strlen(command_line)-1] = '\0';
					break;
				default:
					fprintf(stderr, "%s%s%s%s%s",
						switch_help, switch_help_l,
						switch_help_b, switch_help_e,
						switch_help_n);
					exit(1);
				}
			}
		}
		else
		{
			if (*nickname)
				build_server_list(arg);
			else
				strmcpy(nickname, arg, NICKNAME_LEN);
		}
	}
	malloc_strcpy(&args_str,buffer);
	if (ptr = getenv("IRCLIB"))
	{
		malloc_strcpy(&irc_lib, ptr);
		malloc_strcat(&irc_lib, "/");
	}
	else
		malloc_strcpy(&irc_lib, IRCLIB);
	if ((ircrc_file == null(char *)) && (ptr = getenv("IRCRC")))
		malloc_strcpy(&ircrc_file, ptr);
	if ((*nickname == null(char)) && (ptr = getenv("IRCNICK")))
		strmcpy(nickname, ptr, NICKNAME_LEN);
	if (ptr = getenv("IRCUMODE"))
		malloc_strcpy(&send_umode, ptr);
	if (ptr = getenv("IRCNAME"))
		strmcpy(realname, ptr, REALNAME_LEN);
	if (ptr = getenv("IRCPATH"))
		malloc_strcpy(&irc_path, ptr);
	else
	{
#ifdef IRCPATH
		malloc_strcpy(&irc_path, IRCPATH);
#else
		malloc_strcpy(&irc_path, ".:~/.irc:");
		malloc_strcat(&irc_path, irc_lib);
		malloc_strcat(&irc_path, "script");
#endif
	}
	set_string_var(LOAD_PATH_VAR, irc_path);
	new_free(&irc_path);
	if (ptr = getenv("IRCSERVER"))
		build_server_list(ptr);
	if ((server_list_size() == 0) || add_servers)
	{
#ifdef SERVERS_FILE
		if (read_server_file() || (server_list_size() == 0))
#endif
		{
			char *ptr = null(char *);

			malloc_strcpy(&ptr, DEFAULT_SERVER);
			build_server_list(ptr);
			new_free(&ptr);
		}
	}
	if (entry = getpwuid(getuid()))
	{
		if ((*realname == null(char)) && entry->pw_gecos && *(entry->pw_gecos))
		{
#ifdef GECOS_DELIMITER
			if (ptr = index(entry->pw_gecos, GECOS_DELIMITER))
				*ptr = null(char);
#endif /* GECOS_DELIMITER */
			strmcpy(realname, entry->pw_gecos, REALNAME_LEN);
		}
		if (ptr = getenv("IRCUSER"))
			strmcpy(username, ptr, NAME_LEN);
		else
		/* bpk <3/9/93> */
		if (entry->pw_name && *(entry->pw_name))
			strmcpy(username, entry->pw_name, NAME_LEN);
		if (entry->pw_dir && *(entry->pw_dir))
			malloc_strcpy(&my_path, entry->pw_dir);
	}
	if (ptr = getenv("HOME"))
		malloc_strcpy(&my_path, ptr);
	else if (*my_path == null(char))
		malloc_strcpy(&my_path, "/");
	if (*realname == null(char))
		strmcpy(realname, "*Unknown*", REALNAME_LEN);
	if (*username == null(char))
	{
		if (ptr = getenv("USER"))
			strmcpy(username, ptr, NAME_LEN);
		else
			strmcpy(username, "Unknown", NAME_LEN);
	}
	gethostname(MyHostName, sizeof(MyHostName));
	if (hp = gethostbyname(MyHostName))
	{
		bcopy(hp->h_addr, (char *) &MyHostAddr, sizeof(MyHostAddr));
		local_ip_address = ntohl(MyHostAddr.s_addr);
	}
#if 0
	for (c = username; *c != null(char); c++)
		if (*c == '@' || *c == '!')
			*c = '_';
#endif
	if (*nickname == null(char))
		strmcpy(nickname, username, NICKNAME_LEN);
	if (ircrc_file == null(char *))
	{
		ircrc_file = (char *) new_malloc(strlen(my_path) +
			strlen(IRCRC_NAME) + 1);
		strcpy(ircrc_file, my_path);
		strcat(ircrc_file, IRCRC_NAME);
	}
	return (channel);
}

/*
 * TimerTimeout:  Called from irc_io to help create the timeout
 * part of the call to select.
 */
Long	TimerTimeout()
{
	Long	current;
	int	timeout_in;

	if (!PendingTimers)
		return 70; /* Just larger than the maximum of 60 */
	time(&current);
	timeout_in = PendingTimers->time - current;
	return (timeout_in < 0) ? 0 : timeout_in;
}

/*
 * irc_io: the main irc input/output loop.   Handles all io from keyboard,
 * server, exec'd processes, etc.  If a prompt is specified, it is displayed
 * in the input line and cannot be backspaced over, etc. The func is a
 * function which will take the place of the SEND_LINE function (which is
 * what happens when you hit return at the end of a line). This function must
 * decide if it's ok to exit based on anything you really want.  It can then
 * set the global irc_io_loop to false to cause irc_io to exit. 
 */
int	irc_io(prompt, func, use_input, loop)
char	*prompt;
void	(*func) ();
int	use_input;
int	loop;
{
	static	int	level = 0;
	fd_set	rd,
		wd;
	char	buffer[BIG_BUFFER_SIZE + 1];	/* buffer much bigger than
						 * IRCD_BUFFER_SIZE */
	struct	timeval cursor_timeout,
		clock_timeout,
		right_away,
		timer,
		*timeptr;
	int	hold_over;
	int	old_loop;
	char	*last_input = null(char *);
	char	*last_prompt = null(char *);
	void	(*last_func)();
	int	one_key = 0;
	Screen	*screen,
		*old_current_screen;

	last_func = get_send_line();
	if (use_input == -1)
		one_key = 1, prompt = null(char *);
#ifdef	PRIV_PORT_ULC
	seteuid(getuid());
#endif
	/* 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 */
	clock_timeout.tv_usec = 0L;
	clock_timeout.tv_sec = 30L;

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

	timer.tv_usec = 0L;

	old_loop = irc_io_loop;
	irc_io_loop = loop;

			/*
	if (level++ > 20)
	{
			 * irc_io has been recursive to date.
			 * with multiple xterms and screen
			 * windows, this has to change
			 */
	if (level++ > 5)
	{
		level--;
		irc_io_loop = old_loop;
		return (1);
	}
	if (!dumb)
	{
		if (use_input)
		{
			malloc_strcpy(&last_input, get_input());
			set_input(empty_string);
			last_func = get_send_line();
			change_send_line(func);
		}
		if (prompt)
		{
			malloc_strcpy(&last_prompt, get_input_prompt());
			set_input_prompt(prompt);
		}
	}
	/*
	 * Here we work out if this has been called recursively or
	 * not..  and if not so.. -phone
	 */

#ifdef DEBUG
	if (level != 1)
		yell("--- Recursive call to irc_io() - careful");
	else
#endif /* DEBUG */
#if  0
		if (setjmp(outta_here))
			yell("*** Got SIGUSR2, Aborting");
#endif

	timeptr = &clock_timeout;
	do
	{
		break_io_processing = 0;
		FD_ZERO(&rd);
		FD_ZERO(&wd);
		if (use_input)
		{
			for (screen = screen_list;screen; screen = screen->next)
				if (screen->alive)
					FD_SET(screen->fdin, &rd);
		}
		set_process_bits(&rd);
		set_server_bits(&rd);
		set_dcc_bits(&rd, &wd);
		if (term_reset_flag)
		{
			refresh_screen();
			term_reset_flag = 0;
		}
		timer.tv_sec = TimerTimeout();
		if (timer.tv_sec <= timeptr->tv_sec)
			timeptr = &timer;
		if (hold_over = unhold_windows())
			timeptr = &right_away;
		switch (new_select(&rd, &wd, timeptr))
		{
		case 0:
		case -1:
			if (cntl_c_hit)
			{
				if (one_key)
				{
					irc_io_loop = 0;
					break;
				}
				edit_char('\003');
				cntl_c_hit = 0;
			}
			if (!hold_over)
				cursor_to_input();
			break;
		default:
			if (term_reset_flag)
			{
				refresh_screen();
				term_reset_flag = 0;
			}
			old_current_screen = current_screen;
			set_current_screen(last_input_screen);
			if (!break_io_processing)
				dcc_check(&rd);
			if (!break_io_processing)
				do_server(&rd);
			set_current_screen(old_current_screen);
			for (screen = screen_list; screen &&
				!break_io_processing; screen = screen->next)
			{
				if (!screen->alive)
					continue;
				set_current_screen(screen);
				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..
	 *
	 * This section indented - phone, jan 1993
	 */

			idle_time = time(0);
			if (dumb)
			{
				if (dgets(buffer, INPUT_BUFFER_SIZE,
						screen->fdin))
				{
					if (one_key)
					{
						irc_io_loop = 0;
						break;
					}
					*(buffer + strlen(buffer) - 1) =
						null(char);
					if (get_int_var(INPUT_ALIASES_VAR))	
						parse_line(null(char *),
						buffer,empty_string, 1, 0);
					else
						parse_line(null(char *),
						buffer,null(char *), 1, 0);
				}
				else
				{
					say("IRCII exiting on EOF from stdin");
					irc_exit();
				}
			}
			else
			{
				int server;

				server = from_server;
				from_server = get_window_server(0);
				last_input_screen = screen;
				if (read(screen->fdin, buffer, 1))
				{
					if (one_key)
					{
						irc_io_loop = 0;
						break;
					}
					edit_char(*buffer);
				}
		/*
		 * if the current screen isn't the main  screen,
		 * then the socket to the current screen must have
		 * closed, so we call kill_screen() to handle 
		 * this - phone, jan 1993.
		 */
					else
					{
						if (!is_main_screen(screen))
							kill_screen(screen);
					}
					cntl_c_hit = 0;
					from_server = server;
				}
		/* End of intendation */
					}
				}
				set_current_screen(old_current_screen);
				if (!break_io_processing)
					do_processes(&rd);
				break;
			}
			ExecuteTimers();
			check_process_limits();
			check_wait_status();
			if ((primary_server == -1) && ! never_connected)
				do_hook(DISCONNECT_LIST, "%s", nickname); 
			timeptr = &clock_timeout;

			old_current_screen = current_screen;
			for (current_screen = screen_list; current_screen;
					current_screen = current_screen->next)
				if (current_screen->alive && is_cursor_in_display())
					timeptr = &cursor_timeout;
			set_current_screen(old_current_screen);

			if (update_clock(0))
			{
				if (get_int_var(CLOCK_VAR) || check_mail_status())
				{
					update_all_status();
					cursor_to_input();
				}
				do_notify();
			}
		}
		while (irc_io_loop);
		level--;
		irc_io_loop = old_loop;
		if (! dumb)
		{
			if (use_input)
			{
				set_input(last_input);
				new_free(&last_input);
				change_send_line(last_func);
			}
		if (prompt)
		{
			if (level == 0)
			    set_input_prompt(get_string_var(INPUT_PROMPT_VAR));
			else
			    set_input_prompt(last_prompt);
			new_free(&last_prompt);
		}
	}
	update_input(UPDATE_ALL);
	return (0);
}

/*ARGSUSED*/
void	main(argc, argv, envp)
int	argc;
char	*argv[];
char	*envp[];
{
	char	*channel;

#if defined(HPUX) || defined(ESIX)
	/* Curses code added for HP-UX use */
	if (!dumb)
	{
		initscr();
		noecho();
		cbreak();
	}
#endif /* defined(HPUX) || defined(ESIX) */
	channel = parse_args(argv, argc);
	if ((use_input == 0) && !no_fork)
	{
		if (fork())
			_exit(0);
	}
#ifdef ESIX
	if (gethostname(hostname, NAME_LEN) == NULL)
#else
	if (gethostname(hostname, NAME_LEN))
#endif /* ESIX */
	{
		fprintf(stderr, "irc: couldn't figure out the name of your machine!\n");
		exit(1);
	}
	if (dumb)
		new_window();
	else
	{
		init_screen();
#if !defined(MUNIX) && !defined(_RT) && !defined(ESIX)
		signal(SIGCONT, term_cont);
#endif /* !defined(MUNIX) && !defined(_RT) && !defined(ESIX) */
#if !defined(_RT) && defined(SIGWINCH)
		signal(SIGWINCH, refresh_screen);
#endif /* _RT */
#ifndef ALLOC_DEBUG
# ifdef CORECATCH
		signal(SIGSEGV, coredump);
#  ifndef linux
		signal(SIGBUS, coredump);   
#  endif
# else
		signal(SIGSEGV, SIG_DFL);
		/* Linux doesn't have SIGBUS */
#  ifndef linux
		signal(SIGBUS, SIG_DFL);   
#  endif /* linux */
# endif /* CORECATCH */
#endif /* ALLOC_DEBUG */
#ifdef MUNIX
		signal(SIGQUIT, cntl_y);
#endif
		signal(SIGPIPE, SIG_IGN);
		signal(SIGINT, cntl_c);
		signal(SIGSTOP, SIG_IGN);
		signal(SIGUSR1, sig_user1);
#if DO_USER2
		signal(SIGUSR2, sig_user2);
#endif
	}
#ifdef HPUX
	new_stty("opost");
#endif /* HPUX */

	init_variables();

	if (!dumb)
	{
		build_status(null(char *));
		update_input(UPDATE_ALL);
	}

#ifdef MOTD_FILE
	{
		struct	stat	motd_stat,
				my_stat;
		char	*motd = NULL;
		int	des;

		malloc_strcpy(&motd, irc_lib);
		malloc_strcat(&motd, MOTD_FILE);
		if (stat_file(motd, &motd_stat) == 0)
		{
			strmcpy(buffer, my_path, BIG_BUFFER_SIZE);
			strmcat(buffer, "/.ircmotd", BIG_BUFFER_SIZE);
			if (stat_file(buffer, &my_stat))
			{
				my_stat.st_atime = 0L;
				my_stat.st_mtime = 0L;
			}
			unlink(buffer);
			if ((des = open(buffer, O_CREAT, S_IREAD | S_IWRITE))
					!= -1)
				close(des);
			if (motd_stat.st_mtime > my_stat.st_mtime)
			{
				put_file(motd);
		/* Thanks to Mark Dame <mdame@uceng.ec.edu> for this one */

#if PAUSE_AFTER_MOTD
		input_pause("********  Press any key to continue  ********");
#endif
				clear_window_by_refnum(0);
			}
		}
		new_free(&motd);
	}
#endif /* MOTD_FILE */

	global_all_off[0] = ALL_OFF;
	global_all_off[1] = '\0';
	get_connected(0);
	if (channel)
	{
		set_channel_by_refnum(0, channel);
		add_channel(channel, primary_server);
		new_free(&channel);
	}
	idle_time = time(0);
	set_input(empty_string);
	irc_io(get_string_var(INPUT_PROMPT_VAR), NULL, use_input, irc_io_loop);
	irc_exit();
	return;
}
