#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#include "config.h"

#include <string>
#ifdef USING_STD_STRING
using std::string;
#endif

#ifdef DMALLOC
#include <dmalloc.h>
#endif

#ifdef SOCKS
#include <socks.h>
#endif

#include "command.h"
#include "serverdcc.h"
#include "window.h"
#include "tcltk.h"
#include "messages.h"
#include "format.h"

extern ilist<twindow> windows;
extern char currentwindow[20];

int check(char *command, char *data, char *argument) {
  char temp[TEMPLEN];
  *argument=0;
  if((strlen(command)==strlen(data))&&(!(strcasecmp(command,data)))) return 1;
  sprintf(temp,"%s ",command);
  if(!strncasecmp(temp,data,strlen(temp))) {
    if(strlen(data)>strlen(temp)) {
      strcpy(argument,data+strlen(temp));
    }
    return 1;
  }
  return 0;
}

int do_command(const char *pathname, const char *comm) {
  tchan chan;
  tchan *chanp=0;
  tquery query;
  tquery *queryp=0;
  char argument[TEMPLEN];
  char command[TEMPLEN]={0};
  char tempcommand[TEMPLEN];
  int parsed=0;
  int n;
  char *position;
  twindow window;
  twindow *windowp=0;
  struct hostent *h;
  string argumentstr;
  int oldparsed;

  if(!comm) return 1;

  strcpy(command,comm);
  if(command[0]=='/') strcpy(command,command+1);

  /* Set up channel or query pointers */
  if(pathname&&strcmp(pathname,".main")) {
    strcpy(window.pathname,pathname);
    if((windowp=windows.find(window))) {
      if(!strncasecmp(pathname,".channel",8)) {
	strcpy(chan.pathname,pathname);
	chanp=windowp->server->chanlist.find(chan);
      }
      if(!strncasecmp(pathname,".query",6)) {
	strcpy(query.pathname,pathname);
	queryp=windowp->server->querylist.find(query);
      }
    }
  }

  if(command[0]=='/') {
    if(windowp) {
      TT_EvalF(TT_ARGS,"namespace eval ::%d %q",windowp->server->index,command);
    } else {
      TT_EvalF(TT_ARGS,"%s",command);
    }
    return 0;
  }
   
  /* lookup */
  if(check("lookup",command,argument)) {
    parsed=1;
    if(strlen(argument)) {
      if(!(h=gethostbyname(argument))) {
	switch(h_errno) {
	case HOST_NOT_FOUND:
	  fdisplay("DNS_ERROR",-1,1,M_DNS_ERROR_UNKNOWN);
	  break;
	case NO_ADDRESS:
	  fdisplay("DNS_ERROR",-1,1,M_DNS_ERROR_NOIP);
	  break;
	case NO_RECOVERY:
	  fdisplay("DNS_ERROR",-1,1,M_DNS_ERROR_NORECOVER);
	  break;
	case TRY_AGAIN:
	  fdisplay("DNS_ERROR",-1,1,M_DNS_ERROR_TEMPORARY);
	  break;
	}
      } else {
	fdisplay("DNS_FOR",-1,1,argument);
	fdisplay("DNS_HOSTNAME",-1,1,h->h_name);
	fdisplay("DNS_IP",-1,1,inet_ntoa(*((struct in_addr*)h->h_addr)));
      }
    }
  }

  oldparsed=parsed;

  if(comm&&strlen(comm)) {
    if(pathname&&strlen(pathname)) {
      strcpy(window.pathname,pathname);
      windowp=windows.find(window);
    }
    if(windowp) {
      if(comm[0]=='/') {
	strcpy(tempcommand,comm+1);
      } else {
	strcpy(tempcommand,comm);
      }
      if((position=strstr(tempcommand," "))) {
	argumentstr=position+1;
	*position=0;
      }
      for(n=0;n<(signed)strlen(tempcommand);n++) tempcommand[n]=tolower(tempcommand[n]);
      TT_Eval(TT_ARGS,"\
        set ::internal::alias_parsed 0\n\
        set ::internal::alias_returnvalue 0\n\
      ");
      if(windowp->server) {
	TT_EvalF(TT_ARGS,"\
          foreach script $::%d::scripts {\n\
            if { [info commands ::%d::${script}::alias_%s]!=\"\" } {\n\
              set ::internal::alias_parsed 1\n\
              set ::internal::alias_returnvalue [::%d::${script}::alias_%s %q]\n\
              if { $::internal::alias_returnvalue==1 } {\n\
                break\n\
              } else {\n\
                set ::internal::alias_returnvalue 0\n\
              }\n\
            }\n\
          }\n\
        ",windowp->server->index,windowp->server->index,tempcommand,windowp->server->index,tempcommand,argumentstr.c_str());
      }
      TT_EvalF(TT_ARGS,"\
        if { !$::internal::alias_returnvalue && [info commands ::dynamic::alias_%s]!=\"\" } {\n\
          set ::internal::alias_parsed 1\n\
          set ::internal::alias_returnvalue [::dynamic::alias_%s %q]\n\
          if { $::internal::alias_returnvalue!=1 } {\n\
            set ::internal::alias_returnvalue 0\n\
          }\n\
        }\n\
      ",tempcommand,tempcommand,argumentstr.c_str());
      TT_EvalF(TT_ARGS,"\
        if { !$::internal::alias_returnvalue && [info commands alias_%s]!=\"\" } {\n\
          set ::internal::alias_parsed 1\n\
          alias_%s %q\n\
        }\n\
      ",tempcommand,tempcommand,argumentstr.c_str());
      parsed=TT_Int(TT_ARGS,"set ::internal::alias_parsed");
    }
  }
  
  if(!parsed&&!oldparsed) {
    // DEBUG
    //TT_EvalF(TT_ARGS,".raw.text insert end \"Command (command.cc:171): %q\\n\"",command);
    if(windowp&&windowp->server) windowp->server->senddata(command);
  }
  
  return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1