/*
	Schrodinger's Box Haven  code version -0.1 alpha
        Copyright (C) 1994, Gordon Chan

	You can do whatever ya want with this code as long as you leave this
        copyright & disclaimer intact.  You can hack it up all you want, etc...
        No guarantees.

	Send comments, flames, bug reports, etc ... to
		au233@freenet.carleton.ca  <---- (preferred address for now)
		gjc@achilles.net
		gchan@ccs.carleton.ca
*/


/* Here's the copyrights & disclaimers from the Opium Den and unixCB codes */

/* Opium Den */
/*
  val's haven code v -0.85

        Copyright (C) 1994 Joel Ward

        Warranty:
                Don't blame me for anything.

        You can do whatever the fuck you want with this code as long as you
don't remove this copyright/disclaimer notice.
*/

/* unixCB */
/*
  
  cbd.c
  
  "cbd.c" is the main code for the CB simulator.
  
  Copyright (c) 1992, Gary Grossman.  All rights reserved.
  Send comments and questions to: garyg@soda.berkeley.edu
  
  */

#include <string.h>
#include <arpa/telnet.h>
#include <sys/time.h>

#include "linked_lists.h"
#include "user_input.h"
#include "main.h"

void process_input(user)
  struct user *user;
{
  char input_buffer[INPUTMAX+2], *buffer, 
   output_buffer[INPUTMAX], *output,
   message_buffer[160], prompt_buffer[20], temp[120];
  int size, output_buffer_length, i;
  struct timeval temptime;
  struct timezone tempzone;

  size = read_user(user, input_buffer, INPUTMAX+1);
  while (size > 0) {

    (void) gettimeofday(&temptime, &tempzone);
    buffer = input_buffer; 
    output = output_buffer;

    while (*buffer) { 
	
    /* kick off the spammers */
      if ( ((temptime.tv_sec - user->idletime) <= 2) && 
           is_user_not(user, Ftyping) && user->input->length) {
        if (++(user->number_of_lines) >= SPAMMAX) {
          sprintf(temp, ">> %s on line %d has been kicked off for Spamming.\r\n",
           user->name, user->desc);
          delete_user(user, ">> Spam alert!!!\r\n", 0, temp);
          return;
        }
      } else 
        user->number_of_lines = 0;

      if (is_user_not(user, Ftyping)) {
        clear_queue(user->input);
        clear_queue(user->output);
        toggle_user(user, Ftyping);
      }

      user->idletime = temptime.tv_sec;
      output_buffer_length = 0;
		
      while (*buffer && (*buffer!='\n' && *buffer!='\r')) {	

        /* check for telnet sequence characters */
        if ((unsigned char)*buffer == IAC || user->ts_mode) {
          buffer = (char *)process_telnet_sequence(user, buffer);
          user->number_of_lines = 0;
          toggle_user (user, Ftyping);

        } else if (*buffer >= ' ' && *buffer <= '~' && 
            (user->input->length < user->linecharmax)) {
          *(output++) = *buffer;				
          *user->input->queue = *buffer;
          user->input->queue++;
          output_buffer_length++;			
          user->input->length++;
          is_command(user, buffer, message_buffer, prompt_buffer);
          buffer++;

        } else if (*buffer == '\177' || *buffer == '\b') {
          /* write_err("got ERASE CHAR\r\n"); */
          erase_char (user);
          buffer++;

        } else  {
          /* write_err("in ELSE\r\n"); */
          if (user->input->length == 0)
            toggle_user(user, Ftyping);
          buffer++; 
        }
      }

      /* echo text back to user */
      if (is_user(user, Fecho_text)) {
        if (is_user(user, Flinemode) && is_user(user, Fgot_comm))
          echo_line(user->desc, output_buffer, 2);
        else 
          echo_line(user->desc, output_buffer, output_buffer_length);

        if (is_user(user, Fgot_comm)) {
          echo_cr(user->desc);
          echo_line(user->desc, message_buffer, strlen(message_buffer));
          if (*prompt_buffer) {
            echo_line(user->desc, prompt_buffer, strlen(prompt_buffer));
            if (is_user(user, Flinemode))
      	      echo_line(user->desc, output_buffer+2, output_buffer_length-2);
          } else {
            *buffer = '\0';
            clear_queue(user->input);
            toggle_user(user, Ftyping);
            user->present_comm(user, user->input->begin);
          }
          toggle_user(user, Fgot_comm);
        }
      } else {
    /* this assumes user never goes into the local echo & char mode and 
     is never possible */
        if (is_user(user, Fgot_comm)) {
          echo_line(user->desc, message_buffer, strlen(message_buffer));
          if (*prompt_buffer) {
            echo_line(user->desc, prompt_buffer, strlen(prompt_buffer));
            if (is_user(user, Flinemode))
	      echo_line(user->desc, output_buffer+2, output_buffer_length-2);
            echo_cr(user->desc);
          } else {
            *buffer = '\0';
            clear_queue(user->input);
            toggle_user(user, Ftyping);
            user->present_comm(user, user->input->begin);
          }
        toggle_user(user, Fgot_comm);
        }
      }
      flush_fully(output_buffer);
      output = output_buffer;

      while (*buffer && (*buffer=='\n' || *buffer=='\r')) {
        if (is_user_not(user, Fgot_cr))
          toggle_user (user, Fgot_cr);
        buffer++;
      }

      /* when carriage return is caught, process input */		
      if (is_user(user, Fgot_cr))
        execute_command(user);
    }
    size = read_user(user, input_buffer, INPUTMAX+1);
  }
}


void execute_command (user)
  struct user *user;
{

  if ((user->input->length > 0) || is_user(user, Fcomm_line)) {
    /* process user command */
    if (is_user(user, Fecho_text))
      echo_cr(user->desc);
    if (is_user(user, Fcomm_line)) {
      *user->input->queue = '\0';
      user->present_comm(user, user->input->begin);
      if (is_user_not(user, Fmultiple_comm)) {
        dump_output_buffer(user);
	toggle_user(user, Ftyping);
      }
    } else {
      /* process normal talk */
      dump_output_buffer(user);
      toggle_user(user, Ftyping);
      *user->input->queue = '\0';
      handle_talk_output(user, user->input->begin);
    }
    toggle_user(user, Fgot_cr);
  } else {
    toggle_user(user, Ftyping);
    toggle_user(user, Fgot_cr); 
  }
}


int is_command (user, buffer, message, prompt)
  struct user *user;
  char *buffer, *message, *prompt;
{
  if ((*user->input->begin == '/' ||
       *user->input->begin == '.' ||
       *user->input->begin == ',') &&
       (user->input->length == 2) && is_user_not(user, Fcomm_line)) {
    toggle_user(user, Fgot_comm);
    user->which_comm = *buffer;
    set_command(user, user->which_comm, message, prompt); 
  } else
    return;
}


void dump_output_buffer(user)
  struct user *user;
{
/* dump out everything in the stopped output buffer if there's anything there */
  if (user->output->length > 0)
    write_user(user->desc, user->output->queue); 
}	


void echo_line(desc, str, size)
  char *str;
  int desc, size;
{
  char temp_str[INPUTMAX];

  strncpy(temp_str, str, size);
  temp_str[size] = '\0'; 
  write_user(desc, temp_str);
}


void echo_cr(desc)
  int desc;
{
  write_user(desc, "\r\n");
}


void echo_char(desc, letter)
  char letter;
  int desc;
{
  char temp[1];
  sprintf (temp, "%c", letter);
  write_user (desc, temp);
}


void erase_char(user)
  struct user *user;
{
  if (user->input->length > 0) {
    user->input->queue--;
    *user->input->queue = '\0';
    write_user(user->desc, "\b \b");
    user->input->length--;
    if ((user->input->length == 0) && is_user_not(user, Fcomm_line)) {
      dump_output_buffer(user);
      toggle_user (user, Ftyping);
    }
  } else if (is_user_not(user, Fcomm_line))
    toggle_user(user, Ftyping);
}

