/*
    yamm, Yet Another Micro Monitor
    mpreprocess.c
    Copyright (C) 1992  Andrea Marangoni
    Copyright (C) 1994, 1995  Riccardo Facchetti

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "kversion.h"

#include <stdio.h>
#include <signal.h>
#if !defined(linux) || (KERNEL_VERSION < 1001076)
#include <string.h>
#else
#include <linux/string.h>
#endif /* !linux || KERNEL_VERSION < 1001076 */
#if defined(linux)
#include <sys/resource.h>
#endif /* linux */
#if defined(NCURSES)
#include "ncurses.h"
#else
#include <curses.h>
#endif /* NCURSES */

#include "yamm.h"

/*
 * If you want disable "P" and "K" comment out this lines
 */
#if !defined(SU_COMMAND)
#define SU_COMMAND "su"
#endif /* !SU_COMMAND */

#if !defined(SU_KILLUSER)
#define SU_KILLUSER 9
#endif /* !SU_KILLUSER */

#if !defined(SU_KILLPROCESS)
#define SU_KILLPROCESS 9
#endif /* !SU_KILLPROCESS */


void mpreprocess( int ac, char *av[], char *cmd_line )
{
	int car;
	extern char *optarg;
#if !defined (linux)
	extern long atol();
#endif /* !linux */

	if ( !av ) {
		car = ac; 
		goto jump;  /* :-) */
	}

#if !defined(linux)
	while ( ( car = getopt ( ac, av, cmd_line ) ) != EOF )
#else
/*
 * Linux's getopt is a little different form the one of HP-UX, so
 * i need to break the while before call getopt() if the av=NULL
 */
	while ( av != NULL && ( car = getopt ( ac, av, cmd_line ) ) != EOF )
#endif /* !linux */

jump:

	switch ( car ) {
#if !defined(NO_CURSES)
#if defined(NCURSES)
		case '-':
#if defined(KEY_LEFT)
		case KEY_LEFT:
#endif /* KEY_LEFT */
			if (has_colors()) {
				init_pair( MAIN_PAIR,
					(fgc = fgc == 0 ? COLORS - 1 : fgc - 1), bgc );
				refresh_all();
			}
			break;
		case '=':
#if defined(KEY_RIGHT)
		case KEY_RIGHT:
#endif /* KEY_RIGHT */
			if (has_colors()) {
				init_pair( MAIN_PAIR,
					fgc = fgc == COLORS - 1 ? 0 : fgc + 1, bgc );
				refresh_all();
			}
			break;
		case '_':
			if (has_colors()) {
				init_pair( MAIN_PAIR,
					fgc, (bgc = bgc == 0 ? COLORS - 1 : bgc - 1) );
				refresh_all();
			}
			break;
		case '+':
			if (has_colors()) {
				init_pair( MAIN_PAIR,
					fgc, (bgc = bgc == COLORS - 1 ? 0 : bgc + 1) );
				refresh_all();
			}
			break;
#endif /* NCURSES */
#endif /* NO_CURSES */
		case 'm':
			if ( look_uid == -1L )
				look_uid = getuid();
			else
				look_uid = -1L;
			pages = 0;
			who = 0;
			reverse = 0;
			reverse_index = -1;
			look_utmp = 0;
			if (look_uid == 0)
				allow_root = 1;
		break;
		case 'C':
			print_configuration = 1;
			who = 0;
			look_utmp = 0;
			reverse = 0;
			reverse_index = -1;
			look_process = -1;
		break;
		case 'V':
			vm_config = 1;
			who = 0;
			look_utmp = 0;
			reverse = 0;
			reverse_index = -1;
			look_process = -1;
			print_configuration = 0;
		break;
		case '%':
			if ( look_cols() < 90 )
				wcpu = !wcpu;
		break;
		case 'e':
			who = 0;
			look_utmp = !look_utmp;
		break;
#if defined(NO_CURSES)
		case 'L':
			long_format = 1;
		break;
#endif /* NO_CURSES */
#if !defined(NO_CURSES)
		case 'L':
			load_graph = !load_graph;
			ResetHist();
		break;
		case ' ':
		case '\n':
			look_process = -1L;
			look_user = 0;
			pages = print_configuration = vm_config = who = look_utmp =0;
			Num_display_proc = look_lines() - 6;
			reverse = 0;
			reverse_index = -1;
			load_graph = 0;
			ResetHist();

			if ( car == ' ' )  {
				order = NULL;
				look_uid = -1;
				if ( sstring ) {
					reg_set ( NULL );
					sstring = 0;
				}
			}

		break;
		case 'j':
#if defined(KEY_DOWN)
		case KEY_DOWN:
#endif /* KEY_DOWN */
			if ( displayed && reverse <= displayed )
				reverse++;

			if ( displayed && reverse > displayed  ) {
				reverse = 0;
				reverse_index = -1;
			}
		break;
		case 'k':
#if defined(KEY_UP)
		case KEY_UP:
#endif /* KEY_UP */
			if ( displayed && reverse == 0 )
				reverse = displayed + 1;   /* Next instruct decrement reverse */

			if ( displayed && reverse > 0 )
				reverse--;

			if ( displayed && reverse == 0 )
				reverse_index = -1;
		break;
		case 'f':
#if defined(KEY_NPAGE)
		case KEY_NPAGE:
#endif /* KEY_NPAGE */
			if ( displayed || (look_process > 0))
				pages++;
			reverse = 0;
			reverse_index = -1;
		break;
		case 'b':
#if defined(KEY_PPAGE)
		case KEY_PPAGE:
#endif /* KEY_PPAGE */
			if ( --pages < 0 )
				pages = 0;
			reverse = 0;
			reverse_index = -1;
		break;
		case 'B':
#if defined(KEY_HOME)
		case KEY_HOME:
#endif /* KEY_HOME */
			pages = 0;
			reverse = 0;
			reverse_index = -1;
		break;
#endif /* !NO_CURSES */
		case 'I':
			if ( reverse ) 
				look_uid = pbuf [ reverse_index ].pst_uid;
			else
				if ( av )
					if ( *optarg < '0' || *optarg > '9' )
						look_uid = get_user_id ( optarg );
					else
						look_uid = atol ( optarg );
				else {
					char *u_name = curses_get_string ( "Type uid or name ( <RET> for previous state ): " );

					if ( !u_name ) {
						look_user = 0;
						reverse = 0;
						reverse_index = -1;
						look_uid = -1L;
						return;
					}
					else
						if ( *u_name < '0' || *u_name > '9' ) 
							look_uid = get_user_id ( u_name );
						else
							look_uid = atol ( u_name );
				}

			if ( look_uid == 0L )   /* look for root */
				allow_root =1;

			look_user =1;
		break;
#if !defined(NO_CURSES)
#if defined (SU_COMMAND) && (SU_KILLPROCESS)
		case 'P':
#if defined(KEY_DC)
		case KEY_DC:
#endif /* KEY_DC */
		{
			static char buf[ 128 ];
			char *user = NULL;
			register long ret;
			long pid;
			int signo = SU_KILLUSER;

			if ( !reverse ) {
				int i;

				pid = ask_curses( "Type PID you would like to KILL: " );
				
				for (i = 0; i < MAX_PROC; i++)
					if ( pbuf [ i ].pst_pid == pid)
						user = get_user_info ( i );
				if (user == NULL) {
					curses_error("No such process");
					break;
				}
			}
			else {
				pid = pbuf [ reverse_index ].pst_pid;
				user = get_user_info ( reverse_index );
			}
			sprintf ( buf, "kill proc %ld (%s) ? ( type 1 to confirm KILL, 9 change signal ): ", pid, user );
			ret = ask_curses ( buf );

			if ( ( ret != 1 ) && ( ret != 9 ) )
				break;

			if ( ret == 9 ) {
				char *sptr;

				sprintf( buf, "which signal ? (type signumber or signame ) : " );

				sptr = curses_get_string ( buf );
				ret = atol ( sptr );

				if ( ret && ret < NSIG && ret > 0)
					signo = ret;
				else {
#if defined(STRFY)
					int size = strlen ( sptr );

					signo = 0; /* A valid signal number is > 0 */
					for ( ret = 0; signames [ ret ].signo; ret++ )
						if (( size > 3 &&
						    !strncmp(signames [ ret ].name, sptr, size ) ) ||
						    !strncmp(signames [ ret ].name + 3, sptr, size) ) {
							signo = signames [ ret ].signo;
							break; /* This breaks the for loop */
						}
					if (!signo)
						break;
#else
					curses_error("Signal names not supported");
					break;
#endif /* STRFY */
				}
			}

			sprintf ( buf, "%s %s -c \"kill -%d %ld\"",
				SU_COMMAND, user, signo , pid );

			if ( kill ( pid, signo ) == -1 )
				system ( buf );

			refresh_all();
			}
		break;
#endif /* defined (SU_COMMAND) && (SU_KILLPROCESS) */
#if defined (SU_COMMAND) && (SU_KILLUSER)
		case 'K':
			{
			static char buf[ 128 ];
			char *user;
			long ret;

			if ( !reverse )
				break;

			user = get_user_info ( reverse_index );
			sprintf ( buf, "kill user %s ? ( type 1 to confirm ): ", user );
			ret = ask_curses ( buf );
			if ( ret != 1 )
				break;

			sprintf ( buf, "%s %s -c \"kill -%d -1\"",
				SU_COMMAND, user, SU_KILLUSER );

			system ( buf ); 
			refresh_all();
			}
		break;
#endif /* defined (SU_COMMAND) && (SU_KILLUSER) */
		case 'R':
		{
			static char buf [ 128 ];
			if ( reverse ) {
				look_process = pbuf [ reverse_index ].pst_pid;
				sprintf ( buf, "User %s (%ld). Type New priority: ",
					get_user_info ( reverse_index ) ,
					look_process );
			}
			else {
				look_process = ask_curses ( "Type Process number: " );

				if (!isProc( look_process )) {
					look_process = -1L;
					curses_error("No such process");
					break;
				}

				sprintf ( buf, "Process %ld. Type New priority: ",
					look_process );
			}


#if !defined(linux)
			renice ( ( int )look_process, ( int )ask_curses ( buf ));
#else
			renice ( PRIO_PROCESS, ( int )look_process, ( int )ask_curses ( buf ));
#endif /* linux */
			
			look_process = -1L;
		}
		break;
#if defined(linux)
		case 'G':
		{
			static char buf [ 128 ];
			if ( reverse ) {
				look_process = pbuf [ reverse_index ].pst_pgrp;
				sprintf ( buf, "User %s (%ld). Type New priority: ",
					get_user_info ( reverse_index ) ,
					look_process );
			}
			else {
				look_process = ask_curses ( "Type Process group: " );

				if (!isProc( look_process )) {
					look_process = -1L;
					curses_error("No such process");
					break;
				}

				sprintf ( buf, "Process %ld. Type New priority: ",
					look_process );
			}


			renice ( PRIO_PGRP, ( int )look_process, ( int )ask_curses ( buf ));
			
			look_process = -1L;
		}
		break;
		case 'A':
		{
			static char buf [ 128 ];
			if ( reverse ) {
				look_process = pbuf [ reverse_index ].pst_uid;
				sprintf ( buf, "User %s (%ld). Type New priority: ",
					get_user_info ( reverse_index ) ,
					look_process );
			}
			else {
				look_process = ask_curses ( "Type User ID: " );

				if (!isProc( look_process )) {
					look_process = -1L;
					curses_error("No such process");
					break;
				}

				sprintf ( buf, "Process %ld. Type New priority: ",
					look_process );
			}


			renice ( PRIO_USER, ( int )look_process, ( int )ask_curses ( buf ));
			
			look_process = -1L;
		}
		break;
#endif /* linux */
#endif /* !NO_CURSES */
		case 'p':

			if ( reverse ) 
				look_process = pbuf [ reverse_index ].pst_pid;

			else

				if ( av )
					look_process = atol ( optarg );
#if !defined(NO_CURSES)
				else {
					look_process = ask_curses ( "Type Process number: " );

					if (!isProc( look_process )) {
						look_process = -1L;
						curses_error("No such process");
						break;
					}
				}
#endif /* NO_CURSES */
			who = 0;
			look_utmp = 0;
			reverse = 0;
			reverse_index = -1;
		break;
		case 'E':
			set_euid = !set_euid;
			pages = 0;
			reverse = 0;
			reverse_index = -1;
		break;
		case 'w':
			who = !who;
			pages = 0;
			reverse = 0;
			reverse_index = -1;
		break;
		case 'W':
			if ( av )
				wait_second = atoi ( optarg );
			else
				wait_second = ( int )ask_curses ( "Type seconds: " );

			if ( wait_second < 0 )
				wait_second *= -1;
		break;
		case '/':
			if ( av ) {
				reg_set ( optarg );
				sstring = 1;
			}
			else {
				char *search = curses_get_string ( "Type string to search: " );
				if ( search ) {
					reg_set ( search );
					sstring = 1;
				}
				else {
					sstring = 0;
					reg_set ( NULL );
				}
			}
		break;
		case 'N':
			if ( av )
				Num_display_proc = atoi ( optarg ); 
			else {
				int lines = look_lines ();
				Num_display_proc =
					( int )ask_curses ( "Type number of processes: " );
				if ( Num_display_proc > lines - 6 || Num_display_proc < 0 )
					Num_display_proc = lines - 6;
			}
			pages = 0;
			reverse = 0;
			reverse_index = -1;
		break;
		case 'i':
			invert = !invert;
		break;
		case 's':
			order = compare_start_time;
		break;
		case 'd':
			order = compare_size;
		break;
		case 'D':
			order = compare_ressize;
		break;
		case 't':
			order = compare_user_time;
		break;
		case 'c':
			order = compare_sched_time; /* added by HV */
		break;
		case 'S':
			system_time_include = 1;
			user_time_include = !user_time_include;
		break;
		case 'U':
			user_time_include = 1;
			system_time_include = !system_time_include;
		break;
		case 'u':

			if ( reverse ) 
				look_uid = pbuf [ reverse_index ].pst_uid;

			else

				if ( av )
					if ( *optarg < '0' || *optarg > '9' )
						look_uid = get_user_id ( optarg );
					else
						look_uid = atol ( optarg );
				else {
					char *u_name = curses_get_string ( "Type uid or name ( <RET> for previous state ): " );

					if ( !u_name )
						look_uid = -1L;
					else
						if ( *u_name < '0' || *u_name > '9' ) 
							look_uid = get_user_id ( u_name );
						else
							look_uid = atol ( u_name );
				}

			if ( look_uid == 0L )   /* look for root */
				allow_root =1;

			pages = 0;
			who = 0;
			look_utmp = 0;
			reverse = 0;
			reverse_index = -1;
		break;
		case 'r':
			allow_root = !allow_root;
			pages = 0;
			reverse = 0;
			reverse_index = -1;
		break;

#if !defined(NO_CURSES)
#define PF	(void)printw
		case '$':
			clear_screen();
			move (0, 0);
			PF ( "\n" );
			PF ( "Copyright notice, as required by General Public License.\n" );
			PF ( "\n" );
			PF ( "    yamm, Yet Another Micro Monitor\n" );
			PF ( "    Copyright (C) 1992  Andrea Marangoni\n" );
			PF ( "    Copyright (C) 1994, 1995  Riccardo Facchetti\n" );
			PF ( "\n" );
			PF ( "\n" );
			PF ( "    This program is free software; you can redistribute it and/or modify\n" );
			PF ( "    it under the terms of the GNU General Public License as published by\n" );
			PF ( "    the Free Software Foundation; either version 2 of the License, or\n" );
			PF ( "    (at your option) any later version.\n" );
			PF ( "\n" );
			PF ( "    This program is distributed in the hope that it will be useful,\n" );
			PF ( "    but WITHOUT ANY WARRANTY; without even the implied warranty of\n" );
			PF ( "    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n" );
			PF ( "    GNU General Public License for more details.\n" );
			PF ( "\n" );
			PF ( "    You should have received a copy of the GNU General Public License\n" );
			PF ( "    along with this program; if not, write to the Free Software\n" );
			PF ( "    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n" );
			curses_refresh();
#undef PF
			(void)ask_curses("Press <RETURN> to exit.");
			refresh_all();
			break;
#endif /* !NO_CURSES */

		default:
			if ( !av )
				return;

			puts ( "-m          -  Display only 'm'y processes.");
			puts ( "-s          -  Sort by 's'tart time." );
			puts ( "-t          -  Sort by process 't'ime."  );
			puts ( "-c          -  Sort by process %cpu time, default." ); /* HV */
			puts ( "-d          -  Sort by process size ( data + text + stack ).");
			puts ( "-D          -  Sort by process resident set size.");
			puts ( "-E          -  Show processes with uid != euid.");
			puts ( "-r          -  Allow display of 'r'oot process." );
			puts ( "-%          -  Switch between  STIME and WCPU fields." );
			puts ( "-u uid|name -  Restrict to a specific 'U'ser." );
#if defined(NO_CURSES)
			puts ( "-L          -  Display long format of command name." );
#else
			puts ( "-L          -  Display Load Average 1 min bar chart." );
#endif /* NO_CURSES */
			puts ( "-i          -  Invert sorting order." );
			puts ( "-e          -  Display the entries in utmp." );
			puts ( "-S          -  Display only System time in field \"TIME\".");
			puts ( "-U          -  Display only User time in field \"TIME\".");
			puts ( "-p process  -  Analyze a single process" );
			puts ( "-C          -  Display configuration of machine." );
			puts ( "-V          -  Virtual memory info." );
			puts ( "-w          -  Like who." );
			puts ( "-I uid|name -  User Info." );
			puts ( "-N number   -  Display only \"number\" process." );
			puts ( "-/ string   -  Search string in command line.");
			puts ( "-W second   -  Loop forever waiting \"second\" for each loop ( CTRL-c to exit." );
			exit ( 1 );
		break;
	}
#if defined(linux)
/*
 * Read all the waiting characters to disable typematic behaviour
 */
#define __KBHIT stdin->_IO_read_ptr < stdin->_IO_read_end
	while ( __KBHIT )
		car = getchar();
#endif /* linux */
}

int isProc (int pid) {
	register int count;

	for ( count = 0; count < MAX_PROC; count++)
		if ( pbuf [ count ].pst_pid == pid)
			return 1;
	return 0;
}
