/*********************************************************************/
/* file: session.c.c - funtions related to sessions                  */
/*                             TINTIN III                            */
/*          (T)he K(I)cki(N) (T)ickin D(I)kumud Clie(N)t             */
/*                     coded by peter unold 1992                     */
/*********************************************************************/
#include <ctype.h>
#include <string.h>
#include "tintin.h"

extern int sessionsstarted;
extern struct session *sessionlist, *activesession;
extern struct listnode *common_aliases, *common_actions, *common_subs;
extern char vars[10][BUFFER_SIZE]; /* the &0, &1, &2,....&9 variables */

/************************/
/* the #session command */
/************************/
struct session *session_command(char *arg, struct session *ses)
{
  char left[BUFFER_SIZE], right[BUFFER_SIZE];
  struct session *sesptr;
  struct listnode *ln;
  int i;

  arg=get_arg_stop_spaces(arg, left);
  arg=get_arg_with_spaces(arg, right);

  if(!*left) {
    tintin_puts("#THESE SESSIONS HAS BEEN DEFINED:", ses);
    for(sesptr=sessionlist; sesptr; sesptr=sesptr->next)
      show_session(sesptr);
    prompt(ses);
  }

  else if(*left && !*right) {
    for(sesptr=sessionlist; sesptr; sesptr=sesptr->next)
      if(!strcmp(sesptr->name, left)) {
        show_session(sesptr);
        break;
      }
    if(sesptr==NULL)
      tintin_puts("#THAT SESSION IS NOT DEFINED.", ses);
  }

  else {
    for(sesptr=sessionlist; sesptr; sesptr=sesptr->next)
      if(strcmp(sesptr->name, left)==0) {
        tintin_puts("#THERE'S A SESSION WITH THAT NAME ALREADY.", ses);
        return ses;
      }
    ses=new_session(left, right, ses);
  }

  return ses;
}


/******************/
/* show a session */
/******************/
void show_session(struct session *ses) 
{
  printf("%-10s%s", ses->name, ses->address);
  if(ses==activesession) 
    printf(" (active)");
  if(ses->snoopstatus)
    printf(" (snooped)");
  if(ses->logfile)
    printf(" (logging)");
  puts("");
}

/**********************************/
/* find a new session to activate */
/**********************************/
struct session *newactive_session()
{

  if(sessionlist) {
    char buf[BUFFER_SIZE];
    activesession=sessionlist;
    sprintf(buf, "#SESSION '%s' ACTIVATED.", sessionlist->name);    
    tintin_puts(buf, NULL);
  }
  else
    tintin_puts("#THERE'S NO ACTIVE SESSION NOW.", NULL);

  return sessionlist;
}


/**********************/
/* open a new session */
/**********************/
struct session *new_session(char *name, char *address, struct session *ses)
{
  int i,sock;
  char *host, *port;
  struct session *newsession;

  port=host=space_out(mystrdup(address));

  if(!*host) {
    tintin_puts("#HEY! SPECIFY AN ADDRESS WILL YOU?", ses);
    return ses;
  }

  while(*port && !isspace(*port))
    port++;
  *port++='\0';
  port=space_out(port);

  if(!*port) {
    tintin_puts("#HEY! SPECIFY A PORT NUMBER WILL YOU?", ses);
    return ses;
  }
  
  if(!(sock=connect_mud(host, port, ses)))
   return ses;

  newsession=(struct session *)malloc(sizeof(struct session));
  newsession->name=mystrdup(name);
  newsession->address=mystrdup(address);
  newsession->tickstatus=FALSE;
  newsession->snoopstatus=FALSE;
  newsession->logfile=NULL;
  newsession->aliases=copy_list(common_aliases);
  newsession->actions=copy_list(common_actions);
  newsession->subs=copy_list(common_subs);

  newsession->socket=sock;
  newsession->socketbit=1<<sock;
  newsession->next=sessionlist;
  for(i=0; i<HISTORY_SIZE-1; i++)
    newsession->history[i]=NULL;
  newsession->path_mark=0;
  newsession->path_lenght=0;

  sessionlist=newsession;
  activesession=newsession;  
  sessionsstarted++;


  return(newsession);
}

/*************************************************************************************/
/* cleanup after a session died. if session==activesession, then try find new active */
/*************************************************************************************/
void cleanup_session(struct session *ses)
{
  int i;
  char buf[BUFFER_SIZE];
  struct session *sesptr;

  sessionsstarted--;
  kill_list(ses->aliases);
  for(i=0; i<HISTORY_SIZE; i++)
    if(ses->history[i])
      free(ses->history[i]); 
  if(ses==sessionlist)
    sessionlist=ses->next;
  else {
    for(sesptr=sessionlist; sesptr->next!=ses; sesptr=sesptr->next);
    sesptr->next=ses->next;
  }
  sprintf(buf, "#SESSION '%s' DIED.", ses->name);
  tintin_puts(buf, NULL);
/*  if(write(ses->socket, "ctld\n", 5)<5)
    syserr("write in cleanup"); */    /* can't do this, cozof the peer stuff in net.c */
  if(close(ses->socket)==-1)
    syserr("close in cleanup");
  if(ses->logfile)
    fclose(ses->logfile);
  
  free(ses);
}