/************************************************************************
 *   psybnc2.2.2, src/p_dcc.c
 *   Copyright (C) 2001 the most psychoid  and
 *                      the cool lam3rz IRC Group, IRCnet
 *			http://www.psychoid.lam3rz.de
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 1, or (at your option)
 *   any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#ifndef lint
static char rcsid[] = "@(#)$Id: p_dcc.c, v 2.2.2 2001/03/25 02:02:02 psychoid Exp $";
#endif

#define P_DCC

#include <p_global.h>

#ifdef DCCCHAT

/* DCC - Support */
/* adding a dcc */

int adddcc(int usern, char *host, int port, char *luser, char *pass, char *name,int noini)
{
    char buf[400];
    char buf2[400];
    struct linknodes *thisdcc;
    char afile[30];
    char *ppt;
    int userp;
    pcontext;
    if (user(usern)->parent!=0) userp=user(usern)->parent; else userp=usern;
    ap_snprintf(afile,sizeof(afile),"USER%d.DCC",usern);
    thisdcc=user(usern)->dcc;
    while (1)
    {
	if (thisdcc->link==NULL) {
	    thisdcc->link=(struct datalinkt *)pmalloc(sizeof(struct datalinkt));
	    break;
	}
	if (thisdcc->next==NULL)
	{
	    thisdcc->next=(struct linknodes *)pmalloc(sizeof(struct linknodes));
	    thisdcc->next->link=(struct datalinkt *)pmalloc(sizeof(struct datalinkt));
	    thisdcc=thisdcc->next;
	    break;
	}
	thisdcc=thisdcc->next;
    }
    thisdcc->link->outstate==0;
    thisdcc->link->outsock=0;
    thisdcc->link->port=port;
    thisdcc->uid=usern;
    thisdcc->link->type=LI_DCC;
    thisdcc->link->delayed=1;
    strmncpy(thisdcc->link->user,luser,sizeof(thisdcc->link->user));
    strmncpy(thisdcc->link->name,name,sizeof(thisdcc->link->user));
    strmncpy(thisdcc->link->pass,pass,sizeof(thisdcc->link->user));
    strmncpy(thisdcc->link->host,host,sizeof(thisdcc->link->user));
    if (noini==1) return 0x0;
    strmncpy(buf,pass,sizeof(buf));
    ppt=cryptit(buf);
    ap_snprintf(buf,sizeof(buf),"%s %s %s",thisdcc->link->name,thisdcc->link->user,ppt);
    ap_snprintf(buf2,sizeof(buf2),"%s:%d\n",thisdcc->link->host,thisdcc->link->port);
    writelist(buf,buf2,afile,NULL);
    log(LOG_INFO,usern,"DCC to %s(%s:%d) added by %s.",thisdcc->link->name,thisdcc->link->host,thisdcc->link->port,user(usern)->login);
    return 0x0;
}

#endif

/* load all dccs of a user */

int loaddccs(int usern)
{
#ifdef DCCCHAT
    char buf[400];
    struct linknodes *thisdcc;
    char afile[30];
    char section[30];
    char entry[30];
    char *hpt;
    char *upt;
    char *ppt;
    char *npt;
    char *spt;
    int port;
    int cnt=0;
    ap_snprintf(afile,sizeof(afile),"USER%d",usern);
    strcpy(section,"DCC");
    for(cnt=0;cnt<20;cnt++)
    {
      ap_snprintf(entry,sizeof(entry),"ENTRY%d",cnt);
      if(getini(section,entry,afile)==0) 
      {
	npt=value;
	upt=strchr(npt,' ');
	if (upt!=NULL)
	{
	    *upt=0;upt++;
	    ppt=strchr(upt,' ');
	    if (ppt!=NULL)
	    {
		*ppt=0;ppt++;
		hpt=strchr(ppt,';');
		if (hpt!=NULL)
		{
		    *hpt=0;hpt++;
		    spt=strchr(hpt,':');
		    if(spt!=NULL)
		    {
			while(strchr(spt+1,':')!=NULL)
			{
			    spt=strchr(spt+1,':');
			}
		    }
		    if (spt!=NULL)
		    {
			*spt=0;spt++;
			port=atoi(spt);
			adddcc(usern,hpt,port,upt,decryptit(ppt),npt,1);
		    }	    
		}
	    }	
	}
      }      
    }
#endif
    return 0x0;
}

#ifdef DCCCHAT

/* listing dccs */

int listdccs(int usern)
{
    char buf[400];
    struct linknodes *thisdcc;
    int cnt;
    char l;
    int userp;
    pcontext;
    if (user(usern)->parent!=0) userp=user(usern)->parent; else userp=usern;
    cnt =1;
    thisdcc=user(usern)->dcc;
    ssnprintf(user(usern)->insock,":-psyBNC!psyBNC@lam3rz.de NOTICE %s :Listing DCCs\r\n",user(userp)->nick);
    while (thisdcc != NULL)
    {
	if (thisdcc->link!=NULL)
	{
	    if (thisdcc->link->outstate==STD_CONN)
		l='*';
	    else
		l=' ';
	    ssnprintf(user(usern)->insock,":-psyBNC!psyBNC@lam3rz.de NOTICE %s :%d%c %s (%s:%d)\r\n",user(userp)->nick,cnt,l,thisdcc->link->name,thisdcc->link->host,thisdcc->link->port);
	    cnt++;
	}
	thisdcc=thisdcc->next;
    }
    ssnprintf(user(usern)->insock,":-psyBNC!psyBNC@lam3rz.de NOTICE %s :End of DCCs\r\n",user(userp)->nick);
    listpdccs(usern);
    return 0x0;
}


/* erasing dccs */

int erasedcc(int usern,int dccn)
{
    struct linknodes *thisdcc;
    struct linknodes *lastdcc;
    char l;
    FILE *infile;
    FILE *tmp;
    char fbuf[40];
    char afile[30];
    char section[30];
    char entry[30];
    int userp;
    int cnt;
    pcontext;
    if (user(usern)->parent!=0) userp=user(usern)->parent; else userp=usern;
    cnt =1;
    thisdcc=user(usern)->dcc;
    lastdcc=thisdcc;
    while (thisdcc != NULL)
    {
	if (thisdcc->link!=NULL)
	{
	    if (cnt==dccn) break;
	    lastdcc=thisdcc;
	    cnt++;
	}
	thisdcc=thisdcc->next;
    }
    if (thisdcc==NULL || thisdcc->link==NULL)
    {
	ssnprintf(user(usern)->insock,":-psyBNC!psyBNC@lam3rz.de NOTICE %s :No such DCC.\r\n",user(userp)->nick);
	return 0x0;    
    }
    if (thisdcc->link->outstate==STD_CONN)
    {
	killsocket(thisdcc->link->outsock);
	ssnprintf(user(usern)->insock,":-psyBNC!psyBNC@lam3rz.de NOTICE %s :DCC %d session closed.\r\n",user(userp)->nick);
    }
    if (thisdcc==user(usern)->dcc)
    {
	if (thisdcc->next==NULL)
	{
	    free(thisdcc->link);
	    thisdcc->link=NULL;
	} else {
	    user(usern)->dcc=thisdcc->next;
	    free(thisdcc->link);
	    free(thisdcc);
	}
    } else {
	lastdcc->next=thisdcc->next;
	free(thisdcc->link);
	free(thisdcc);
    }
    ap_snprintf(afile,sizeof(afile),"USER%d",usern);
    ap_snprintf(entry,sizeof(entry),"ENTRY%d",dccn-1);
    strcpy(section,"DCC");
    writeini(section,entry,afile,NULL);
    cnt=dccn;
    ap_snprintf(entry,sizeof(entry),"ENTRY%d",cnt);
    while(getini(section,entry,afile)==0)
    {
	writeini(section,entry,afile,NULL);
	ap_snprintf(entry,sizeof(entry),"ENTRY%d",cnt-1);
	writeini(section,entry,afile,value);
	cnt++;
	ap_snprintf(entry,sizeof(entry),"ENTRY%d",cnt);
    }
    ssnprintf(user(usern)->insock,":-psyBNC!psyBNC@lam3rz.de NOTICE %s :DCC %d deleted.\r\n",user(userp)->nick,dccn);
    return 0x0;
}

#endif

/* check a dcc connection */

struct datalinkt *checkdcc(int usern, char *dccname)
{
    struct linknodes *th;
    th=user(usern)->dcc;
    while (th!=NULL)
    {
	if (th->link != NULL)
	{
	    if (strlen(th->link->name)==strlen(dccname))
	    {
		if (strstr(th->link->name,dccname)!=NULL)
		    return th->link;
	    }
	}
	th=th->next;
    }
    return NULL;
}

#ifdef DCCCHAT

int dcchandler(int usern)
{
    struct linknodes *lkm;
    struct datalinkt *th;
    char l=')';
    char netc[15];
    int rc;
    netc[0]=0;
    pcontext;
    if (user(usern)->parent!=0)
	ap_snprintf(netc,sizeof(netc),"%s~",user(usern)->network);
    else
	memset(netc,0x0,sizeof(netc));
    lkm=user(usern)->dcc;
    while(lkm!=NULL)
    {
	if(lkm->link!=NULL)
	    if(lkm->link->outsock==currentsocket->sock->syssock) break;
	lkm=lkm->next;    
    }
    if (lkm==NULL) return 0x0;
    th=lkm->link;
    if(th->outstate==STD_CONN)
    {
	if (user(usern)->instate==STD_CONN)
	{
	    ssnprintf(user(usern)->insock,":%s%c%s!DCC@%s PRIVMSG %s :%s\r\n",netc,l,th->name,th->host,user(usern)->nick,ircbuf);
	    return 0x0;
	}
    }
}

/* connected dcc */

int connecteddcc(int usern)
{
    struct linknodes *lkm;
    struct datalinkt *th;
    char *pt;
    char buf[100];
    pcontext;
    lkm=user(usern)->dcc;
    while(lkm!=NULL)
    {
	if(lkm->link!=NULL)
	    if(lkm->link->outsock==currentsocket->sock->syssock) break;
	lkm=lkm->next;    
    }
    if (lkm==NULL) return 0x0;
    th=lkm->link;
    log(LOG_INFO,usern,"Connected to DCC: %s to %s (%s:%d)",user(usern)->login,th->name,th->host,th->port);
    th->delayed=1;
    ap_snprintf(buf,sizeof(buf),"%s\r\n",th->user);
    writesock_DELAY(th->outsock,buf,10); /* should be enough */
    pt=rtrim(th->pass);
    ap_snprintf(buf,sizeof(buf),"%s\r\n",pt);
    writesock_DELAY(th->outsock,buf,5);
    th->outstate=STD_CONN;
    th->delayed=1;
}

/* connection terminated */

int killeddcc(int usern)
{
    struct linknodes *lkm;
    struct datalinkt *th;
    pcontext;
    lkm=user(usern)->dcc;
    while(lkm!=NULL)
    {
	if(lkm->link!=NULL)
	    if(lkm->link->outsock==currentsocket->sock->syssock) break;
	lkm=lkm->next;    
    }
    if (lkm==NULL) return 0x0;
    th=lkm->link;
    log(LOG_WARNING,usern,"Lost DCC: %s to %s (%s:%d)",user(usern)->login,th->name,th->host,th->port);
    th->delayed=1;
    killsocket(th->outsock);
    th->outstate=0;
    return 0x0;	
}

/* connection could not be established */

int errordcc(int usern, int errn)
{
    struct linknodes *lkm;
    struct datalinkt *th;
    pcontext;
    lkm=user(usern)->dcc;
    while(lkm!=NULL)
    {
	if(lkm->link!=NULL)
	    if(lkm->link->outsock==currentsocket->sock->syssock) break;
	lkm=lkm->next;    
    }
    if (lkm==NULL) return 0x0;
    currentsocket->sock->destructor=NULL;
    th=lkm->link;
    log(LOG_ERROR,usern,"Cant connect DCC: %s to %s (%s:%d)",user(usern)->login,th->name,th->host,th->port);
    th->delayed=1;
    th->outstate=0;
    killsocket(th->outsock);
    return 0x0;	
}



/* checking a single dcc link */

int checkdcclink(int usern, struct datalinkt *th)
{
    struct socketnodes *eth;
    char buf[8192];
    char l=')';
    char netc[15];
    int proto;
    int rc;
    netc[0]=0;
#ifdef DYNAMIC
    if(user(usern)->instate!=STD_CONN) return 0x0;
#endif
    if (user(usern)->parent!=0)
	ap_snprintf(netc,sizeof(netc),"%s~",user(usern)->network);
    else
	memset(netc,0x0,sizeof(netc));
    if (th->outstate==0) {
	if (th->delayed >0)
	{
	    th->delayed-=delayinc;
	    return 0x0;
	}
	pcontext;
    	log(LOG_INFO,usern,"Connecting DCC: %s to %s (%s:%d)",user(usern)->login,th->name,th->host,th->port);
	proto=getprotocol(th->host);
	th->outsock=createsocket(0,ST_CONNECT,usern,NULL,connecteddcc,errordcc,dcchandler,killeddcc,proto);
	th->outsock=connectto(th->outsock,th->host,th->port,NULL);
	eth=getpsocketbysock(th->outsock);
	if (eth!=NULL)
	{
	    eth->sock->encryption=SE_REFUSE;
	}
	th->outstate=STD_NEWCON;
	if (th->outsock==0)
	{
    	    log(LOG_ERROR,usern,"Cant connect DCC: %s to %s (%s:%d)",user(usern)->login,th->name,th->host,th->port);
	    th->delayed=1;
	    return 0x0;	
	}
	return 0x1;
    }
    return 0x0;
}

#endif

/* checking all dcc links */

int checkdccs()
{
#ifdef DCCCHAT
    struct usernodes *th;
    struct linknodes *dh;
    th=usernode;
    while (th!=NULL)
    {
	if (th->user != NULL)
	{
#ifdef DYNAMIC
	    if(user(th->uid)->instate==STD_CONN)
	    {
#endif
		dh=th->user->dcc;
		while (dh!=NULL)
		{
		    if (dh->link!=NULL)
		    {
			if(checkdcclink(th->uid,dh->link)==1) break;
		    }
		    dh=dh->next;
		}
#ifdef DYNAMIC
	    }
#endif
	}
	th=th->next;
    }
#endif
    return 0x0;
}

/*
 * pending dcc support for files and chats
 * this allows the user to send and receive files from and to the
 * bouncer host and to receive or to send chats.
 *
 */


int randport()
{
    unsigned short port;
    port=random();
    while(port<1024)
	port+=1024;
    return port;
}

char stdcc[2048];

/* strip the filename without . and / */

char *stripdccfile(char *realname,int rec)
{
    char *pt;
    pt=realname;
    if(rec==0)
    {
	if(strstr(pt,"/dev/")==pt) /* so we send a device ? yes, right. */
	    return NULL;
	if(strstr(pt,"/etc/")==pt) /* so we send from etc ? yes, right. */
	    return NULL;
    }
    if(strchr(pt,'?')!=NULL) return NULL;
    if(strchr(pt,'*')!=NULL) return NULL;
    while(strchr(pt,'/')!= NULL)
    {
	if(rec==1) return NULL;
	pt=strchr(pt,'/');
	pt++;
    }
    while(strchr(pt,'\\')!= NULL)
    {
	pt=strchr(pt,'\\');
	pt++;
    }
    if(rec==1)
    {
	if(strstr(pt,"..")!=NULL)
	    return NULL;
    }
    strmncpy(stdcc,pt,sizeof(stdcc));
    return pt;    
}

/* create a new pdcc entry */

struct dcct *createpdcc(int usern)
{
    struct dcct *pd;
    pd=user(usern)->pdcc;
    if(pd==NULL)
    {
	user(usern)->pdcc=(struct dcct *)pmalloc(sizeof(struct dcct));
	pd=user(usern)->pdcc;
    } else {
	while(pd->next!=NULL) pd=pd->next;
	pd->next=(struct dcct *)pmalloc(sizeof(struct dcct));
	pd=pd->next;
    }
    return pd;
}

/* get the current dcc struct */

struct dcct *getcurrentpdcc(int usern)
{
    struct dcct *pdcc;
    pdcc=user(usern)->pdcc;
    while(pdcc!=NULL)
    {
	if(currentsocket->sock->syssock==pdcc->sock) return pdcc;
	pdcc=pdcc->next;
    }
    return NULL;
}

/* remove a dcc struct entry */

int removepdcc(int usern)
{
    struct dcct *apdcc,*pdcc,*epdcc=NULL;
    struct socketnodes *ps;
    apdcc=getcurrentpdcc(usern);
    if(apdcc==NULL) return 0x0;
    pdcc=user(usern)->pdcc;
    while(pdcc!=NULL)
    {
	if(pdcc==apdcc)
	{
	    if(epdcc==NULL)
	    {
		user(usern)->pdcc=pdcc->next;
	    } else {
		epdcc->next=pdcc->next;
	    }
	    if(pdcc->sock>0) 
	    {
		ps=getpsocketbysock(pdcc->sock);
		if(ps!=NULL)
		{
		    ps->sock->destructor=NULL;
		    ps->sock->errorhandler=NULL;
#ifdef SCRIPTING
		    if(pdcc->pid!=0)
		    {
			if(getsubtaskbypid(pdcc->pid)!=NULL)
			    terminatetask(pdcc->pid,0);
		    }
#endif
		    killsocket(pdcc->sock);
		}
	    }
	    free(pdcc);
	    return 0x0;
	}
	epdcc=pdcc;
	pdcc=pdcc->next;
    }
    return 0x0;
}

/* event routines for dcc chats */

int pdccconnected(int usern)
{
    struct dcct *pdcc;
#ifdef SCRIPTING
    struct subtask *stsk;
#endif
    char netc[20];
    netc[0]=0;
    if(user(usern)->parent!=0)
    {
	ap_snprintf(netc,sizeof(netc),"%s~",user(usern)->network);
    }
    pdcc=getcurrentpdcc(usern);
    if(pdcc==NULL) return 0x0;
    pdcc->delay=0;
    if(user(usern)->instate==STD_CONN)
    {
	ssnprintf(user(usern)->insock,":%s(%s!DCCChat@%s PRIVMSG %s :[%d] Chat established",netc,pdcc->nick,pdcc->host,user(usern)->nick,currentsocket->sock->syssock);
    }    
#ifdef SCRIPTING
    if(pdcc->pid!=0)
    {
	stsk=getsubtaskbypid(pdcc->pid);
	if(stsk!=NULL)
	{
	    ssnprintf(stsk->fdout,"CONNECTED");
	}
    }
#endif
    return 0x0;
}

int pdccerror(int usern, int r)
{
    struct dcct *pdcc;
    char netc[20];
    netc[0]=0;
    if(user(usern)->parent!=0)
    {
	ap_snprintf(netc,sizeof(netc),"%s~",user(usern)->network);
    }
    pdcc=getcurrentpdcc(usern);
    if(pdcc==NULL) return 0x0;
    if(user(usern)->instate==STD_CONN)
    {
	ssnprintf(user(usern)->insock,":%s(%s!DCCChat@%s PRIVMSG %s :[%d] Chat closed",netc,pdcc->nick,pdcc->host,user(usern)->nick,currentsocket->sock->syssock);
    }    
    removepdcc(usern);
}

int pdccquery(int usern)
{
#ifdef SCRIPTING
    struct subtask *stsk;
#endif
    struct dcct *pdcc;
    char netc[20];
    char *pt;
    netc[0]=0;
    if(user(usern)->parent!=0)
    {
	ap_snprintf(netc,sizeof(netc),"%s~",user(usern)->network);
    }
    pdcc=getcurrentpdcc(usern);
    if(pdcc!=NULL && user(usern)->instate==STD_CONN)
    {
	ssnprintf(user(usern)->insock,":%s(%s!DCCChat@%s PRIVMSG %s :%s",netc,pdcc->nick,pdcc->host,user(usern)->nick,ircbuf);
    }
#ifdef SCRIPTING
    if(pdcc->pid!=0)
    {
	stsk=getsubtaskbypid(pdcc->pid);
	if(stsk!=NULL)
	{
	    pt=strchr(ircbuf,'\r');
	    if(pt!=NULL)
	    {
		*pt='\n';
		pt++;
		*pt=0;
	    }
	    writesock_STREAM(stsk->fdout,ircbuf,strlen(ircbuf));
	}
    }
#endif
    return 0x0;
}

int pdccclosed(int usern)
{
    pdccerror(usern,0);
    return 0x0;
}

/* event for the incoming chat */

int acceptpdccchat(int usern)
{
    struct dcct *pdcc;
    int nsock;
    int userp=usern;
    struct socketnodes *ps,*eps;
    char netc[20];
    netc[0]=0;
    if(user(usern)->parent!=0)
    {
	ap_snprintf(netc,sizeof(netc),"%s~",user(usern)->network);
    }
    pdcc=getcurrentpdcc(usern);
    if(pdcc==NULL) return 0x0;
    nsock=bncaccept(pdcc->sock);
    if(nsock<=0) return -1;
    nsock=createsocket(nsock,ST_CONNECT,usern,NULL,NULL,pdccerror,pdccquery,pdccclosed,AF_INET);
    if(nsock<=0) return 0x0;
    ps=getpsocketbysock(nsock);
    if(ps==NULL) return 0x0;
    strmncpy(ps->sock->source,currentsocket->sock->source,sizeof(ps->sock->source));
    ps->sock->sport=currentsocket->sock->sport;
    killsocket(currentsocket->sock->syssock);
    ps->sock->flag=SOC_CONN;
    ps->sock->sport=pdcc->port;
    strmncpy(ps->sock->dest,ntoares,sizeof(ps->sock->dest));
    ps->sock->dport=ps->sock->sport;
    pdcc->delay=0;
    pdcc->type=PDC_CHATTO;
    pdcc->sock=nsock;
    strmncpy(pdcc->host,ntoares,sizeof(pdcc->host));
    if(user(usern)->instate==STD_CONN)
    {
	ssnprintf(user(usern)->insock,":%s(%s!DCCChat@%s PRIVMSG %s :[%d] Chat established",netc,pdcc->nick,pdcc->host,user(usern)->nick,nsock);
    }    
    return 0x0;
}

/* events for the incoming file transfers */

int pdccfileerror(int usern, int r)
{
    struct dcct *pdcc;
    char netc[20];
    netc[0]=0;
    if(user(usern)->parent!=0)
    {
	ap_snprintf(netc,sizeof(netc),"%s~",user(usern)->network);
    }
    pdcc=getcurrentpdcc(usern);
    if(pdcc==NULL) return 0x0;
    if(user(usern)->instate==STD_CONN)
    {
	ssnprintf(user(usern)->insock,":-psyBNC!psyBNC@lam3rz.de NOTICE %s :Filetransfer of %s by %s%s aborted.",user(usern)->nick,pdcc->file,netc,pdcc->nick);
    }    
    fclose(pdcc->fhandle);
    removepdcc(usern);
}

int pdccfileclosed(int usern)
{
    struct dcct *pdcc;
    char netc[20];
    netc[0]=0;
    if(user(usern)->parent!=0)
    {
	ap_snprintf(netc,sizeof(netc),"%s~",user(usern)->network);
    }
    pdcc=getcurrentpdcc(usern);
    if(pdcc==NULL) return 0x0;
    if(user(usern)->instate==STD_CONN)
    {
	ssnprintf(user(usern)->insock,":-psyBNC!psyBNC@lam3rz.de NOTICE %s :Filetransfer of %s by %s%s stopped.",user(usern)->nick,pdcc->file,netc,pdcc->nick);
    }    
    fclose(pdcc->fhandle);
    removepdcc(usern);
}

int pdccfilesendack(int usern)
{
    struct dcct *pdcc;
    char *pt=ircbuf;
    unsigned long *addrp;
    unsigned long ackdcc;
    int rc;
    char netc[20];
    netc[0]=0;
    if(user(usern)->parent!=0)
    {
	ap_snprintf(netc,sizeof(netc),"%s~",user(usern)->network);
    }
    addrp=(unsigned long *)pt;
    ackdcc=ntohl(*addrp);
    pdcc=getcurrentpdcc(usern);
    if(pdcc==NULL) return 0x0;
    if(pdcc->transferred!=ackdcc)
    {
	return 0x0;
    }        
    if(feof(pdcc->fhandle)!=0)
    {
	if(user(usern)->instate==STD_CONN)
	{
	    log(LOG_INFO,usern,"File %s sent to %s%s completed.",pdcc->file,netc,pdcc->nick);
	}
	fclose(pdcc->fhandle);
	removepdcc(usern);
    } else {
	rc=fread(stdcc,1,2048,pdcc->fhandle);    
	pdcc->lasttransferred=rc;
	pdcc->transferred+=rc;
	writesock_STREAM(pdcc->sock,stdcc,rc);
    }    
    return 0x0;
}

int acceptpdccfile(int usern)
{
    struct dcct *pdcc;
    int nsock,rc;
    int userp=usern;
    struct socketnodes *ps;
    char netc[20];
    netc[0]=0;
    if(user(usern)->parent!=0)
    {
	ap_snprintf(netc,sizeof(netc),"%s~",user(usern)->network);
    }
    pdcc=getcurrentpdcc(usern);
    if(pdcc==NULL) return 0x0;
    nsock=bncaccept(pdcc->sock);
    if(nsock<=0) return -1;
    pdcc->fhandle=fopen(pdcc->file,"r");
    if(pdcc->fhandle==NULL) 
    {
	killsocket(nsock);
	return 0x0;
    }
    nsock=createsocket(nsock,ST_CONNECT,usern,NULL,NULL,pdccfileerror,pdccfilesendack,pdccfileclosed,AF_INET);
    if(nsock<=0) return 0x0;
    ps=getpsocketbysock(nsock);
    if(ps==NULL) return 0x0;
    strmncpy(ps->sock->source,currentsocket->sock->source,sizeof(ps->sock->source));
    ps->sock->sport=currentsocket->sock->sport;
    strmncpy(ps->sock->dest,ntoares,sizeof(ps->sock->dest));
    ps->sock->dport=currentsocket->sock->sport;
    killsocket(currentsocket->sock->syssock);
    ps->sock->flag=SOC_CONN;
    ps->sock->dataflow=SD_STREAM;
    pdcc->delay=0;
    pdcc->sock=nsock;
    pdcc->type=PDC_SENDTO;
    strmncpy(pdcc->host,ntoares,sizeof(pdcc->host));
    if(user(usern)->instate==STD_CONN)
    {
	ssnprintf(user(usern)->insock,":-psyBNC!psyBNC@lam3rz.de NOTICE %s :User %s%s(%s) accepted File %s. Start sending.",user(usern)->nick,netc,pdcc->nick,pdcc->host,pdcc->file);
    }    
    rc=fread(stdcc,1,2048,pdcc->fhandle);
    pdcc->lasttransferred=rc;
    pdcc->transferred=rc;
    writesock_STREAM(nsock,stdcc,rc);
    return 0x0;
}

/* file receive */

int pdccfconnected(int usern)
{
    struct dcct *pdcc;
    char netc[20];
    char mypath[100];
    mode_t oldum;
    netc[0]=0;
    if(user(usern)->parent!=0)
    {
	ap_snprintf(netc,sizeof(netc),"%s~",user(usern)->network);
    }
    pdcc=getcurrentpdcc(usern);
    if(pdcc==NULL) return 0x0;
    oldum=umask(0000);
    umask(0000);    
    mkdir("downloads", 0777 );
    ap_snprintf(mypath,sizeof(mypath),"downloads/USER%d",usern);
    mkdir(mypath, 0777 );
    umask(oldum);
    unlink(pdcc->file);
    pdcc->fhandle=fopen(pdcc->file,"w");
    if(pdcc->fhandle==NULL)
    {
	log(LOG_ERROR,usern,"Cannot create File %s - aborting.",pdcc->file);
	killsocket(currentsocket->sock->syssock);
	return 0x0;
    }
    if(user(usern)->instate==STD_CONN)
    {
	ssnprintf(user(usern)->insock,":-psyBNC!psyBNC@lam3rz.de NOTICE %s :Connected to %s%s(%s). Receiving File %s.",user(usern)->nick,netc,pdcc->nick,pdcc->host,pdcc->file);
    }    
    return 0x0;
}

int pdccferror(int usern,int r)
{
    struct dcct *pdcc;
    char netc[20];
    netc[0]=0;
    if(user(usern)->parent!=0)
    {
	ap_snprintf(netc,sizeof(netc),"%s~",user(usern)->network);
    }
    pdcc=getcurrentpdcc(usern);
    if(pdcc==NULL) return 0x0;
    if(pdcc->fhandle!=NULL)
	fclose(pdcc->fhandle);
    if(user(usern)->instate==STD_CONN)
    {
	ssnprintf(user(usern)->insock,":-psyBNC!psyBNC@lam3rz.de NOTICE %s :Connection to %s%s(%s) lost. File %s incomplete.",user(usern)->nick,netc,pdcc->nick,pdcc->host,pdcc->file);
    }    
    removepdcc(usern);
}

int pdccfget(int usern)
{
    unsigned long acks;
    unsigned long *addrptr;
    char *pt;
    int rc;
    struct dcct *pdcc;
    char netc[20];
    netc[0]=0;
    if(user(usern)->parent!=0)
    {
	ap_snprintf(netc,sizeof(netc),"%s~",user(usern)->network);
    }
    pdcc=getcurrentpdcc(usern);
    if(pdcc==NULL) return 0x0;
    pdcc->lasttransferred=currentsocket->sock->datalen;
    pdcc->transferred+=pdcc->lasttransferred;
    /* store data */
    rc=fwrite(ircbuf,1,pdcc->lasttransferred,pdcc->fhandle);
    if(rc!=pdcc->lasttransferred)
    {
	if(user(usern)->instate==STD_CONN)
	{
	    ssnprintf(user(usern)->insock,":-psyBNC!psyBNC@lam3rz.de NOTICE %s :File write error while receiving from %s%s(%s). File %s incomplete.",user(usern)->nick,netc,pdcc->nick,pdcc->host,pdcc->file);
	    fclose(pdcc->fhandle);
	    removepdcc(usern);
	    return 0x0;
	}    
    }
    /* send back ack */
    acks=htonl(pdcc->transferred);
    addrptr=&acks;
    pt=(char *)addrptr;
    writesock_STREAM(currentsocket->sock->syssock,pt,4);
    return 0x0;
}

int pdccfclosed(int usern)
{
    struct dcct *pdcc;
    char netc[20];
    netc[0]=0;
    if(user(usern)->parent!=0)
    {
	ap_snprintf(netc,sizeof(netc),"%s~",user(usern)->network);
    }
    pdcc=getcurrentpdcc(usern);
    if(pdcc==NULL) return 0x0;
    {
	if(pdcc->filesize!=pdcc->transferred)
	    ssnprintf(user(usern)->insock,":-psyBNC!psyBNC@lam3rz.de NOTICE %s :EOF while receiving from %s%s(%s). File %s incomplete.",user(usern)->nick,netc,pdcc->nick,pdcc->host,pdcc->file);
	else
	    log(LOG_INFO,usern,"File %s from %s%s(%s) received.",pdcc->file,netc,pdcc->nick,pdcc->host);
    }    
    if(pdcc->fhandle!=NULL)
	fclose(pdcc->fhandle);    
    removepdcc(usern);
}

/* add a pending dcc connection */

int addpendingdcc(int usern, int type, char *host, int port, char *nick, char *file, char *newfile, unsigned long fsize, int eproto)
{
    struct dcct *pd;
    struct socketnodes *ps;
    int prt;
    char c=1;
    int sck;
    int proto;
    int rc,cnt=0;
#ifdef IPV6
    struct hostent *he;
    struct sockaddr_in6 sin6;
#endif
    struct sockaddr_in sin;
    unsigned long flen;
    unsigned long dip;
    FILE *check;
    char myfile[800];
    char myhost[200];
    char ihost[60];
    char en[64],an[64];
    char netc[20];
    char *fil;
    int mf=0;
    unsigned long dccreq;
    int userp=usern;
    pcontext;
    netc[0]=0;
    if(eproto!=0) proto=eproto;
    if(user(usern)->parent!=0)
    {
	userp=user(usern)->parent;
	ap_snprintf(netc,sizeof(netc),"%s~",user(usern)->network);
    }
    switch(type)
    {
	case PDC_CHATTORQ:
	    if(user(usern)->outstate!=STD_CONN)
	    {
		ssnprintf(user(usern)->insock,":-psyBNC!psyBNC@lam3rz.de NOTICE %s :You are not connected.",user(usern)->nick);
		return -1;
	    }
	    if(dcchost[0]==0)
	    {
		log(LOG_ERROR,usern,"No IP defined for DCC Usage. Please create a line 'PSYBNC.SYSTEM.DCCHOST=IP' in the psybnc.conf.");
		return -1;
	    }
	    sck=0;cnt=0;
	    while(sck<=0 && cnt<20)
	    {
		prt=randport();
		sck=createlistener(dcchost,prt,getprotocol(dcchost),1,acceptpdccchat);
		cnt++;
	    }
	    if(sck<=0)
	    {
		log(LOG_ERROR,usern,"Cannot create listening Port in 20 tries.. giving up.");
		return -1;
	    }
	    ps=getpsocketbysock(sck);
	    if(ps==NULL)
	    {
		log(LOG_ERROR,usern,"Cannot create Socket.. giving up.");
		return -1;
	    }
	    ps->sock->param=usern;
	    strmncpy(ps->sock->dest,"DCC",sizeof(ps->sock->dest));
	    pd=createpdcc(usern);
	    strmncpy(pd->nick,nick,sizeof(pd->nick));
	    strmncpy(pd->host,ps->sock->source,sizeof(pd->host));
	    pd->type=PDC_CHATTORQ;
	    pd->port=prt;
	    pd->sock=sck;
	    pd->uid=usern;
	    pd->delay=50;
	    if(user(usern)->instate==STD_CONN)
		ssnprintf(user(usern)->insock,":-psyBNC!psyBNC@lam3rz.de NOTICE %s :DCC Chat request sent to %s%s (%s:%d)",user(usern)->nick,netc,pd->nick,pd->host,pd->port);
	    /* telling the user we want to dcc chat him */
	    ssnprintf(user(usern)->outsock,"NOTICE %s :DCC Chat (%s)",pd->nick,pd->host);
	    /* sending the request */
#ifdef IPV6
	    if(getprotocol(dcchost)==AF_INET6)
	    {
#ifdef SUNOS
		he=getipnodebyname(dcchost,AF_INET6,AI_DEFAULT,&error_num);
#else
		he=gethostbyname2(dcchost,AF_INET6);
#endif
		if(he!=NULL)
		{
		    memcpy(&sin6.sin6_addr,he->h_addr,he->h_length);
		    sin6.sin6_family=he->h_addrtype;
		    inet_ntop(AF_INET6,&sin6,myhost,sizeof(myhost));
		    ssnprintf(user(usern)->outsock,"PRIVMSG %s :%cDCC CHAT chat %s %d%c",pd->nick,c,myhost,pd->port,c);
		}
	    } else
#endif
		ssnprintf(user(usern)->outsock,"PRIVMSG %s :%cDCC CHAT chat %lu %d%c",pd->nick,c,htonl(inet_addr(pd->host)),pd->port,c);
	    return 0x0; 	    
	case PDC_CHATFROMRQ:
	    dccreq=user(usern)->lastdccchat;
	    time(&user(usern)->lastdccchat);
	    if((user(usern)->lastdccchat-dccreq)<5) return -1; /* 5 seconds before next chat */
	    if(port<1024) return -1; /* silent ignore */
	    pd=createpdcc(usern);
	    if(pd!=NULL)
	    {
		pd->delay=50;
		pd->uid=usern;
		pd->type=PDC_CHATFROMRQ;
		pd->port=port;
		if(getprotocol(host)==AF_INET) /* bsd does not resolve longs */
		{
		    sscanf(host,"%lu",&dip);
		    sin.sin_addr.s_addr=htonl(dip);
		    strmncpy(pd->host,inet_ntoa(sin.sin_addr),sizeof(pd->host));
		} else
		    strmncpy(pd->host,host,sizeof(pd->host));
		strmncpy(pd->nick,nick,sizeof(pd->nick));
		ssnprintf(user(usern)->insock,":-psyBNC!psyBNC@lam3rz.de NOTICE %s :%s%s sent a DCC Chat Request. Use /DCCANSWER %s to establish the connection (%s/%d).",user(usern)->nick,netc,pd->nick,pd->nick,pd->host,pd->port);
#ifdef SCRIPTING
		pd->pid=dccchatscript(usern,ircfrom);
#endif
		return 0x0;
	    }
	    break;
	case PDC_CHATFROM:
	    pd=user(usern)->pdcc;
	    strmncpy(en,nick,sizeof(en));
	    ucase(en);
	    while(pd!=NULL)
	    {
		strmncpy(an,pd->nick,sizeof(an));
		ucase(an);
		if(pd->type==PDC_CHATFROMRQ && strmcmp(en,an)==1)
		{
		    proto=getprotocol(pd->host);
		    sck=createsocket(0,ST_CONNECT,usern,NULL,pdccconnected,pdccerror,pdccquery,pdccclosed,proto);
		    sck=connectto(sck,pd->host,pd->port,NULL);
		    if(sck!=0) /* silently ignore errors */
		    {
			pd->sock=sck;
			pd->delay=0;
			pd->type=PDC_CHATFROM;
			return 0;
		    }	
		}
		pd=pd->next;
	    }
	    if(user(usern)->instate==STD_CONN)
		ssnprintf(user(usern)->insock,":-psyBNC!psyBNC@lam3rz.de NOTICE %s :No DCC Request from '%s'",user(usern)->nick,nick);
	    break;
	case PDC_SENDTORQ:
	    if(user(usern)->outstate!=STD_CONN)
	    {
		ssnprintf(user(usern)->insock,":-psyBNC!psyBNC@lam3rz.de NOTICE %s :You are not connected.",user(usern)->nick);
		return -1;
	    }
	    if(dcchost[0]==0)
	    {
		log(LOG_ERROR,usern,"No IP defined for DCC Usage. Please create a line 'PSYBNC.SYSTEM.DCCHOST=IP' in the psybnc.conf.");
		return -1;
	    }
	    fil=stripdccfile(file,0);
	    if(fil==NULL)
	    {
		log(LOG_ERROR,usern,"Invalid Filename '%s'.",file);
		return -1;
	    }
	    check=fopen(file,"r");
	    if(check==NULL)
	    {
		ap_snprintf(myfile,sizeof(myfile),"downloads/USER%d/%s",usern,fil);
		check=fopen(myfile,"r");
		if(check==NULL)
		{		
		    ssnprintf(user(usern)->insock,":-psyBNC!psyBNC@lam3rz.de NOTICE %s :File %s not found.",user(usern)->nick,file);
		    return -1;
		}
		mf=1;
	    }
	    fseek(check,0,SEEK_END);
	    flen=ftell(check);
	    fclose(check);
	    sck=0;cnt=0;
	    while(sck<=0 && cnt<20)
	    {
		prt=randport();
		sck=createlistener(dcchost,prt,getprotocol(dcchost),1,acceptpdccfile);
		cnt++;
	    }
	    if(sck<=0)
	    {
		log(LOG_ERROR,usern,"Cannot create listening Port in 20 tries.. giving up.");
		return -1;
	    }
	    ps=getpsocketbysock(sck);
	    if(ps==NULL)
	    {
		log(LOG_ERROR,usern,"Cannot create Socket.. giving up.");
		return -1;
	    }
	    ps->sock->param=usern;
	    strmncpy(ps->sock->dest,"DCC",sizeof(ps->sock->dest));
	    pd=createpdcc(usern);
	    strmncpy(pd->nick,nick,sizeof(pd->nick));
	    strmncpy(pd->host,ps->sock->source,sizeof(pd->host));
	    if(mf==1)
		strmncpy(pd->file,myfile,sizeof(pd->file));
	    else
		strmncpy(pd->file,file,sizeof(pd->file));
    	    pd->type=PDC_SENDTORQ;
    	    pd->port=prt;
	    pd->sock=sck;
	    pd->uid=usern;
	    pd->filesize=flen;
	    pd->delay=50;
	    if(user(usern)->instate==STD_CONN)
		ssnprintf(user(usern)->insock,":-psyBNC!psyBNC@lam3rz.de NOTICE %s :DCC File Send for %s request sent to %s%s (%s:%d)",user(usern)->nick,fil,netc,pd->nick,pd->host,pd->port);
	    /* telling the user we want to dcc send him a file */
	    ssnprintf(user(usern)->outsock,"NOTICE %s :DCC Send %s (%s)",pd->nick,fil,pd->host);
	    /* sending the request */
#ifdef IPV6
	    if(getprotocol(dcchost)==AF_INET6)
	    {
#ifdef SUNOS
		he=getipnodebyname(dcchost,AF_INET6,AI_DEFAULT,&error_num);
#else
		he=gethostbyname2(dcchost,AF_INET6);
#endif
		if(he!=NULL)
		{
		    memcpy(&sin6.sin6_addr,he->h_addr,he->h_length);
		    sin6.sin6_family=he->h_addrtype;
		    inet_ntop(AF_INET6,&sin6,myhost,sizeof(myhost));
		    ssnprintf(user(usern)->outsock,"PRIVMSG %s :%cDCC SEND %s %s %d %lu%c",pd->nick,c,fil,myhost,pd->port,flen,c);
		}
	    } else
#endif
		ssnprintf(user(usern)->outsock,"PRIVMSG %s :%cDCC SEND %s %lu %d %lu%c",pd->nick,c,fil,htonl(inet_addr(pd->host)),pd->port,flen,c);
	    return 0x0;
	case PDC_RECVFROMRQ:
	    if(port<1024) return -1; /* silent ignore of lame from ports */
	    fil=stripdccfile(file,1);
	    if(fil==NULL) return -1; /* silent ignore of bogus file sends */
	    /* file should be the file itself now, without /,.. or ~ */
	    ap_snprintf(myfile,sizeof(myfile),"downloads/USER%d/%s",usern,fil);
	    pd=createpdcc(usern);
	    if(pd!=NULL)
	    {
		pd->delay=50;
		pd->uid=usern;
		pd->type=PDC_RECVFROMRQ;
		pd->port=port;
		strmncpy(pd->file,myfile,sizeof(pd->file));
		pd->filesize=fsize;
		if(getprotocol(host)==AF_INET) /* bsd does not resolve longs */
		{
		    sscanf(host,"%lu",&dip);
		    sin.sin_addr.s_addr=htonl(dip);
		    strmncpy(pd->host,inet_ntoa(sin.sin_addr),sizeof(pd->host));
		} else
		    strmncpy(pd->host,host,sizeof(pd->host));
		strmncpy(pd->nick,nick,sizeof(pd->nick));
		if(user(usern)->autogetdcc==1)
		{
		    ssnprintf(user(usern)->insock,":-psyBNC!psyBNC@lam3rz.de NOTICE %s :%s%s sent a DCC File Send Request for File %s. The file will be auto-downloaded. (%s/%d).",user(usern)->nick,netc,pd->nick,fil,netc,pd->host,pd->port);
		    /* recursive */
		    addpendingdcc(usern, PDC_RECVFROM, pd->host, pd->port, pd->nick, fil, NULL, pd->filesize, getprotocol(pd->host));
		} else
		    ssnprintf(user(usern)->insock,":-psyBNC!psyBNC@lam3rz.de NOTICE %s :%s%s sent a DCC File Send Request for File %s. Use /DCCGET %s%s :%s to receive the file. (%s/%d).",user(usern)->nick,netc,pd->nick,fil,netc,pd->nick,fil,pd->host,pd->port);
#ifdef SCRIPTING
		strmncpy(irccontent,pd->file,sizeof(irccontent));
		pd->pid=dccfilescript(usern,ircfrom);
#endif
		return 0x0;
	    }
	    break;
	case PDC_RECVFROM:
	    pd=user(usern)->pdcc;
	    while(pd!=NULL)
	    {
		if(pd->type==PDC_RECVFROMRQ && strmcmp(nick,pd->nick)==1)
		{
		    fil=stripdccfile(pd->file,0);
		    if(fil!=NULL)
		    {
		        if (strmcmp(file,fil)!=0 || *file == '*')
			{ 
			    proto=getprotocol(pd->host);
			    sck=createsocket(0,ST_CONNECT,usern,NULL,pdccfconnected,pdccferror,pdccfget,pdccfclosed,proto);
			    sck=connectto(sck,pd->host,pd->port,NULL);
			    /* offering a possibility to change the filename (RFC..) */
			    if(newfile!=NULL && *file != '*')
			    {
				strmncpy(pd->file,newfile,sizeof(pd->file));
			    }
			    if(sck!=0) /* silently ignore errors */
			    {
				ps=getpsocketbysock(sck);
				if(ps!=NULL)
				{
				    ps->sock->dataflow=SD_STREAM;
				    pd->sock=sck;
				    pd->delay=0;
				    pd->type=PDC_RECVFROM;
				    return 0x0;
				}
			    }	
			}
		    }
		}
		pd=pd->next;
	    }
	    if(user(usern)->instate==STD_CONN)
		ssnprintf(user(usern)->insock,":-psyBNC!psyBNC@lam3rz.de NOTICE %s :No DCC File Request from '%s' for %s",user(usern)->nick,nick,file);
	    break;
	
    }
    return -1;    
}

/* querying to a dcc chat */

int querydccchat(int usern, char *nick)
{
    struct dcct *pdcc;
    pdcc=user(usern)->pdcc;
    while(pdcc!=NULL)
    {
	if(pdcc->type==PDC_CHATFROM || pdcc->type==PDC_CHATTO)
	{
	    if(strmcmp(nick,pdcc->nick)==1)
	    {
		writesock(pdcc->sock,irccontent);
		return 0x1;
	    }
	}
	pdcc=pdcc->next;
    }
    return 0x0;
}

/* checking timeouts for userdccs */

int checkdcctimeouts()
{
    struct usernodes *un;
    struct socketnodes *ps;
    struct dcct *pdcc,*epdcc=NULL,*prevdcc=NULL,*ipdcc;
    pcontext;
    un=usernode;
    while(un!=NULL)
    {
	if(un->user!=NULL)
	{
	    if(un->user->pdcc!=NULL)
	    {
		pdcc=un->user->pdcc;
		epdcc=NULL;prevdcc=NULL;
		while(pdcc!=NULL)
		{
		    epdcc=pdcc->next;
		    ipdcc=pdcc;
		    if((pdcc->type==PDC_SENDTORQ || pdcc->type==PDC_RECVFROMRQ || 
		       pdcc->type==PDC_CHATTORQ || pdcc->type==PDC_CHATFROMRQ) && 
		       pdcc->delay>0)
		    {
			pdcc->delay--;
			if(pdcc->delay==0)
			{
			    if(prevdcc==NULL)
			    {
				un->user->pdcc=epdcc;
				ipdcc=NULL;
			    } else {
				prevdcc->next=epdcc;
				ipdcc=prevdcc; /* bug -> just a case of prevdcc */
			    }
#ifdef SCRIPTING
			    if(pdcc->pid!=0)
			    {
				if(getsubtaskbypid(pdcc->pid)!=NULL)
				    terminatetask(pdcc->pid,0);
			    }
#endif
			    ps=getpsocketbysock(pdcc->sock);
			    if(ps!=NULL)
			    {
				killsocket(pdcc->sock);
			    }
			    free(pdcc);
			}
		    }
		    prevdcc=ipdcc;
		    pdcc=epdcc;
		}
	    }
	}
	un=un->next;
    }
    return 0x0;
}

/* list the pending dccs  */

int listpdccs(int usern)
{
    char *dcckind[]={
    "Unknown",
    "DCC Chat Request To",
    "DCC Chat To",
    "DCC Chat Request From",
    "DCC Chat From",
    "DCC Send Request To",
    "DCC Send To ",
    "DCC Send Request From",
    "DCC Send From",
    "Unknown"
    };
    int idx,pnd=0;
    struct dcct *pdcc;
    pdcc=user(usern)->pdcc;
    while(pdcc!=NULL)
    {
	idx=pdcc->type;
	if(idx>0 && idx <9)
	{
	    if(pnd==0)
	    {
		ssnprintf(user(usern)->insock,":-psyBNC!psyBNC@lam3rz.de NOTICE %s : Listing Pending DCCs",user(usern)->nick);
		pnd=1;
	    }
	    if(idx>4)
		ssnprintf(user(usern)->insock,":-psyBNC!psyBNC@lam3rz.de NOTICE %s : %d %s %s (%s)",user(usern)->nick,pdcc->sock,dcckind[idx],pdcc->nick,pdcc->file);
	    else
		ssnprintf(user(usern)->insock,":-psyBNC!psyBNC@lam3rz.de NOTICE %s : %d %s %s",user(usern)->nick,pdcc->sock,dcckind[idx],pdcc->nick);
	}
	pdcc=pdcc->next;
    }
    if(pnd==1)
    {
	ssnprintf(user(usern)->insock,":-psyBNC!psyBNC@lam3rz.de NOTICE %s : End of Pending DCCs",user(usern)->nick);
    }
    return 0x0;
}

/* cancel a dcc */

int canceldcc(int usern, char *nick, char *file)
{
    struct dcct *pdcc,*epdcc;
    struct socketnodes *sckn;
    char *fil;
    sckn=currentsocket;
    pdcc=user(usern)->pdcc;
    while(pdcc!=NULL)
    {
	epdcc=pdcc->next;
	if(file==NULL && (pdcc->type==PDC_CHATTO || pdcc->type==PDC_CHATFROM))
	{
	    if(strmcmp(nick,pdcc->nick)==1)
	    {
		currentsocket=getpsocketbysock(pdcc->sock);
		if(currentsocket!=NULL)
		{
		    pdccerror(usern,0);
		}
		currentsocket=sckn;
		return 0x0;
	    }
	} else 
	if (file!=NULL) 
	{
	    if(pdcc->type==PDC_RECVFROM || pdcc->type==PDC_SENDTO)
	    {
		fil=stripdccfile(pdcc->file,0);
		if(fil==NULL) return 0x0;
		if(strmcmp(nick,pdcc->nick)==1 && (strmcmp(file,fil)==1 || *file=='*'))
		{
		    currentsocket=getpsocketbysock(pdcc->sock);
		    if(currentsocket!=NULL)
		    {
			pdccferror(usern,0);
		    }
		    currentsocket=sckn;
		    return 0x0;
		}
	    }	
	}
	pdcc=epdcc;
    }
    ssnprintf(user(usern)->insock,":-psyBNC!psyBNC@lam3rz.de NOTICE %s :Unknown DCC. Please use /DCCCANCEL nick :file or /DCCCANCEL nick.",user(usern)->nick);
    return 0x0;
}

/* answering a ctcp request */

int answerctcp(int usern,char *nick, char *ctcp)
{
    char c=1;
#ifdef SCRIPTING
    if(ctcpscript(usern,ctcp)==0)
    {
#endif 
#ifdef CTCPVERSION
	if(strmcmp(ctcp,"VERSION"))
	{
	    ssnprintf(user(usern)->outsock,"NOTICE %s :%cVERSION " CTCPVERSION "%c",nick,c,c);
	}
#endif
#ifdef SCRIPTING
    }
#endif   
    return 0x0;
}

/* parsing a sent request from a user */

int parsectcps(int usern)
{
    static char host[200],file[200];
    int port;
    unsigned long filelen;
    char *pt,*ept,*pt2;
    if(*irccontent==0x1 && strmcmp(ircto,user(usern)->nick)==1)
    {
	if(strchr(irccontent,' ')==NULL)
	{
	    pt=irccontent+1;
	    pt2=strchr(pt,1);
	    if(pt2!=NULL)
	    {
		*pt2=0;
		return answerctcp(usern,ircnick,pt);
	    }
	    /* a request for a ctcp */
	} else {
	    /* an answer or a dcc */
#ifdef DCCCHAT
	    ept=irccontent+1;
	    if(strstr(ept,"DCC CHAT")==ept && user(usern)->dccenabled==1)
	    {
		pt=irccontent+10;
		pt=strchr(pt,' ');
		if(pt!=NULL)
		{
		    pt++;
		    pt2=strchr(pt,' ');
		    if(pt2!=NULL)
		    {
			*pt2=0;
			strmncpy(host,pt,sizeof(host));
			pt2++;
			pt=strchr(pt2,1);
			if(pt!=NULL)
			{
			    *pt=0;
			    port=atoi(pt2);
			    addpendingdcc(usern, PDC_CHATFROMRQ, host, port, ircnick, NULL, NULL, 0L, getprotocol(host));
			    return 0x1;
			}
		    }
		}
	    }
#endif	
#ifdef DCCFILES
	    ept=irccontent+1;
	    if(strstr(ept,"DCC SEND")==ept && strmcmp(ircnick,user(usern)->nick)==0 && user(usern)->dccenabled==1)
	    {
		pt=irccontent+10;
		pt=strchr(pt,' ');
		if(pt!=NULL)
		{
		    *pt=0;
		    ept=irccontent+10;
		    strmncpy(file,ept,sizeof(file));
		    pt++;
		    pt2=strchr(pt,' ');
		    if(pt2!=NULL)
		    {
			*pt2=0;
			strmncpy(host,pt,sizeof(host));
			pt2++;
			pt=strchr(pt2,' ');
			if(pt!=NULL)
			{
			    *pt=0;
			    port=atoi(pt2);
			    pt++;
			    pt2=strchr(pt,1);
			    if(pt2!=NULL)
			    {
				*pt2=0;			
				filelen=atol(pt);
				addpendingdcc(usern, PDC_RECVFROMRQ, host, port, ircnick, file, NULL, filelen, getprotocol(host));
				return 0x1;
			    }
			}
		    }
		}
	    
	    }
#endif	    
	}
    }
    return 0x0;
}
