/*
 * output.c: handles a variety of tasks dealing with the output from the irc
 * program 
 *
 * Written By Michael Sandrof
 *
 * Copyright(c) 1990 
 *
 * See the COPYRIGHT file, or do a HELP IRCII COPYRIGHT 
 */

#if 0
static	char	rcsid[] = "@(#)$Id: output.c,v 1.8 1994/07/02 02:32:13 mrg Exp $";
#endif

#include "irc.h"

#include <sys/ioctl.h>
#include <sys/stat.h>

#ifdef HAVE_STDARG_H
#include <stdarg.h>
#endif

#include "output.h"
#include "vars.h"
#include "input.h"
#include "term.h"
#include "lastlog.h"
#include "window.h"
#include "screen.h"
#include "hook.h"
#include "ctcp.h"
#include "log.h"

	int	in_help = 0;

/* make this buffer *much* bigger than needed */
static	char	putbuf[BIG_BUFFER_SIZE * 10 + 1];

/* unflash: sends a ^[c to the screen */
/* Must be defined to be useful, cause some vt100s really *do* reset when
   sent this command. >;-) */
/* Now that you can send ansi sequences, this is much less inportant.. */
void unflash _((void))
{
#ifdef HARD_UNFLASH
	fwrite("\033c", 2, 1, stdout);		/* hard reset */
#else
	fwrite("\033)0", 3, 1, stdout);		/* soft reset */
#endif
}

/* sig_refresh_screen: the signal-callable versino of refresh_screen */
#ifdef __STDC__
RETSIGTYPE sig_refresh_screen _((int unused))
#else
RETSIGTYPE sig_refresh_screen (unused)
int unused;
#endif
{
#ifdef SYSVSIGNALS
	(void) MY_SIGNAL (SIGWINCH, sig_refresh_screen, 0);
#endif
	refresh_screen(0, NULL);
}

/*
 * refresh_screen: Whenever the REFRESH_SCREEN function is activated, this
 * swoops into effect 
 */
/* More keybinding lossage -- who the **** left all these old protos around? */
#ifdef __STDC__
void refresh_screen (char dumb, char *dumber)
#else
void refresh_screen(dumb, dumber)
char dumb;
char *dumber;
#endif
{
	unflash();
	term_clear_screen();
	if (term_resize())
		recalculate_windows();
	else
		redraw_all_windows();
	update_all_windows();
	update_input(UPDATE_ALL);
}

/* extern_write -- controls whether others may write to our terminal or not. */
/* This is basically stolen from bsd -- so its under the bsd copyright */
#ifdef __STDC__
void extern_write (char *command, char *args, char *subargs)
#else
void	extern_write (command, args, subargs)
char *command, *args, *subargs;
#endif
{
	char *tty;
	struct stat sbuf;
	const int OTHER_WRITE = 020;

	if (!(tty = ttyname(2)))
	{
		yell("Internal error: notify %s", EMAIL_CONTACT);
		yell("Error in ttyname()");
		return;
	}
	if (stat(tty, &sbuf) < 0)
	{
		yell("Internal error: notify %s", EMAIL_CONTACT);
		yell("Error in stat()");
		return;
	}
	if (!args || !*args)
	{
		if (sbuf.st_mode & 020)
			say("Mesg is 'y'");
		else
			say("Mesg is 'n'");
		return;
	}
	switch (args[0])
	{
		case 'y' :
			if (chmod(tty, sbuf.st_mode | OTHER_WRITE) < 0)
			{
				yell("Sorry, couldnt set your tty's mode");
				return;
			}
			break;
		case 'n' :
			if (chmod(tty, sbuf.st_mode &~ OTHER_WRITE) < 0)
			{
				yell("Sorry, couldnt set your tty's mode");
				return;
			}
			break;
		default :
			say("Usage: /MESG [Y|N]");
			break;
	}
}

/* init_windows:  */
void	init_screen _((void))
{
	term_init();
	term_clear_screen();
	term_resize();
	new_window();
	recalculate_windows();
	update_all_windows();
	init_input();
	term_move_cursor(0, 0);
}

/* put_file: uses put_it() to display the contents of a file to the display */
#ifdef __STDC__
void 		put_file (const char *filename)
#else
void		put_file(filename)
const char	*filename;
#endif
{
	FILE	*fp;
	char	line[256];		/* too big?  too small?  who cares? */
	int	len;

	if ((fp = fopen(filename, "r")) != (FILE *) 0)
	{
		while (fgets(line, 256, fp))
		{
			len = strlen(line);
			if (*(line + len - 1) == '\n')
				*(line + len - 1) = (char) 0;
			put_it("%s", line);
		}
		fclose(fp);
	}
}

/*
 * put_it: the irc display routine.  Use this routine to display anything to
 * the main irc window.  It handles sending text to the display or stdout as
 * needed, add stuff to the lastlog and log file, etc.  Things NOT to do:
 * Dont send any text that contains \n, very unpredictable.  Tabs will also
 * screw things up.  The calling routing is responsible for not overwriting
 * the 1K buffer allocated.  
 *
 * For Ultrix machines, you can't call put_it() with floating point arguements.
 * It just doesn't work.  - phone, jan 1993.
 */
#if defined(__STDC__) && defined(HAVE_STDARG_H)
void put_it(const char *format, ...)
#else
void	put_it(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10)
const char	*format;
char		*arg1, *arg2, *arg3, *arg4, *arg5,
		*arg6, *arg7, *arg8, *arg9, *arg10;
#endif
{
	if (window_display && format)
	{
#if defined(__STDC__) && defined(HAVE_STDARG_H)
		va_list args;
		va_start (args, format);
		vsprintf(putbuf, format, args);
		va_end(args);
#else
		sprintf(putbuf, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10);
#endif
		add_to_log(irclog_fp, putbuf);
		add_to_screen(putbuf);
	}
}

/* This is an alternative form of put_it which writes three asterisks
 * before actually putting things out.
 */
#if defined(__STDC__) && defined(HAVE_STDARG_H)
void say (const char *format, ...)
#else
void	say(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10)
const char	*format;
char		*arg1, *arg2, *arg3, *arg4, *arg5,
		*arg6, *arg7, *arg8, *arg9, *arg10;
#endif
{
	if (window_display && format)
	{
#if defined(__STDC__) && defined(HAVE_STDARG_H)
		va_list args;
		va_start (args, format);
		vsprintf(&(putbuf[4]), format, args);
		va_end(args);
#else
		sprintf(&(putbuf[4]), format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10);
#endif
		putbuf[0] = putbuf[1] = putbuf[2] = '*';
		putbuf[3] = ' ';
		add_to_log(irclog_fp, putbuf);
		add_to_screen(putbuf);
	}
}

#if defined(__STDC__) && defined(HAVE_STDARG_H)
void	yell(const char *format, ...)
#else
void	yell(format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10)
const char	*format;
char		*arg1, *arg2, *arg3, *arg4, *arg5,
		*arg6, *arg7, *arg8, *arg9, *arg10;
#endif
{
	if (format)
	{
#if defined(__STDC__) && defined(HAVE_STDARG_H)
		va_list args;
		va_start (args, format);
		vsprintf(putbuf, format, args);
		va_end(args);
#else
		sprintf(putbuf, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10);
#endif
		add_to_log(irclog_fp, putbuf);
		add_to_screen(putbuf);
	}
}


/* help_put_it: works just like put_it, but is specially used by help */
#if defined(__STDC__) && defined(HAVE_STDARG_H)
void	help_put_it (const char *topic, const char *format, ...)
#else
void	help_put_it (topic, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10)
const char	*format,
		*topic;
char		*arg1, *arg2, *arg3, *arg4, *arg5,
		*arg6, *arg7, *arg8, *arg9, *arg10;
#endif
{
	if (format)
	{
#if defined(__STDC__) && defined(HAVE_STDARG_H)
		va_list args;
		va_start (args, format);
		vsprintf(putbuf, format, args);
		va_end(args);
#else
		sprintf(putbuf, format, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10);
#endif

		in_help = 1;
		if (do_hook(HELP_LIST, "%s %s", topic, putbuf))
		{
			/*
			 * XXXXX - setting this every time like this is absymal.
			 * Buts its needed to avoid major hacks to help.c, which
			 * ultimately makes sure everything goes to the right window.
			 */
			message_from((char *) 0, LOG_CURRENT);
			if (window_display)
			{
				add_to_log(irclog_fp, putbuf);
				add_to_screen(putbuf);
			}
			message_from((char *) 0, LOG_CRAP);
		}
		in_help = 0;
	}
}
