/************************************************************************
 *   psybnc2.2.2, src/p_peer.c
 *   Copyright (C) 2000 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_peer.c, v 2.2.2 2001/03/25 02:02:02 psychoid Exp $";
#endif

#define P_PEER

#include <p_global.h>

/* check, if host is already connected */

jmp_buf peertimeout;

int checkpeerhostname (char *hostname)
{
   int apeer;
   int cnt=0;
   struct peernodes *th;
   pcontext;
   th=peernode;
   while (th!=NULL)
   {
       apeer=th->uid;
       if (newpeer(apeer)->state > STD_NOUSE) {
          if (strmcmp(newpeer(apeer)->host,hostname)) {
	     cnt++;
	     if(cnt>2) 
	         return -1;
          }
       }
       th=th->next;
   }
   return 0;
}

/* get a free peer descriptor */

int getnewpeer ()
{
   int apeer;
   pcontext;
   apeer = 1;
   P_CREATE=1;
   while (apeer < 255) 
   {
       if (newpeer(apeer)->state == STD_NOUSE) {
	  clearpeer(apeer);    
          return apeer;
       }
       apeer++;
   }
   return -1;
}

/* erase a connected peer */

int erasepeer(int npeer)
{
    pcontext;
    killsocket(newpeer(npeer)->insock);
    clearpeer(npeer);
    return 0x0;
}

#ifdef LINKAGE

/* linking a link (...) */

int linklink(int npeer)
{
    int lnk;
    char buf[200];
    struct socketnodes *lkm;
    pcontext;
    lnk=getlink(npeer);
    if (lnk==0) return -1;
    if (getlinkbyname(newpeer(npeer)->name)!=lnk && newpeer(npeer)->type!=NP_RELAY) return -1;
    /* hostname, name of the bouncer, and port are correct */
    pcontext;
    if (*datalink(lnk)->pass==0 && newpeer(npeer)->type!=NP_RELAY)
    {
	strmncpy(datalink(lnk)->pass,newpeer(npeer)->pass,sizeof(datalink(lnk)->pass));
	writelink(lnk);
    }
    if (strmcmp(datalink(lnk)->pass,newpeer(npeer)->pass)==0) return -1;
    /* password is correct */	
    if (newpeer(npeer)->type==NP_LINK) 
    {
	if (datalink(lnk)->type!=LI_ALLOW)
	{
	    return -1; /* invalid link type, only 'allowed' links get accepted */
	}
	ssnprintf(newpeer(npeer)->insock,":%s!*@%s IAM :\r\n",me,me);
#ifdef PARTYCHANNEL
	ssnprintf(newpeer(npeer)->insock,":*!*@* BWHO :\r\n"); /* getting the 'WHO' */
	ssnprintf(newpeer(npeer)->insock,":psyBNC@%s!*@%s TOPIC " PARTYCHAN " :%s\r\n",me,me,partytopic);
#endif
	ssnprintf(newpeer(npeer)->insock,":*!*@* LISTLINKS :\r\n"); /* getting the 'WHO' */
	datalink(lnk)->insock=newpeer(npeer)->insock;
	datalink(lnk)->instate=STD_CONN;
	datalink(lnk)->outsock=0;
	datalink(lnk)->outsock=0;
	clearpeer(npeer);
#ifdef INTNET
	joinintnettolink(lnk);
#endif
	lkm=getpsocketbysock(datalink(lnk)->insock);
        pcontext;
	if(lkm!=NULL)
	{
	    lkm->sock->param=lnk;
	    lkm->sock->handler=checklinkdata;
	    lkm->sock->errorhandler=checklinkerror;
	    lkm->sock->destructor=checklinkkill;
	}
	log(LOG_INFO,-1,"Linked to %s",datalink(lnk)->name);
	sysparty("Linked to %s",datalink(lnk)->name);
	addtopology(datalink(lnk)->name,me);
	return 0x0; /* done, linked */
    }
    pcontext;
    if (newpeer(npeer)->type==NP_RELAY)
    {
	if(datalink(lnk)->allowrelay!=1)
	{
	    ssnprintf(newpeer(npeer)->insock,":-psyBNC!psyBNC@lam3rz.de NOTICE * :No Relays allowed. Good Bye.\r\n");
	    return -1;
	}
	return linkrelay(npeer,lnk);
    }
}

#endif

/* linking the new peer */

int linkpeer(int npeer)
{
    int rc;
    int rc2;
    struct usernodes *th;
    struct socketnodes *lkm;
    int sck;
    char buf[200];
    char *pt;
    pcontext;
#ifdef ANONYMOUS
#ifdef MULTIUSER
    rc=checkuser(newpeer(npeer)->login);
#else
    rc=1;
#endif
    if (rc==0x0) nousers=1;
#endif
    if (nousers==1) {
       nousers = 0;
       rc = firstuser(npeer);
       pcontext;
       if(rc==-1) return -1;
       if (rc) {
	  strmncpy(user(rc)->nick,newpeer(npeer)->nick,sizeof(user(rc)->nick));
	  strmncpy(user(rc)->wantnick,newpeer(npeer)->nick,sizeof(user(rc)->wantnick));
	  strmncpy(user(rc)->user,newpeer(npeer)->user,sizeof(user(rc)->user));
	  strmncpy(user(rc)->host,newpeer(npeer)->host,sizeof(user(rc)->host));
          user(rc)->insock = newpeer(npeer)->insock;
	  user(rc)->instate = STD_CONN;
	  lkm=getpsocketbysock(user(rc)->insock);
	  pcontext;
	  if(lkm!=NULL)
	  {
	    lkm->sock->param=rc;
	    lkm->sock->handler=userinbound;
	    lkm->sock->errorhandler=userinerror;
	    lkm->sock->destructor=userinkill;
	  }
#ifdef PARTYCHANNEL
	  joinparty(rc);
#endif
	  writeuser(rc);
          clearpeer(npeer);
	  pcontext;
	  memset(nulluser,0x0,sizeof(struct usert));
	  memset(dummyuser,0x0,sizeof(struct usert));
          return 0x0;
       }
    }
#ifdef MULTIUSER
    rc=checkuser(newpeer(npeer)->login);
#else
    rc=1;
#endif
    pcontext;
    if (rc==0x0) return -1;
    ap_snprintf(buf,sizeof(buf),"%s%s",slt1,slt2);
    pt=BLOW_stringencrypt(buf,newpeer(npeer)->pass);
    pcontext;
    ap_snprintf(newpeer(npeer)->pass,sizeof(newpeer(npeer)->pass),"=%s",pt);
    free(pt);
    if (strmcmp(newpeer(npeer)->pass,user(rc)->pass)==0x0) return -1;
#ifndef PARTYCHANNEL
    sysparty("User %s logged in.",newpeer(npeer)->login);
#endif
    log(LOG_INFO,-1,"User %s logged in.",newpeer(npeer)->login);
    lkm=getpsocketbysock(newpeer(npeer)->insock);
    pcontext;
    if(lkm!=NULL)
    {
	lkm->sock->param=rc;
	lkm->sock->handler=userinbound;
	lkm->sock->errorhandler=userinerror;
	lkm->sock->destructor=userinkill;
    }
    /* authentification proceeded */
    if (user(rc)->insock > 0) {
       ssnprintf(user(rc)->insock,":-psyBNC!psychiod@lam3rz.de NOTICE %s :New Connection from %s\n",user(rc)->nick,newpeer(npeer)->host);
       killsocket(user(rc)->insock);	
    }
#ifdef PARTYCHANNEL
    if(user(rc)->sysmsg==0)
	ap_snprintf(buf,sizeof(buf),"User %s logged in (not on Partyline).",newpeer(npeer)->login);
#else
    if(user(rc)->sysmsg==0)
	ap_snprintf(buf,sizeof(buf),"User %s logged in.",newpeer(npeer)->login);
#endif
    pcontext;
    th=usernode;
    while (th!=NULL)
    {
	if (th->user!=NULL)
	{
	    if (th->user->parent==rc || th->uid==rc)
	    {
#ifdef DYNAMIC
		cmdbconnect(th->uid);
#endif
		user(th->uid)->delayed=0; /* if a user is not connected, he will get an addserver message at login */
		user(th->uid)->insock = newpeer(npeer)->insock;
#ifdef SCRIPTING
		startdialogues(th->uid);
#endif
		strmncpy(user(th->uid)->host,newpeer(npeer)->host,sizeof(user(th->uid)->host));
		strmncpy(user(th->uid)->wantnick,newpeer(npeer)->nick,sizeof(user(th->uid)->wantnick));
		if (user(th->uid)->outstate == STD_CONN) {
		    user(th->uid)->instate = STD_CONN;
		    if (user(th->uid)->parent==0) repeatserverinit(rc);
		    if (user(th->uid)->parent == 0)
			ssnprintf(user(rc)->insock,":%s!%s@%s NICK :%s\r\n",user(rc)->firstnick,user(rc)->login,user(rc)->host,user(rc)->nick);
		    if(user(th->uid)->leavequit==1)
			rejoinchannels(th->uid);
		    else
			rejoinclient(th->uid);
#ifdef PARTYCHANNEL
		    if(user(th->uid)->sysmsg==1 || th->user->parent==0)
		    {
			user(th->uid)->sysmsg=0;
			strcpy(irccontent,PARTYCHAN);
			cmdjoin(th->uid);
			user(th->uid)->sysmsg=1;
		    }
#endif
		    ap_snprintf(buf,sizeof(buf),"NICK %s\r\n",user(th->uid)->wantnick);
		    writesock_URGENT(user(th->uid)->outsock,buf);
		} else {
		    strmncpy(user(th->uid)->nick,newpeer(npeer)->nick,sizeof(user(th->uid)->nick));
		    user(th->uid)->instate = STD_CONN;
		    if (user(th->uid)->parent==0)
		    {
			if (checkforlog(th->uid))
                           ssnprintf(user(th->uid)->insock,":-psyBNC!psyBNC@lam3rz.de NOTICE %s :You have Messages. Type /QUOTE PLAYPRIVATELOG to read your messages.",user(th->uid)->nick);
			else
                           ssnprintf(user(th->uid)->insock,":-psyBNC!psyBNC@lam3rz.de NOTICE %s :You have no new Messages.",user(th->uid)->nick);
		    }
#ifdef PARTYCHANNEL
		    if(user(th->uid)->sysmsg==1 || th->user->parent==0)
		    {
			user(th->uid)->sysmsg=0;
			strcpy(irccontent,PARTYCHAN);
			cmdjoin(th->uid);
			user(th->uid)->sysmsg=1;
		    }
#endif
		}
	    }
	}
	th=th->next;
    }
    clearpeer(npeer);
#ifdef INTNET
    rejoinintchannels(rc);
#endif
    return 0x0;
}

/* if an new peer gets killed */

int killoldlistener(int npeer)
{
    pcontext;
    if(npeer==0) return 0x0;
    log(LOG_WARNING,-1,"Lost Connection from %s (%s)",newpeer(npeer)->host,newpeer(npeer)->login);
    erasepeer(npeer);
    return;	  
}

/* if an new peer gets killed */

int erroroldlistener(int npeer,int errn)
{
    pcontext;
    if(npeer==0) return 0x0;
    log(LOG_ERROR,-1,"Lost Connection from %s (%s)",newpeer(npeer)->host,newpeer(npeer)->login);
    currentsocket->sock->destructor=NULL;
    erasepeer(npeer);
    return;	  
}

/* checking data coming on a peer */

int checkoldlistener(int npeer)
{
    int rc;
    int i;
    struct socketnodes *lkm;
    char buf[200];
    char *po;
    pcontext;
    if (newpeer(npeer)->state != STD_NOUSE) {
          newpeer(npeer)->delayed++;
	  if (newpeer(npeer)->delayed > 8) {
	     /* all your bases are belong to us */
	     writesock(newpeer(npeer)->insock,"Login failed. Disconnecting.\n");
	     erasepeer(npeer);
	     return;
	  }
	  parse();
	  if (ifcommand("USER")) {
	     strmncpy(newpeer(npeer)->user,irccontent,sizeof(newpeer(npeer)->user));
	     po=ircto;
	     po=strchr(ircto,' ');
	     if (po==NULL) return 0x0;
	     *po=0;
	     strmncpy(newpeer(npeer)->login,ircto,sizeof(newpeer(npeer)->login));
	     i=checkuser(newpeer(npeer)->login);
	     if(i!=0)
	     {
	         if(*user(i)->crkey!=0)
		 {
		     lkm=getpsocketbysock(newpeer(npeer)->insock);
		     if(lkm!=NULL)
		     {
#ifdef CRYPT
			 strmncpy(lkm->sock->incrkey,user(i)->crkey,sizeof(lkm->sock->incrkey));
			 strmncpy(lkm->sock->outcrkey,user(i)->crkey,sizeof(lkm->sock->outcrkey));
			 lkm->sock->encryption=SE_ENC;
#endif
		     }
		 }
	     }
	  }
#ifdef LINKAGE
	  if (ifcommand("PSYBNC")) {
	     newpeer(npeer)->lnkport=atoi(irccontent);
	     strmncpy(newpeer(npeer)->name,ircto,sizeof(newpeer(npeer)->name));
	     newpeer(npeer)->type=NP_LINK; /* this is a bouncer */
	     i=getlink(npeer);
	     if(i!=0)
	     {
		 if(*datalink(i)->crkey!=0)
		 {
	             lkm=getpsocketbysock(newpeer(npeer)->insock);
		     if(lkm!=NULL)
		     {
#ifdef CRYPT
			 strmncpy(lkm->sock->incrkey,datalink(i)->crkey,sizeof(lkm->sock->incrkey));
			 strmncpy(lkm->sock->outcrkey,datalink(i)->crkey,sizeof(lkm->sock->outcrkey));
			 lkm->sock->encryption=SE_ENC;
#endif
		     }
		 }
	     }
	  }
	  if (ifcommand("VHOST")) {
	     strmncpy(newpeer(npeer)->vhost,irccontent,sizeof(newpeer(npeer)->vhost));
	  }
	  if (ifcommand("CONNECT")) {
	     strmncpy(newpeer(npeer)->server,ircto,sizeof(newpeer(npeer)->server));	    
	     newpeer(npeer)->port=atoi(irccontent);
	  }
	  if (ifcommand("RELAY")) {
	     newpeer(npeer)->lnkport=atoi(irccontent);
	     strmncpy(newpeer(npeer)->name,ircto,sizeof(newpeer(npeer)->name));
	     newpeer(npeer)->type=NP_RELAY; /* this is a relay */
	  }
#endif
	  if (ifcommand("NICK")) {
	     strmncpy(newpeer(npeer)->nick,irccontent,sizeof(newpeer(npeer)->nick));
	     if (strlen(newpeer(npeer)->pass)==0 && newpeer(npeer)->type==0) {
	         ssnprintf(newpeer(npeer)->insock,":-psyBNC!psyBNC@lam3rz.de NOTICE %s :Your IRC Client did not support a password. Please type /QUOTE PASS yourpassword to connect.",newpeer(npeer)->nick);
	     }
	  }
	  if (ifcommand("PASS")) {
	     if (*irccontent=='+') *irccontent='-';
	     strmncpy(newpeer(npeer)->pass,irccontent,sizeof(newpeer(npeer)->pass));
#ifdef LINKAGE
	     if (newpeer(npeer)->type!=NP_USER)
	     {
	         if (linklink(npeer)==-1)
		 {
		     log(LOG_ERROR,-1,"Failed incoming Link %s (%s)",newpeer(npeer)->host,newpeer(npeer)->name);
	             erasepeer(npeer);
		     return 0x0;		     
		 }
		 return 0x0;
	     }
#endif
	  }
	  if (strlen(newpeer(npeer)->nick) != 0) {
  	    if (strlen(newpeer(npeer)->login) != 0) {
	      if (strlen(newpeer(npeer)->pass) != 0) {
	          if (linkpeer(npeer) ==-1) {
		     ssnprintf(newpeer(npeer)->insock,":-psyBNC!psyBNC@lam3rz.de NOTICE %s :Wrong Password. Disconnecting.\n",newpeer(npeer)->nick);
		     log(LOG_ERROR,-1,"Failed Authentification for %s from host %s",newpeer(npeer)->login,newpeer(npeer)->host);
	             erasepeer(npeer);
		  }
	      }
	    }  
	  }
    }
}

char ntoares[60];
int sport;

/* checking a hosts allow */

int checkhostallows(char *host)
{
    char buf[350];
    char buf2[350];
    struct stringarray *th;
    char *pt;
    ap_snprintf(buf,sizeof(buf),"*!*@%s",host);
    th=hostallows;
    while(th!=NULL)
    {
	ap_snprintf(buf2,sizeof(buf2),"*!*@%s",th->entry);
	pt=strchr(buf2,';');
	if(pt!=NULL) *pt=0;
	if(wild_match(buf2,buf)) return 1;
	th=th->next;
    }
    return -1;
}

/* check a connected peer structure */

int checknewlistener(int i)
{
    int ret;
    int asocket;
    int npeer;
    struct socketnodes *lkm;
    int listensocket;
    int p_proto;
    pcontext;
    p_proto=currentsocket->sock->protocol;
    listensocket=currentsocket->sock->syssock;
    asocket = bncaccept( listensocket );
    pcontext;
    if(checkhostallows(ntoares)==-1 && checkhostallows(bnchost)==-1)
    {
	log(LOG_ERROR,-1,"Illecit Connection from %s. Closing Connection.",bnchost);
	lkm=getpsocketbysock(listensocket);
	if(lkm!=NULL)
	{
	    lkm->sock->flag=SOC_SYN; /* resetting the listener to listen again */
	}
	shutdown(asocket,2);
	close(asocket);
	return 0x0;
    }
    if(asocket<=0) return;    
    asocket=createsocket(asocket,ST_LISTEN,0,NULL,NULL,erroroldlistener,checkoldlistener,killoldlistener,p_proto);
    lkm=getpsocketbysock(listensocket);
    if(lkm!=NULL)
    {
	lkm->sock->flag=SOC_SYN; /* resetting the listener to listen again */
    }
    pcontext;
    if (asocket==-1) return -1;
    if (checkpeerhostname(bnchost) == -1) {
	write(asocket,"Only three Connections per Host allowed !\n",39);
	killsocket(asocket);
	return;
    }
    npeer = getnewpeer();
    pcontext;
    if (npeer == -1) {
	log(LOG_ERROR,-1,"Too many connections, removing connection from %s",bnchost);
        write(asocket,"Too many host connctions !\n",28);
	killsocket(asocket);
	return;
    }
    ssnprintf(asocket,":Welcome!psyBNC@lam3rz.de NOTICE * :" APPNAME APPVER);
    lkm=getpsocketbysock(asocket);
    pcontext;
    if(lkm!=NULL)
    {
	lkm->sock->param=npeer;
	lkm->sock->flag=SOC_CONN;
	strmncpy(lkm->sock->source,ntoares,sizeof(lkm->sock->source));
	strmncpy(lkm->sock->dest,currentsocket->sock->dest,sizeof(lkm->sock->dest));
	lkm->sock->sport=sport;
	if(socketnode->sock!=NULL)
	{
             lkm->sock->dport=socketnode->sock->sport;
	}
    }
    clearpeer(npeer);	
    pcontext;
    newpeer(npeer)->insock = asocket;
    strmncpy(newpeer(npeer)->host,bnchost,sizeof(newpeer(npeer)->host));
    newpeer(npeer)->state = STD_NEWCON;
    newpeer(npeer)->delayed = 0;
    log(LOG_WARNING,-1,"connect from %s",bnchost);
    return;
}
/* create listening sock */

void killed ()
{
   log(LOG_ERROR,-1,"killed by user abort");
   exit(0x0);
}

/* error routine */

void errored ()
{
   errn = 1;
   return;
}

int p_proto;

/* create a single listener */

int createlistener(char *host,int listenport,int proto,int pending, int(*listenhandler)(int))
{
#ifdef IPV6
  struct sockaddr_in6 listen_sa6;
#endif
  struct hostent *he;
  struct sockaddr_in listen_sa;
  struct socketnodes *lkm;
  int sopts = 1;
  int opt;
  int listensocket;
  int rc;
  const char *pt;
  listensocket = socket (proto, SOCK_STREAM, IPPROTO_TCP);
  listensocket = createsocket(listensocket,ST_LISTEN,0,NULL,listenhandler,NULL,NULL,NULL,proto);
  lkm=getpsocketbysock(listensocket);
  if(lkm==NULL || listensocket==0)
  {
      if(pending==0)
          log(LOG_ERROR,-1,"Can't create listening sock on host %s port %d",host,listenport);
      return 0;
  }
  strmncpy(lkm->sock->source,host,sizeof(lkm->sock->source));
  strcpy(lkm->sock->dest,"*");    
  lkm->sock->sport=listenport;
  lkm->sock->dport=0;
  lkm->sock->flag=SOC_SYN; /* we are open */
  highestsocket = listensocket;

  opt=sizeof(int);
  setsockopt (listensocket, SOL_SOCKET, SO_REUSEADDR, &sopts, opt);
#ifdef IPV6
  if(proto==AF_INET6)
     memset (&listen_sa6, 0, sizeof (struct sockaddr_in6));
  else
#endif
     memset (&listen_sa, 0, sizeof (struct sockaddr_in));

#ifdef IPV6
  if(proto==AF_INET6)
  {
      listen_sa6.sin6_port = htons (listenport);
#ifdef SUNOS
      he=getipnodebyname(host,AF_INET6,AI_DEFAULT,&error_num);
#else
      he=gethostbyname2(host,AF_INET6);
#endif
      if(*host=='*')
      {
          memcpy(&listen_sa6.sin6_addr,&in6addr_any,16);
	  listen_sa6.sin6_family=AF_INET6;
      } else {
          if(!he)
          {
              killsocket(listensocket);
              if(pending==0)
                  log(LOG_ERROR,-1,"Can't create listening sock on host %s port %d (lookup)",host,listenport);
	      return 0x0;
          }                   
          listen_sa6.sin6_family=he->h_addrtype;
          memcpy(&listen_sa6.sin6_addr,he->h_addr,he->h_length);
      }
      pt=inet_ntop(AF_INET6,&listen_sa6,lkm->sock->source,sizeof(lkm->sock->source));
/* ipv6 dcc not yet specified
      if(dcc6host[0]==0) strmncpy(dcc6host,lkm->sock->source,sizeof(dcc6host)); */
  } else {
#endif
      listen_sa.sin_port = htons (listenport);
      if(*host=='*')
      {
          listen_sa.sin_addr.s_addr=htonl(INADDR_ANY);
	  listen_sa.sin_family=AF_INET;
      } else {
          he=gethostbyname(host);
          if(!he)
          {
              killsocket(listensocket);
              if(pending==0)
                  log(LOG_ERROR,-1,"Can't create listening sock on host %s port %d (lookup)",host,listenport);
	      return 0x0;
          }
          listen_sa.sin_family=he->h_addrtype;
          memcpy(&listen_sa.sin_addr,he->h_addr,he->h_length);
      }
      strmncpy(lkm->sock->source,inet_ntoa(listen_sa.sin_addr),sizeof(lkm->sock->source));
      if(listen_sa.sin_addr.s_addr!=htonl(INADDR_ANY))
          if(dcchost[0]==0) strmncpy(dcchost,lkm->sock->source,sizeof(dcchost));
#ifdef IPV6
  }
  if(proto==AF_INET6)
    rc=bind(listensocket, (struct sockaddr *) &listen_sa6, sizeof(listen_sa6));
  else  
#endif
    rc=bind(listensocket, (struct sockaddr *) &listen_sa, sizeof (struct sockaddr_in));

  if (rc < 0)
  {	
      killsocket(listensocket);
      if(pending==0)
          log(LOG_ERROR,-1,"Can't create listening sock on host %s port %d (bind)",host,listenport);
      return 0; /* cannot create socket */
  }	
  if ((listen (listensocket, 1)) == -1)
  {	
      killsocket(listensocket);
      if(pending==0)
          log(LOG_ERROR,-1,"Can't create listening sock on host %s port %d (listen)",host,listenport);
      return 0; /* cannot create socket */
  }
  if(pending==0)
  {
      printf("Listening on: %s port %d\n",lkm->sock->source,listenport);
      log(LOG_INFO,-1,"Listener created :%s port %d",lkm->sock->source,listenport);
  }
  return listensocket;
}

/* creating listening ports on the hosts given in the config for the demon */

int createlisteners ()
{
  struct sigaction sv;
  struct sigaction sx;
  struct socketnodes *lkm;
  int proto;
  int rc;
  char entry[40];
  char host[200];
  int listenport;
  int cntlisten;
  int successes=0;
  dcchost[0]=0;
  dcc6host[0]=0;
  sigemptyset(&sv.sa_mask);
  sv.sa_handler = killed;
  sigemptyset(&sx.sa_mask);
  sx.sa_handler = errored;
  sigaction( SIGTERM, &sv, NULL);
  sigaction( SIGINT, &sx, NULL);
  sigaction( SIGKILL, &sv, NULL);
  sigaction( SIGHUP, &sx, NULL);
  sigaction( SIGUSR1, &sx, NULL);
  sigaction( SIGPIPE, &sx, NULL);
  umask( ~S_IRUSR & ~S_IWUSR );
  srand( time( NULL) ); /* here we randomize to the timer (for randstring) */
  srandom(rand()); /* salt of random bases on rand of time */
  if(getini("SYSTEM","DCCHOST","PSYBNC")==0)
  {
      if(inet_addr(value)<=0)
      {
          log(LOG_ERROR,0,"DCCHOST has to be in IP Format (nnn.nnn.nnn.nnn)");
      } else {
          strmncpy(dcchost,value,sizeof(dcchost));
      }	
  }
  for(cntlisten=0;cntlisten<100;cntlisten++)
  {
      ap_snprintf(entry,sizeof(entry),"PORT%d",cntlisten);
      if(getini("SYSTEM",entry,"PSYBNC")==0)
      {
	  listenport=atoi(value);
	  ap_snprintf(entry,sizeof(entry),"HOST%d",cntlisten);
	  rc=getini("SYSTEM",entry,"PSYBNC");
	  if(rc==0)
	  {
	      strmncpy(host,value,sizeof(host));
	  } else {
	      strcpy(host,"*");
	  }
	  if(strmcmp(host,"*"))
	  {
#ifdef IPV6
	      if(createlistener("*",listenport,AF_INET,0,checknewlistener)>0) successes++;

	      proto=AF_INET6;
#else
	      proto=AF_INET;
#endif
	  } else {
	      proto=getprotocol(host);
	  }      
	  if(createlistener(host,listenport,proto,0,checknewlistener)>0) successes++;
      }	
  }
  if(successes!=0)
  {
      if(dcchost[0]==0)
          log(LOG_ERROR,-1,"Can't set a suitable Host for DCC Chats or Files. Please define at least one Listener for an IP.");
/* IPV6 DCC not yet specified
#ifdef IPV6
      if(dcc6host[0]==0)
          log(LOG_ERROR,-1,"Can't set a suitable Host for DCC Chats or Files for IPV6. Please define at least one Listener for an IP to IPv6 if you want to use IPV6-DCC Chats.");
#endif
*/
  }
  return successes; /* success */
}


/* accept incoming call on listener */

int bncaccept( int lsock)
{
#ifdef IPV6
   struct sockaddr_in6 addr6;
#endif
   struct sockaddr_in addr;
   struct socketnodes *lkm;
   int tm;
   int str;
   pcontext;
   lkm=getpsocketbysock(lsock);
   if(lkm==NULL)
      return -1;
#ifdef IPV6
   if(lkm->sock->protocol==AF_INET6)
   {
      tm = sizeof(addr6);
      str = accept(lsock, ( struct sockaddr *)&addr6, &tm);
      if(str==-1) return -1;
      if(!setjmp(peertimeout))
      {
	  alarm(10);
          hostinfo = gethostbyaddr( (char * )&addr6.sin6_addr.s6_addr, 16, AF_INET6);
	  alarm(0);
      } else
          hostinfo=NULL;
      if(hostinfo)
         strmncpy(bnchost,hostinfo->h_name,sizeof(bnchost));
      else
         inet_ntop(AF_INET6,&addr6,bnchost,sizeof(bnchost));
      inet_ntop(AF_INET6,&addr6,ntoares,sizeof(ntoares));
      sport=ntohs(addr6.sin6_port);
   }
   else
#endif
   {
       tm = sizeof(addr);
       str = accept(lsock, ( struct sockaddr * )&addr, &tm);
       if (str==-1) return -1;
       if(!setjmp(peertimeout))
       {
	   alarm(10);
           hostinfo = gethostbyaddr( ( char * )&addr.sin_addr.s_addr, sizeof( struct in_addr), AF_INET);
	   alarm(0);
       } else
           hostinfo=NULL;
       if (hostinfo) 
          strmncpy(bnchost,hostinfo->h_name,sizeof(bnchost));
       else 
          strmncpy(bnchost,inet_ntoa( addr.sin_addr ),sizeof(bnchost));
       strmncpy(ntoares,inet_ntoa(addr.sin_addr),sizeof(ntoares));
       sport=ntohs(addr.sin_port);
   }
   return str;
}
