/*

                                   _JNJ`                        
                               .JNMH`                           
                              JMMF`       `;.                   
                            .NMM)          `MN.                 
                            MMM)            (MML                
                           (MMM`             MMML               
                     M  I  D  N  I  G  H  T    C  o  D  E       
                           (NMMF             MHNH               
                            NMML            .MMM                
                             NMML          .NMH                 
                              4MMNL       .#F                   
                               `4HNNL_   `                      
                                   `"""`                        

                          Copyright (C) 2004-2007
       "Ian (Larry) Latter" <ian dot latter at midnightcode dot org>

    Midnight Code is a registered trademark of Ian Latter.

    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, and mirrored at the Midnight Code web
    site; as at version 2 of the License only.
  
    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
    (version 2) along with this program; if not, write to the Free
    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA, or see http://midnightcode.org/gplv2.txt

*/

/* midnightcode-terminal.c :: Midnight Code terminal/console library	*/


#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <signal.h>
#include <termios.h>
#include <fcntl.h>
#include <linux/sockios.h>
#include <arpa/inet.h>

#include "preferences.h"
#include "midnightcode-colour.h"
#include "midnightcode-logo.h"
#include "midnightcode-license.h"
#include "midnightcode-process.h"
#include "midnightcode-terminal.h"



int
midnightcode_terminal_console_open(int * fd) {
  int attempt;
  int max_tries;


  max_tries = 3;
  for(attempt = 1; attempt <= max_tries; attempt++) {
    if((*fd = open(MIDNIGHTCODE_TERMINAL_DEFAULT_CONSOLE,
      O_NOCTTY|O_NONBLOCK|O_RDWR)) < 0)
      break;
    usleep(250);
  }
  if(*fd < 0)
    return -1;

  fcntl(*fd, F_SETFL, O_NOCTTY|O_RDWR);


  return 0;
}



int
midnightcode_terminal_console_close(void) {


  close(2);
  close(1);
  close(0);

  return 0;
}



int
midnightcode_terminal_console_usurp(int * fd) {


  midnightcode_terminal_console_close();

  if(midnightcode_terminal_console_open(fd) < 0)
    return -1;

  if(midnightcode_terminal_properties(MIDNIGHTCODE_TERMINAL_VIRTUAL_NULL,
    MIDNIGHTCODE_TERMINAL_CONTROL_UNIX) < 0)
    return -1;

  setsid();

  ioctl(*fd, TIOCSCTTY, 1);
  dup(*fd);
  dup(*fd);


  return 0;
}



int
midnightcode_terminal_virtual_open(int terminal, int options) {
  char device[12];
  int fd;
  FILE *fp;
  char * buffer;
  int buffer_size;


  if(terminal < 1 || terminal > 9)
    return -1;

  memset(device, 0, sizeof(device));
  snprintf(device, sizeof(device), "/dev/tty%d", terminal);

  fflush(stdout);
  if((fd = open(device, O_RDWR, 0777)) < 0)
    return -1;
  fflush(stdout);

  if(options & MIDNIGHTCODE_TERMINAL_DISPLAY_LOGO) {
    write(fd, "\n\n", strlen("\n\n"));
    buffer_size = midnightcode_logo_buffer(&buffer, 0,
      MIDNIGHTCODE_COLOUR_STYLE_BLOOD_MOON);
    if(buffer == NULL)
      return -1;
    if(buffer_size <= 0) {
      if(buffer)
        free(buffer);
      return -1;
    }
    write(fd, buffer, buffer_size);
    free(buffer);
    fsync(fd);
    buffer_size = midnightcode_license_buffer(&buffer, 0,
      MIDNIGHTCODE_COLOUR_STYLE_BLOOD_MOON, 
      MIDNIGHTCODE_LICENSE_TEXT_COPYRIGHT |
      MIDNIGHTCODE_LICENSE_TEXT_TRADEMARK);
    if(buffer == NULL)
      return -1;
    if(buffer_size <= 0) {
      if(buffer)
        free(buffer);
      return -1;
    }
    write(fd, buffer, buffer_size);
    free(buffer);
    write(fd, MIDNIGHTCODE_COLOUR_NORMAL,
      strlen(MIDNIGHTCODE_COLOUR_NORMAL));
    write(fd, "\n\n", strlen("\n\n"));
    fsync(fd);
  }

  if(options & MIDNIGHTCODE_TERMINAL_DISPLAY_ISSUE) {
    buffer_size = 128;
    if((fp = fopen("/etc/issue", "rb")) != NULL) {
      write(fd, MIDNIGHTCODE_COLOUR_DK_GREY,
        strlen(MIDNIGHTCODE_COLOUR_DK_GREY));
      buffer = malloc(buffer_size);
      if(buffer == NULL)
        return -1;
      memset(buffer, 0, buffer_size);
      while(fgets(buffer, buffer_size, fp) != NULL)
        write(fd, buffer, strlen(buffer));
      free(buffer);
      fclose(fp);
      write(fd, MIDNIGHTCODE_COLOUR_NORMAL,
        strlen(MIDNIGHTCODE_COLOUR_NORMAL));
    }
    write(fd, "\n\n", strlen("\n\n"));
    fsync(fd);
  }

  close(fd);

  if(options & MIDNIGHTCODE_TERMINAL_DISPLAY_SHELL) {
    midnightcode_terminal_environment(MIDNIGHTCODE_TERMINAL_ENVIRONMENT_ALL);
    if(midnightcode_process(MIDNIGHTCODE_TERMINAL_DEFAULT_SHELL,
      MIDNIGHTCODE_PROCESS_OPTION_BACKGROUND, terminal))
      return -1;
  }


  return 0;
}



int
midnightcode_terminal_virtuals_open(int terminals, int options) {
  int terminal;
  int ret_i;


  if(terminals < 1 || terminals > 9)
    return -1;

  ret_i = 0;

  for(terminal = 1; terminal <= terminals; terminal++) {

    if(midnightcode_terminal_virtual_open(terminal, options) < 0)
      continue;

    ret_i++;
  }


  return ret_i;
}



int
midnightcode_terminal_environment(int options) {
  int ret_i;


  ret_i = 0;

  if(options & MIDNIGHTCODE_TERMINAL_ENVIRONMENT_PATH) {
    if(putenv(MIDNIGHTCODE_TERMINAL_ENV_PATH))
      ret_i--;
  }

  if(options & MIDNIGHTCODE_TERMINAL_ENVIRONMENT_SHELL) {
    if(putenv(MIDNIGHTCODE_TERMINAL_ENV_PS1))
      ret_i--;
    if(putenv(MIDNIGHTCODE_TERMINAL_ENV_PS2))
      ret_i--;
    if(putenv(MIDNIGHTCODE_TERMINAL_ENV_PS3))
      ret_i--;
  }

  return ret_i;
}



int
midnightcode_terminal_properties(int terminal, int options) {
  char device[12];
  int fd;
  struct termios tty;


  if(terminal < 0 || terminal > 9)
    return -1;

  if(terminal == MIDNIGHTCODE_TERMINAL_VIRTUAL_NULL) {

    if((midnightcode_terminal_console_open(&fd)) < 0)
      return -1;

  } else {

    memset(device, 0, sizeof(device));
    snprintf(device, sizeof(device), "/dev/tty%d", terminal);
    if((fd = open(device, O_RDWR, 0777)) < 0)
      return -1;

  }

  switch(options) {

    case MIDNIGHTCODE_TERMINAL_CONTROL_UNIX:

      tcgetattr(fd, &tty);
      tty.c_cflag &= CBAUD|CBAUDEX|CSIZE|CSTOPB|PARENB|PARODD;
      tty.c_cflag |= CLOCAL|CREAD|HUPCL;

      tty.c_cc[VEOF]   = 4;
      tty.c_cc[VERASE] = 127;
      tty.c_cc[VINTR]  = 3;
      tty.c_cc[VKILL]  = 24;
      tty.c_cc[VQUIT]  = 28;

      tty.c_cc[VMIN]   = 1;
      tty.c_cc[VTIME]  = 0;

      tty.c_cc[VSTART] = 17;
      tty.c_cc[VSTOP]  = 19;
      tty.c_cc[VSUSP]  = 26;

      tty.c_iflag = ICRNL|IGNPAR|IXANY|IXON;
      tty.c_oflag = ONLCR|OPOST;
      tty.c_lflag = ECHO|ECHOCTL|ECHOKE|ECHOPRT|ICANON|ISIG;

      tcsetattr(fd, TCSADRAIN, &tty);

      break;

    case MIDNIGHTCODE_TERMINAL_CONTROL_KEYPRESS:

      tcgetattr(fd, &tty);

      tty.c_lflag &= ~ICANON;
      tty.c_lflag &= ~ECHO;

      tty.c_cc[VMIN] = 1;
      tty.c_cc[VTIME] = 0;

      tcsetattr(fd, TCSANOW, &tty);

      break;


    default:

      break;

  }

  close(fd);


  return 0;
}


