/******************************************************************************
 * This file is part of a software distribution, which is furnished under the *
 * terms of a license.  Use of this software  by any means is subject to this *
 * license  and  signifies  the  acceptance of  the  licensing  terms  stated *
 * therein. Please see  the file LICENSE in the  top-level directory  of this *
 * software  distribution  for detailed copyright  disclaimers  and licensing *
 * terms.                                                                     *
 ******************************************************************************
 * Copryight (c) by Andreas S. Wetzel - All rights reserved.                  *
 ******************************************************************************/

/* $Id: subr.c,v 1.5 2002/06/23 23:29:37 mickey Exp $ */

#include <vchat.h>
#include <proto_common.h>

#include <fcntl.h>
#include <signal.h>

#if HAVE_SYS_SELECT_H
  #include <sys/select.h>
#endif

/*** Externals ***/

extern int in_chat_window;

extern ED *ed;
extern VP vp;
extern VCONN sconn;
extern VTCAP vtcap;
extern VTIMER vtimer;

/*
 * void history_init(void);
 *
 * Initialize command history buffer.
 */

void history_init(void)
{
	if(vp.history_lines > 0)
	{
		++vp.history_lines;

		if((vp.history = (u_char **)calloc(vp.history_lines, sizeof(u_char *))) == NULL)
		{
			/*** FAILURE: Disable command history ***/

			vp.history_lines = 0;
		}
	}
	else
	{
		vp.history	 = NULL;
		vp.history_lines = 0;
	}

	vp.history_start	= 0;
	vp.history_current	= 0;
	vp.history_next		= 0;
	vp.history_cycle	= 0;
}

/*
 * void history_exit(void);
 *
 * Free all buffers used for the command history
 */

void history_exit(void)
{
	int	i;
	u_char	*ptr;

	if(vp.history != NULL)
	{
		for(i = 0; i < vp.history_lines; i++)
		{
			ptr = vp.history[i];

			if(ptr != NULL)
			{
				free(ptr);
			}
		}

		free(vp.history);
	}
}

/*
 * void history_save(u_char *text);
 *
 * Store the commandline pointed to by <text> at the
 * next buffer position in the command history.
 */

void history_save(u_char *text)
{
	size_t	size = strlen(text) + 1;
	u_char	*newbuf;

	/*
	 * If command history is disabled, there is
	 * nothing left to to in here.
	 */

	if(!vp.history_lines)
		return;

	/*
	 * Allocate a new buffer to store the text into.
	 * If this fails the history will be unmodified.
	 */

	if((newbuf = (u_char *)calloc(1, size)) == NULL)
	{
		return;
	}

	/*
	 * If the buffer to which vp.history_next points
	 * was already used then free the buffer at first.
	 */

	if(vp.history[vp.history_next] != NULL)
	{
		free(vp.history[vp.history_next]);
	}

	/*
	 * Store the text into the newly allocated buffer
	 * and store address of new buffer in the history vector
	 */

	strncpy(newbuf, text, size);
	vp.history[vp.history_next++] = newbuf;

	/*
	 * Set the index to the next buffer
	 */

	if(vp.history_next >= vp.history_lines)
	{
		/*
		 * History buffer has filled up, enable cycling
		 */

		vp.history_cycle = 1;
		vp.history_next = 0;
	}

	vp.history_current = vp.history_next;

	/*
	 * If the cycle history flag is set, then
	 * move the starting position up one place.
	 */

	if(vp.history_cycle)
	{
		if(++vp.history_start >= vp.history_lines)
			vp.history_start = 0;
	}
}

/*
 * void vsleep(u_long sec, u_long usec);
 *
 * Suspend program execution for <sec> seconds
 * plus <usec> microseconds.
 */

void vsleep(u_long sec, u_long usec)
{
	int ret;
	struct timeval tm;
	struct timeval start;
	struct timeval end;
	struct timeval elapsed;
	struct timeval remain;

	tm.tv_sec = sec;
	tm.tv_usec = usec;

restart:

	timestamp(&start);
	ret = select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tm);
	timestamp(&end);

	if(ret == -1 && errno != EINTR)
		return;

	BCOPY(diff_t(&start, &end), &elapsed, sizeof(struct timeval));
	BCOPY(diff_t(&elapsed, &tm), &remain, sizeof(struct timeval));

	if(remain.tv_sec >= 0 && remain.tv_usec >= 0)
	{
		tm = remain;
		goto restart;
	}
}

/*
 * void str_lower(char *s);
 *
 * Convert the string pointed to by <s> into lowercase
 */

void str_lower(char *s)
{
	while(*s != '\0')
	{
		*s = (*s >= 'A' && *s <= 'Z') ? *s + 0x20 : *s;
		++s;
	}
}

/*
 * char *pr_timer(time_t tim);
 *
 * Return a pointer to a sring representing the date/time from <tim>
 */

char *pr_timer(time_t tim)
{
	static char prt[30];

	strftime((char *)&prt, 30, "%a %R", localtime(&tim));

	return(prt);
}

/*
 * void pbc_enable(void);
 *
 * Enable put-back-cursor timer event
 */

void pbc_enable(void)
{
	vtimer.pbc_timer = vp.cursordelay;
	vp.vclock_pbc_enable = 0xff;
}

/*
 * void pbc_disable(void);
 *
 * Disable put-back-cursor timer event
 */

void pbc_disable(void)
{
	vtimer.pbc_timer = vp.vclock_pbc_enable = 0;
}

/*
 * void line_update(void);
 *
 * Clear and redraw the current input line pointed to by
 * the global ED *ed pointer.
 */

void line_update(void)
{
	char *cptr;
	char *endp;

	/*
	 * Prevent us from being interrupted
	 */

	vlock(LOCK, (V_IO | V_TIMER | V_WINCH));

	/*
	 * Print the prompt (if any)
	 */

	mv(1, vtcap.rows);
	in_chat_window = 0;

	if(ed->prompt)
		cprintf(input, "%s", ed->prompt);

	/*
	 * Redraw input line
	 */

	if(!(ed->flags & ED_NO_ECHO))
	{
		endp = (ed->margin + (vtcap.cols - ed->offset));

		for(cptr = ed->margin; cptr < endp && *cptr != '\0'; cptr++)
			putchar(*cptr);

		if(cptr < endp)
		{
			if(vtcap.clear2eol)
				tputs(vtcap.clear2eol, 1, (void *)outc);
			else if(vtcap.clear2eod)
				tputs(vtcap.clear2eod, 1, (void *)outc);
		} 

		if(ED_SCRPOS != ((endp - ed->margin) + ed->offset))
			mv(ED_SCRPOS, vtcap.rows);
	}
	else
	{
		/*
		 * Clear the line remaining right of the prompt
		 */

		if(vtcap.clear2eol)
			tputs(vtcap.clear2eol, 1, (void *)outc);
		else if(vtcap.clear2eod)
			tputs(vtcap.clear2eod, 1, (void *)outc);
	}

	vlock(UNLOCK, (V_IO | V_TIMER | V_WINCH));
}

/*
 * void nop(void)
 *
 * Simply do nothing - this is used for unknown keys in input_line();
 */

void nop(void)
{
	/* PENG! */
}

/*
 * int escape_str(u_char *str, u_char *buf, size_t len);
 *
 * Read input from the string pointed to by <str> escaping
 * all occurances of a CSI or space character with a CSI
 * character. At most <len> bytes of output will be written
 * to the buffer pointed to by <buf>.
 */

int escape_str(u_char *str, u_char *buf, size_t len)
{
	int	cnt	= 0;

	if(str == NULL || buf == NULL)
		return(0);

	for(;;)
	{
		if(*str == '\0')
		{
			*buf = '\0';
			return(cnt);
		}
		else if(*str == CSI)
		{
			if(cnt < (len -1))
			{
				*buf++ = CSI;
				++cnt;
			}
			else
			{
				*buf = '\0';
				return(cnt);
			}
	
			if(cnt < (len -1))
			{
				*buf++ = CSI;
				++cnt;
			}
			else
			{
				*buf = '\0';
				return(cnt);
			}

			++str;
		}
		else if(*str == ' ')
		{
			if(cnt < (len -1))
			{
				*buf++ = CSI;
				++cnt;
			}
			else
			{
				*buf = '\0';
				return(cnt);
			}

			if(cnt < (len - 1))
			{
				*buf++ = ' ';
				++cnt;
			}
			else
			{
				*buf = '\0';
				return(cnt);
			}

			++str;
		}
		else
		{
			if(cnt < (len - 1))
			{
				*buf++ = *str++;
				++cnt;
			}
			else
			{
				*buf = '\0';
				return(cnt);
			}
		}
	}
}

/*
 * int netmask_bits(struct in_addr netmask);
 *
 * Get the number of mask bits in the specified netmask
 */

int netmask_bits(struct in_addr netmask)
{
	u_int32_t	mask	= ntohl(netmask.s_addr);
	int		bits	= 0;
	int		flg	= 0;
	int		i;

	for(i = 0; i < (CHAR_BIT * sizeof(u_int32_t)); i++)
	{
		if(mask & 0x00000001)
		{
			flg = 1;
			++bits;
		}
		else
		{
			if(flg)
				return(-1);
		}

		mask = (mask >> 1);
	}

	return(bits);
}

/*
 * void netmask_create(int bits, struct in_addr *netmask);
 *
 * Create a netmask with the number of <bits> specified, and store
 * it into the in_addr struct pointed to by <netmask>.
 */

void netmask_create(int bits, struct in_addr *netmask)
{
	netmask->s_addr = htonl(~0 << ((CHAR_BIT * sizeof(u_int32_t)) - bits));
}

/*
 * int permission_mask(char *privname, u_int32_t *maskptr);
 *
 * Store the binary representation for the permission named
 * by the <privname> parameter into the permission mask pointed
 * to by the <maskptr> parameter. Returns 0 if successfull or
 * -1 in case the specified permission name was invalid.
 */

int permission_mask(char *permname, u_int32_t *maskptr)
{
	str_lower(permname);

	if(!strcmp(permname, "add"))
		*maskptr = AUTH_ADD;
	else if(!strcmp(permname, "delete"))
		*maskptr = AUTH_DELETE;
	else if(!strcmp(permname, "chacc"))
		*maskptr = AUTH_CHACCPERM;
	else if(!strcmp(permname, "chmod"))
		*maskptr = AUTH_CHMODPERM;
	else if(!strcmp(permname, "kill"))
		*maskptr = AUTH_KILL;
	else if(!strcmp(permname, "bcast"))
		*maskptr = AUTH_BROADCAST;
	else if(!strcmp(permname, "acl"))
		*maskptr = AUTH_ACL;
	else if(!strcmp(permname, "query"))
		*maskptr = AUTH_QUERY;
	else if(!strcmp(permname, "sopt"))
		*maskptr = AUTH_SOPT;
	else if(!strcmp(permname, "fix"))
		*maskptr = AUTH_FIXCHAN;
	else if(!strcmp(permname, "status"))
		*maskptr = AUTH_STATUS;
	else if(!strcmp(permname, "exclude"))
		*maskptr = AUTH_EXCLUDE;
	else
		return(-1);

	return(0);
}

/*
 * int clopt_mask(char *optname, u_int32_t *maskptr);
 *
 * Store the binary representation for the client option named
 * by the <optname> parameter into the client option mask pointed
 * to by the <maskptr> parameter. Returns 0 if successfull or
 * -1 in case the specified client option name was invalid.
 */

int clopt_mask(char *optname, u_int32_t *maskptr)
{
	str_lower(optname);

	if(!strcmp(optname, "wakeup"))
		*maskptr = CL_OPT_WAKEUP;
	else if(!strcmp(optname, "sgnmsg"))
		*maskptr = CL_OPT_SGNMSG;
	else if(!strcmp(optname, "prvecho"))
		*maskptr = CL_OPT_PRVECHO;
	else
		return(-1);

	return(0);
}

/*
 * int svopt_mask(char *optname, u_int32_t *maskptr);
 *
 * Store the binary representation for the server option named
 * by the <optname> parameter into the server option mask pointed
 * to by the <maskptr> parameter. Returns 0 if successfull or
 * -1 in case the specified server option name was invalid.
 */

int svopt_mask(char *optname, u_int32_t *maskptr)
{
	str_lower(optname);

	if(!strcmp(optname, "show_ip"))
		*maskptr = SV_OPT_SHOW_IP;
	else if(!strcmp(optname, "mail_inv"))
		*maskptr = SV_OPT_MAIL_INV;
	else if(!strcmp(optname, "reg_only"))
		*maskptr = SV_OPT_REG_ONLY;
	else if(!strcmp(optname, "flood_guard"))
		*maskptr = SV_OPT_FLOOD_GUARD;
	else
		return(-1);

	return(0);
}


syntax highlighted by Code2HTML, v. 0.9.1