/*********************************************************************/
/* file: main.c - main module - signal setup/shutdown etc            */
/*                             TINTIN III                            */
/*          (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t             */
/*                     coded by peter unold 1992                     */
/*********************************************************************/
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include "tintin.h"

#ifndef BADSIG
  #define BADSIG (void (*)())-1
#endif

/*************** globals ******************/
int term_echoing=TRUE;
int echo=DEFAULT_ECHO;
int ignore=DEFAULT_IGNORE;
int speedwalk=DEFAULT_SPEEDWALK;
int sessionsstarted;
struct session *sessionlist, *activesession;
struct listnode *common_aliases, *common_actions, *common_subs;
char vars[10][BUFFER_SIZE]; /* the &0, &1, &2,....&9 variables */
char tintin_char=DEFAULT_TINTIN_CHAR;    

/************ externs *************/
extern int ticker_interrupted, time0;
extern int tick_size, sec_to_tick;
extern int ignore;

/**************************************************************************/
/* main() - show title - setup signals - init lists - readcoms - tintin() */
/**************************************************************************/
main(int argc, char *argv[])
{
  puts("##################################################");
  puts("#                 T I N T I N                    #");
  puts("#                 version III                    #"); 
  puts("#  (T)he k(I)cki(N) (T)ickin d(I)kumud clie(N)t  #");
  puts("#  a DIKU-mud client coded by peter unold 1992.  #");
  puts("##################################################");
  prompt(NULL);  

  if(signal(SIGTERM, myquitsig)==BADSIG)
    syserr("signal SIGTERM");
  if(signal(SIGINT, myquitsig)==BADSIG)
    syserr("signal SIGINT");
  if(signal(SIGALRM, tick_func)==BADSIG)
    syserr("signal SIGALRM");
  time0=time(NULL);
  alarm(1);  

  common_aliases=init_list();
  common_actions=init_list();
  common_subs=init_list();

  if(argv[1])
    activesession=read_command(argv[1], NULL);

  tintin();
}

/***************************/
/* the main loop of tintin */
/***************************/
void tintin()
{
  char buffer[BUFFER_SIZE];
  int didget;
  int readfdmask;
  struct session *sesptr;
  
  while(TRUE) {

    readfdmask=1;
    for(sesptr=sessionlist; sesptr; sesptr=sesptr->next)
      readfdmask|=sesptr->socketbit;
    ticker_interrupted=FALSE;
    if(select(32, &readfdmask,  0, 0, 0)<0 && !ticker_interrupted)
      syserr("select");
    if(ticker_interrupted)
      ticker_interrupted=FALSE;
    else {
      if(readfdmask&1) {
        if((didget=read(0, buffer, sizeof(buffer)))<0)
          syserr("read from fd 0");
        *(buffer+didget-1)='\0';
        if(activesession && term_echoing)
          do_history(buffer, activesession);
        activesession=parse_input(buffer, activesession);
      }
   
      for(sesptr=sessionlist; sesptr; sesptr=sesptr->next)
        if(sesptr->socketbit&readfdmask)
          read_mud(sesptr);
    }

  }
}

/*************************************************************/
/* read text from mud and test for actions/snoop/substitutes */
/*************************************************************/
void read_mud(struct session *ses)
{
  char buffer[BUFFER_SIZE], subresult[BUFFER_SIZE], linebuffer[BUFFER_SIZE], *cp, *cpsource, *cpdest;
  int didget; 

  if(!(didget=read_buffer_mud(buffer, ses))) {
    cleanup_session(ses);
    if(ses==activesession)
      activesession=newactive_session();
  }

  else {
    if(ses->logfile)
      fwrite(buffer, didget, 1, ses->logfile);

      do_all_subs(buffer, subresult, ses);
    
      if(ses==activesession) 
        write(1, subresult, strlen(subresult)); 
      else if(ses->snoopstatus)
        snoop(buffer, ses);
      if(!ignore)
        split_check_all_actions(buffer, ses);
  }
}

/**********************************************************/
/* snoop session ses - chop up lines and put'em in buffer */
/**********************************************************/
void snoop(char *buffer, struct session *ses) 
{
  int n;
  char *cpsource, *cpdest, linebuffer[BUFFER_SIZE];

  putchar('\n');

  cpsource=buffer; 
  cpdest=linebuffer;

  while(*cpsource) {  /*cut out each of the lines and sub'em if a sub is triggered*/
    if(*cpsource=='\n' || *cpsource=='\r') {
      *cpdest='\0';      
      if(*linebuffer!='\0')
        printf("%s%% %s\n", ses->name, linebuffer);
      if(*cpsource=='\n' || *cpsource=='\r') 
        cpsource++;
      cpdest=linebuffer;
    }
    else
      *cpdest++=*cpsource++;
  }

  *cpdest='\0';
  if(*linebuffer!='\0')
    printf("%s%% %s\n", ses->name, linebuffer);

}

/*****************************************************/
/* output to screen should go throught this function */
/* text gets checked for actions                     */
/*****************************************************/
void tintin_puts(char *cptr, struct session *ses)
{
  if(ses==activesession || ses==NULL) {
    printf("%s\n\r", cptr);
    prompt(ses);
  }
  
  if(ses)
    check_all_actions(cptr, ses); 
}

/****************************************/
/* alarm signal handler used for ticker */
/****************************************/
static void tick_func()
{
  ticker_interrupted=TRUE;
  alarm(1);
  if(signal(SIGALRM, tick_func)==BADSIG)
    syserr("signal SIGALRM"); 

  sec_to_tick=tick_size-((time(NULL)-time0)%tick_size);
  if(sec_to_tick==tick_size || sec_to_tick==10) {
    struct session *sesptr;
    for(sesptr=sessionlist; sesptr; sesptr=sesptr->next)
      if(sesptr->tickstatus) 
        if(sec_to_tick==tick_size)
          tintin_puts("#TICK!!!", sesptr);
        else
          tintin_puts("#10 SECONDS TO TICK!!!", sesptr);
  }
}

/**********************************************************/
/* Here's where we go when we wanna quit TINTIN FAAAAAAST */
/**********************************************************/
static void myquitsig()
{
  struct session *sesptr;

  for(sesptr=sessionlist; sesptr; sesptr=sesptr->next) 
    cleanup_session(sesptr);
     
  puts("\n\rYour fireball hits TINTIN with full force, causing an immediate death.");
  puts("TINTIN is dead! R.I.P.");
  puts("Your blood freezes as you hear TINTIN's death cry.");
  exit(0);
}