#include <iodef.h>
#include <file.h>
#include <ssdef.h>
#include <string.h>
#ifdef __GNUC__
#include <stat.h>
#else
#include <stdlib.h>
#include <unixio.h>
#endif
#include <time.h>
#include <lib$routines.h>
#include "global.h"
#include "command.h"
#include "constants.h"
#include "window_i.h"
#include "window.h"
#include "qio.h"
#include "on.h"
#include "dcc.h"
#include "split.h"
#include "builtin.h"
#include "ff.h"
#include "mycompare.h"
#include "sock.h"

struct dcc_node {
  short iochan, padding1;
  SIN *mysin;
  char *from;
  char file[TOLEN];
  int flags, output, stream, start;
  int hostid, port;
  unsigned long transmit;
  unsigned long received;
  char savebuffer[MAXBRK*2];
  int saved;
  dcc_ptr next;
};

#define MAXSEND MAXBRK   /* Max number of bytes to send on a dcc send */
                         /* Must be smaller than buffer size */
                    
extern long myaddress;
extern server_ptr gsrv;
static int dcc_complete(connect_node *);
static int dcc_infile_data(connect_node *), dcc_outfile_data(connect_node *),
    dcc_chat_data(connect_node *);

static void dcc_userchat(char *string), dcc_userclose(char *string),
     dcc_userget(char *string), dcc_userlist(char *string),
     dcc_usersend(char *string), dcc_userraw(char *string);
   
static CmdList dcc_opt[] =
{
 {{""}  ,      dcc_userlist,  0 },
 {{"CHAT"},    dcc_userchat,  DCC_CHAT },
 {{"CLOSE"},   dcc_userclose, 0 },
 {{"GET"},     dcc_userget,   DCC_FILE|DCC_GET },
 {{"LIST"},    dcc_userlist,  0 },
 {{"RAW"},     dcc_userraw,   0 },
 {{"SEND"},    dcc_usersend,  DCC_FILE|DCC_SEND },
};
 
#define DCC_COMMANDS sizeof(dcc_opt)/sizeof(CmdList) - 1
 
/* ----------------------------------------------------------------------- */
static dcc_ptr dcc_list = NULL;

/* ----------------------------------------------------------------------- */
static dcc_ptr remove_dcc_entry(dcc_ptr temp)
{
  dcc_ptr n, p;
  for (p=NULL, n = dcc_list; n && (n != temp); p = n, n = n->next);
  if (!n) return NULL;
  if (p) p->next = n->next;
  else dcc_list = n->next;
  return n;
}
/* ----------------------------------------------------------------------- */
static void erase_dcc_entry(dcc_ptr entry)
{
  dcc_ptr front;
  front = remove_dcc_entry(entry);
  if (front) {
    tcp_shutdown(front->iochan);
    myfree(front->from);
    myfree(front);
  }
}
/* ----------------------------------------------------------------------- */
void user_dcc(char *str, int varpar, char *subparams)
{
  char *word, *orig, *line;
  int cmd_cnt;
  CmdList *command;
 
  orig = line = m_strcpy(str);
  word = next_arg(&line);
  command = find_command(dcc_opt, DCC_COMMANDS, word, &cmd_cnt);
  
  if (cmd_cnt == 0)
    say("DCC option \"%s\" is unknown.", word?word:"(null)");
  else if (((cmd_cnt < 0) || (cmd_cnt == 1)) && command)
    command->cmdfcn(line);
  else
    say("DCC option \"%s\" is ambiguous.", word?word:"(null)");
  myfree(orig);
}
 
/* ----------------------------------------------------------------------- */
/* Look up a dcc entry in the queue.                                       */
/* ----------------------------------------------------------------------- */
static dcc_ptr dcc_lookup(char *nick, char *file, int type, int send)
{
  dcc_ptr w;
  for (w=dcc_list; w; w = w->next)
  {
    if ((wild_match(nick, w->from) >= 0) && ((w->flags & type) == type) &&
        (wild_match(file, w->file) >= 0) &&
        (w->flags & send))
      return w;
  }
  return NULL;
}
 
/* ----------------------------------------------------------------------- */ 
static short make_connection(dcc_ptr temp)
{
  char msg[80];
  int status;
  short chan;
  SIN *mysin;

  mysin = (SIN *)mymalloc(sizeof(SIN));
  if (!mysin) {
    say("*** Could not malloc space for SIN in make_connection");
    return FALSE;
  }
  (void)memset(mysin, 0, sizeof(SIN));
  mysin->sin_family = AF_INET;
  mysin->sin_port = tcp_htons(temp->port);
  mysin->sin_address = tcp_htonl(temp->hostid);
 
  chan = tcp_socket_and_connect(mysin, sizeof(SIN));
  if (chan == -1) {
    get_socket_error(msg);
    say("*** connent in make_connection: %s", msg);
    return FALSE;
  }

  temp->start = time(NULL);
  add_connect_to_list(chan, mysin, (char *)temp, CONNECT_DCC);
  temp->flags |= DCC_CONN;
  if (temp->flags & DCC_NOCONN) temp->flags -= DCC_NOCONN;
  temp->iochan = chan;
  if (temp->flags & DCC_CHAT)
    start_read(chan, chan, dcc_chat_data, dcc_complete);
  else if (temp->flags & DCC_FILE)
    start_read(chan, chan, dcc_infile_data, dcc_complete);
  else say("*** Attemping to make a dcc connection to an unknown type");
  return 1;
}
 
/* ----------------------------------------------------------------------- */
static char rfm_str[7][5] =
  { {""}, {"fix"}, {"var"}, {"vfc"}, {"stm"}, {"stmlf"}, {"stmcr"} };
static char rat_str[5][3] =
  { {""}, {"blk"}, {"cr"},  {"ftn"}, {"prn"} };
/* ----------------------------------------------------------------------- */
static int dcc_accept(short chan)
{
  SIN *sin;
  int num, count;
  unsigned short nchan;
  dcc_ptr walk;
  dcc_ptr temp;
  char msg[80], rfm[10], rat[10], mrs[10];
  struct stat zz;

  for (walk = dcc_list; walk && (walk->iochan != chan) ; walk = walk->next);
  if (!walk) {
    tcp_shutdown(chan);
    return FALSE;
  }
  if (!(sin = (SIN *)mymalloc(sizeof(SIN)))) {
    say("*** Could not malloc for dcc accept");
    return 0;
  }
  
  add_connect_to_list(chan, sin, (char *)walk, CONNECT_DCC);
  nchan = tcp_accept_after_wait(chan, chan, sin, sizeof(SIN));
  walk->start = time(NULL);
  walk->flags |= DCC_CONN;
  walk->flags -= DCC_NOCONN;
  walk->iochan = nchan;
  if (walk->flags & DCC_CHAT) {
    say("*** DCC CHAT connection to %s established.", walk->from);
    start_read(chan, nchan, dcc_chat_data, dcc_complete);
    return TRUE;
  }
  if ((walk->flags & DCC_FILE) && (walk->flags & DCC_GET)) {
    walk->stream = -1;
    start_read(chan, nchan, dcc_infile_data, dcc_complete);
    return TRUE;
  }
  if (stat(walk->file, &zz)==-1)
  {
    say("*** Could not stat %s.", walk->file);
    erase_dcc_entry(walk);
    return 0;
  }
  count = 2;

  if ((zz.st_fab_rfm>=1) && (zz.st_fab_rfm>=6))
    sprintf(rfm, "rfm=%s", rfm_str[zz.st_fab_rfm]);
   else strcpy(rfm, "rfm=udf");
  if ((zz.st_fab_rat>=1) && (zz.st_fab_rat>=4))
    sprintf(rat, "rat=%s", rat_str[zz.st_fab_rfm]);
  else {
    *rat = 0;
    count--;
  }
  sprintf(mrs, "mrs=%d", zz.st_fab_mrs);
  say("*** DCC connection to %s/%s established %s.", walk->from,
      walk->file, walk->stream?"(binary)":"(ascii)");     
  start_read(chan, nchan, dcc_outfile_data, dcc_complete);
  if (count==2)
    walk->output = open(walk->file, O_RDONLY, 0, rfm, mrs, rat);
  else
    walk->output = open(walk->file, O_RDONLY, 0, rfm, mrs);
  if (walk->output!=-1)
    if ((num = read(walk->output, walk->savebuffer, MAXSEND)) != -1)
    {
      walk->transmit = num;
      if (tcp_send(nchan, walk->savebuffer, num) != -1)
        return TRUE;
      get_socket_error(msg);
      say("*** send in accept: %s", msg);
    } else say("*** DCC read failed - aborting.");
  else say("*** %s could not be opened.", walk->file);
  erase_dcc_entry(walk);
  return FALSE;
}
 
/* ----------------------------------------------------------------------- */
SIN *dcc_bind(short *chan)
{
  SIN *sin;
  char msg[80];
  sin = tcp_bind_and_listen(chan, dcc_accept);
  if (sin) return sin;
  get_socket_error(msg);
  say("*** dcc bind and listen: %s", msg);
  return NULL;
}
 
/* ----------------------------------------------------------------------- */
static void dcc_userraw(char *string)
{
  char *chan, *host, ret[10], line[MAXLEN];
  chan = next_arg(&string);
  host = next_arg(&string);
  sprintf(line, "%s 1 %s", chan, string);
  built_write(line, ret, sizeof(ret)-1);
}

/* ----------------------------------------------------------------------- */
static void dcc_userchat(char *string)
{
  SIN sin, *new_sin;
  short chan;
  int type, ret;
  dcc_ptr temp;
  char *nick;

  nick = next_arg(&string);
  if (!nick || !*nick) {
    say("*** Nickname required for DCC CHAT.");
    return;
  }
  
  temp = dcc_lookup(nick, "CHAT", DCC_CHAT+DCC_NOCONN, DCC_GET);
  if (temp)
  {
    if (make_connection(temp) == TRUE)
      say("*** DCC chat connection started.");
    else {
      say("*** DCC chat link could not be established.");
      erase_dcc_entry(temp);
    }              
  } else {
    if ((new_sin = dcc_bind(&chan)))
    {
      if (logdcc_request(0, 0, nick, "CHAT", DCC_CHAT|DCC_SEND, new_sin, chan))
        (void)new_send(gsrv, "PRIVMSG %s :\001DCC CHAT CHAT %u %u\001\n", nick, 
                       tcp_htonl(myaddress), tcp_htons(new_sin->sin_port));
      else say("*** Could not log dcc chat request");
    }
  }
}
 
/* ----------------------------------------------------------------------- */
static void dcc_userclose(char *string)
{
  int type, ret, cmd_cnt;
  char *file, *nick, *type_s;
  dcc_ptr temp;
  CmdList *command;

  type_s = next_arg(&string);
  nick = next_arg(&string);
  file = next_arg(&string);
  if (!type_s || !*type_s || !nick || !*nick) {
    say("*** You must specify a type and nick for DCC CLOSE");
    return;
  }
  if (strcasecmp(type_s, "RAW") == 0) {
    tcp_shutdown(atoi(nick));
    return;
  }
  if (!(command = find_command(dcc_opt, DCC_COMMANDS, type_s, &cmd_cnt))) {
    say("*** Unknown or ambiguous DCC type %s", type_s);
    return;
  }
  type = command->varpar;
  if (!file || !*file) file = "*";
  temp = dcc_lookup(nick, file, type, DCC_SEND|DCC_GET);
  if (!temp) {
    say("*** No matching DCC entry from %s", nick);
    return;
  }
/* The close of the send triggers the dcc_accept routine, causing it to think
 * that it's active. */
  if (temp->flags & DCC_CONN)
    tcp_shutdown(temp->iochan);
  else {
    erase_dcc_entry(temp);
    say("*** DCC entry deleted.");
  }
}
 
/* ----------------------------------------------------------------------- */
static char *dcc_typename(int flag)
{
  if (flag & DCC_CHAT) return "CHAT";
  else if (flag & DCC_FILE)
    if (flag & DCC_SEND) return "SEND";
    else return "GET";
  return "UNK";
}

/* ----------------------------------------------------------------------- */
static void dcc_userlist(char *string)
{
  dcc_ptr temp;
  int old;

  old = sys$setast(0);
  say("Type  Nick      Status     Transmit  Received  Port  Arguments");
  for (temp=dcc_list; temp; temp = temp->next)
  {
    say("%-5.5s %-9.9s %-10s %-9d %-9d %-5d %-25s", dcc_typename(temp->flags), 
        temp->from, (temp->flags&DCC_CONN)?"ACTIVE":"WAITING", 
        temp->transmit, temp->received,
        temp->mysin?tcp_htons(temp->mysin->sin_port):-1, temp->file);
  }
  if (old==SS$_WASSET) sys$setast(1);
  say("*** End DCC listing.");
}
 
/* ----------------------------------------------------------------------- */
static void dcc_usersend(char *string)
{
  short chan;
  dcc_ptr temp;
  struct stat stat_buff;
  SIN *new_sin;
  char *nick, *file, *start;
 
  nick = next_arg(&string);
  file = next_arg(&string);

  if (!nick || !*nick || !file || !*file) {
    say("*** Nick and file required for DCC SEND.");
    return;
  }
  if (stat(file, &stat_buff)==-1) {
    say("*** Could not access that file.");
    return;
  }
  if ((new_sin = dcc_bind(&chan)))
    if ((temp = logdcc_request(0, 0, nick, file, DCC_FILE|DCC_SEND,
                               new_sin, chan)))
    {
      if ((start = (char *)strstr(file, "]"))) start++;
      else start = file;
      if (stat_buff.st_fab_rat == 2) temp->stream = 0;
      new_send(gsrv, "PRIVMSG %s :\001DCC SEND %s %u %u\001\n", nick,
               start, tcp_htonl(myaddress), tcp_htons(new_sin->sin_port));
    } else say("*** Could not logdcc request");
}
 
/* ----------------------------------------------------------------------- */
/* When the user tries to get a file, this routine is called.              */
/* ----------------------------------------------------------------------- */
static void dcc_userget(char *string)
{
  char *nick, *file, *altfile, *w, *real_file;
  dcc_ptr temp;
  int type, c;
  SIN sin;

  nick = next_arg(&string);
  file = next_arg(&string);
  altfile = next_arg(&string);
  if (!nick || !*nick) {
    say("*** Nickname required for DCC GET.");
    return;
  }
  if (!file || !*file) file = "*";
  temp = dcc_lookup(nick, file, DCC_FILE+DCC_NOCONN, DCC_GET);
  if (temp) {
    if (!altfile || !*altfile) real_file = m_strcpy(temp->file);
    else real_file = m_strcpy(altfile);
    temp->stream = -1;
    for (w = real_file, c = 0; *w; w++)
    {
      if (*w=='.') { c++; if (c>1) *w = '_'; }
      if (*w=='/') *w = '$';
    }
    strcpy(temp->file, real_file);
    myfree(real_file);
    if (make_connection(temp) == TRUE)
      say("*** DCC connection started.");
    else {
      say("*** DCC link could not be established.");
      erase_dcc_entry(temp);
    }
  } else
    say("*** No file (%s) offerred in SEND mode by %s", file, nick);
}
 
/* ----------------------------------------------------------------------- */
static int dcc_complete(connect_node *node)
{
  dcc_ptr temp, nt;
 
  temp = (dcc_ptr)node->specific;
  if (!temp) return 0;
  nt = remove_dcc_entry(temp);
  if (!nt) say("*** Data may be invalid at completion time");
  tcp_shutdown(temp->iochan);
  if (temp->flags & DCC_CHAT)
    say("*** DCC CHAT with %s completed in %d seconds.", temp->from,
        time(NULL) - temp->start);
  else if (temp->flags & DCC_FILE)
  {
    float rate;
    char str[20];
    temp->start = time(NULL) - temp->start;
    if (temp->start<=0) temp->start = 1;
    if (temp->flags & DCC_SEND)
      rate = (float)temp->transmit/(float)(1024 * temp->start);
    else
      rate = (float)temp->received/(float)(1024 * temp->start);
    sprintf(str, "%2.2f", rate);
    if (temp->flags & DCC_GET)
    {
      if (temp->saved) write(temp->output, temp->savebuffer, temp->saved);
      say("*** DCC GET:%s from %s completed %s kb/sec. (%u bytes)",
          temp->file, temp->from, str, temp->received);
    } else
      say("*** DCC SEND:%s to %s completed %s kb/sec. (%u bytes)",
          temp->file, temp->from, str, temp->transmit);
    close(temp->output);
  }
  return 0;
}
 
/* ----------------------------------------------------------------------- */
static int dcc_bad_complete(connect_node *node, char *str)
{
  char msg[80];
  get_socket_error(msg);
  yell("%s: %s", str, msg);
/* The expectation is that the shutdown will trigger the real complete */
  tcp_shutdown(node->iochan);
/*   dcc_complete(node); */
  return 0;
}

/* ----------------------------------------------------------------------- */
static int dcc_infile_data(connect_node *node)
{
  char msg[80];
  dcc_ptr temp;
  int size, loop;
  temp = (dcc_ptr)node->specific;
  if (!temp) return dcc_bad_complete(node, "lost connection data");
  if (temp->stream == -1)
  {
    temp->stream = 0;
    for (loop=0; loop < (int)node->iosb.length; loop++)
      if (node->buffer[loop] <= 0) {
        temp->stream = 1;
	loop = (int)node->iosb.length;
      }
    if (temp->stream)
      temp->output = open(temp->file, O_WRONLY|O_CREAT|O_TRUNC, 0, "rfm=fix",
                          "mrs=512", "ctx=stm");
    else
      temp->output = open(temp->file, O_WRONLY|O_CREAT|O_TRUNC, 0, "rfm=var",
                          "rat=cr");
    if (temp->output==-1) {
      sprintf(msg, "Could not open %s for write (stream: %d)",
              temp->file, temp->stream);
      return dcc_bad_complete(node, msg);
    }
  }
  temp->received += (int)node->iosb.length;
  if (temp->stream)
    write(temp->output, node->buffer, (int)node->iosb.length);
  else {
    int written;
    char *walk;
    memcpy(&temp->savebuffer[temp->saved], node->buffer,
           (int)node->iosb.length);
    temp->saved += (int)node->iosb.length;
    walk = &temp->savebuffer[temp->saved-1];
    while ((*walk != '\n') && (walk >= temp->savebuffer)) walk--;
    written = walk - temp->savebuffer + 1;
    if (written>0) {
      if (write(temp->output, temp->savebuffer, written)==-1)
        yell("*** error writeing dcc incoming file!");
      temp->saved -= written;
      memcpy(temp->savebuffer, &temp->savebuffer[written], temp->saved);
    }
  }
  size = tcp_htonl(temp->received);
  if (tcp_send(temp->iochan, (char *)&size, sizeof(size)) == -1)
    return dcc_bad_complete(node, "getdata1 status");
  return 1;
}

/* ----------------------------------------------------------------------- */
static int dcc_outfile_data(connect_node *node)
{
  dcc_ptr temp;
  int size, status, cl, indx;

  temp = (dcc_ptr)node->specific;
  if (!temp) return dcc_bad_complete(node, "lost connection data");
  indx = (int)node->iosb.length - 4;
  if (indx<0) return 0;
  memcpy(&size, &node->buffer[indx], 4);
  if (tcp_htonl(size) != temp->transmit) return 1;
  cl = 0;
  do {
    size = read(temp->output, &temp->savebuffer[cl], MAXSEND-cl);
    cl += size;
  } while ((size>0) && (cl <= (MAXSEND/2)));
  if (cl>0) {
    temp->transmit += cl;
    if (tcp_send(node->iochan, temp->savebuffer, cl) == -1)
      return dcc_bad_complete(node, "getdata2 status");
  } else return dcc_complete(node);
  return 1;
}

/* ----------------------------------------------------------------------- */
int dcc_send_chat_msg(char *nick, char *msg)
{
  dcc_ptr temp;
  int len;
  temp = dcc_lookup(nick, "CHAT", DCC_CHAT|DCC_CONN, DCC_SEND|DCC_GET);
  if (!temp) return -1;
  len = strlen(msg);
  tcp_send(temp->iochan, msg, len);
  tcp_send(temp->iochan, "\n", strlen("\n"));
  temp->transmit += len;
  return len;
}

/* ----------------------------------------------------------------------- */
extern win_ptr awins;
static int dcc_chat_data(connect_node *node)
{
  char *sline, *walk, *handle_line;
  int old_loglevel, len, done;
  dcc_ptr temp;

  temp = (dcc_ptr)node->specific;
  if (!temp) return dcc_bad_complete(node, "lost connection data");
  temp->received += (int)node->iosb.length;
  strncat(temp->savebuffer, node->buffer, (int)node->iosb.length);
  sline = walk = temp->savebuffer;
  done = FALSE;
  do {
    while (*walk && (*walk != '\012')) walk++;
    if (*walk == '\012') {
      win_ptr oldwin = NW, index;
      *walk++ = 0;
      for (index=awins; index; index = index->next)
        if (index->query && (index->query[0] == '=') &&
           (strcasecmp(&index->query[1], temp->from) == 0))
          oldwin = set_outwin(index);
      old_loglevel = set_loglevel(DCC);
      handle_line = m_strcat(temp->from, sline, 1, 0);
      if (!handle_on(o_dcc_chat, handle_line, 0))
        say("=%s= %s", temp->from, sline);
      myfree(handle_line);
      set_loglevel(old_loglevel);
      if (oldwin) set_outwin(oldwin);
      sline = walk;
    } else {
      if (sline != temp->savebuffer)
        strcpy(temp->savebuffer, sline);
      done = TRUE;
    }
  } while (!done);
  return 1;
}

/* ----------------------------------------------------------------------- */
static char *hostid_to_string(unsigned hostid, char *str)
{
  int a[4], loop;
  for (loop=3; loop>=0; loop--) {
     a[loop] = hostid & 0xff;
     hostid = hostid/256;
  }
  sprintf(str, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]);
  return str;
}

/* ----------------------------------------------------------------------- */
/* Log an entry into the dcc queue so the user can get retrieve it later   */
/* ----------------------------------------------------------------------- */
dcc_ptr logdcc_request(unsigned long hostid, unsigned long port, char *from,
                       char *file, int type, SIN *mysin, short chan)
{
  dcc_ptr temp = NULL, t1 = NULL;
  char *start, dummy[MAXLEN];
  int tmask, wmask;

  tmask = type & DCC_TYPEMASK;
  wmask = type & DCC_WAYMASK;

  type |= DCC_NOCONN;    /* mark it as not connected */
  if (type&DCC_CONN) type -= DCC_CONN; /* clear the connected flag */
/* If we are already connected something similar, reject */
  t1 = dcc_lookup(from, file, tmask + DCC_CONN, DCC_WAYMASK);
  if ((tmask == DCC_GET) && (type & DCC_CHAT)) temp = NULL;
  else  temp = dcc_lookup(from, file, tmask + DCC_NOCONN, wmask);
  if (t1 || temp) {
    say("*** DCC connection to %s/%s already %s - rejecting",
        from, file, t1?"active":"queued");
    return NULL;
  }
  if ((temp=(dcc_ptr)mymalloc(sizeof(struct dcc_node))) == NULL)
    return NULL;

  temp->from = m_strcpy(from);
  if ((start = (char *)strrchr(file, '/')) == NULL) start = file;
  else start++;
  (void)strcpy(temp->file, start);
  temp->flags = type;
  temp->output = 0;
  temp->stream = 1;
  temp->hostid = hostid;
  temp->port = port;
  temp->transmit = temp->received = 0;
  temp->savebuffer[0] = 0;
  temp->saved = 0;
  temp->iochan = chan;
  temp->mysin = mysin;

  temp->next = dcc_list;
  dcc_list = temp;
  if (!mysin) {
    temp->mysin = (SIN *)mymalloc(sizeof(SIN));
    if (temp->mysin) {
      memset(temp->mysin, 0, sizeof(SIN));
      temp->mysin->sin_family = AF_INET;
      temp->mysin->sin_port = tcp_htons(port);
      temp->mysin->sin_address = hostid;
    }
  }

  if (temp->flags & DCC_FILE)
    if (temp->flags & DCC_SEND)
      say("*** DCC SEND request to %s for %s queued.", from, file);
    else
      say("*** DCC SEND request from %s for %s on %s[%d] queued.",
          from, file, hostid_to_string(hostid, dummy), port);
  else if (temp->flags & DCC_CHAT)
    say("*** DCC CHAT request %s %s for %s queued.",
        (temp->flags & DCC_SEND)?"to":"from", from, file);
  return temp;
}

void logdcc_in(int hostid, int port, char *from, char *file, char *type)
{
  dcc_ptr tmp, new;
  int itype = 0; /* assumes DCC types can not be 0 */
  if (strcasecmp(type, "SEND")==0) itype = DCC_FILE;
  else if (strcasecmp(type, "CHAT")==0) itype = DCC_CHAT;
  else {
    say("*** Unknown DCC %s request from %s/%s", type, from, file);
    return;
  }
  itype = itype | DCC_GET | DCC_NOCONN;
  new = logdcc_request(hostid, port, from, file, itype, NULL, 0);
/* If we have received a DCC chat request, check to see if we already have
   one queued to them */
  if (itype&DCC_CHAT) {
    tmp = dcc_lookup(from, file, DCC_CHAT+DCC_NOCONN, DCC_SEND);
    if (new && tmp) {
      if (make_connection(new) == TRUE) {
        say("*** DCC chat connection started.");
        erase_dcc_entry(tmp);
      } else {
        say("*** DCC chat link could not be established.");
        erase_dcc_entry(new);
      }
    }
  }
}

