/***************************************
  $Revision: 1.29 $

  Protocol config module (pc).  This is the protocol that the admin uses to
  talk to the server.

  Status: NOT REVUED, NOT TESTED

  ******************/ /******************
  Filename            : protocol_config.c
  Authors             : ottrey@ripe.net
                        marek@ripe.net
  To Do               : Add a facility to take callbacks instead of
                        hard-coding menu options.
                        Add in all the menu support provided by the GLib
                        libraries.
                        (Remove strtok if multiple threads are to be used.)
			use gnu readline with expansion and history
  ******************/ /******************
  Copyright (c) 1999                              RIPE NCC
 
  All Rights Reserved
  
  Permission to use, copy, modify, and distribute this software and its
  documentation for any purpose and without fee is hereby granted,
  provided that the above copyright notice appear in all copies and that
  both that copyright notice and this permission notice appear in
  supporting documentation, and that the name of the author not be
  used in advertising or publicity pertaining to distribution of the
  software without specific, written prior permission.
  
  THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
  AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
  DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
  AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  ***************************************/
#include <stdio.h>
#include <stdlib.h>
/*** solaris' header file doesn't contain the crypt definition...
     #include <unistd.h> */

extern char* crypt(const char *, const char *);   /* crypt stuff */
#include <time.h>       /* Time stuff */
#include <sys/ioctl.h>  /* Terminal control stuff */
#include <termio.h>     /* Terminal control stuff */
#include "thread.h"
#include "constants.h"
#include "properties.h"
#include <glib.h>

#include "sk.h"
#include "ta.h"

#include "pc_commands.h"

#define PC_IMPL
#include "protocol_config.h"

static 
int find_command(char *comm_name, Command *comm) 
{
  int i;
  char *comm_buffer = wr_string(comm_name);
  char *token, *cursor;
  int index = -1;
  
  cursor = comm_buffer;
  if( (token = strsep(&cursor, " \t")) != NULL) {
    for (i=0; comm[i].name != NULL; i++) {
      if ( strcmp(token, comm[i].name) == 0) {
	index = i;
	break;
      }
    }
  }
  
  wr_free(comm_buffer);

  return index; /* returns -1 when command not found */
} /* find_command() */

static 
int show_commands(Command *comm, char *comm_name, GString *output) 
{
  int i = 0;

  g_string_sprintfa(output, "%scommands are:\n\n", comm_name);
  while (comm[i].name != NULL) {
    g_string_sprintfa(output, "%s\t%s\n", comm[i].name, comm[i].help);
    i++;
  }

  return 1;
} /* show_commands() */


int command_execute(Command *comm, char *comm_name,
		    char *input, GString *output, sk_conn_st *condat) 
{ 
  char *name, *next_word, *tmp_input;
  int index, result=0;

  /* find the command in the string - first whitespace delimited word */
  /* make a copy of the input */
  dieif( (tmp_input = wr_string(input)) == NULL );  
  next_word = tmp_input;
  
  /* find the first word and set the pointer to the rest of the string */
  name = strsep(&next_word, " \t");
  
  if( name != NULL && strlen(name) != 0 ) {
    index = find_command(name, comm);
    if( index != -1 ) {
      if( next_word != NULL ) {
	/* advance the input pointer to the next word */
	while(  *next_word != '\0' && isspace(*next_word) ) {
	  next_word++;
	}
      }
      else {
	next_word = "";
      }
      
      /* run, Forrest, run...*/
      result = comm[index].function(next_word, output, condat);
    }
    else {	    
      g_string_sprintfa(output, "invalid %scommand: %s\n", comm_name, name);
      show_commands(comm, comm_name, output);
      result = 2;
    }
  }  
  else {  
    show_commands(comm, comm_name, output);
    result = 2;
  }
  
  free(tmp_input);

  return result;
} /* command_execute() */


static 
int command_help(char *input, GString *output, sk_conn_st *condat) 
{
  /* by the time it came here, the "help" bit is already taken away. */
  return show_commands(command, "", output);

}






/* proces_input() */
/*++++++++++++++++++++++++++++++++++++++

  Process the input.

  sk_conn_st *condat         connection data    

  More:
  +html+ <PRE>
  Author:
        ottrey
  +html+ </PRE>
  ++++++++++++++++++++++++++++++++++++++*/
static 
int process_input(char *input, sk_conn_st *condat) 
{
  int  index;
  int res=0;
  GString *output = g_string_new("");

  index = find_command(input, command);

  switch (index) {
  case -1:
    /* Command not found */
    command_help(NULL, output, condat);
    break;
    
  default: 
    res = command_execute(command, "", input, output, condat);
  }
  
  if(res != PC_RET_QUIT) {
    /*
      printf("thread output=\n%s\n", output);
    */
    if ( CO_get_clear_screen() == 1 ) {
      SK_cd_puts(condat, CLEAR_SCREEN);
    }
    SK_cd_puts(condat,  output->str);
    SK_cd_printf(condat, "\n\n=%d= %s", res, CO_get_prompt());
    
  }
  
  g_string_free( output, TRUE );

  /* the return value is the connection state: 1=still open, 0=to be closed
   */

  return (res != PC_RET_QUIT);
} /* process_input() */


static 
char *authenticate_user(sk_conn_st *condat) 
{
  char *user = NULL;
  const char Salt[2] = "DB";
  char input[MAX_INPUT_SIZE];
  int read_result;
  char *password=NULL;
  char *user_password=NULL;
  char user_buf[10];

  SK_cd_puts(condat, LOGIN_PROMPT);
  read_result = SK_cd_gets(condat, input, MAX_INPUT_SIZE);

  strncpy(user_buf, input, 10);

  SK_cd_puts(condat, PASSWD_PROMPT);
  /* XXX These aren't working.
  SK_puts(sock, ECHO_ON);
  echo_off(sock);
  */
  read_result = SK_cd_gets(condat, input, MAX_INPUT_SIZE);
  /* XXX These aren't working.
  echo_on(sock);
  SK_puts(sock, ECHO_OFF);
  */

  password = crypt(input, Salt);

  user_password = PR_get_property(user_buf, DEFAULT_USER_NAME);

  if (user_password != NULL) {
    if (strcmp(password, user_password) == 0) {
      /*user = (char *)calloc(1, strlen(user_buf)+1);*/
      dieif( wr_malloc((void **)&user, strlen(user_buf)+1) != UT_OK);  
      strcpy(user, user_buf);
    }
  }

  
  return user;

} /* authenticate_user() */

void PC_interact(int sock) {
  char input[MAX_INPUT_SIZE];
  int connected = 1;
  char *user=NULL;
  sk_conn_st condat;

  memset( &condat, 0, sizeof(condat));
  condat.sock = sock;
  SK_getpeerip(sock, &(condat.rIP));
  condat.ip = SK_getpeername(sock); /* XXX *alloc involved */
  
  /* Welcome the client */
  SK_cd_puts(&condat, CO_get_welcome());

  /* Authenticate the user */
  if (CO_get_authenticate() == 1) {
    user = authenticate_user(&condat);

    if (user == NULL) {
      ER_inf_va(FAC_PC, ASP_PC_I_SESSION, 
		"unsuccesful login attempt from %s", condat.ip );
    }
  }
  else {
    user="nobody";
  }

  if (user != NULL) {    

    /* Log admin logging on */
    ER_inf_va(FAC_PC, ASP_PC_I_SESSION, 
		"user %s from %s logged on", user, condat.ip );
    
    {
      char timestring[26];
      extern time_t SV_starttime;
      
      ctime_r(&SV_starttime, timestring); 
      SK_cd_printf(&condat, 
		   "System running since %sUptime in seconds: %ld \n\n",
		   timestring,		  
		   time(NULL) - SV_starttime);
    }
    
    SK_cd_puts(&condat, CO_get_prompt());

    while (condat.rtc==0 && connected) {
      char *ichr;
      char *icopy;
      char *chr;
      /* Read input. Quit if no input (socket closed) */
      if( SK_cd_gets(&condat, input, MAX_INPUT_SIZE) <= 0 ) {
	break;
      }

      /* filter junk out: leading/trailing whitespaces */
      
      

      /* 1. advance to non-whitespace */
      for(ichr=input; *ichr != 0 && isspace(*ichr); ichr++) {
	/* EMPTY */
      }

      /* 2. copy the rest (even if empty) */
      dieif( (icopy = strdup(ichr)) == NULL);
      
      if( *ichr != '\0') {
	/* 3. chop trailing spaces */
	for( chr = icopy + strlen(icopy)-1 ; 
	     chr != icopy && isspace(*chr);
	     chr--) {
	  *chr = 0;
	}
      }
      
      /* set thread accounting */
      TA_setactivity(icopy);
      TA_increment();
      
      /*      if( strlen(icopy) > 0 ) {*/
      {
	ER_inf_va(FAC_PC, ASP_PC_I_COMMAND, icopy);
		  
	connected = process_input(icopy, &condat);
      }
      
      TA_setactivity("");
      
      free(icopy);
    }
    
    /* Log admin logging off */
    ER_inf_va(FAC_PC, ASP_PC_I_SESSION, 
		"user %s from %s logged off", user, condat.ip );
    
  }
  
  /* Close the socket */
  SK_close(sock);

  wr_free(condat.ip);
} /* PC_interact() */

