
/*viewer.c - main viewer file*/

/*log viewer - very usefull program to see RSBAC (or other) log files.
 *
 * (c) Stanislav Ievlev inger@linux.ru.net
 */
#include <curses.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <signal.h>
#include <pwd.h>
#include <unistd.h>

#include "rklogd-viewer.h"

WINDOW *win, *view_win, *top_win;	/*view window */

/*curr_point, vertical and horizontal shift*/
int     curr_select = 0, curr_shift = 0, curr_h_shift = 0;

/*limits for horizontal scrolling*/
int     left_limit = 0, right_limit = 0;

unsigned long loaded = 0;	/*loaded string to view */
char   *logname = NULL;
FILE   *logfile = NULL;

/*forward*/
void    help_win (int, int);
void    about_win (int, int);
void    stat_menu (int, int);
void    file_menu (int, int);
void    options_menu (int, int);
void    exit_logger (char *);
void    select_line (int num, int mode);
void    line_print (WINDOW * curr_win, int y_point, int x_point, char *string,
		    int hlimit);

/*external functions*/
extern int in_filter (log_info tmp_log);
extern int open_log ();
extern int close_log ();
extern log_info read_log ();
extern log_info filter_log;

/*widgets*/
extern int confirm_win (char *head, char *text);
extern int menu_win (menu_item * items, int nr_items, char *title, int xpos,
		     int ypos);
extern int top_menu_win (top_menu_item * items, int nr_items);
extern void inform_win (char *head, char *text, char *buttontext);
extern char *enterline_win (char *head, char *val_name, char *old_value);
void    check_menu_win (menu_item * items, int nr_items, char *title,
			int posx, int posy);

/*usage of program*/
usage   usage_list[COUNT_OPTIONS] = { {"F1", "This window"},
{"F2", "Re-read log"},
{"F3", "Statictics"},
{"F4", "Select columns to view"},
{"F9", "Go to menu"},
{"u", "By user filter"},
{"r", "By request filter"},
{"p", "By program filter"},
{"t", "By target type"},
{"i", "By target id"},
{"a", "By attribute"},
{"z", "By result"},
{"q", "Exit program"},
};

/*stat menu*/
menu_item stat_items[3] = { {"1", "User denies   "},
{"2", "Program denies"},
{"3", "Target denies "}
};

/*file menu*/
menu_item file_items[4] = { {"1", "Open log    "},
{"1", "Refresh     "},
{"2", "------------"},
{"3", "Exit logger "}
};

/*options menu*/
menu_item options_items[7] = { {"1", "Filter by user...   "},
{"2", "Filter by program..."},
{"3", "Filter by target... "},
{"4", "Filter by request..."},
{"5", "Filter by tid...    "},
{"6", "Filter by attr...   "},
{"7", "Filter by result... "}
};

/*top menu*/
top_menu_item top_items[5] = { {file_menu, "File"},
{stat_menu, "Statistics"},
{options_menu, "Options"},
{help_win, "Help"},
{about_win, "About"}
};

/*width of columns*/
int     column[COUNT_DATA + 2] = { 20,	/*time */
	21,			/*request */
	5,			/*pid */
	30,			/*progname */
	10,			/*username */
	10,			/*target type */
	50,			/*tid */
	15,			/*attr */
	10,			/*value */
	20			/*result */
		/*by */
};

/*check views*/
menu_item view_check_items[COUNT_DATA + 1] = { {"*", "Time        "},
{"*", "Request     "},
{"*", "PID         "},
{"*", "Program     "},
{"*", "User        "},
{"*", "Target      "},
{"*", "Target ID   "},
{"*", "Attribute   "},
{"*", "Value       "},
{"*", "Result      "}
};

/*print clock*/
void
print_time ()
{
	time_t  now;

	now = time (0);
	wattrset (stdscr, COLOR_PAIR (2) | A_BOLD);
	mvwprintw (stdscr, LINES - 1, COLS - strlen ("time time time time"),
		   "%s", ctime (&now));
	alarm (1);
	refresh ();
	wrefresh (top_win);
}

/*print head of table*/
void
print_menu_top ()
{
	int     i = 0, horizontal = 1;
	char    tmpstr[MAX_LINE];

	wclear (top_win);
	wrefresh (top_win);

	init_pair (1, COLOR_BLACK, COLOR_CYAN);
	wattrset (top_win, COLOR_PAIR (1));

	while (i <= COUNT_DATA)
	{

		if (strchr (view_check_items[i].key, '*') == NULL)
		{
			/*don't display this */
			i++;
			continue;
		}

		switch (i)
		{
			case 0:
				strncpy (tmpstr, "Time", MAX_LINE);
				break;
			case 1:
				strncpy (tmpstr, "Request", MAX_LINE);
				break;
			case 2:
				strncpy (tmpstr, "PID", MAX_LINE);
				break;
			case 3:
				strncpy (tmpstr, "Program name", MAX_LINE);
				break;
			case 4:
				strncpy (tmpstr, "User", MAX_LINE);
				break;
			case 5:
				strncpy (tmpstr, "Target", MAX_LINE);
				break;
			case 6:
				strncpy (tmpstr, "Target Id", MAX_LINE);
				break;
			case 7:
				strncpy (tmpstr, "Attribute", MAX_LINE);
				break;
			case 8:
				strncpy (tmpstr, "Value", MAX_LINE);
				break;
			case 9:
				strncpy (tmpstr, "Result", MAX_LINE);
				break;
			default:
				break;
		}
		line_print (top_win, 0, horizontal + curr_h_shift, tmpstr,
			    COLS);
		horizontal += column[i];
		i++;
	}
	wrefresh (top_win);
}

/*print menu */
void
print_menu ()
{

	int     width = COLS;
	int     height = 2;

	top_win = newwin (height, width, 0, 0);

	/*bottom info */
	init_pair (2, COLOR_CYAN, COLOR_BLACK);
	wattrset (stdscr, COLOR_PAIR (2));
	mvwaddstr (stdscr, LINES - 1, 0, "Press F1 for help, F9 for menu");

	/*setup clock */
	signal (SIGALRM, print_time);
	print_time ();
	return;
}

/*print view window*/
void
print_view ()
{
	int     width = COLS, height = LINES - 2;

	/*view helper */
	view_win =
		newwin (height, width, (LINES - height) / 2,
			(COLS - width) / 2);
	/*view main */
	width = COLS - 2;
	height = LINES - 4;
	win = newwin (height, width, (LINES - height) / 2,
		      (COLS - width) / 2);

	/*menu */
	width = COLS;
	height = 1;
	top_win = newwin (height, width, 0, 0);

	/*check for failure */
	if ((win == NULL) || (view_win == NULL) || (top_win == NULL))
	{
		endwin ();
		return;
	}

	/*print top menu */
	print_menu_top ();

	init_pair (2, COLOR_CYAN, COLOR_BLACK);

	wattrset (view_win, COLOR_PAIR (2));
	wattrset (win, COLOR_PAIR (2));

	box (view_win, ACS_VLINE, ACS_HLINE);
	waddstr (view_win, "log-viewer (beta 1)");

	wrefresh (top_win);
	wrefresh (view_win);
	wrefresh (win);
	return;
}

/*special version of function for horizontal scroling*/
void
line_print (WINDOW * curr_win, int y_point, int x_point, char *string,
	    int hlimit)
{
	int     str_point = 0;

	if (x_point < 0)
		str_point += (-x_point);
	if (str_point > strlen (string))
		return;

	while (string[str_point])
	{
		if ((str_point + x_point) > hlimit)
			return;
		mvwaddch (curr_win, y_point, (str_point + x_point),
			  string[str_point]);
		str_point++;

	}			/*while we have a string */
	return;
}

/*print one line*/
void
print_log_line (log_info curr_info, int point)
{
	int     horizontal = 0, count = 0;
	char   *tmpstr;

	while (count <= COUNT_DATA)
	{
		if (strchr (view_check_items[count].key, '*') == NULL)
		{
			/*don't display this */
			count++;
			continue;
		}

		switch (count)
		{
			case 0:
				tmpstr = curr_info.time;
				break;
			case 1:
				tmpstr = curr_info.request;
				break;
			case 2:
				tmpstr = malloc (MAX_NAME);
				snprintf (tmpstr, MAX_NAME, "%u",
					  curr_info.pid);
				break;
			case 3:
				tmpstr = curr_info.progname;
				break;
			case 4:
				tmpstr = curr_info.username;
				break;
			case 5:
				tmpstr = curr_info.target_type;
				break;
			case 6:
				tmpstr = curr_info.tid;
				break;
			case 7:
				tmpstr = curr_info.attr;
				break;
			case 8:
				tmpstr = malloc (MAX_NAME);
				snprintf (tmpstr, MAX_NAME, "%u",
					  curr_info.value);
				break;
			case 9:
				tmpstr = curr_info.result;
				break;
			default:
				break;
		}

		line_print (win, point, curr_h_shift + horizontal, tmpstr,
			    COLS - 4);

		if ((count == 2) || (count == 8))
			free (tmpstr);

		horizontal += column[count];

		count++;
	}
}

/*light version of re-reading*/
void
light_fill_view ()
{
	int     curr_point;

	/*clear window */
	wclear (win);
	wrefresh (win);

	/*set color */
	init_pair (3, COLOR_YELLOW, COLOR_BLACK);
	wattrset (win, COLOR_PAIR (3));

	/*draw items per screen */
	for (curr_point = 0;
	     (curr_point < LINES - 2) && (curr_point < loaded); curr_point++)
		if (!(in_filter (log_buffer[curr_point + curr_shift])))
			print_log_line (log_buffer[curr_point + curr_shift],
					curr_point);

	/*set line as selected */
	select_line (curr_select, 1);
	wrefresh (win);
}

/*re-read data*/
void
fill_view ()
{
	log_info curr_info;
	int     curr_point;

	/*init data */
	curr_shift = 0;
	curr_select = 0;
	loaded = 0;
	wclear (win);
	wrefresh (win);

	init_pair (3, COLOR_YELLOW, COLOR_BLACK);
	wattrset (win, COLOR_PAIR (3));

	open_log ();
	for (curr_point = 0, loaded = 0; loaded < MAX_BUFFER;)
	{			/*while */
		/*read next line */

		curr_info = read_log ();
		log_buffer[curr_point] = curr_info;

		if (curr_info.res == -1 || curr_info.res == -2)
			break;
		if (curr_info.res == -3)
			continue;

		print_log_line (curr_info, curr_point);
		loaded++;
		curr_point++;
	}

	close_log ();
	wrefresh (win);
}

/* select/unselect line */
void
select_line (int num, int mode)
{
	log_info curr_info = log_buffer[num + curr_shift];

	if (!(loaded))
		return;		/*return if list is empty */

	if (mode)
	{
		init_pair (4, COLOR_BLACK, COLOR_YELLOW);
		wattrset (win, COLOR_PAIR (4));
	} else
	{
		wattrset (win, COLOR_PAIR (3));
	}

	print_log_line (curr_info, num);

	wrefresh (win);

	return;
}

/*horizontal scrolling*/
void
h_scroll_view (int num)
{
	curr_h_shift += num;
	light_fill_view ();
	print_menu_top ();
}

/*vertical scrolling*/
void
scroll_view (int num)
{
	log_info curr_info;

	/*increment or decrement window shift */
	if (num > 0)
	{
		curr_shift++;
	} else
	{
		curr_shift--;
	}

	/*get last or first line */
	if (num > 0)
	{
		curr_info = log_buffer[LINES - 5 + curr_shift];
	} else
	{
		curr_info = log_buffer[curr_shift];
	}

	/*scroll window down */
	wscrl (win, num);

	/*print last line */
	print_log_line (curr_info, (num > 0) ? LINES - 5 : 0);

	/*refresh data */
	wrefresh (win);
}

/*draw about window*/
void
about_win (int xpos, int ypos)
{
	WINDOW *tmp_win;

	int     width = 50, height = 10;

	tmp_win =
		newwin (height, width, (LINES - height) / 2,
			(COLS - width) / 2);
	init_pair (6, COLOR_WHITE, COLOR_BLACK);

	wattrset (tmp_win, COLOR_PAIR (2));
	box (tmp_win, ACS_VLINE, ACS_HLINE);
	mvwaddstr (tmp_win, 0,
		   (int) ((width - strlen ("About this ...")) / 2),
		   "About this ...");

	wattrset (tmp_win, COLOR_PAIR (2) | A_BOLD);
	mvwaddstr (tmp_win, (int) (height / 2) - 1,
		   (int) ((width - strlen ("Smart logger for RSBAC")) / 2),
		   "Smart logger for RSBAC");
	mvwaddstr (tmp_win, (int) (height / 2) + 1,
		   (int) ((width -
			   strlen
			   ("(c) Stanislav Ievlev <inger@linux.ru.net>")) /
			  2), "(c) Stanislav Ievlev <inger@linux.ru.net>");
	mvwaddstr (tmp_win, (int) (height / 2) + 2,
		   (int) ((width - strlen ("2000")) / 2), "2000");
	wrefresh (tmp_win);
	(void) getch ();

	delwin (tmp_win);
	redrawwin (win);
}

/*draw help window*/
void
help_win (int xpos, int ypos)
{
	WINDOW *tmp_win;

	int     width = 35, height = 15;
	int     curr_point;

	tmp_win =
		newwin (height, width, (LINES - height) / 2,
			(COLS - width) / 2);
	init_pair (6, COLOR_WHITE, COLOR_BLACK);

	wattrset (tmp_win, COLOR_PAIR (2));
	box (tmp_win, ACS_VLINE, ACS_HLINE);
	waddstr (tmp_win, "HELP WINDOW");

	for (curr_point = 0; curr_point < COUNT_OPTIONS; curr_point++)
	{
		wattrset (tmp_win, COLOR_PAIR (6) | A_BOLD);
		mvwaddstr (tmp_win, curr_point + 1, 1,
			   usage_list[curr_point].key);

		wattrset (tmp_win, COLOR_PAIR (2));
		mvwprintw (tmp_win, curr_point + 1, 6, "%s",
			   usage_list[curr_point].description);
	}

	wrefresh (tmp_win);

	(void) getch ();
	delwin (tmp_win);
	redrawwin (win);
}

/*draw filter window*/
void
filter_win (char type)
{
	char   *tmpstr;
	char   *value_name = malloc (MAX_LINE);

	switch (type)
	{
		case KEY_USER:
			strncpy (value_name, "Username", MAX_LINE);
			tmpstr = filter_log.username;
			break;
		case KEY_REQUEST:
			strncpy (value_name, "Request", MAX_LINE);
			tmpstr = filter_log.request;
			break;
		case KEY_PROGRAM:
			strncpy (value_name, "Program", MAX_LINE);
			tmpstr = filter_log.progname;
			break;
		case KEY_TARGET_TYPE:
			strncpy (value_name, "Target type", MAX_LINE);
			tmpstr = filter_log.target_type;
			break;
		case KEY_TARGET_ID:
			strncpy (value_name, "Target ID", MAX_LINE);
			tmpstr = filter_log.tid;
			break;
		case KEY_ATTR:
			strncpy (value_name, "Attribute", MAX_LINE);
			tmpstr = filter_log.attr;
			break;
		case KEY_RESULT:
			strncpy (value_name, "Result", MAX_LINE);
			tmpstr = filter_log.result;
			break;

	}
	strncpy (tmpstr, enterline_win ("View Filter", value_name, tmpstr),
		 MAX_NAME);

	free (value_name);
}

/*compute deny count of item*/
int
stat_item_deny (int type, char *who)
{
	int     count = 0, res = 0;

	while (count < loaded)
	{
		char   *tmpstr;

		switch (type)
		{
			case KEY_USER:
				tmpstr = log_buffer[count].username;
				break;
			case KEY_PROGRAM:
				tmpstr = log_buffer[count].progname;
				break;
			case KEY_TARGET_TYPE:
				tmpstr = log_buffer[count].target_type;
				break;
			default:
				break;
		}
		if ((strstr (log_buffer[count].result, "NOT")) &&
		    (!(strcmp (who, tmpstr))))
			res++;
		count++;
	}

	return res;
}

/*draw statistic window*/
void
stat_deny_win (int type, char *title)
{
	WINDOW *tmp_win;
	int     key;
	int     width = 70, height = 20, curr_point = 1;
	struct passwd *user_info_p;

	tmp_win =
		newwin (height, width, (LINES - height) / 2,
			(COLS - width) / 2);

	wattrset (tmp_win, COLOR_PAIR (2));
	box (tmp_win, ACS_VLINE, ACS_HLINE);
	wattrset (tmp_win, COLOR_PAIR (2) | A_BOLD);
	mvwaddstr (tmp_win, 0, (int) ((width - strlen (title)) / 2), title);
	wattrset (tmp_win, COLOR_PAIR (2));

	if (type == KEY_USER)
	{
		/*process all users */
		while ((user_info_p = getpwent ()))
		{
			if (((user_info_p->pw_uid) >= MIN_USER_LIMIT) ||
			    ((user_info_p->pw_uid) == 0) ||
			    ((user_info_p->pw_uid) == 400))
				mvwprintw (tmp_win, curr_point++, 1,
					   "user %s\tdenies %u times",
					   user_info_p->pw_name,
					   stat_item_deny (KEY_USER,
							   user_info_p->
							   pw_name));
		}		/*while */
		endpwent ();
		/*end process all users */
	};			/*if KEY_USER */

	if (type == KEY_PROGRAM || type == KEY_TARGET_TYPE)
	{
#define MAX_PROGS 30
		char    programs[MAX_PROGS][MAX_LINE];
		int     finded = 0, i, j;

		for (i = 0; i < loaded; i++)
		{
			for (j = 0;
			     ((j < finded)
			      &&
			      (strcmp
			       ((type ==
				 KEY_PROGRAM) ? log_buffer[i].
				progname : log_buffer[i].target_type,
				programs[j]))); j++) ;
			if ((j >= finded) && (finded < MAX_PROGS))
				strncpy (programs[finded++],
					 (type ==
					  KEY_PROGRAM) ? log_buffer[i].
					 progname : log_buffer[i].target_type,
					 MAX_LINE);
		}
		for (i = 0; i < finded; i++)
			mvwprintw (tmp_win, curr_point++, 1,
				   "%s %s\tdenies %u times",
				   (type ==
				    KEY_PROGRAM) ? "program" : "target type",
				   programs[i], stat_item_deny (type,
								programs[i]));

	}
	wrefresh (tmp_win);

	/*wait key pressed */
	key = getch ();
	delwin (tmp_win);

	/*refresh data */
	redrawwin (win);
	wrefresh (win);
}

/*draw data window*/
void
data_win ()
{
	WINDOW *tmp_win;

	int     width = 60, height = 15, curr_point;
	log_info curr_info = log_buffer[curr_select + curr_shift];
	char   *tmpstr;

	tmp_win =
		newwin (height, width, (LINES - height) / 2,
			(COLS - width) / 2);

	wattrset (tmp_win, COLOR_PAIR (2));
	box (tmp_win, ACS_VLINE, ACS_HLINE);
	waddstr (tmp_win, "FULL LOG DATA");

	init_pair (5, COLOR_RED, COLOR_BLACK);

	for (curr_point = 0; curr_point <= COUNT_DATA; curr_point++)
	{
		wattrset (tmp_win, COLOR_PAIR (2) | A_BOLD);
		switch (curr_point)
		{
			case 0:
				mvwaddstr (tmp_win, curr_point + 1, 1,
					   "time:");
				break;
			case 1:
				mvwaddstr (tmp_win, curr_point + 1, 1,
					   "request:");
				break;
			case 2:
				mvwaddstr (tmp_win, curr_point + 1, 1,
					   "PID:");
				break;
			case 3:
				mvwaddstr (tmp_win, curr_point + 1, 1,
					   "program:");
				break;
			case 4:
				mvwaddstr (tmp_win, curr_point + 1, 1,
					   "username:");
				break;
			case 5:
				mvwaddstr (tmp_win, curr_point + 1, 1,
					   "target type:");
				break;
			case 6:
				mvwaddstr (tmp_win, curr_point + 1, 1,
					   "target ID:");
				break;
			case 7:
				mvwaddstr (tmp_win, curr_point + 1, 1,
					   "Attribute:");
				break;
			case 8:
				mvwaddstr (tmp_win, curr_point + 1, 1,
					   "Value:");
				break;
			case 9:
				mvwaddstr (tmp_win, curr_point + 1, 1,
					   "result:");
				break;

			default:
				break;
		}
		wattrset (tmp_win, COLOR_PAIR (2));
		switch (curr_point)
		{
			case 0:
				tmpstr = curr_info.time;
				break;
			case 1:
				tmpstr = curr_info.request;
				break;
			case 2:
				tmpstr = malloc (MAX_NAME);
				snprintf (tmpstr, MAX_NAME, "%u",
					  curr_info.pid);
				break;
			case 3:
				tmpstr = curr_info.progname;
				break;
			case 4:
				tmpstr = curr_info.username;
				break;
			case 5:
				tmpstr = curr_info.target_type;
				break;
			case 6:
				tmpstr = curr_info.tid;
				break;
			case 7:
				tmpstr = curr_info.attr;
				break;
			case 8:
				tmpstr = malloc (MAX_NAME);
				snprintf (tmpstr, MAX_NAME, "%u",
					  curr_info.value);
				break;
			case 9:
				tmpstr = curr_info.result;
				break;

			default:
				break;
		}
		mvwaddstr (tmp_win, curr_point + 1, 15, tmpstr);

		if ((curr_point == 2) || (curr_point == 8))
			free (tmpstr);
	}

	wrefresh (tmp_win);

	/*wait any key pressed */
	(void) getch ();
	delwin (tmp_win);
	redrawwin (win);
}

/*statistics menu */
void
stat_menu (int xpos, int ypos)
{
	int     res = 0;

	res = menu_win (stat_items, 3, "Statistics", xpos, ypos);
	if (res == -1)
		return;

	switch (res)
	{
		case 1:
			stat_deny_win (KEY_USER, "By User Deny Statistics");
			break;
		case 2:
			stat_deny_win (KEY_PROGRAM,
				       "By Program Deny Statistics");
			break;
		case 3:
			stat_deny_win (KEY_TARGET_TYPE,
				       "By Target Deny Statistics");
			break;
		default:
			break;
	}
}

/*file menu*/
void
file_menu (int xpos, int ypos)
{
	int     res = 0;

	res = menu_win (file_items, 4, "   File   ", xpos, ypos);
	if (res == -1)
		return;

	switch (res)
	{
		case 1:
			strncpy (logname,
				 enterline_win ("Log-file name", "File name",
						logname), MAX_NAME);
		case 2:	/*refresh */
			fill_view ();
			break;
		case 3:	/*separator */
			break;
		case 4:	/*exit */
			if (confirm_win ("Wow!", "Exit this program?"))
				exit_logger ("");
			break;
		default:
			break;
	}
}

/*options*/
void
options_menu (int xpos, int ypos)
{
	int     res = 0;

	res = menu_win (options_items, 7, "    Options    ", xpos, ypos);
	if (res == -1)
		return;

	switch (res)
	{
		case 1:
			res = KEY_USER;
			break;
		case 2:
			res = KEY_PROGRAM;
			break;
		case 3:
			res = KEY_TARGET_TYPE;
			break;
		case 4:
			res = KEY_REQUEST;
			break;
		case 5:
			res = KEY_TARGET_ID;
			break;
		case 6:
			res = KEY_ATTR;
			break;
		case 7:
			res = KEY_RESULT;
			break;
		default:
			break;
	}

	filter_win (res);
	fill_view ();
}

/*exit this program*/
void
exit_logger (char *exit_str)
{
	if (exit_str[0] != 0)
		inform_win ("Error", exit_str, "  OK  ");

	/*end of work */
	free (logname);
	clear ();
	refresh ();

	standend ();
	endwin ();
	fprintf (stderr, "%s\n", exit_str);
	exit (EXIT_SUCCESS);
}

/*fill again after selecting columns to see*/
void
fill_again ()
{
	int     i = 0;

	right_limit = 0;
	left_limit = 0;
	curr_h_shift = 0;

	while (i <= COUNT_DATA)
	{
		if (strchr (view_check_items[i].key, '*') == NULL)
		{
			/*don't display this */
			i++;
			continue;
		}

		right_limit += column[i];
		i++;
	}

	fill_view ();
	print_menu_top ();
}

/*main work*/
int
main (int argc, char *argv[])
{
	int     key;
	int     do_exit;

	/*first compute of right horizontal limit */
	for (key = 0; key <= COUNT_DATA; key++)
		right_limit += column[key];

	logname = malloc (MAX_LINE);
	if (argc > 1)
	{
		strncpy (logname, argv[1], MAX_LINE);
	} else
	{
		strncpy (logname, LOG_FILE_NAME, MAX_LINE);
	}

	/*init curses */
	initscr ();
	start_color ();

	/*print menu and view */
	print_menu ();
	print_view ();

	/*fill view-window with data */
	fill_view ();

	/*allow to scroll windows */
	scrollok (win, TRUE);
	keypad (stdscr, 1);
	keypad (win, 1);
	noecho ();
	nonl ();

	/*main loop */
	do_exit = 1;
	while (1)
	{
		select_line (curr_select, 1);
		key = getch ();
		switch (key)
		{
			case KEY_DOWN:
				if ((curr_select + curr_shift) < (loaded - 1))
					select_line (curr_select++, 0);
				if (curr_select > LINES - 5)
				{
					scroll_view (1);
					curr_select--;
				}

				break;
			case KEY_UP:
				if ((curr_select + curr_shift) >= 0)
					select_line (curr_select--, 0);
				if (curr_select < 0)
				{
					curr_select++;
					if (curr_shift > 0)
						scroll_view (-1);
				}

				break;
			case KEY_RIGHT:
				if ((right_limit) > (COLS - 3))
				{
					left_limit--;
					right_limit--;
					h_scroll_view (-1);
				}
				break;
			case KEY_LEFT:
				if ((left_limit) < 0)
				{
					left_limit++;
					right_limit++;
					h_scroll_view (1);
				}
				break;
			case KEY_DONE:
			case KEY_EXT:
				if (confirm_win
				    ("Exit", "Do you want to exit?"))
					exit_logger ("");
				break;
			case KEY_F (1):
				help_win (0, 0);
				break;
			case KEY_F (2):
				fill_view ();
				break;
			case KEY_F (3):
				stat_menu (1, 1);
				break;
			case KEY_F (4):
				(void) check_menu_win (view_check_items,
						       COUNT_DATA + 1,
						       "   View   ", 1, 1);
				fill_again ();
				break;
			case KEY_F (9):
				top_menu_win (top_items, 5);
				break;
			case KEY_ENT:
			case KEY_DATA:
				data_win ();
				break;
			case KEY_USER:
				filter_win (KEY_USER);
				fill_view ();
				break;
			case KEY_TARGET_TYPE:
				filter_win (KEY_TARGET_TYPE);
				fill_view ();
				break;
			case KEY_PROGRAM:
				filter_win (KEY_PROGRAM);
				fill_view ();
				break;
			case KEY_REQUEST:
				filter_win (KEY_REQUEST);
				fill_view ();
				break;
			case KEY_TARGET_ID:
				filter_win (KEY_TARGET_ID);
				fill_view ();
				break;
			case KEY_ATTR:
				filter_win (KEY_ATTR);
				fill_view ();
				break;
			case KEY_RESULT:
				filter_win (KEY_RESULT);
				fill_view ();
				break;

			default:
				break;
		}
	}			/*while */

	exit_logger ("strange exit");
}
