/*
 * status.c: handles the status line updating, etc for IRCII 
 *
 * Written By Michael Sandrof
 *
 * Copyright (c) 1990 Michael Sandrof.
 * Copyright (c) 1991, 1992 Troy Rollo.
 * Copyright (c) 1992-2006 Matthew R. Green.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

/*
 * WARNING!  THIS CODE HAS DRAGONS.  BE *VERY* CAREFUL WHEN CHANGING
 * ANYTHING IN HERE.  TEST IT EXTENSIVELY.
 */

#include "irc.h"
IRCII_RCSID("@(#)$eterna: status.c,v 1.89 2006/07/22 03:50:10 mrg Exp $");

#include "ircterm.h"
#include "status.h"
#include "server.h"
#include "vars.h"
#include "hook.h"
#include "input.h"
#include "edit.h"
#include "window.h"
#include "screen.h"
#include "mail.h"
#include "output.h"
#include "names.h"
#include "ircaux.h"
#include "translat.h"
#include "debug.h"

static	u_char	*convert_format(u_char *, int);
static	u_char	*status_nickname(Window *);
static	u_char	*status_query_nick(Window *);
static	u_char	*status_right_justify(Window *);
static	u_char	*status_chanop(Window *);
static	u_char	*status_channel(Window *);
static	u_char	*status_server(Window *);
static	u_char	*status_mode(Window *);
static	u_char	*status_umode(Window *);
static	u_char	*status_insert_mode(Window *);
static	u_char	*status_overwrite_mode(Window *);
static	u_char	*status_away(Window *);
static	u_char	*status_oper(Window *);
static	u_char	*status_voice(Window *);
static	u_char	*status_user0(Window *);
static	u_char	*status_user1(Window *);
static	u_char	*status_user2(Window *);
static	u_char	*status_user3(Window *);
static	u_char	*status_hold(Window *);
static	u_char	*status_version(Window *);
static	u_char	*status_clock(Window *);
static	u_char	*status_hold_lines(Window *);
static	u_char	*status_window(Window *);
static	u_char	*status_mail(Window *);
static	u_char	*status_refnum(Window *);
static	u_char	*status_null_function(Window *);
static	u_char	*status_notify_windows(Window *);
static	u_char	*status_group(Window *);
static	u_char	*status_scrolled(Window *);
static	u_char	*status_scrolled_lines(Window *);
static	void	alarm_switch(int);
static	u_char	*convert_sub_format(u_char *, int);
static	void	make_status_one(Window *, int, int);

/*
 * Maximum number of "%" expressions in a status line format.  If you change
 * this number, you must manually change the snprintf() in make_status 
 */
#define MAX_FUNCTIONS 45

/* The format statements to build each portion of the status line */
static	u_char	*mode_format = (u_char *) 0;
static	u_char	*umode_format = (u_char *) 0;
static	u_char	*status_format[3] = {(u_char *) 0, (u_char *) 0, (u_char *) 0,};
static	u_char	*query_format = (u_char *) 0;
static	u_char	*clock_format = (u_char *) 0;
static	u_char	*hold_lines_format = (u_char *) 0;
static	u_char	*scrolled_lines_format = (u_char *) 0;
static	u_char	*channel_format = (u_char *) 0;
static	u_char	*mail_format = (u_char *) 0;
static	u_char	*server_format = (u_char *) 0;
static	u_char	*notify_format = (u_char *) 0;
static	u_char	*group_format = (u_char *) 0;

/*
 * status_func: The list of status line function in the proper order for
 * display.  This list is set in convert_format() 
 */
static	u_char	*(*status_func[3][MAX_FUNCTIONS])(Window *);

/* func_cnt: the number of status line functions assigned */
static	int	func_cnt[3];

static	int	alarm_hours,		/* hour setting for alarm in 24 hour time */
		alarm_minutes;		/* minute setting for alarm */

/* Stuff for the alarm */
static	struct itimerval clock_timer = { { 10L, 0L }, { 1L, 0L } };
static	struct itimerval off_timer = { { 0L, 0L }, { 0L, 0L } };

static	RETSIGTYPE alarmed(int);
	int	do_status_alarmed;

/* alarmed: This is called whenever a SIGALRM is received and the alarm is on */
static	RETSIGTYPE
alarmed(signo)
	int signo;
{
	do_status_alarmed = 1;
}

void
real_status_alarmed()
{
	u_char	time_str[16];

	say("The time is %s", update_clock(time_str, 16, GET_TIME));
	term_beep();
	term_beep();
	term_beep();
}

/*
 * alarm_switch: turns on and off the alarm display.  Sets the system timer
 * and sets up a signal to trap SIGALRMs.  If flag is 1, the alarmed()
 * routine will be activated every 10 seconds or so.  If flag is 0, the timer
 * and signal stuff are reset 
 */
static	void
alarm_switch(flag)
	int	flag;
{
	static	int	alarm_on = 0;

	if (flag)
	{
		if (!alarm_on)
		{
			setitimer(ITIMER_REAL, &clock_timer,
				(struct itimerval *) 0);
			(void) MY_SIGNAL(SIGALRM, alarmed, 0);
			alarm_on = 1;
		}
	}
	else if (alarm_on)
	{
		setitimer(ITIMER_REAL, &off_timer, (struct itimerval *) 0);
		(void) MY_SIGNAL(SIGALRM, (sigfunc *)SIG_IGN, 0);
		alarm_on = 0;
	}
}

/*
 * set_alarm: given an input string, this checks its validity as a clock
 * type time thingy.  It accepts two time formats.  The first is the HH:MM:XM
 * format where HH is between 1 and 12, MM is between 0 and 59, and XM is
 * either AM or PM.  The second is the HH:MM format where HH is between 0 and
 * 23 and MM is between 0 and 59.  This routine also looks for one special
 * case, "OFF", which sets the alarm string to null 
 */
void
set_alarm(str)
	u_char	*str;
{
	u_char	hours[10],
		minutes[10],
		merid[3];
	u_char	time_str[10];
	int	c,
		h,
		m,
		min_hours,
		max_hours;

	if (str == (u_char *) 0)
	{
		alarm_switch(0);
		return;
	}
	if (!my_stricmp(str, UP(var_settings[OFF])))
	{
		set_string_var(CLOCK_ALARM_VAR, (u_char *) 0);
		alarm_switch(0);
		return;
	}
	
	c = sscanf(CP(str), " %2[^:]:%2[^paPA]%2s ", hours, minutes, merid);
	switch (c)
	{
	case 2:
		min_hours = 0;
		max_hours = 23;
		break;
	case 3:
		min_hours = 1;
		max_hours = 12;
		upper(UP(merid));
		break;
	default:
		say("CLOCK_ALARM: Bad time format.");
		set_string_var(CLOCK_ALARM_VAR, (u_char *) 0);
		return;
	}
	
	h = my_atoi(hours);
	m = my_atoi(minutes);
	if (h >= min_hours && h <= max_hours && isdigit(hours[0]) &&
		(isdigit(hours[1]) || hours[1] == (u_char) 0))
	{
		if (m >= 0 && m <= 59 && isdigit(minutes[0]) &&
				isdigit(minutes[1]))
		{
			alarm_minutes = m;
			alarm_hours = h;
			if (max_hours == 12)
			{
				if (merid[0] != 'A')
				{
					if (merid[0] == 'P')
					{
						if (h != 12)
							alarm_hours += 12;
					}
					else
					{
	say("CLOCK_ALARM: alarm time must end with either \"AM\" or \"PM\"");
	set_string_var(CLOCK_ALARM_VAR, (u_char *) 0);
					}
				}
				else
				{
					if (h == 12)
						alarm_hours = 0;
				}
				if (merid[1] == 'M')
				{
					snprintf(CP(time_str), sizeof time_str,
					    "%02d:%02d%s", h, m, merid);
					set_string_var(CLOCK_ALARM_VAR,
						time_str);
				}
				else
				{
	say("CLOCK_ALARM: alarm time must end with either \"AM\" or \"PM\"");
	set_string_var(CLOCK_ALARM_VAR, (u_char *) 0);
				}
			}
			else
			{
				snprintf(CP(time_str), sizeof time_str,
				    "%02d:%02d", h, m);
				set_string_var(CLOCK_ALARM_VAR, time_str);
			}
		}
		else
		{
	say("CLOCK_ALARM: alarm minutes value must be between 0 and 59.");
	set_string_var(CLOCK_ALARM_VAR, (u_char *) 0);
		}
	}
	else
	{
		say("CLOCK_ALARM: alarm hour value must be between %d and %d.",
			min_hours, max_hours);
		set_string_var(CLOCK_ALARM_VAR, (u_char *) 0);
	}
}

u_char	*
format_clock(buf, len, hour, min)
	u_char	*buf;
	size_t	len;
	int	hour;
	int	min;
{
	char	*merid;

	if (get_int_var(CLOCK_24HOUR_VAR))
		merid = CP(empty_string);
	else
	{
		if (hour < 12)
			merid = "AM";
		else
			merid = "PM";
		if (hour > 12)
			hour -= 12;
		else if (hour == 0)
			hour = 12;
	}
	snprintf(CP(buf), len, "%02d:%02d%s", hour, min, merid);

	return buf;
}


/* update_clock: figures out the current time and returns it in a nice format */
u_char	*
update_clock(buf, len, flag)
	u_char	*buf;
	size_t	len;
	int	flag;
{
	struct tm	*time_val;
	static	u_char	time_str[10];
	static	int	min = -1, hour = -1;
	time_t	t;
	int	tmp_hour, tmp_min;

	t = time(0);
	time_val = localtime(&t);
	tmp_hour = time_val->tm_hour;
	tmp_min = time_val->tm_min;

	Debug((8, "update_clock (%s): time %lu (%02d:%02d) [old %02d:%02d]",
	    flag == RESET_TIME ? "reset" :
	     flag == GET_TIME ? "get" :
	     flag == UPDATE_TIME ? "update" : "unknown", 
	    (long unsigned) t, tmp_hour, tmp_min, hour, min));

	if (get_string_var(CLOCK_ALARM_VAR))
	{
		if ((tmp_hour == alarm_hours) && (tmp_min == alarm_minutes))
			alarm_switch(1);
		else
			alarm_switch(0);
	}

	if (flag == RESET_TIME ||
	    (flag == UPDATE_TIME && (tmp_min != min || tmp_hour != hour)))
	{
		int server;

		format_clock(time_str, sizeof time_str, tmp_hour, tmp_min);
		server = from_server;
		from_server = primary_server;
		Debug((8, "update_clock: in reset_time block, time_str: %s", time_str));
		if (flag == UPDATE_TIME && (tmp_min != min || tmp_hour != hour))
		{
			hour = tmp_hour;
			min = tmp_min;
			do_hook(TIMER_LIST, "%s", time_str);
		}
		do_hook(IDLE_LIST, "%ld", (t - idle_time) / 60L);
		from_server = server;
		flag = GET_TIME;
	}
	if (buf)
	{
		my_strncpy(buf, time_str, len - 1);
		buf[len - 1] = '\0';
	}
	if (flag == GET_TIME)
		return(buf ? buf : time_str);
	else
		return ((u_char *) 0);
}

/*ARGSUSED*/
void
reset_clock(unused)
	int	unused;
{
	update_clock(0, 0, RESET_TIME);
	update_all_status();
}

/*
 * convert_sub_format: This is used to convert the formats of the
 * sub-portions of the status line to a format statement specially designed
 * for that sub-portions.  convert_sub_format looks for a single occurence of
 * %c (where c is passed to the function). When found, it is replaced by "%s"
 * for use is a snprintf.  All other occurences of % followed by any other
 * character are left unchanged.  Only the first occurence of %c is
 * converted, all subsequence occurences are left unchanged.  This routine
 * mallocs the returned string. 
 */
static	u_char	*
convert_sub_format(format, c)
	u_char	*format;
	int	c;
{
	u_char	lbuf[BIG_BUFFER_SIZE];
	static	u_char	bletch[] = "%% ";
	u_char	*ptr = (u_char *) 0;
	int	dont_got_it = 1;

	if (format == (u_char *) 0)
		return ((u_char *) 0);
	*lbuf = (u_char) 0;
	while (format)
	{
		if ((ptr = my_index(format, '%')) != NULL)
		{
			*ptr = (u_char) 0;
			my_strmcat(lbuf, format, sizeof lbuf);
			*(ptr++) = '%';
			if ((*ptr == c) && dont_got_it)
			{
				dont_got_it = 0;
				my_strmcat(lbuf, "%s", sizeof lbuf);
			}
			else
			{
				bletch[2] = *ptr;
				my_strmcat(lbuf, bletch, sizeof lbuf);
			}
			ptr++;
		}
		else
			my_strmcat(lbuf, format, sizeof lbuf);
		format = ptr;
	}
	malloc_strcpy(&ptr, lbuf);
	return (ptr);
}

static	u_char	*
convert_format(format, k)
	u_char	*format;
	int	k;
{
	u_char	lbuf[BIG_BUFFER_SIZE];
	u_char	*ptr,
		*malloc_ptr = (u_char *) 0; 
	int	*cp;
	
	*lbuf = (u_char) 0;
	while (format)
	{
		if ((ptr = my_index(format, '%')) != NULL)
		{
			*ptr = (u_char) 0;
			my_strmcat(lbuf, format, sizeof lbuf);
			*(ptr++) = '%';
			cp = &func_cnt[k];
			if (*cp < MAX_FUNCTIONS)
			{
				switch (*(ptr++))
				{
				case '%':
					/* %% instead of %, because this will be passed to snprintf */
					my_strmcat(lbuf, "%%", sizeof lbuf);
					break;
				case 'N':
					my_strmcat(lbuf, "%s", sizeof lbuf);
					status_func[k][(*cp)++] =
						status_nickname;
					break;
				case '>':
					my_strmcat(lbuf, "%s", sizeof lbuf);
					status_func[k][(*cp)++] =
						status_right_justify;
					break;
				case 'G':
					new_free(&group_format);
					group_format =
					convert_sub_format(get_string_var(STATUS_GROUP_VAR), 'G');
					my_strmcat(lbuf, "%s", sizeof lbuf);
					status_func[k][(*cp)++] =
						status_group;
					break;
				case 'Q':
					new_free(&query_format);
					query_format =
		convert_sub_format(get_string_var(STATUS_QUERY_VAR), 'Q');
					my_strmcat(lbuf, "%s", sizeof lbuf);
					status_func[k][(*cp)++] =
						status_query_nick;
					break;
				case 'F':
					new_free(&notify_format);
					notify_format = 
		convert_sub_format(get_string_var(STATUS_NOTIFY_VAR), 'F');
					my_strmcat(lbuf, "%s", sizeof lbuf);
					status_func[k][(*cp)++] =
						status_notify_windows;
					break;
				case '@':
					my_strmcat(lbuf, "%s", sizeof lbuf);
					status_func[k][(*cp)++] =
						status_chanop;
					break;
				case 'C':
					new_free(&channel_format);
					channel_format =
		convert_sub_format(get_string_var(STATUS_CHANNEL_VAR), 'C');
					my_strmcat(lbuf, "%s", sizeof lbuf);
					status_func[k][(*cp)++] =
						status_channel;
					break;
				case 'S':
					new_free(&server_format);
					server_format =
		convert_sub_format(get_string_var(STATUS_SERVER_VAR), 'S');
					my_strmcat(lbuf,"%s",sizeof lbuf);
					status_func[k][(*cp)++] =
						status_server;
					break;
				case '+':
					new_free(&mode_format);
					mode_format =
		convert_sub_format(get_string_var(STATUS_MODE_VAR), '+');
					my_strmcat(lbuf, "%s", sizeof lbuf);
					status_func[k][(*cp)++] =
						status_mode;
					break;
				case '#':
					new_free(&umode_format);
					umode_format =
		convert_sub_format(get_string_var(STATUS_UMODE_VAR), '#');
					my_strmcat(lbuf, "%s", sizeof lbuf);
					status_func[k][(*cp)++] =
						status_umode;
					break;
				case 'M':
					new_free(&mail_format);
					mail_format =
		convert_sub_format(get_string_var(STATUS_MAIL_VAR), 'M');
					my_strmcat(lbuf, "%s", sizeof lbuf);
					status_func[k][(*cp)++] =
						status_mail;
					break;
				case 'I':
					my_strmcat(lbuf, "%s", sizeof lbuf);
					status_func[k][(*cp)++] =
						status_insert_mode;
					break;
				case 'O':
					my_strmcat(lbuf, "%s", sizeof lbuf);
					status_func[k][(*cp)++] =
						status_overwrite_mode;
					break;
				case 'A':
					my_strmcat(lbuf, "%s", sizeof lbuf);
					status_func[k][(*cp)++] =
						status_away;
					break;
				case 'V':
					my_strmcat(lbuf, "%s", sizeof lbuf);
					status_func[k][(*cp)++] =
						status_version;
					break;
				case 'R':
					my_strmcat(lbuf, "%s", sizeof lbuf);
					status_func[k][(*cp)++] =
						status_refnum;
					break;
				case 'T':
					new_free(&clock_format);
					clock_format =
		convert_sub_format(get_string_var(STATUS_CLOCK_VAR), 'T');
					my_strmcat(lbuf, "%s", sizeof lbuf);
					status_func[k][(*cp)++] =
						status_clock;
					break;
				case 'U':
					my_strmcat(lbuf, "%s", sizeof lbuf);
					status_func[k][(*cp)++] =
						status_user0;
					break;
				case 'H':
					my_strmcat(lbuf, "%s", sizeof lbuf);
					status_func[k][(*cp)++] =
						status_hold;
					break;
				case 'B':
					new_free(&hold_lines_format);
					hold_lines_format =
		convert_sub_format(get_string_var(STATUS_HOLD_LINES_VAR), 'B');
					my_strmcat(lbuf, "%s", sizeof lbuf);
					status_func[k][(*cp)++] =
						status_hold_lines;
					break;
				case 'P':
					my_strmcat(lbuf, "%s", sizeof lbuf);
					status_func[k][(*cp)++] =
						status_scrolled;
					Debug((2, "got P in status"));
					break;
				case 's':
					new_free(&scrolled_lines_format);
					scrolled_lines_format =
		convert_sub_format(get_string_var(STATUS_SCROLLED_LINES_VAR), 's');
					my_strmcat(lbuf, "%s", sizeof lbuf);
					status_func[k][(*cp)++] =
						status_scrolled_lines;
					Debug((2, "got s in status: sl-format '%s'", scrolled_lines_format));
					break;
				case '*':
					my_strmcat(lbuf, "%s", sizeof lbuf);
					status_func[k][(*cp)++] =
						status_oper;
					break;
				case 'v':
					my_strmcat(lbuf, "%s", sizeof lbuf);
					status_func[k][(*cp)++] =
						status_voice;
					break;
				case 'W':
					my_strmcat(lbuf, "%s", sizeof lbuf);
					status_func[k][(*cp)++] =
						status_window;
					break;
				case 'X':
					my_strmcat(lbuf, "%s", sizeof lbuf);
					status_func[k][(*cp)++] =
						status_user1;
					break;
				case 'Y':
					my_strmcat(lbuf, "%s", sizeof lbuf);
					status_func[k][(*cp)++] =
						status_user2;
					break;
				case 'Z':
					my_strmcat(lbuf, "%s", sizeof lbuf);
					status_func[k][(*cp)++] =
						status_user3;
					break;
		/* no default..?? - phone, jan 1993 */
		/* empty is a good default -lynx, mar 93 */
				}
			}
			else
				ptr++;
		}
		else
			my_strmcat(lbuf, format, sizeof lbuf);
		format = ptr;
	}
	/* this frees the old str first */
	malloc_strcpy(&malloc_ptr, lbuf);
	return (malloc_ptr);
}

void
build_status(format)
	u_char	*format;
{
	int	i, k;

	for (k = 0; k < 3; k++) 
	{
		new_free(&status_format[k]);
		func_cnt[k] = 0;
		switch (k)
		{
		case 0 : 
			format = get_string_var(STATUS_FORMAT_VAR);
			break;
			
		case 1 : 
			format = get_string_var(STATUS_FORMAT1_VAR);
			break;
			
		case 2 : 
			format = get_string_var(STATUS_FORMAT2_VAR);
			break;
		}
		if (format != NULL)	/* convert_format mallocs for us */
			status_format[k] = convert_format(format, k);
		for (i = func_cnt[k]; i < MAX_FUNCTIONS; i++)
			status_func[k][i] = status_null_function;
	}
	update_all_status();
}

void
make_status(window)
	Window	*window;
{
	int	k, l, final;

	switch (window->double_status) {
	case -1:
		new_free(&window->status_line[0]);
		new_free(&window->status_line[1]);
		goto out;
	case 0:
		new_free(&window->status_line[1]);
		final = 1;
		break;
	case 1:
		final = 2;
		break;
	default:
		yell("--- make_status: unknown window->double value %d", window->double_status);
		final = 1;
	}
	for (k = 0 ; k < final; k++)
	{
		if (k)
			l = 2;
		else if (window->double_status)
			l = 1;
		else
			l = 0;
			
		if (!dumb && status_format[l])
			make_status_one(window, k, l);
	}
out:
	cursor_to_input();
}

static	void
make_status_one(window, k, l)
	Window	*window;
	int	k;
	int	l;
{
	Screen	*old_current_screen;
	u_char	lbuf[BIG_BUFFER_SIZE];
	u_char	rbuf[BIG_BUFFER_SIZE];
	u_char	*func_value[MAX_FUNCTIONS];
	size_t	len;
	int	i;
	int rjustifypos;
	int justifypadlen;
	int RealPosition;

	/*
	 * XXX: note that this code below depends on the definition
	 * of MAX_FUNCTIONS (currently 45), and the snprintf must
	 * be updated if MAX_FUNCTIONS is changed.
	 */
	for (i = 0; i < MAX_FUNCTIONS; i++)
		func_value[i] = (status_func[l][i]) (window);
	lbuf[0] = REV_TOG;
	snprintf(CP(lbuf+1),
	       sizeof(lbuf) - 1,
	       CP(status_format[l]),
		func_value[0], func_value[1], func_value[2],
		func_value[3], func_value[4], func_value[5],
		func_value[6], func_value[7], func_value[8],
		func_value[9], func_value[10], func_value[11],
		func_value[12], func_value[13], func_value[14],
		func_value[15], func_value[16], func_value[17],
		func_value[18], func_value[19], func_value[20],
		func_value[21], func_value[22], func_value[23],
		func_value[24], func_value[25], func_value[26],
		func_value[27], func_value[28], func_value[29],
		func_value[30], func_value[31], func_value[32],
		func_value[33], func_value[34], func_value[35],
		func_value[36], func_value[37], func_value[38],
		func_value[39], func_value[40], func_value[41],
		func_value[42], func_value[43], func_value[44]);
	for (i = 0; i < MAX_FUNCTIONS; i++)
		new_free(&(func_value[i]));
	
	/*  Patched 26-Mar-93 by Aiken
	 *  make_window now right-justifies everything 
	 *  after a %>
	 *  it's also more efficient.
	 */
	
	rjustifypos   = -1;
	justifypadlen = 0;
	for (i = 0; lbuf[i]; i++)
	{
		/* formfeed is a marker for left/right border*/
		if (lbuf[i] == '\f')
		{
			int len_left;
			int len_right;
			
			/* Split the line to left and right part */
			lbuf[i] = '\0';
			
			/* Get lengths of left and right part in number of columns */
			len_right = my_strlen_c(lbuf);
			len_left  = my_strlen_c(lbuf+i+1);
			
			justifypadlen = current_screen->co - len_right - len_left;
			
			if (justifypadlen < 0)
				justifypadlen = 0;
			
			/* Delete the marker */
			/* FIXME: strcpy may not be used for overlapping buffers */
			my_strcpy(lbuf+i, lbuf+i+1);
			
			rjustifypos = i;
		}
	}
	
	if (get_int_var(FULL_STATUS_LINE_VAR))
	{
		if (rjustifypos == -1)
		{
			int length    = my_strlen_c(lbuf);

			justifypadlen = current_screen->co - length;
			if (justifypadlen < 0)
				justifypadlen = 0;
			rjustifypos = my_strlen(lbuf);
		}
		if (justifypadlen > 0)
		{
			/* Move a part of the data out of way */
			memmove(lbuf + rjustifypos + justifypadlen,
					lbuf + rjustifypos,
					my_strlen(lbuf) - rjustifypos + 1); // +1 = zero terminator
			
			/* Then fill the part with spaces */
			memset(lbuf + rjustifypos,
				   ' ',
				   justifypadlen);
		}
	}
	
	len = my_strlen(lbuf);
	if (len > (sizeof(lbuf) - 2))
		len = sizeof(lbuf) - 2;
	lbuf[len] = ALL_OFF;
	lbuf[len+1] =  '\0';
	
	my_strcpy_ci(rbuf, lbuf);
	
	RealPosition = 0;
	i = 0;
	
	old_current_screen = current_screen;
	set_current_screen(window->screen);
	term_move_cursor(RealPosition, window->bottom + k);
	len = output_line(rbuf, i);
	cursor_in_display();
	if (term_clear_to_eol() && len < current_screen->co)
		term_space_erase(current_screen->co - len);
	malloc_strcpy(&window->status_line[k], rbuf);
	set_current_screen(old_current_screen);
}

static	u_char	*
status_nickname(window)
	Window	*window;
{
	u_char	*ptr = (u_char *) 0;

	if ((connected_to_server == 1) && !get_int_var(SHOW_STATUS_ALL_VAR)
	    && (!window->current_channel) &&
	    (window->screen->current_window != window))
		malloc_strcpy(&ptr, empty_string);
	else
		malloc_strcpy(&ptr, get_server_nickname(window->server));
	return (ptr);
}

static	u_char	*
status_server(window)
	Window	*window;
{
	u_char	*ptr = NULL,
		*rest,
		*name;
	u_char	lbuf[BIG_BUFFER_SIZE];

	if (connected_to_server != 1)
	{
		if (window->server != -1)
		{
			if (server_format)
			{
				name = get_server_name(window->server);
				rest = my_index(name, '.');
				if (rest != NULL && my_strnicmp(name, UP("irc"), 3) != 0 &&
				    my_strnicmp(name, UP("icb"), 3) != 0)
				{
					if (is_number(name))
						snprintf(CP(lbuf), sizeof lbuf, CP(server_format), name);
					else
					{
						*rest = '\0';
						snprintf(CP(lbuf), sizeof lbuf, CP(server_format), name);
						*rest = '.';
					}
				}
				else
					snprintf(CP(lbuf), sizeof lbuf, CP(server_format), name);
			}
			else
				*lbuf = '\0';
		}
		else
			my_strcpy(lbuf, " No Server");
	}
	else
		*lbuf = '\0';
	malloc_strcpy(&ptr, lbuf);
	return (ptr);
}

static	u_char	*
status_group(window)
	Window	*window;
{
	u_char	*ptr = (u_char *) 0;

	if (window->server_group && group_format)
	{
		u_char	lbuf[BIG_BUFFER_SIZE];

		snprintf(CP(lbuf), sizeof lbuf, CP(group_format), find_server_group_name(window->server_group));
		malloc_strcpy(&ptr, lbuf);
	}
	else
		malloc_strcpy(&ptr, empty_string);
	return (ptr);
}

static	u_char	*
status_query_nick(window)
	Window	*window;
{
	u_char	*ptr = (u_char *) 0;

	if (window->query_nick && query_format)
	{
		u_char	lbuf[BIG_BUFFER_SIZE];

		snprintf(CP(lbuf), sizeof lbuf, CP(query_format), window->query_nick);
		malloc_strcpy(&ptr, lbuf);
	}
	else
		malloc_strcpy(&ptr, empty_string);
	return (ptr);
}

static	u_char	*
status_right_justify(window)
	Window	*window;
{
	u_char	*ptr = (u_char *) 0;

	malloc_strcpy(&ptr, UP("\f"));
	return (ptr);
}

static	u_char	*
status_notify_windows(window)
	Window	*window;
{
	u_char	refnum[10];
	int	doneone = 0;
	u_char	*ptr = (u_char *) 0;
	int	flag = 1;
	u_char	buf2[81];

	if (get_int_var(SHOW_STATUS_ALL_VAR) ||
	    window == window->screen->current_window)
	{
		buf2[0] = '\0';
		while ((window = traverse_all_windows(&flag)) != NULL)
		{
			if (window->miscflags & WINDOW_NOTIFIED)
			{
				if (!doneone)
				{
					doneone++;
					snprintf(CP(refnum), sizeof refnum, "%d", window->refnum);
				}
				else
					snprintf(CP(refnum), sizeof refnum, ",%d", window->refnum);
				my_strmcat(buf2, refnum, sizeof buf2);
			}
		}
	}
	if (doneone && notify_format)
	{
		u_char	lbuf[BIG_BUFFER_SIZE];

		snprintf(CP(lbuf), sizeof lbuf, CP(notify_format), buf2);
		malloc_strcpy(&ptr, lbuf);
	}
	else
		malloc_strcpy(&ptr, empty_string);
	return ptr;
}

static	u_char	*
status_clock(window)
	Window	*window;
{
	u_char	*ptr = (u_char *) 0;

	if ((get_int_var(CLOCK_VAR) && clock_format)  &&
	    (get_int_var(SHOW_STATUS_ALL_VAR) ||
	    (window == window->screen->current_window)))
	{
		u_char	lbuf[BIG_BUFFER_SIZE];
		u_char	time_str[16];

		snprintf(CP(lbuf), sizeof lbuf, CP(clock_format), update_clock(time_str, sizeof time_str, GET_TIME));
		malloc_strcpy(&ptr, lbuf);
	}
	else
		malloc_strcpy(&ptr, empty_string);
	return (ptr);
}

static	u_char	*
status_mode(window)
	Window	*window;
{
	u_char	*ptr = (u_char *) 0,
		*mode;

	if (window->current_channel && chan_is_connected(window->current_channel, window->server))
	{
		mode = get_channel_mode(window->current_channel,window->server);
		if (mode && *mode && mode_format)
		{
			u_char	lbuf[BIG_BUFFER_SIZE];

			snprintf(CP(lbuf), sizeof lbuf, CP(mode_format), mode);
			malloc_strcpy(&ptr, lbuf);
			return (ptr);
		}
	}
	malloc_strcpy(&ptr, empty_string);
	return (ptr);
}


static	u_char	*
status_umode(window)
	Window	*window;
{
	u_char	*ptr = (u_char *) 0;
	u_char	localbuf[10];
	u_char	*c;

	if (connected_to_server == 0)
		malloc_strcpy(&ptr, empty_string);
	else if ((connected_to_server == 1) && !get_int_var(SHOW_STATUS_ALL_VAR)
	    && (window->screen->current_window != window))
		malloc_strcpy(&ptr, empty_string);
	else
	{
		c = localbuf;
		if (get_server_flag(window->server, USER_MODE_I))
			*c++ = 'i';
		if (get_server_operator(window->server))
			*c++ = 'o';
		if (get_server_flag(window->server, USER_MODE_R))
			*c++ = 'r';
		if (get_server_flag(window->server, USER_MODE_S))
			*c++ = 's';
		if (get_server_flag(window->server, USER_MODE_W))
			*c++ = 'w';
		if (get_server_flag(window->server, USER_MODE_Z))
			*c++ = 'z';
		*c++ = '\0';
		if (*localbuf != '\0' && umode_format)
		{
			u_char	lbuf[BIG_BUFFER_SIZE];

			snprintf(CP(lbuf), sizeof lbuf, CP(umode_format), localbuf);
			malloc_strcpy(&ptr, lbuf);
		}
		else
			malloc_strcpy(&ptr, empty_string);
	}
	return (ptr);
}

static	u_char	*
status_chanop(window)
	Window	*window;
{
	u_char	*ptr = (u_char *) 0,
		*text;

	if (window->current_channel &&
	    chan_is_connected(window->current_channel, window->server) &&
	    get_channel_oper(window->current_channel, window->server) &&
	    (text = get_string_var(STATUS_CHANOP_VAR)))
		malloc_strcpy(&ptr, text);
	else
		malloc_strcpy(&ptr, empty_string);
	return (ptr);
}


static	u_char	*
status_hold_lines(window)
	Window	*window;
{
	u_char	*ptr = (u_char *) 0;
	int	num;
	u_char	localbuf[40];

	num = window->held_lines - window->held_lines%10;
	if (num)
	{
		u_char	lbuf[BIG_BUFFER_SIZE];

		snprintf(CP(localbuf), sizeof localbuf, "%d", num);
		snprintf(CP(lbuf), sizeof lbuf, CP(hold_lines_format), localbuf);
		malloc_strcpy(&ptr, lbuf);
	}
	else
		malloc_strcpy(&ptr, empty_string);
	return (ptr);
}

static	u_char	*
status_scrolled(window)
	Window	*window;
{
	u_char	*ptr = (u_char *) 0,
		*text;

Debug((2, "status_scrolled: lines = %d", window->scrolled_lines + window->new_scrolled_lines));
	if ((window->scrolled_lines + window->new_scrolled_lines) &&
	    (text = get_string_var(STATUS_SCROLLED_VAR)))
		malloc_strcpy(&ptr, text);
	else
		malloc_strcpy(&ptr, empty_string);
	return (ptr);
}

static	u_char	*
status_scrolled_lines(window)
	Window	*window;
{
	u_char	*ptr = (u_char *) 0;
	int	num;
	u_char	localbuf[40];

	num = window->scrolled_lines + window->new_scrolled_lines;
	if (num)
	{
		u_char	lbuf[BIG_BUFFER_SIZE];

		snprintf(CP(localbuf), sizeof localbuf, "%d", num);
		snprintf(CP(lbuf), sizeof lbuf, CP(hold_lines_format), localbuf);
		malloc_strcpy(&ptr, lbuf);
	}
	else
		malloc_strcpy(&ptr, empty_string);
Debug((2, "status_scrolled_lines: lines = %d, str = '%s'", num, ptr));
	return (ptr);
}

static	u_char	*
status_channel(window)
	Window	*window;
{
	int	num;
	u_char	*s, *ptr,
		channel[IRCD_BUFFER_SIZE + 1];

	s = window->current_channel;
	if (s && chan_is_connected(s, window->server))
	{
		u_char	lbuf[BIG_BUFFER_SIZE];

		if (get_int_var(HIDE_PRIVATE_CHANNELS_VAR) &&
		    is_channel_mode(window->current_channel,
				MODE_PRIVATE | MODE_SECRET,
				window->server))
			ptr = UP("*private*");
		else
			ptr = window->current_channel;
		strmcpy(channel, ptr, IRCD_BUFFER_SIZE);
		if ((num = get_int_var(CHANNEL_NAME_WIDTH_VAR)) &&
		    ((int) my_strlen(channel) > num))
			channel[num] = (u_char) 0;
		/* num = my_atoi(channel); */
		ptr = (u_char *) 0;
		snprintf(CP(lbuf), sizeof lbuf, CP(channel_format), channel);
		malloc_strcpy(&ptr, lbuf);
	}
	else
	{
		ptr = (u_char *) 0;
		malloc_strcpy(&ptr, empty_string);
	}
	return (ptr);
}

static	u_char	*
status_mail(window)
	Window	*window;
{
	u_char	*ptr = (u_char *) 0,
		*number;

	if ((get_int_var(MAIL_VAR) && (number = check_mail()) && mail_format) &&
	    (get_int_var(SHOW_STATUS_ALL_VAR) ||
	    (window == window->screen->current_window)))
	{
		u_char	lbuf[BIG_BUFFER_SIZE];

		snprintf(CP(lbuf), sizeof lbuf, CP(mail_format), number);
		malloc_strcpy(&ptr, lbuf);
	}
	else
		malloc_strcpy(&ptr, empty_string);
	return (ptr);
}

static	u_char	*
status_insert_mode(window)
	Window	*window;
{
	u_char	*ptr = (u_char *) 0,
		*text;

	text = empty_string;
	if (get_int_var(INSERT_MODE_VAR) && (get_int_var(SHOW_STATUS_ALL_VAR)
	    || (window->screen->current_window == window)))
	{
		if ((text = get_string_var(STATUS_INSERT_VAR)) == (u_char *) 0)
			text = empty_string;
	}
	malloc_strcpy(&ptr, text);
	return (ptr);
}

static	u_char	*
status_overwrite_mode(window)
	Window	*window;
{
	u_char	*ptr = (u_char *) 0,
		*text;

	text = empty_string;
	if (!get_int_var(INSERT_MODE_VAR) && (get_int_var(SHOW_STATUS_ALL_VAR)
	    || (window->screen->current_window == window)))
	{
	    if ((text = get_string_var(STATUS_OVERWRITE_VAR)) == (u_char *) 0)
		text = empty_string;
	}
	malloc_strcpy(&ptr, text);
	return (ptr);
}

static	u_char	*
status_away(window)
	Window	*window;
{
	u_char	*ptr = (u_char *) 0,
		*text;

	if (connected_to_server == 0)
		malloc_strcpy(&ptr, empty_string);
	else if ((connected_to_server == 1) && !get_int_var(SHOW_STATUS_ALL_VAR)
	    && (window->screen->current_window != window))
		malloc_strcpy(&ptr, empty_string);
	else
	{
		if (server_list[window->server].away &&
				(text = get_string_var(STATUS_AWAY_VAR)))
			malloc_strcpy(&ptr, text);
		else
			malloc_strcpy(&ptr, empty_string);
	}
	return (ptr);
}

static	u_char	*
status_user0(window)
	Window	*window;
{
	u_char	*ptr = (u_char *) 0,
	*text;

	if ((text = get_string_var(STATUS_USER_VAR)) &&
	    (get_int_var(SHOW_STATUS_ALL_VAR) ||
	    (window == window->screen->current_window)))
		malloc_strcpy(&ptr, text);
	else
		malloc_strcpy(&ptr, empty_string);
	return (ptr);
}

static  u_char    *
status_user1(window)
	Window  *window;
{
        u_char    *ptr = (u_char *) 0,
        *text;

        if ((text = get_string_var(STATUS_USER1_VAR)) &&
            (get_int_var(SHOW_STATUS_ALL_VAR) ||
            (window == window->screen->current_window)))
                malloc_strcpy(&ptr, text);
        else
                malloc_strcpy(&ptr, empty_string);
        return (ptr);
}

static  u_char    *
status_user2(window)
	Window  *window;
{
        u_char    *ptr = (u_char *) 0,
		*text;

        if ((text = get_string_var(STATUS_USER2_VAR)) &&
            (get_int_var(SHOW_STATUS_ALL_VAR) ||
            (window == window->screen->current_window)))
                malloc_strcpy(&ptr, text);
        else
                malloc_strcpy(&ptr, empty_string);
        return (ptr);
}

static  u_char    *
status_user3(window)
	Window  *window;
{
        u_char    *ptr = (u_char *) 0,
		*text;

        if ((text = get_string_var(STATUS_USER3_VAR)) &&
            (get_int_var(SHOW_STATUS_ALL_VAR) ||
            (window == window->screen->current_window)))
                malloc_strcpy(&ptr, text);
        else
                malloc_strcpy(&ptr, empty_string);
        return (ptr);
}

static	u_char	*
status_hold(window)
	Window	*window;
{
	u_char	*ptr = (u_char *) 0,
		*text;

	if (window->held && (text = get_string_var(STATUS_HOLD_VAR)))
		malloc_strcpy(&ptr, text);
	else
		malloc_strcpy(&ptr, empty_string);
	return (ptr);
}

static	u_char	*
status_oper(window)
	Window	*window;
{
	u_char	*ptr = (u_char *) 0,
		*text;

	if (!connected_to_server)
		malloc_strcpy(&ptr, empty_string);
	else if (get_server_operator(window->server) &&
			(text = get_string_var(STATUS_OPER_VAR)) &&
			(get_int_var(SHOW_STATUS_ALL_VAR) ||
			connected_to_server != 1 || 
			(window->screen->current_window == window)))
		malloc_strcpy(&ptr, text);
	else
		malloc_strcpy(&ptr, empty_string);
	return (ptr);
}

static	u_char	*
status_voice(window)
	Window	*window;
{
	u_char	*ptr = (u_char *) 0,
		*text;

	if (!connected_to_server)
		malloc_strcpy(&ptr, empty_string);
	else if (has_voice(window->current_channel, get_server_nickname(window->server), window->server) &&
			(text = get_string_var(STATUS_VOICE_VAR)) &&
			(get_int_var(SHOW_STATUS_ALL_VAR) ||
			connected_to_server != 1 || 
			(window->screen->current_window == window)))
		malloc_strcpy(&ptr, text);
	else
		malloc_strcpy(&ptr, empty_string);
	return (ptr);
}

static	u_char	*
status_window(window)
	Window	*window;
{
	u_char	*ptr = (u_char *) 0,
		*text;

	if ((text = get_string_var(STATUS_WINDOW_VAR)) &&
	    (number_of_windows() > 1) && (window->screen->current_window == window))
		malloc_strcpy(&ptr, text);
	else
		malloc_strcpy(&ptr, empty_string);
	return (ptr);
}

static	u_char	*
status_refnum(window)
	Window	*window;
{
	u_char	*ptr = (u_char *) 0;

	if (window->name)
		malloc_strcpy(&ptr, window->name);
	else
	{
		u_char	lbuf[10];

		snprintf(CP(lbuf), sizeof lbuf, "%u", window->refnum);
		malloc_strcpy(&ptr, lbuf);
	}
	return (ptr);
}

static	u_char	*
status_version(window)
	Window	*window;
{
	u_char	*ptr = (u_char *) 0;

	if ((connected_to_server == 1) && !get_int_var(SHOW_STATUS_ALL_VAR)
	    && (window->screen->current_window != window))
		malloc_strcpy(&ptr, empty_string);
	else
	{
		malloc_strcpy(&ptr, irc_version);
	}
	return (ptr);
}

static	u_char	*
status_null_function(window)
	Window	*window;
{
	u_char	*ptr = (u_char *) 0;

	malloc_strcpy(&ptr, empty_string);
	return (ptr);
}


syntax highlighted by Code2HTML, v. 0.9.1