/*
   tcldcc.c -- handles:
     Tcl stubs for the dcc commands

   dprintf'ized, 1aug96
*/
/*
   This file is part of the eggdrop source code
   copyright (c) 1997 Robey Pointer
   and is distributed according to the GNU general public license.
   For full details, read the top of 'main.c' or the file called
   COPYING that was distributed with this code.
*/
     
#if HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include "../lush.h"
#include "eggdrop.h"
#include "tandem.h"
#include "proto.h"
#include "cmdt.h"
#include "tclegg.h"


extern Tcl_Interp *interp;
extern char cx_file[];
extern int cx_line;
extern struct dcc_t dcc[];
extern int dcc_total;
extern int copy_to_tmp;
extern char tempdir[];
extern char origbotname[];
extern int backgrd;
extern int noshare;
extern party_t *party;
extern int parties;
extern int isolate;

/***********************************************************************/

int tcl_putdcc STDVAR
{ 
  int i,j;
  BADARGS(3,3," idx text");
  i=atoi(argv[1]);
  j=findidx(i); if (j<0) {
    Tcl_AppendResult(irp,"illegal idx",NULL);
    return TCL_ERROR;
  }
  dprintf(j,"%s\n",argv[2]);
  return TCL_OK;
}

int tcl_dccsimul STDVAR
{
  int i,idx; char cmd[512];
  BADARGS(3,3," idx command");
  i=atoi(argv[1]);
  idx=findidx(i);
  if (idx<0) {
    Tcl_AppendResult(irp,"invalid idx",NULL);
    return TCL_ERROR;
  }
  if ((dcc[idx].type!=DCC_CHAT) && (dcc[idx].type!=DCC_FILES) &&
      (dcc[idx].type!=DCC_SCRIPT)) {
    Tcl_AppendResult(irp,"invalid idx",NULL);
    return TCL_ERROR;
  }
  if (strlen(argv[2])>510) argv[2][510]=0;  /* restrict length of cmd */
  strcpy(cmd,argv[2]);
  dcc_activity(dcc[idx].sock,cmd,strlen(cmd));
/*  if (got_dcc_cmd(idx,cmd)) {
    dcc_activity(dcc[idx].sock,".quit",5);
  } */
  return TCL_OK;
}

int tcl_dccsend STDVAR
{
  char s[5],sys[512],*nfn; int i; FILE *f;
  BADARGS(3,3," filename ircnick");
  f=fopen(argv[1],"r"); if (f==NULL) {
    /* file not found */
    Tcl_AppendResult(irp,"3",NULL);
    return TCL_OK;
  }
  fclose(f);
  nfn=strrchr(argv[1],'/');
  if (nfn==NULL) nfn=argv[1]; else nfn++;
  if (at_limit(argv[2])) {
    /* queue that mother */
    if (nfn==argv[1]) queue_file("*",nfn,"(script)",argv[2]);
    else {
      nfn--; *nfn=0; nfn++;
      sprintf(sys,"*%s",argv[1]);
      queue_file(sys,nfn,"(script)",argv[2]);
    }
    Tcl_AppendResult(irp,"4",NULL);
    return TCL_OK;
  }
  if (copy_to_tmp) {
    sprintf(sys,"%s%s",tempdir,nfn);   /* new filename, in /tmp */
    copyfile(argv[1],sys);
  }
  else strcpy(sys,argv[1]);
  i=raw_dcc_send(sys,argv[2],"*",argv[1]);
  if (i>0) wipe_tmp_filename(sys,-1);
  sprintf(s,"%d",i);
  Tcl_AppendResult(irp,s,NULL);
  return TCL_OK;
}

int tcl_dccbroadcast STDVAR
{
  char msg[401];
  BADARGS(2,2," message");
  strncpy(msg,argv[1],400); msg[400]=0;
  chatout("*** %s\n",msg);
  tandout("chat %s %s\n",origbotname,msg);
  return TCL_OK;
}

int tcl_hand2idx STDVAR
{
  int i; char s[10];
  BADARGS(2,2," nickname");
  for (i=0; i<dcc_total; i++)
    if ((strcasecmp(argv[1],dcc[i].nick)==0) &&
	((dcc[i].type==DCC_CHAT) || (dcc[i].type==DCC_FILES) ||
	 (dcc[i].type==DCC_SCRIPT))) {
      sprintf(s,"%d",dcc[i].sock);
      Tcl_AppendResult(irp,s,NULL);
      return TCL_OK;
    }
  Tcl_AppendResult(irp,"-1",NULL);
  return TCL_OK;
}

int tcl_getchan STDVAR
{
  char s[10]; int idx,i;
  BADARGS(2,2," idx");
  i=atoi(argv[1]);
  idx=findidx(i);
  if (idx<0) {
    Tcl_AppendResult(irp,"invalid idx",NULL);
    return TCL_ERROR;
  }
  if ((dcc[idx].type!=DCC_CHAT) && (dcc[idx].type!=DCC_SCRIPT)) {
    Tcl_AppendResult(irp,"invalid idx",NULL);
    return TCL_ERROR;
  }
  if (dcc[idx].type==DCC_SCRIPT)
    sprintf(s,"%d",dcc[idx].u.script->u.chat->channel);
  else sprintf(s,"%d",dcc[idx].u.chat->channel);
  Tcl_AppendResult(irp,s,NULL);
  return TCL_OK;
}

int tcl_setchan STDVAR
{
  int idx,i,chan;
  BADARGS(3,3," idx channel");
  i=atoi(argv[1]);
  idx=findidx(i);
  if (idx<0) {
    Tcl_AppendResult(irp,"invalid idx",NULL);
    return TCL_ERROR;
  }
  if ((dcc[idx].type!=DCC_CHAT) && (dcc[idx].type!=DCC_SCRIPT)) {
    Tcl_AppendResult(irp,"invalid idx",NULL);
    return TCL_ERROR;
  }
  if ((argv[2][0]<'0') || (argv[2][0]>'9')) {
    if ((strcmp(argv[2],"-1")==0) || (strcasecmp(argv[2],"off")==0))
      chan=(-1);
    else {
      chan=get_assoc(argv[2]);
      if (chan == (-1)) {
	Tcl_AppendResult(irp,"channel name is invalid",NULL);
	return TCL_ERROR;
      }
    }
  }
  else chan=atoi(argv[2]);
  if ((chan<-1) || (chan>99999)) {
    Tcl_AppendResult(irp,"channel out of range; must be -1 thru 99999",NULL);
    return TCL_ERROR;
  }
  if (dcc[idx].type==DCC_SCRIPT) dcc[idx].u.script->u.chat->channel=chan;
  else {
    if (dcc[idx].u.chat->channel != 123456)
      tandout("join %s %s %d\n",origbotname,dcc[idx].nick,chan);
    dcc[idx].u.chat->channel=chan;
  }
  return TCL_OK;
}

int tcl_dccputchan STDVAR
{
  int chan; char msg[401];
  BADARGS(3,3," channel message");
  chan=atoi(argv[1]);
  if ((chan<0) || (chan>99999)) {
    Tcl_AppendResult(irp,"channel out of range; must be 0 thru 99999",NULL);
    return TCL_ERROR;
  }
  strncpy(msg,argv[2],400); msg[400]=0;
  chanout2(chan,"%s\n",argv[2]);
  return TCL_OK;
}

int tcl_console STDVAR
{
  int i,j,pls,arg;
  BADARGS(2,4," idx ?channel? ?console-modes?");
  j=atoi(argv[1]); i=findidx(j);
  if (i<0) {
    Tcl_AppendResult(irp,"invalid idx",NULL);
    return TCL_ERROR;
  }
  if (dcc[i].type!=DCC_CHAT) {
    Tcl_AppendResult(irp,"invalid idx",NULL);
    return TCL_ERROR;
  }
  pls=1;
  for (arg=2; arg<argc; arg++) {
    if ((argv[arg][0]=='#') || (argv[arg][0]=='&') || (argv[arg][0]=='*')) {
      if ((argv[arg][0]!='*') && (!defined_channel(argv[arg]))) {
	Tcl_AppendResult(irp,"invalid channel",NULL);
	return TCL_ERROR;
      }
      strncpy(dcc[i].u.chat->con_chan,argv[arg],80);
      dcc[i].u.chat->con_chan[80]=0;
    }
    else {
      if ((argv[arg][0]!='+') && (argv[arg][0]!='-'))
	dcc[i].u.chat->con_flags=0;
      for (j=0; j<strlen(argv[arg]); j++) {
	if (argv[arg][j]=='+') pls=1;
	else if (argv[arg][j]=='-') pls=(-1);
	else {
	  char s[2];
	  s[0]=argv[arg][j]; s[1]=0;
	  if (pls==1) dcc[i].u.chat->con_flags|=logmodes(s);
	  else dcc[i].u.chat->con_flags&=~logmodes(s);
	}
      }
    }
  }
  Tcl_AppendElement(irp,dcc[i].u.chat->con_chan);
  Tcl_AppendElement(irp,masktype(dcc[i].u.chat->con_flags));
  return TCL_OK;
}

int tcl_echo STDVAR
{
  int i,j;
  BADARGS(2,3," idx ?status?");
  j=atoi(argv[1]); i=findidx(j);
  if (i<0) {
    Tcl_AppendResult(irp,"invalid idx",NULL);
    return TCL_ERROR;
  }
  if (dcc[i].type!=DCC_CHAT) {
    Tcl_AppendResult(irp,"invalid idx",NULL);
    return TCL_ERROR;
  }
  if (argc==3) {
    if (atoi(argv[2])) dcc[i].u.chat->status|=STAT_ECHO;
    else dcc[i].u.chat->status&=~STAT_ECHO;
  }
  if (dcc[i].u.chat->status&STAT_ECHO) Tcl_AppendResult(irp,"1",NULL);
  else Tcl_AppendResult(irp,"0",NULL);
  return TCL_OK;
}

int tcl_control STDVAR
{
  int idx,i;
  BADARGS(3,3," idx command");
  i=atoi(argv[1]); idx=findidx(i);
  if (idx<0) {
    Tcl_AppendResult(irp,"invalid idx",NULL);
    return TCL_ERROR;
  }
  if ((dcc[idx].type==DCC_CHAT) && (dcc[idx].u.chat->channel >= 0))
    chanout2_but(idx,dcc[idx].u.chat->channel,"%s has gone.\n",dcc[idx].nick);
  set_script(idx);
  strncpy(dcc[idx].u.script->command,argv[2],120);
  dcc[idx].u.script->command[119]=0;
  return TCL_OK;
}

int tcl_killdcc STDVAR
{
  int idx,i;
  BADARGS(2,2," idx");
  i=atoi(argv[1]); idx=findidx(i);
  if (idx<0) {
    Tcl_AppendResult(irp,"invalid idx",NULL);
    return TCL_ERROR;
  }
  if ((dcc[idx].type!=DCC_CHAT) && (dcc[idx].type!=DCC_FILES) &&
      (dcc[idx].type!=DCC_SCRIPT) && (dcc[idx].type!=DCC_SOCKET)) {
    Tcl_AppendResult(irp,"invalid idx",NULL);
    return TCL_ERROR;
  }
  /* don't kill terminal socket */
  if ((dcc[idx].sock==STDOUT) && !backgrd) return TCL_OK;
  /* make sure 'whom' info is updated for other bots */
  if (dcc[idx].type==DCC_CHAT) {
    tandout("part %s %s\n",origbotname,dcc[idx].nick);
    /* no notice is sent to the party line -- that's the scripts' job */
  }
  killsock(dcc[idx].sock); lostdcc(idx);
  return TCL_OK;
}

int tcl_putbot STDVAR
{
  int i; char msg[401];
  BADARGS(3,3," botnick message");
  i=nextbot(argv[1]);
  if (i<0) {
    Tcl_AppendResult(irp,"bot is not in the botnet",NULL);
    return TCL_ERROR;
  }
  strncpy(msg,argv[2],400); msg[400]=0;
  tprintf(dcc[i].sock,"zapf %s %s %s\n",origbotname,argv[1],msg);
  return TCL_OK;
}

int tcl_putallbots STDVAR
{
  char msg[401];
  BADARGS(2,2," message");
  strncpy(msg,argv[1],400); msg[400]=0;
  tandout("zapf-broad %s %s\n",origbotname,msg);
  return TCL_OK;
}

int tcl_idx2hand STDVAR
{
  int i,idx;
  BADARGS(2,2," idx");
  i=atoi(argv[1]); idx=findidx(i);
  if (idx<0) {
    Tcl_AppendResult(irp,"invalid idx",NULL);
    return TCL_ERROR;
  }
  Tcl_AppendResult(irp,dcc[idx].nick,NULL);
  return TCL_OK;
}

int tcl_bots STDVAR
{
  int i;
  BADARGS(1,1,"");
  for (i=0; i<get_tands(); i++)
    Tcl_AppendElement(irp,get_tandbot(i));
  return TCL_OK;
}

/* list of { idx nick host type } */
/* type: "chat", "files", "script" */
int tcl_dcclist STDVAR
{
  int i,ok; char typ[20],idxstr[10]; char *list[4],*p;
  BADARGS(1,1,"");
  for (i=0; i<dcc_total; i++) {
    ok=0;
    switch (dcc[i].type) {
    case DCC_CHAT: strcpy(typ,"chat"); ok=1; break;
    case DCC_FILES: strcpy(typ,"files"); ok=1; break;
    case DCC_SCRIPT: strcpy(typ,"script"); ok=1; break;
    case DCC_SOCKET: strcpy(typ,"socket"); ok=1; break;
    case DCC_BOT: strcpy(typ,"bot"); ok=1; break;
    case DCC_SEND: strcpy(typ,"receiving_file"); ok=1; break;
    case DCC_GET: strcpy(typ,"sending_file"); ok=1; break;
    case DCC_GET_PENDING: strcpy(typ,"send_file_pending"); ok=1; break;
    }
    if (ok) {
      sprintf(idxstr,"%d",dcc[i].sock);
      list[0]=idxstr; list[1]=dcc[i].nick; list[2]=dcc[i].host;
      list[3]=typ;
      p=Tcl_Merge(4,list);
      Tcl_AppendElement(irp,p); n_free(p,"",0);
    }
  }
  return TCL_OK;
}

/* list of { nick bot host flag idletime awaymsg } */
int tcl_whom STDVAR
{
  char c[2],idle[10],away[121]; int chan; time_t now=time(NULL);
  char *list[6],*p; int i;
  context;
  BADARGS(2,2," chan");
  if ((argv[1][0]<'0') || (argv[1][0]>'9')) {
    chan=get_assoc(argv[1]);
    if (chan == (-1)) {
      Tcl_AppendResult(irp,"channel name is invalid",NULL);
      return TCL_ERROR;
    }
  }
  else chan=atoi(argv[1]);
  if ((chan<0) || (chan>99999)) {
    Tcl_AppendResult(irp,"channel out of range; must be 0 thru 99999",NULL);
    return TCL_ERROR;
  }
  for (i=0; i<dcc_total; i++) if (dcc[i].type==DCC_CHAT) {
    if (dcc[i].u.chat->channel==chan) {
      c[0]=geticon(i); c[1]=0;
      sprintf(idle,"%lu",(now-dcc[i].u.chat->timer)/60);
      if (dcc[i].u.chat->away!=NULL) strcpy(away,dcc[i].u.chat->away);
      else away[0]=0;
      list[0]=dcc[i].nick; list[1]=origbotname; list[2]=dcc[i].host;
      list[3]=c; list[4]=idle; list[5]=away;
      p=Tcl_Merge(6,list);
      Tcl_AppendElement(irp,p); n_free(p,"",0);
    }
  }
  if (!isolate) for (i=0; i<parties; i++) {
    if (party[i].chan==chan) {
      c[0]=party[i].flag; c[1]=0;
      if (party[i].timer==0L) strcpy(idle,"0");
      else sprintf(idle,"%lu",(now-party[i].timer)/60);
      if (party[i].status&PLSTAT_AWAY) strcpy(away,party[i].away);
      else away[0]=0;
      list[0]=party[i].nick; list[1]=party[i].bot; list[2]=party[i].from;
      list[3]=c; list[4]=idle; list[5]=away;
      p=Tcl_Merge(6,list);
      Tcl_AppendElement(irp,p); n_free(p,"",0);
    }
  }
  return TCL_OK;
}

int tcl_dccused STDVAR
{
  char s[20];
  BADARGS(1,1,"");
  sprintf(s,"%d",dcc_total);
  Tcl_AppendResult(irp,s,NULL);
  return TCL_OK;
}

int tcl_getdccidle STDVAR
{
  int i,x,idx; char s[21]; time_t now=time(NULL);
  BADARGS(2,2," idx");
  i=atoi(argv[1]); idx=findidx(i);
  if (idx<0) {
    Tcl_AppendResult(irp,"invalid idx",NULL);
    return TCL_ERROR;
  }
  switch(dcc[idx].type) {
  case DCC_CHAT:
    x=(now-(dcc[idx].u.chat->timer));
    break;
  case DCC_FILES:
    x=(now-(dcc[idx].u.file->chat->timer));
    break;
  case DCC_SCRIPT:
    if (dcc[idx].u.script->type == DCC_CHAT)
      x=(now-(dcc[idx].u.script->u.chat->timer));
    else
      x=(now-(dcc[idx].u.script->u.file->chat->timer));
    break;
  default:
    Tcl_AppendResult(irp,"invalid idx",NULL);
    return TCL_ERROR;
  }
  sprintf(s,"%d",x);
  Tcl_AppendElement(irp,s);
  return TCL_OK;
}

int tcl_getdccaway STDVAR
{
  int i,idx;
  BADARGS(2,2," idx");
  i=atol(argv[1]); idx=findidx(i);
  if (idx<0) {
    Tcl_AppendResult(irp,"invalid idx",NULL);
    return TCL_ERROR;
  }
  if (dcc[idx].type!=DCC_CHAT) {
    Tcl_AppendResult(irp,"invalid idx",NULL);
    return TCL_ERROR;
  }
  if (dcc[idx].u.chat->away == NULL) return TCL_OK;
  Tcl_AppendResult(irp,dcc[idx].u.chat->away,NULL);
  return TCL_OK;
}

int tcl_setdccaway STDVAR
{
  int i,idx;
  BADARGS(3,3," idx message");
  i=atol(argv[1]); idx=findidx(i);
  if (idx<0) {
    Tcl_AppendResult(irp,"invalid idx",NULL);
    return TCL_ERROR;
  }
  if (dcc[idx].type!=DCC_CHAT) {
    Tcl_AppendResult(irp,"invalid idx",NULL);
    return TCL_ERROR;
  }
  if (!argv[2][0]) {
    /* un-away */
    if (dcc[idx].u.chat->away!=NULL) not_away(idx);
    return TCL_OK;
  }
  /* away */
  set_away(idx,argv[2]);
  return TCL_OK;
}

int tcl_link STDVAR
{
  int x,i; char bot[10],bot2[10];
  BADARGS(2,3," ?via-bot? bot");
  strncpy(bot,argv[1],9); bot[9]=0;
  if (argc==2)
    x=botlink("",-1,bot);
  else {
    x=1; strncpy(bot2,argv[2],9); bot2[9]=0;
    i=nextbot(bot); if (i<0) x=0;
    else tprintf(dcc[i].sock,"link %s %s %s\n",origbotname,bot,bot2);
  }
  sprintf(bot,"%d",x); Tcl_AppendResult(irp,bot,NULL);
  return TCL_OK;
}

int tcl_unlink STDVAR
{
  int i,x; char bot[10];
  BADARGS(2,2," bot");
  strncpy(bot,argv[1],9); bot[9]=0;
  i=nextbot(bot); if (i<0) x=0;
  else {
    x=1;
    if (strcasecmp(bot,dcc[i].nick)==0) x=botunlink(-2,bot);
    else
      tprintf(dcc[i].sock,"unlink %s %s %s\n",origbotname,lastbot(bot),bot);
  }
  sprintf(bot,"%d",x); Tcl_AppendResult(irp,bot,NULL);
  return TCL_OK;
}

int tcl_filesend STDVAR
{
  int i,idx; char s[10];
  BADARGS(3,4," idx filename ?nick?");
  i=atoi(argv[1]); idx=findidx(i);
  if (idx<0) {
    Tcl_AppendResult(irp,"invalid idx",NULL);
    return TCL_ERROR;
  }
  if (dcc[idx].type!=DCC_FILES) {
    Tcl_AppendResult(irp,"invalid idx",NULL);
    return TCL_ERROR;
  }
  if (argc==4) i=files_get(idx,argv[2],argv[3]);
  else i=files_get(idx,argv[2],"");
  sprintf(s,"%d",i);
  Tcl_AppendResult(irp,s,NULL);
  return TCL_OK;
}

int tcl_assoc STDVAR
{
  int chan; char name[21],*p;
  BADARGS(2,3," chan ?name?");
  chan=atoi(argv[1]);
  if ((chan<1) || (chan>99999)) {
    Tcl_AppendResult(irp,"invalid channel #",NULL);
    return TCL_ERROR;
  }
  if (argc==3) {
    strncpy(name,argv[2],20); name[20]=0;
    add_assoc(name,chan);
  }
  p=get_assoc_name(chan);
  if (p==NULL) name[0]=0; else strcpy(name,p);
  Tcl_AppendResult(irp,name,NULL);
  return TCL_OK;
}

int tcl_killassoc STDVAR
{
  int chan;
  BADARGS(2,2," chan");
  chan=atoi(argv[1]);
  if ((chan<1) || (chan>99999)) {
    Tcl_AppendResult(irp,"invalid channel #",NULL);
    return TCL_ERROR;
  }
  kill_assoc(chan);
  return TCL_OK;
}

int tcl_connect STDVAR
{
  int i,z,sock; char s[81];
  BADARGS(3,3," hostname port");
  if (dcc_total==MAXDCC) {
    Tcl_AppendResult(irp,"out of dcc table space",NULL);
    return TCL_ERROR;
  }
  i=dcc_total;
  sock=getsock(0);
  z=open_telnet_raw(sock,argv[1],atoi(argv[2]));
  if (z<0) {
    if (z==(-2)) strcpy(s,"DNS lookup failed");
    else neterror(s);
    Tcl_AppendResult(irp,s,NULL); return TCL_ERROR;
  }
  /* well well well... it worked! */
  dcc[i].sock=sock;
  dcc[i].addr=0L;
  dcc[i].port=atoi(argv[2]);
  strcpy(dcc[i].nick,"*");
  strncpy(dcc[i].host,argv[1],UHOSTLEN); dcc[i].host[UHOSTLEN]=0;
  dcc[i].type=DCC_SOCKET;
  dcc[i].u.other=NULL;
  dcc_total++;
  sprintf(s,"%d",sock);
  Tcl_AppendResult(irp,s,NULL); return TCL_OK;
}
