/************************************************************************
 *   psybnc2.2.2, src/p_intnet.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_intnet.c, v 2.2.2 2001/03/25 02:02:02 psychoid Exp $";
#endif

#define P_INTNET

#include <p_global.h>

/*
 * This snippet of code was created to emulate an internal ircd
 * on psybnc. Channels and modes are shared thruout the linked
 * bouncers.
 */

#ifdef INTNET

struct clientt {
    int intuser;
    char nick[64];
    char ident[30];
    char host[200];
    char server[200];
    struct clientt *next;
};

struct clientt *clients=NULL;

/* helper to add a client */

struct clientt *createclient(int usern, char *nick, char *ident, char *host, char *server)
{
    struct clientt *cl,*cl1=NULL;
    cl=clients;
    while(cl!=NULL)
    {
	if(cl->intuser==usern && usern!=0) return cl;
	cl1=cl;
	cl=cl->next;
    }
    if(cl1==NULL)
    {
	clients=(struct clientt *)pmalloc(sizeof(struct clientt));
	cl1=clients;
    } else {
	cl1->next=(struct clientt *)pmalloc(sizeof(struct clientt));
	cl1=cl1->next;
    }
    cl1->intuser=usern;
    strmncpy(cl1->nick,nick,sizeof(cl1->nick));
    strmncpy(cl1->ident,ident,sizeof(cl1->ident));
    strmncpy(cl1->host,host,sizeof(cl1->host));
    strmncpy(cl1->server,server,sizeof(cl1->server));
    return cl1;    
}

/* helper to remove a client */

int removeclient(char *nick)
{
    struct clientt *client,*eclient=NULL;
    client=clients;
    while(client!=NULL)
    {
	if(strmcmp(client->nick,nick)==1)
	{
	    if(eclient==NULL)
	    {
		clients=client->next;
	    } else {
		eclient->next=client->next;
	    }
	    free(client);
	    return 0x1;
	}
	eclient=client;
	client=client->next;
    }
    return 0x0;
}

/* helper for getting a client from a nickname */

struct clientt *getclientbynick(char *nick)
{
    struct clientt *cl;
    char uc1[64],uc2[64];
    cl=clients;
    strmncpy(uc1,nick,sizeof(uc1));
    ucase(uc1);
    while(cl!=NULL)
    {
	strmncpy(uc2,cl->nick,sizeof(uc2));
	ucase(uc2);
	if(strmcmp(uc1,uc2)==1)
	    return cl;
	cl=cl->next;
    }
    return NULL;
}

/* helper to add a client and to tell this to the network */

struct clientt *enteruser(int usern, char *nick, char *ident, char *host, char *server)
{
    struct clientt *client;
    if(usern>0)
    {
	client=getclientbynick(nick);
	if(client!=NULL)
	{
	    ssnprintf(user(usern)->insock,":-psyBNC!psyBNC@lam3rz.de NOTICE %s :The internal network (int~) could not be joined, because your nick is already in use by %s!%s@%s. Change your nick, then retry to join.",user(usern)->nick,client->nick,client->ident,client->host);
	    return NULL;
	}
    }
    client=createclient(usern,nick,ident,host,server);
    ap_snprintf(ircbuf,sizeof(ircbuf),":intnet!intnet@%s INTNET *@* :USER %s %s %s :%s",me,nick,ident,host,server);
    broadcast(0);
    return client;
}

/* helper for getting a client from a usernumber */

struct clientt *getclientbynumber(int usern)
{
    struct clientt *cl;
    cl=clients;
    while(cl!=NULL)
    {
	if(usern==cl->intuser)
	    return cl;
	cl=cl->next;
    }
    return NULL;
}

/* helper to add a ban */

int addban(struct uchannelt *chan, char *banmask)
{
    struct stringarray *banlist,*oban=NULL;
    char *q,*p;
    int cnt=0;
    banlist=chan->bans;
    while(banlist!=NULL)
    {
	if(strmcmp(banmask,banlist->entry)==1) return 0x0;
	banlist=banlist->next;
    }
    banlist=chan->bans;
    q=strchr(banmask,'!');
    p=strchr(banmask,'@');
    if(p==NULL || q==NULL) return 0x0;
    if(q>p) return 0x0;
    while(banlist!=NULL && cnt<20)
    {
	oban=banlist;
	banlist=banlist->next;
	cnt++;
    }
    if(cnt>=20) return 0x0;
    if(oban==NULL)
    {
	oban=(struct stringarray *)pmalloc(sizeof(struct stringarray));
	chan->bans=oban;
    } else {
	oban->next=(struct stringarray *)pmalloc(sizeof(struct stringarray));
	oban=oban->next;
    }
    oban->entry=(char *)pmalloc(strlen(banmask)+2);
    strmncpy(oban->entry,banmask,strlen(banmask)+1);
    return 0x1;
}

/* helper to remove a ban */

int removeban(struct uchannelt *chan, char *banmask)
{
    struct stringarray *banlist,*oban=NULL;
    char *q,*p;
    int cnt=0;
    banlist=chan->bans;
    q=strchr(banmask,'!');
    p=strchr(banmask,'@');
    if(p==NULL || q==NULL) return 0x0;
    if(q>p) return 0x0;
    while(banlist!=NULL && cnt<20)
    {
	if(strmcmp(banlist->entry,banmask)==1)
	{
	    if(oban==NULL)
	    {
		chan->bans=banlist->next;
	    } else {
		oban->next=banlist->next;
	    }    
	    free(banlist->entry);
	    free(banlist);
	    return 0x1;
	}
	oban=banlist;
	banlist=banlist->next;
	cnt++;
    }
    return 0x0;
}

/* helper to add an invite */

int addinvite(struct uchannelt *chan, char *invite)
{
    struct stringarray *invlist,*oinv=NULL;
    char *q,*p;
    int cnt=0;
    invlist=chan->invites;
    p=strchr(invite,' ');
    if(p!=NULL) *p=0x0;
    while(invlist!=NULL && cnt<20)
    {
	oinv=invlist;
	invlist=invlist->next;
	cnt++;
    }
    if(cnt>=20) return 0x0;
    if(oinv==NULL)
    {
	oinv=(struct stringarray *)pmalloc(sizeof(struct stringarray));
	chan->invites=oinv;
    } else {
	oinv->next=(struct stringarray *)pmalloc(sizeof(struct stringarray));
	oinv=oinv->next;
    }
    oinv->entry=(char *)pmalloc(strlen(invite)+2);
    strmncpy(oinv->entry,invite,strlen(invite)+1);
    return 0x1;
}

/* helper to remove a ban */

int removeinvite(struct uchannelt *chan, char *invite)
{
    struct stringarray *invlist,*oinv=NULL;
    char *q,*p;
    int cnt;
    invlist=chan->invites;
    p=strchr(invite,' ');
    if(p!=NULL) *p=0;
    while(invlist!=NULL && cnt<20)
    {
	if(strmcmp(invlist->entry,invite)==1)
	{
	    if(oinv==NULL)
	    {
		chan->invites=invlist->next;
	    } else {
		oinv->next=invlist->next;
	    }    
	    free(invlist->entry);
	    free(invlist);
	    return 0x1;
	}
	oinv=invlist;
	invlist=invlist->next;
	cnt++;
    }
    return 0x1;
}

/* helper to check if the user may join */

int mayjoin(struct uchannelt *chan, struct clientt *client, char *key)
{
    struct stringarray *lst;
    char ehost[300];
    ap_snprintf(ehost,sizeof(ehost),"%s!%s@%s",client->nick,client->ident,client->host);
    if(strchr(chan->modes,'i')!=NULL)
    {
	lst=chan->invites;
	while(lst!=NULL)
	{
	    if(strmcmp(client->nick,lst->entry)==1) return 0x0;
	    lst=lst->next;
	}
	return -3;
    }
    lst=chan->bans;
    while(lst!=NULL)
    {
	if(wild_match(lst->entry,ehost))
	    return -1;
	lst=lst->next;
    }
    if(strchr(chan->modes,'k')!=NULL)
    {
	if(strmcmp(chan->key,key)==0) return -2;
    }
    return 0x0;
}

/* write from internal network to a client 
 * syntax: sendtoclient(char *nick,int notlink, char *format, ...)
 */

int 
sendtoclient(va_alist)
    va_dcl
{
    va_list va;
    int sock;
    char *format;
    char *nick;
    int notlink;
    char buf[2048];
    struct clientt *client;
    va_start(va);
    nick=va_arg(va,char *);
    notlink=va_arg(va,int);
    format=va_arg(va,char *);
    client=getclientbynick(nick);
    ap_vsnprintf(buf,sizeof(buf),format,va);
    strmncpy(ircbuf,buf,sizeof(ircbuf));
    parse();
    if(client==NULL)
    {
	ap_snprintf(ircbuf,sizeof(ircbuf),":intnet!intnet@%s INTNET *@* :%s",me,ircbuf);
    	broadcast(0);
    } else {
	if(client->intuser>0)
	{
	    if(user(client->intuser)->instate==STD_CONN)
	    {
		strmncpy(ircbuf,buf,sizeof(ircbuf));
		addtoken(client->intuser+10000);
		ssnprintf(user(client->intuser)->insock,"%s",ircbuf);
	    }	
	} else {
	    ap_snprintf(ircbuf,sizeof(ircbuf),":intnet!intnet@%s INTNET *@* :%s",me,buf);
    	    broadcast(notlink);
	}	
    }
    va_end(va);
    return strlen(buf);
}

/* write from internal network to a link
 * syntax: sendtolink(int link, char *format, ...)
 */

int 
sendtolink(va_alist)
    va_dcl
{
    va_list va;
    int sock;
    char *format;
    int link;
    char buf[2048];
    va_start(va);
    link=va_arg(va,int);
    format=va_arg(va,char *);
    
    ap_vsnprintf(buf,sizeof(buf),format,va);
    ap_snprintf(ircbuf,sizeof(ircbuf),":intnet!intnet@%s INTNET *@* :%s",me,buf);
    broadcasttolink(link);
    va_end(va);
    return strlen(buf);
}

/* write from internal network to a channel 
 * syntax: sendtochannel(char *channel, int notlink, char *format, ...)
 */

int sendtochannel(va_alist)
    va_dcl
{
    va_list va;
    int sock;
    char *format;
    char *channel;
    char buf[2048];
    int isextern=0;
    int notlink;
    struct uchannelt *chan;    
    struct uchannelusert *chanu;
    struct clientt *client;
    va_start(va);
    channel=va_arg(va,char *);
    notlink=va_arg(va,int);
    format=va_arg(va,char *);
    ap_vsnprintf(buf,sizeof(buf),format,va);
    chan=getuserchannel(-1,channel);
    strmncpy(ircbuf,buf,sizeof(ircbuf));
    parse();
    if(chan!=NULL)
    {
	chanu=chan->users;
	while(chanu!=NULL)
	{
	    client=getclientbynick(chanu->nick);
	    if(client!=NULL)
	    {
		if(client->intuser>0)
		{
		    if(user(client->intuser)->instate==STD_CONN)
		    {
			strmncpy(ircbuf,buf,sizeof(ircbuf));
			addtoken(client->intuser+10000);
			ssnprintf(user(client->intuser)->insock,"%s",ircbuf);
		    }
		}
	    }
	    chanu=chanu->next;
	}
    }
    ap_snprintf(ircbuf,sizeof(ircbuf),":intnet!intnet@%s INTNET *@* :%s",me,buf);
    broadcast(notlink);
    va_end(va);    
    return 0x0;    
}

/* write from internal network to a channel expect to one user
 * syntax: sendtochannelbutone(char *channel,char *nick, int notlink, char *format, ...)
 */

int sendtochannelbutone(va_alist)
    va_dcl
{
    va_list va;
    int sock;
    char *format;
    char *channel;
    char *nick;
    char notlink;
    char buf[2048];
    int isextern=0;
    struct uchannelt *chan;    
    struct uchannelusert *chanu;
    struct clientt *client;
    va_start(va);
    channel=va_arg(va,char *);
    nick=va_arg(va,char *);
    notlink=va_arg(va,int);
    format=va_arg(va,char *);
    client=getclientbynick(nick);
    ap_vsnprintf(buf,sizeof(buf),format,va);
    chan=getuserchannel(-1,channel);
    strmncpy(ircbuf,buf,sizeof(ircbuf));
    parse();
    if(chan!=NULL)
    {
	chanu=chan->users;
	while(chanu!=NULL)
	{
	    client=getclientbynick(chanu->nick);
	    if(client!=NULL)
	    {
		if(strmcmp(nick,client->nick)==0)
		{
		    if(client->intuser==0)
			isextern=1;
		    else if(user(client->intuser)->instate==STD_CONN)
		    {
			strmncpy(ircbuf,buf,sizeof(ircbuf));
			addtoken(client->intuser+10000);
			ssnprintf(user(client->intuser)->insock,"%s",ircbuf);
		    }
		}
	    } else { 
		isextern=1;
	    }
	    chanu=chanu->next;
	}
    }
    ap_snprintf(ircbuf,sizeof(ircbuf),":intnet!intnet@%s INTNET *@* :%s",me,buf);
    broadcast(notlink);
    va_end(va);    
    return 0x0;    
}

/* write from internal network to all channels of one nick
 * syntax: sendtochannelsofnick(char *nick, int notlink, char *format, ...)
 */

int sendtochannelsofnick(va_alist)
    va_dcl
{
    va_list va;
    int sock;
    char *format;
    char *nick;
    char notlink;
    char buf[2048];
    int isextern=0;
    int didsend=0;
    struct uchannelt *chan;    
    struct uchannelusert *chanu,*chanu2;
    struct clientt *client,*cyc;
    va_start(va);
    nick=va_arg(va,char *);
    notlink=va_arg(va,int);
    format=va_arg(va,char *);
    client=getclientbynick(nick);
    ap_vsnprintf(buf,sizeof(buf),format,va);
    cyc=clients;
    strmncpy(ircbuf,buf,sizeof(ircbuf));
    parse();
    while(cyc!=NULL)
    {
	chan=intchan;
	didsend=0;
	while(chan!=NULL && didsend==0)
	{
	    chanu=getchannelnick(chan,cyc->nick);
	    if(chanu!=NULL)
	    {
		chanu2=getchannelnick(chan,nick);
		if(chanu2!=NULL)
		{
		    if(cyc->intuser>0)
		    {
			if(user(cyc->intuser)->instate==STD_CONN)
			{
			    strmncpy(ircbuf,buf,sizeof(ircbuf));
			    addtoken(cyc->intuser+10000);
			    ssnprintf(user(cyc->intuser)->insock,"%s",ircbuf);
			}
		    }
		    didsend=1;
		}
	    }
	    chan=chan->next;
	}
	cyc=cyc->next;
    }
    ap_snprintf(ircbuf,sizeof(ircbuf),":intnet!intnet@%s INTNET *@* :%s",me,buf);
    broadcast(notlink);
    va_end(va);    
    return 0x0;    
}

char intname[100];

/* handle single events */

int cmdintprivmsg(int usern, int link)
{
    char currentto[200];
    struct uchannelt *chan;
    struct clientt *client;
    struct uchannelusert *chanuser;
    char *pt,*pt2;
    if(link>=0 && usern==0)
    {
	client=getclientbynick(ircnick);
	if(client==NULL && *ircnick!=0) return 0x0; /* ignore fakes */
	if(*ircto=='#')
	    sendtochannel(ircto,link,"%s",ircbuf);
	else
	    sendtoclient(ircto,link,"%s",ircbuf);
    } else {
	pt=ircto;
	while(pt!=NULL)
	{
	    pt2=strchr(pt,',');
	    if(pt2!=NULL)
	    {
		*pt2=0;pt2++;
	    }
	    if(strlen(pt)==0) return 0x0;
	    strmncpy(currentto,pt,sizeof(currentto));
	    if(*currentto=='#')
	    {
		chan=getuserchannel(-1,currentto);
		if(chan==NULL)
		{
		    client=getclientbynumber(usern);
		    if(client==NULL) 
    		    {
			ap_snprintf(intname,sizeof(intname),"%s-psybnc.net",me);
			client=enteruser(usern,user(usern)->nick,user(usern)->login,intname,me);
		    }		    		    
		    if(client==NULL) return 0x0;
		    sendtoclient(client->nick,0,":%s-psybnc.net 401 %s %s :No such Channel",me,user(usern)->nick,currentto);
		} else {
		    client=getclientbynumber(usern);
		    if(client==NULL) 
    		    {
			ap_snprintf(intname,sizeof(intname),"%s-psybnc.net",me);
			client=enteruser(usern,user(usern)->nick,user(usern)->login,intname,me);
		    }		    		    
		    if(client==NULL) return 0x0;
		    chanuser=getchannelnick(chan,client->nick);
		    if(strchr(chan->modes,'n')!=NULL && chanuser==NULL)
		    {
			sendtoclient(client->nick,0,":%s-psybnc.net 404 %s %s :Cannot send to channel",me,client->nick,currentto);
		    } else {
			if(strchr(chan->modes,'m')!=NULL && strchr(chanuser->mode,'@')==NULL && strchr(chanuser->mode,'+')==NULL)
			    sendtoclient(client->nick,0,":%s-psybnc.net 404 %s %s :Cannot send to channel",me,client->nick,currentto);
			else
			    sendtochannelbutone(currentto,client->nick,0,":%s!%s@%s %s %s :%s",client->nick,client->ident,client->host,irccommand,currentto,irccontent);
		    }
		}
	    } else {
		client=getclientbynick(currentto);
		if(client==NULL)
		{
		    client=getclientbynumber(usern);
		    if(client==NULL) 
    		    {
			ap_snprintf(intname,sizeof(intname),"%s-psybnc.net",me);
			client=enteruser(usern,user(usern)->nick,user(usern)->login,intname,me);
		    }		    		    
		    if(client==NULL) return 0x0;
		    sendtoclient(client->nick,0,":%s-psybnc.net 401 %s %s :No such Nick",me,client->nick,currentto);
		} else {
		    client=getclientbynumber(usern);
		    if(client==NULL) 
    		    {
			ap_snprintf(intname,sizeof(intname),"%s-psybnc.net",me);
			client=enteruser(usern,user(usern)->nick,user(usern)->login,intname,me);
		    }		    		    
		    if(client==NULL) return 0x0;
		    sendtoclient(currentto,0,":%s!%s@%s %s %s :%s",client->nick,client->ident,client->host,irccommand,currentto,irccontent);
		}				
	    }
	    pt=pt2;
	    
	}    	
    }
}

/* notice is same as like privmsg, so this is just a recall */

int cmdintnotice(int usern, int link)
{
    cmdintprivmsg(usern,link);
}

/* adding a joined intnet channel to an internal user */

int addconfigchannel(int usern, char *channel)
{
    char buf[200];
    char buf2[200];
    int i,rc;
    int cntchan;
    ap_snprintf(buf,sizeof(buf),"USER%d",usern);
    for(i=0;i<20;i++)
    {
	ap_snprintf(buf2,sizeof(buf2),"ENTRY%d",i);
	rc=getini("INTCHANS",buf2,buf);
	if(rc==0)
	{
	    if(strmcmp(value,channel)==1) return 0x0;
	}
    }
    cntchan=countconfentries("INTCHANS","ENTRY%d",buf);
    ap_snprintf(buf2,sizeof(buf2),"ENTRY%d",lastfree);
    writeini("INTCHANS",buf2,buf,channel);
    flushconfig();
    return 0x0;
}

/* remove a parted channel from the internal user */

int removeconfigchannel(int usern, char *channel)
{
    int i;
    int rc;
    char buf[200];
    char buf2[200];
    ap_snprintf(buf,sizeof(buf),"USER%d",usern);
    for(i=0;i<20;i++)
    {
	ap_snprintf(buf2,sizeof(buf2),"ENTRY%d",i);
	rc=getini("INTCHANS",buf2,buf);
	if(rc==0)
	{
	    if(strmcmp(channel,value)==1)
	    {
		writeini("INTCHANS",buf2,buf,NULL);
		flushconfig();
		return 0x0;
	    }			
	}
    }
}

/* rejoin the client to the saved channels */

int dontsave=0;

int rejoinintchannels(int usern)
{
    int i;
    int rc;
    char buf[200];
    char buf2[200];
    ap_snprintf(buf,sizeof(buf),"USER%d",usern);
    dontsave=1;
    for(i=0;i<20;i++)
    {
	ap_snprintf(buf2,sizeof(buf2),"ENTRY%d",i);
	rc=getini("INTCHANS",buf2,buf);
	if(rc==0)
	{
	    strmncpy(irccontent,value,sizeof(irccontent));
	    cmdintjoin(usern);
	}
    }
    dontsave=0;
    return 0x0;
}

/* the join command */

int cmdintjoin(int usern, int link)
{
    char currentto[200];
    struct uchannelt *chan;
    struct clientt *client;
    int rc;
    struct uchannelusert *chanuser;
    char *pt,*pt2;
    char key[200];
    int newchan=0;
    if(link>=0 && usern==0)
    {
	chan=getuserchannel(-1,ircto);
	client=getclientbynick(ircnick);
	if(client==NULL) return 0x0; /* ignore fakes */
	if(chan==NULL)
	{
	    chan=addchanneltouser(-1,ircto,1);
	}
	removeinvite(chan,client->nick);
	chanuser=addnicktochannel(chan,client->nick,client->ident,client->host);
	sendtochannel(ircto,link,"%s",ircbuf);
    } else {
	pt=irccontent;
	pt2=strchr(pt,' ');
	if(pt2!=NULL)
	{
	    *pt2=0;
	    pt2++;
	    strmncpy(key,pt2,sizeof(key));
	}
	while(pt!=NULL)
	{
	    newchan=0;
	    pt2=strchr(pt,',');
	    if(pt2!=NULL)
	    {
		*pt2=0;pt2++;
	    }
	    if(strlen(pt)==0) return 0x0;
	    strmncpy(currentto,pt,sizeof(currentto));
	    if(*currentto=='#')
	    {
		client=getclientbynumber(usern);
		if(client==NULL) 
    		{
		    ap_snprintf(intname,sizeof(intname),"%s-psybnc.net",me);
		    client=enteruser(usern,user(usern)->nick,user(usern)->login,intname,me);
		}		    		    
		if(client==NULL) return 0x0;
		chan=getuserchannel(-1,currentto);
		if(chan==NULL)
		{
		    chan=addchanneltouser(-1,currentto,0);
		    newchan=1;
		}
		if(getchannelnick(chan,client->nick)!=NULL)
		    rc=-5;
		else
		    rc=mayjoin(chan,client,key);
		if(rc<0)
		{
		    switch(rc)
		    {
			case -1:
			    sendtoclient(client->nick,0,":%s-psybnc.net 474 %s %s :Cannot join Channel (+b)",me,client->nick,currentto);
			    break;
			case -2:
			    sendtoclient(client->nick,0,":%s-psybnc.net 475 %s %s :Cannot join Channel (+k)",me,client->nick,currentto);
			    break;
			case -3:
			    sendtoclient(client->nick,0,":%s-psybnc.net 473 %s %s :Cannot join Channel (+i)",me,client->nick,currentto);
			    break;
		    }
		} else {
		    removeinvite(chan,client->nick);
		    chanuser=addnicktochannel(chan,client->nick,client->ident,client->host);
		    sendtochannel(chan->name,0,":%s!%s@%s JOIN %s",client->nick,client->ident,client->host,currentto);
		    if(newchan==1)
		    {		
			sendtochannel(chan->name,0,":%s!%s@%s MODE %s +o %s",client->nick,client->ident,client->host,currentto,client->nick);
			strmncpy(chanuser->mode,"@",sizeof(chanuser->mode));
		    }
		    sendnames(usern+10000,chan);								
		    if(chan->topic[0]!=0)
		    {
			sendtoclient(client->nick,0,":%s-psybnc.net 332 %s %s :%s",me,client->nick,chan->name,chan->topic);
		    }
		    if(chan->modes[0]!=0)
		    {
			sendmode(usern,chan->name);
		    }
		    if(dontsave==0) addconfigchannel(usern,chan->name);
		}
	    } else {
		client=getclientbynumber(usern);
		if(client==NULL) 
    		{
		    ap_snprintf(intname,sizeof(intname),"%s-psybnc.net",me);
		    client=enteruser(usern,user(usern)->nick,user(usern)->login,intname,me);
		}		    		    
		if(client==NULL) return 0x0;
		sendtoclient(client->nick,0,":%s-psybnc.net 401 %s %s :No such Channel",me,client->nick,currentto);
	    }
	    pt=pt2;
	}    	
    }    
}

/* mode helpers */

int addop(struct uchannelt *chan, char *nick, struct clientt *client)
{
    struct uchannelusert *chanuser;
    chanuser=getchannelnick(chan,nick);
    if(chanuser!=NULL)
    {
	strmncpy(chanuser->mode,"@",sizeof(chanuser->mode));
	return 0x0;
    } else {
	if(client==NULL) return 0x0;
	if(client->intuser>0)
	    sendtoclient(client->nick,0,":%s-psybnc.net 441 %s %s :They aren't on that channel",me,client->nick,chan->name,nick);
    }
    return 0x1;
}

int delop(struct uchannelt *chan, char *nick, struct clientt *client)
{
    struct uchannelusert *chanuser;
    chanuser=getchannelnick(chan,nick);
    if(chanuser!=NULL)
    {
	if(strchr(chanuser->mode,'@')!=NULL)
	{
	    if(strchr(chanuser->mode,'+')!=NULL)
		strmncpy(chanuser->mode,"+",sizeof(chanuser->mode));
	    else
		chanuser->mode[0]=0;
	    return 0x0;
	}
    } else {
	if(client==NULL) return 0x0;
	if(client->intuser>0)
	    sendtoclient(client->nick,0,":%s-psybnc.net 441 %s %s :They aren't on that channel",me,client->nick,chan->name,nick);
    }
    return 0x1;
}

int addvoice(struct uchannelt *chan, char *nick, struct clientt *client)
{
    struct uchannelusert *chanuser;
    chanuser=getchannelnick(chan,nick);
    if(chanuser!=NULL)
    {
	if(strchr(chanuser->mode,'@')==NULL)
	{
	    strmncpy(chanuser->mode,"+",sizeof(chanuser->mode));
	    return 0x0;
	}
    } else {
	if(client==NULL) return 0x0;
	if(client->intuser>0)
	    sendtoclient(client->nick,0,":%s-psybnc.net 441 %s %s :They aren't on that channel",me,client->nick,chan->name,nick);
    }
    return 0x0;
}

int delvoice(struct uchannelt *chan, char *nick, struct clientt *client)
{
    struct uchannelusert *chanuser;
    chanuser=getchannelnick(chan,nick);
    if(chanuser!=NULL)
    {
	if(strchr(chanuser->mode,'+')!=NULL)
	{
	    if(strchr(chanuser->mode,'@')!=NULL)
		strmncpy(chanuser->mode,"@",sizeof(chanuser->mode));
	    else
		chanuser->mode[0]=0;
	    return 0x0;
	}
    } else {
	if(client==NULL) return 0x0;
	if(client->intuser>0)
	    sendtoclient(client->nick,0,":%s-psybnc.net 441 %s %s :They aren't on that channel",me,client->nick,chan->name,nick);
    }
    return 0x1;
}

/* modes */

int intmode(char *to, char *modes, char *params,int link, int usern)
{
    char *m,*p,*pt,*pt2,*p2;
    char prefix='+';
    struct uchannelt *chan;
    struct clientt *client,*oc;
    struct uchannelusert *chanuser;
    struct stringarray *bans;
    char newmode[300];
    char newparam[400];
    int prefixchange=0;
    int rc;
    char mm[2];
    int aktbans=0;
pcontext;
    newmode[0]=0;
    newparam[0]=0;
    mm[1]=0;
    if(usern>0)
    {
	client=getclientbynumber(usern);
	if(client==NULL) 
	{
	    ap_snprintf(intname,sizeof(intname),"%s-psybnc.net",me);
	    client=enteruser(usern,user(usern)->nick,user(usern)->login,intname,me);
	}		    		    
	if(client==NULL) return 0x0;
    }
    chan=getuserchannel(-1,to);
pcontext;
    if(chan==NULL)
    {
	if(usern>0)
	{
	    if(*to=='#')
		sendtoclient(client->nick,0,":%s-psybnc.net 403 %s %s :No such Channel",me,client->nick,to);
	    /* ignore user flags.. */
	}
	return 0x0;
    }
    m=modes;
    if(params[0]==0) 
	p=NULL;
    else
	p=params;
    if(p!=NULL)
	if(strlen(rtrim(p))<=1) p=NULL;
    while(*m)
    {
	    if(strchr("+-",*m)!=NULL) 
	    {
		if(prefix!=*m && prefixchange==0)
		{
		    prefix=*m;
		    prefixchange=1;
		    mm[0]=prefix;
		    strcat(newmode,mm);
		}
	    }
	    else 
	    if(strchr("smitn",*m)!=NULL)
	    {
		if(strchr(newmode,*m)==NULL) 
		{
		    mm[0]=*m;
		    if(prefix=='+' && strchr(chan->modes,*m)==NULL)
		    {	
			strcat(newmode,mm);
			prefixchange=0;
		    }
		    if(prefix=='-' && strchr(chan->modes,*m)!=NULL)
		    {	
			strcat(newmode,mm);
			prefixchange=0;
		    }
		}
	    }
	    else 
	    if(*m=='b')
	    {
		if(p==NULL)
		{
		    if(usern>0)
		    {
			bans=chan->bans;
			while(bans!=NULL)
			{
			    sendtoclient(client->nick,0,":%s-psybnc.net 367 %s %s %s",me,client->nick,chan->name,bans->entry);	    
			    bans=bans->next;
			}
			sendtoclient(client->nick,0,":%s-psybnc.net 368 %s %s :End of Channel Ban-List",me,client->nick,chan->name);
		    }
		} else {
		    p2=strchr(p,' ');
		    if(p2!=NULL)
		    {
			*p2=0;p2++;
			if(*p2==0) p2=NULL;
		    }
		    if(strlen(p)>100)
		    {
			p[99]=0;
		    }
		    if(aktbans<3)
		    {
			if(prefix=='+')
			    rc=addban(chan,p);
			else
			    rc=removeban(chan,p);		
		    } else {
			rc=-1;
		    }
		    if(rc==0x1)
		    {
			mm[0]=*m;
			strcat(newmode,mm);
			if(strlen(newparam)+strlen(p)+1<sizeof(newparam)-1)
			{
			    strcat(newparam,p);
			    strcat(newparam," ");
			}
			aktbans++;
			prefixchange=0;
		    }
		}
		p=p2;
	    }
	    else 
	    if(*m=='o' || *m=='v')
	    {
		if(p!=NULL)
		{
		    p2=strchr(p,' ');
		    if(p2!=NULL)
		    {
			*p2=0;p2++;
			if(*p2==0) p2=NULL;
		    }
		    if(aktbans<3)
		    {
			if(prefix=='+')
			    if(*m=='o')
				rc=addop(chan,p,client);
			    else
				rc=addvoice(chan,p,client);
			else
			    if(*m=='o')
				rc=delop(chan,p,client);
			    else
				rc=delvoice(chan,p,client);
		    } else {
			rc=-1;
		    }
		    if(rc==0x0)
		    {
			mm[0]=*m;
			strcat(newmode,mm);
			if(strlen(newparam)+strlen(p)+1<sizeof(newparam)-1)
			{
			    oc=client;
			    client=getclientbynick(p);
			    if(client!=NULL)
				strcat(newparam,client->nick); /* cases */
			    else
				strcat(newparam,p);
			    client=oc;
			    strcat(newparam," ");
			}
			aktbans++;
			prefixchange=0;
		    }
		}
		p=p2;
	    }
	    else 
	    if(*m=='k' && p!=NULL)
	    {
		p2=strchr(p,' ');
		if(p2!=NULL)
		{
		    *p2=0;p2++;
		    if(*p2==0) p2=NULL;
		}
		mm[0]=*m;
		strcat(newmode,mm);
		if(strlen(newparam)+strlen(p)+1<sizeof(newparam)-1)
		{
		    strcat(newparam,p);
		    strcat(newparam," ");
		    prefixchange=0;
		}
		p=p2;		
	    }
	m++;
    }
    if((strchr("+-",*newmode)!=NULL && strlen(newmode)>1) || (strchr("+-",*newmode)==NULL && strlen(newmode)>0))
    {
	if(*newmode!='+' && *newmode!='-')
	    mm[0]='+';
	else
	    mm[0]=0;
	mm[1]=0;
	if(usern>0)
	    sendtochannel(chan,0,":%s!%s@%s MODE %s %s%s %s",client->nick,client->ident,client->host,to,mm,newmode,rtrim(newparam));
	else
	    sendtochannel(chan,link,":%s MODE %s %s%s %s",ircfrom,to,mm,newmode,rtrim(newparam));
	addchannelmode(chan,newmode,newparam);
    }
}

/* send a channels mode */

int sendmode(int usern, char *to)
{
    struct uchannelt *chan;
    struct clientt *client;
    struct uchannelusert *chanuser;
    chan=getuserchannel(-1,to);
    client=getclientbynumber(usern);
    if(client==NULL) 
    {
        ap_snprintf(intname,sizeof(intname),"%s-psybnc.net",me);
        client=enteruser(usern,user(usern)->nick,user(usern)->login,intname,me);
    }		    		    
    if(client==NULL) return 0x0;
    if(chan==NULL)
	sendtoclient(client->nick,0,":%s-psybnc.net 403 %s %s :No such Channel",me,client->nick,to);
    else
    {
	chanuser=getchannelnick(chan,client->nick);
	if(chanuser!=NULL)
	{
	    if(strchr(chan->modes,'k')!=NULL)
		sendtoclient(client->nick,0,":%s-psybnc.net 324 %s %s %s %s",me,client->nick,to,chan->modes,chan->key);
	    else
		sendtoclient(client->nick,0,":%s-psybnc.net 324 %s %s %s",me,client->nick,to,chan->modes);
	}
	else
	    sendtoclient(client->nick,0,":%s-psybnc.net 324 %s %s %s",me,client->nick,to,chan->modes);
    }
}

/* the caller of the mode */

int cmdintmode(int usern, int link)
{
    char currentto[200];
    char tolist[400];
    char modelist[200];
    char param[400];
    struct uchannelt *chan;
    struct clientt *client;
    int rc;
    struct uchannelusert *chanuser;
    char *pt,*pt2;
    if(link>=0 && usern==0)
    {
	strmncpy(currentto,ircto,sizeof(currentto));
	if(*currentto!=0)
	{
	    pt=irccontent;
	    pt2=strchr(pt,' ');
	    if(pt2!=NULL)
	    {
	        *pt2=0;
	        pt2++;
	    }
	    strmncpy(modelist,pt,sizeof(modelist));
	    if(pt2==NULL)
		param[0]=0;
	    else
		strmncpy(param,pt2,sizeof(param));
	    intmode(currentto,modelist,param,link,usern);
	}	
    } else {
	pt=irccontent;
	if(*pt!=0)
	{
	    pt2=strchr(pt,' ');
	    if(pt2!=NULL)
	    {
		*pt2=0;
		strmncpy(tolist,pt,sizeof(tolist));
		pt2++;
		pt=strchr(pt2,' ');
		if(1)
		{
		    if(pt!=NULL)
		    {
			*pt=0;pt++;
		    }
		    strmncpy(modelist,pt2,sizeof(modelist));
		    if(pt!=NULL)
			strmncpy(param,pt,sizeof(param));
		    else
			param[0]=0;
		    pt=tolist;
		    while(pt!=NULL)
		    {
			pt2=strchr(pt,',');
			if(pt2!=NULL)
			{
			    *pt2=0;pt2++;
			}
			client=getclientbynumber(usern);
			if(client==NULL) 
    			{
			    ap_snprintf(intname,sizeof(intname),"%s-psybnc.net",me);
			    client=enteruser(usern,user(usern)->nick,user(usern)->login,intname,me);
			}		    		    

			strmncpy(currentto,pt,sizeof(currentto));
			chan=getuserchannel(-1,currentto);
			if(chan==NULL)
			    sendtoclient(client->nick,0,":%s-psybnc.net 403 %s %s :No such Channel",me,client->nick,currentto);
			else
			{
			    chanuser=getchannelnick(chan,client->nick);
			    if(chanuser==NULL)
				sendtoclient(client->nick,0,":%s-psybnc.net 442 %s %s :You're not on that Channel",me,client->nick,currentto);
			    else
			    {
				if(strchr(chanuser->mode,'@')!=NULL)
				{
				    intmode(currentto,modelist,param,link,usern);
				} else {
				    sendtoclient(client->nick,0,":%s-psybnc.net 482 %s %s :You're not the Channel-King",me,client->nick,currentto);
				}
			    }
			}
		    	pt=pt2;
		    }		    		
		}	    
	    } else {
		strmncpy(tolist,pt,sizeof(tolist));
		pt=tolist;
		while(pt!=NULL)
		{
		    pt2=strchr(pt,',');
		    if(pt2!=NULL)
		    {
			*pt2=0;pt2++;
		    }
		    strmncpy(currentto,pt,sizeof(currentto));
		    sendmode(usern,currentto);
		    pt=pt2;		    
		}		    		
	    }
	}	
    }
}

int cmdintpart(int usern, int link)
{
    char currentto[200];
    struct uchannelt *chan;
    struct clientt *client;
    int rc;
    struct uchannelusert *chanuser;
    char *pt,*pt2;
    char key[200];
    int newchan=0;
    if(link>=0 && usern==0)
    {
	chan=getuserchannel(-1,ircto);
	client=getclientbynick(ircnick);
	if(client==NULL) return 0x0; /* ignore fakes */
	if(chan==NULL)
	{
	    return 0x0; /* no such channel */
	}
	chanuser=getchannelnick(chan,ircnick);
	if(chanuser==NULL) return 0x0;
	removenickfromchannel(chan,ircnick);
	if(chan->users==NULL)
	    removechannelfromuser(-1,chan->name);
	sendtochannel(ircto,link,"%s",ircbuf);
    } else {
	if(*ircto==0)
	{
	    strmncpy(ircto,irccontent,sizeof(ircto));
	    strmncpy(irccontent,user(usern)->nick,sizeof(irccontent));
	}
	pt=ircto;
	while(pt!=NULL)
	{
	    pt2=strchr(pt,',');
	    if(pt2!=NULL)
	    {
		*pt2=0;pt2++;
	    }
	    if(strlen(pt)==0) return 0x0;
	    strmncpy(currentto,pt,sizeof(currentto));
	    if(*currentto=='#')
	    {
		client=getclientbynumber(usern);
		if(client==NULL) 
    		{
		    ap_snprintf(intname,sizeof(intname),"%s-psybnc.net",me);
		    client=enteruser(usern,user(usern)->nick,user(usern)->login,intname,me);
		}		    		    
		if(client==NULL) return 0x0;
		chan=getuserchannel(-1,currentto);
		if(chan==NULL)
		{
		    sendtoclient(client->nick,0,":%s-psybnc.net 403 %s %s :No such Channel",me,client->nick,currentto);
		} else {
		    chanuser=getchannelnick(chan,client->nick);
		    if(chanuser==NULL)
		    {
			sendtoclient(client->nick,0,":%s-psybnc.net 442 %s %s :You're not on that channel",me,client->nick,currentto);
		    } else {
			sendtochannel(chan->name,0,":%s!%s@%s PART %s :%s",client->nick,client->ident,client->host,currentto,irccontent);
			removenickfromchannel(chan,client->nick);
			removeconfigchannel(usern,chan->name);
			if(chan->users==NULL)
			{
			    removechannelfromuser(-1,chan->name);
			}
		    }
		}
	    } else {
		client=getclientbynumber(usern);
		if(client==NULL) 
    		{
		    ap_snprintf(intname,sizeof(intname),"%s-psybnc.net",me);
		    client=enteruser(usern,user(usern)->nick,user(usern)->login,intname,me);
		}		    		    
		if(client==NULL) return 0x0;
		sendtoclient(client->nick,0,":%s-psybnc.net 401 %s %s :No such Channel",me,client->nick,currentto);
	    }
	    pt=pt2;
	}    	
    }    
}

/* got the kick ? */

int cmdintkick(int usern, int link)
{
    char currentto[200];
    char nicks[400];
    char currentnick[64];
    struct uchannelt *chan;
    struct clientt *client;
    int rc;
    struct uchannelusert *chanuser;
    char *pt,*pt2;
    char *ot,*ot2;
    char *onicks;
    char key[200];
    int newchan=0;
    if(link>=0 && usern==0)
    {
	pt=strstr(ircbuf," KICK ");
	if(pt==NULL) return 0x0;
	pt+=6;
	pt2=strchr(pt,' ');
	if(pt2==NULL) return 0x0;
	*pt2=0;
	pt2++;
	ot=strstr(pt2," :");
	if(ot==NULL) return 0x0;
	*ot=0;
	ot+=2;
	strmncpy(ircto,pt,sizeof(ircto));
	strmncpy(irccontent,pt2,sizeof(irccontent));
	pt=ot;
	chan=getuserchannel(-1,ircto);
	client=getclientbynick(ircnick);
	if(client==NULL) return 0x0; /* ignore fakes */
	if(chan==NULL)
	{
	    return 0x0; /* no such channel */
	}
	chanuser=getchannelnick(chan,irccontent);
	if(chanuser==NULL) return 0x0;
	strmncpy(currentnick,chanuser->nick,sizeof(currentnick));
	sendtochannel(ircto,link,":%s!%s@%s KICK %s %s :%s",client->nick,client->ident,client->host,ircto,currentnick,pt);
	removenickfromchannel(chan,currentnick);
	if(chan->users==NULL)
	    removechannelfromuser(-1,chan->name);
    } else {
	client=getclientbynumber(usern);
	if(client==NULL) 
    	{	
	    ap_snprintf(intname,sizeof(intname),"%s-psybnc.net",me);
	    client=enteruser(usern,user(usern)->nick,user(usern)->login,intname,me);
	}		    		    
	if(client==NULL) return 0x0;
	if(*ircto==0)
	{
	    strmncpy(ircto,irccontent,sizeof(ircto));
	    strmncpy(irccontent,client->nick,sizeof(irccontent));
	}
	/* now we got the channels and the clients to kick in ircto, the reason in irccontent */
	pt=strchr(ircto,' ');
	if(pt==NULL) return 0x0;
	*pt=0;
	pt++;
	onicks=pt;
	pt=ircto;
	while(pt!=NULL)
	{
	    pt2=strchr(pt,',');
	    if(pt2!=NULL)
	    {
		*pt2=0;
		pt2++;
		if(*pt2==0) pt2=NULL;
	    }
	    strmncpy(currentto,pt,sizeof(currentto));
	    chan=getuserchannel(-1,currentto);
	    if (chan==NULL)
		sendtoclient(client->nick,0,":%s-psybnc.net 401 %s %s :No such Channel",me,client->nick,currentto);
	    else
	    {
		chanuser=getchannelnick(chan,client->nick);
		if(chanuser==NULL)
		    sendtoclient(client->nick,0,":%s-psybnc.net 442 %s %s :You're not on that channel",me,client->nick,currentto);
		else
		{
		    if(strchr(chanuser->mode,'@')==NULL)
			sendtoclient(client->nick,0,":%s-psybnc.net 482 %s %s :You're not the Channel-King",me,client->nick,currentto);
		    else
		    {
			strmncpy(nicks,onicks,sizeof(nicks));
			ot=nicks;
			while(ot!=NULL)
			{
			    ot2=strchr(ot,',');
			    if(ot2!=NULL)
			    {
				*ot2=0;
				ot2++;
				if(*ot2==0) ot2=NULL;				
			    }
			    chanuser=getchannelnick(chan,ot);
			    if(chanuser!=NULL)
			    {
				sendtochannel(currentto,0,":%s!%s@%s KICK %s %s :%s",client->nick,client->ident,client->host,currentto,chanuser->nick,irccontent);
				removenickfromchannel(chan,ot);
				if(chan->users==NULL)
				{
				    removechannelfromuser(-1,currentto);
				}
			    } else {
				sendtoclient(client->nick,0,":%s-psybnc.net 441 %s %s :They aren't on that channel",me,client->nick,ot,currentto);
			    }
			    ot=ot2;
			}
		    }
		}
	    }
	    pt=pt2;
	}
    }
}

/* make a nickchange */

int cmdintnick(int usern, int link)
{
    struct clientt *client,*client2;
    char *pt;
    char ocoll[200];
    if(link>=0 && usern==0)
    {
	client=getclientbynick(ircnick);
	if(client==NULL) return 0x0;
	client2=getclientbynick(ircto);
	if(client2!=NULL) /* ohoh, two equal nicks.. refuse that link */
	{
	    ap_snprintf(irccontent,sizeof(irccontent),"%d",link);
#ifdef LINKAGE
	    cmdrelink(1);
#endif
	    sendtoclient(client2->nick,link,":%s!%s@%s NOTICE %s :Your nick was introduced to the intnet by link '%s'. The link had been resetted due to collide.",ircnick,ircident,irchost,client2->nick,datalink(link)->iam);
	} else {
	    strmncpy(ocoll,ircto,sizeof(ocoll));
	    sendtochannelsofnick(ircnick,link,"%s",ircbuf);
	    nickchange(-1,client->nick,ocoll);
	    strmncpy(client->nick,ocoll,sizeof(client->nick));
	}
    } else {
	client=getclientbynick(ircto);
	if(client!=NULL) return 0x0;
	client=getclientbynumber(usern);
	if(client==NULL) 
	{
	    ap_snprintf(intname,sizeof(intname),"%s-psybnc.net",me);
	    client=enteruser(usern,user(usern)->nick,user(usern)->login,intname,me);
	}		    		    
	if(client==NULL) return 0x0;
	pt=ircto;
	if(strmcmp(pt,client->nick)==0)
	{
	    strmncpy(ocoll,ircto,sizeof(ocoll));
	    sendtochannelsofnick(client->nick,0,":%s!%s@%s NICK :%s",client->nick,client->ident,client->host,ircto);
	    nickchange(-1,client->nick,ircto);
	    strmncpy(client->nick,ircto,sizeof(client->nick));
	}
    }
}

/* names */

int cmdintnames(int usern, int link)
{
    struct clientt *client;
    struct uchannelt *chan;
    struct uchannelusert *chanuser;
    if(link>=0 && usern==0)
	return 0x0; /* names from a link !? yes.. right. */
    else
    {
	client=getclientbynumber(usern);
	if(client==NULL) 
	{
	    ap_snprintf(intname,sizeof(intname),"%s-psybnc.net",me);
	    client=enteruser(usern,user(usern)->nick,user(usern)->login,intname,me);
	}		    		    
	if(client==NULL) return 0x0;
	chan=getuserchannel(-1,irccontent);
	if(chan==NULL)
	{
	    sendtoclient(client->nick,0,":%s-psybnc.net 401 %s %s :No such Channel",me,client->nick,irccontent);
	} else {
	    chanuser=getchannelnick(chan,client->nick);
	    if(chanuser==NULL)
	    {
		sendtoclient(client->nick,0,":%s-psybnc.net 442 %s %s :You're not on that channel",me,client->nick,irccontent);
	    } else {
		sendnames(usern+10000,chan);
	    }
	}
    }
}

/* quit */

int cmdintquit(int usern, int link)
{
    char tmpnick[64];
    struct clientt *client;
    if(link>=0 && usern==0)
    {
	client=getclientbynick(ircnick);
	if(client!=NULL)
	{
	    if(client->intuser==0)
	    {
		strmncpy(tmpnick,ircnick,sizeof(tmpnick));
		sendtochannelsofnick(tmpnick,link,"%s",ircbuf);
		removenickfromallchannels(-1,tmpnick);
		removeclient(tmpnick);
	    }
	} 
    } else {
	client=getclientbynumber(usern);
	if(client==NULL) 
	{
	    return 0x0;
	}		    		    
	sendtochannelsofnick(client->nick,0,":%s!%s@%s QUIT :%s",client->nick,client->ident,client->host,irccontent);			
	removenickfromallchannels(-1,client->nick);
	removeclient(client->nick);
    }
    return 0x0;
}

/* who query */

int cmdintwho(int usern, int link)
{
    struct uchannelt *chan;
    struct uchannelusert *chanuser;
    struct clientt *client,*listclient;
    if(link>=0 && usern==0)
	return 0x0; /* who from a link !? yes.. right. */
    else
    {
	client=getclientbynumber(usern);
	if(client==NULL) 
	{
	    ap_snprintf(intname,sizeof(intname),"%s-psybnc.net",me);
	    client=enteruser(usern,user(usern)->nick,user(usern)->login,intname,me);
	}		    		    
        if(client==NULL) return 0x0;
	if(*irccontent==0)
	{
	    listclient=clients;
	    while(listclient!=NULL)
	    {
		sendtoclient(client->nick,0,":%s-psybnc.net 353 %s * %s %s %s %s H :0 ?",me,client->nick,listclient->ident,listclient->host,listclient->server,listclient->nick);
		listclient=listclient->next;
	    }	
	    sendtoclient(client->nick,0,":%s-psybnc.net 315 %s * :End of WHO",me,client->nick);
	} else {
	    chan=getuserchannel(-1,irccontent);
	    if(chan==NULL)
	    {
		sendtoclient(client->nick,0,":%s-psybnc.net 401 %s %s :No such Channel",me,client->nick,irccontent);
	    } else {
		chanuser=getchannelnick(chan,client->nick);
		if(chanuser==NULL)
		{
		    sendtoclient(client->nick,0,":%s-psybnc.net 442 %s %s :You're not on that channel",me,client->nick,irccontent);
		} else {
		    chanuser=chan->users;
		    while(chanuser!=NULL)
		    {
			sendtoclient(client->nick,0,":%s-psybnc.net 353 %s %s %s %s * %s H :0 ?",me,client->nick,chan->name,chanuser->ident,chanuser->host,chanuser->nick);
			chanuser=chanuser->next;
		    }
		    sendtoclient(client->nick,0,":%s-psybnc.net 315 %s %s :End of WHO",me,client->nick,chan->name);
		}
	    }
	}
    }
}

/* whois */

int cmdintwhois(int usern, int link)
{
    struct uchannelt *chan;
    struct uchannelusert *chanuser;
    struct clientt *client,*listclient;
    int gotchan=0;
    char chanbuf[4096];
    if(link>=0 && usern==0)
	return 0x0; /* who from a link !? yes.. right. */
    else
    {
	client=getclientbynumber(usern);
	if(client==NULL) 
	{
	    ap_snprintf(intname,sizeof(intname),"%s-psybnc.net",me);
	    client=enteruser(usern,user(usern)->nick,user(usern)->login,intname,me);
	}		    		    
	if(client==NULL) return 0x0;
	listclient=getclientbynick(irccontent);
	if(listclient==NULL)
	{
	    sendtoclient(client->nick,0,":%s-psybnc.net 401 %s %s :No such Nick",me,client->nick,irccontent);
	} else {
	    sendtoclient(client->nick,0,":%s-psybnc.net 311 %s %s %s %s * :psyBNC Network User",me,client->nick,listclient->nick,listclient->ident,listclient->host);	
	    ap_snprintf(chanbuf,sizeof(chanbuf),":%s-psybnc.net 319 %s %s :",me,client->nick,listclient->nick);
	    chan=intchan;
	    while(chan!=NULL)
	    {
		chanuser=getchannelnick(chan,client->nick);
		if(chanuser==NULL)
		{
		    if(strchr(chan->modes,'s')==NULL && strchr(chan->modes,'p')==NULL) 
		    {
			if(getchannelnick(chan,listclient->nick)!=NULL)
			{
			    if(strlen(chanbuf)+strlen(chan->name)+1<sizeof(chanbuf))
			    {
				strcat(chanbuf,chan->name);
				strcat(chanbuf," ");
				gotchan=1;
			    }
			}
		    }
		}
		chan=chan->next;
	    }
	    if(gotchan==1)
		sendtoclient(client->nick,0,"%s",chanbuf);
	    sendtoclient(client->nick,0,":%s-psybnc.net 312 %s %s %s :psyBNC Network",me,client->nick,listclient->nick,listclient->server);
	    if(listclient->intuser>0)
	    {
		if(user(listclient->intuser)->rights==RI_ADMIN)
		    sendtoclient(client->nick,0,":%s-psybnc.net 313 %s %s :is a Bouncer-Admin",me,client->nick,listclient->nick);
	    }
	    sendtoclient(client->nick,0,":%s-psybnc.net 318 %s %s :End of WHOIS List.",me,client->nick,listclient->nick);
	}
    }
}

/* user received */

int cmdintuser(int usern, int link)
{
    
    struct uchannelt *chan;
    struct uchannelusert *chanuser;
    struct clientt *client;
    char *pt,*ept;
    char nick[64],ident[16],host[200],server[200];
    char renam[64];
    if(link>=0 && usern==0)
    {
	strmncpy(server,irccontent,sizeof(server));
	pt=strchr(ircto,' ');
	if(pt!=NULL)
	{
	    *pt=0;
	    pt++;
	    strmncpy(nick,ircto,sizeof(nick));
	    if(strstr(nick,"Guest")==nick)
	    {
		ept=nick+5;
		if(atoi(ept)!=0)
		{
		    return 0x0; /* silently ignore Guest Nicks */
		}
	    }
	    ept=strchr(pt,' ');
	    if(ept!=NULL)
	    {
		*ept=0;
		ept++;
		strmncpy(ident,pt,sizeof(ident));
		strmncpy(host,ept,sizeof(host));
		pt=strchr(host,' ');
		if(pt!=NULL) *pt=0;
		client=getclientbynick(nick);
		if(client!=NULL)
		{
		    ap_snprintf(irccontent,sizeof(irccontent),"%d",link);
#ifdef LINKAGE
		    cmdrelink(1);
#endif
		    sendtoclient(client->nick,link,":%s!%s@%s NOTICE %s :Your nick was introduced to the intnet by link '%s'. The link had been resetted due to collide.",nick,ident,host,client->nick,datalink(link)->iam);
		} else {
		    createclient(0,nick,ident,host,server);
		    client=getclientbynick(nick);
		    ap_snprintf(ircbuf,sizeof(ircbuf),":intnet!intnet@%s INTNET *@* :USER %s %s %s :%s",me,nick,ident,host,server);		    
		    broadcast(link);
		}
	    }
	}	
    }
    else
    {
	enteruser(usern,user(usern)->nick,user(usern)->login,user(usern)->nick,me);
    }
    return 0x0;
}

/* set the topic */

int cmdinttopic(int usern, int link)
{
    struct uchannelt *chan;
    struct uchannelusert *chanuser;
    struct clientt *client,*listclient;
    int gotchan=0;
    char chanbuf[4096];
    if(link>=0 && usern==0)
    {
	chan=getuserchannel(-1,ircto);
	if(chan!=NULL)
	{
	    strmncpy(chan->topic,irccontent,sizeof(chan->topic));
	    sendtochannel(chan->name,link,"%s",ircbuf);
	}
    }
    else
    {
	client=getclientbynumber(usern);
	if(client==NULL) 
	{
	    ap_snprintf(intname,sizeof(intname),"%s-psybnc.net",me);
	    client=enteruser(usern,user(usern)->nick,user(usern)->login,intname,me);
	}		    		    
	if(client==NULL) return 0x0;
	chan=getuserchannel(-1,ircto);
	if(chan==NULL)
	{
	    sendtoclient(client->nick,0,":%s-psybnc.net 401 %s %s :No such Channel",me,client->nick,ircto);
	} else {
	    chanuser=getchannelnick(chan,client->nick);
	    if(chanuser==NULL)
	    {
		sendtoclient(client->nick,0,":%s-psybnc.net 442 %s %s :You're not on that channel",me,client->nick,ircto);
	    } else {
		if(strchr(chanuser->mode,'@')==NULL)
		{
		    sendtoclient(client->nick,0,":%s-psybnc.net 482 %s %s :You're not the Channel-King",me,client->nick,chan->name);
		} else {
		    if(strlen(irccontent)>80)
			irccontent[80]=0;
		    strmncpy(chan->topic,irccontent,sizeof(chan->topic));
		    sendtochannel(chan->name,0,":%s!%s@%s TOPIC %s :%s",client->nick,client->ident,client->host,chan->name,chan->topic);			
		}
	    }
	}
    }
}

/* add an invite */

int cmdintinvite(int usern, int link)
{
    char currentto[200];
    char nicks[400];
    char currentnick[64];
    struct uchannelt *chan;
    struct clientt *client;
    int rc;
    struct uchannelusert *chanuser;
    char *pt,*pt2;
    char *ot,*ot2;
    char *onicks;
    char key[200];
    int newchan=0;
    if(link>=0 && usern==0)
    {
	chan=getuserchannel(-1,irccontent);
	client=getclientbynick(ircnick);
	if(client==NULL) return 0x0; /* ignore fakes */
	if(chan==NULL) return 0x0; /* no such channel */
	chanuser=getchannelnick(chan,ircto);
	if(chanuser!=NULL) return 0x0;
	addinvite(chan,ircto);
	sendtoclient(ircto,link,"%s",ircbuf);
    } else {
	client=getclientbynumber(usern);
	if(client==NULL) 
    	{	
	    ap_snprintf(intname,sizeof(intname),"%s-psybnc.net",me);
	    client=enteruser(usern,user(usern)->nick,user(usern)->login,intname,me);
	}		    		    
	if(client==NULL) return 0x0;
	if(*ircto==0)
	{
	    strmncpy(ircto,irccontent,sizeof(ircto));
	    strmncpy(irccontent,client->nick,sizeof(irccontent));
	}
	/* now we got the channels and the clients to kick in ircto, the reason in irccontent */
	pt=strchr(ircto,' ');
	if(pt==NULL) return 0x0;
	*pt=0;
	pt++;
	onicks=pt;
	pt=ircto;
	while(pt!=NULL)
	{
	    pt2=strchr(pt,',');
	    if(pt2!=NULL)
	    {
		*pt2=0;
		pt2++;
		if(*pt2==0) pt2=NULL;
	    }
	    strmncpy(currentto,pt,sizeof(currentto));
	    chan=getuserchannel(-1,currentto);
	    if (chan==NULL)
		sendtoclient(client->nick,0,":%s-psybnc.net 401 %s %s :No such Channel",me,client->nick,currentto);
	    else
	    {
		chanuser=getchannelnick(chan,client->nick);
		if(chanuser==NULL)
		    sendtoclient(client->nick,0,":%s-psybnc.net 442 %s %s :You're not on that channel",me,client->nick,currentto);
		else
		{
		    if(strchr(chanuser->mode,'@')==NULL)
			sendtoclient(client->nick,0,":%s-psybnc.net 482 %s %s :You're not the Channel-King",me,client->nick,currentto);
		    else
		    {
			strmncpy(nicks,onicks,sizeof(nicks));
			ot=nicks;
			while(ot!=NULL)
			{
			    ot2=strchr(ot,' ');
			    if(ot2!=NULL)
			    {
				*ot2=0;
				ot2++;
				if(*ot2==0) ot2=NULL;				
			    }
			    chanuser=getchannelnick(chan,ot);
			    if(chanuser==NULL)
			    {
				sendtoclient(ot,0,":%s!%s@%s INVITE %s :%s",client->nick,client->ident,client->host,ot,currentto);
				addinvite(chan,ot);
			    } else {
				sendtoclient(client->nick,0,":%s-psybnc.net 443 %s %s %s :is already on channel",me,client->nick,ot,currentto);
			    }
			    ot=ot2;
			}
		    }
		}
	    }
	    pt=pt2;
	}
    }
}

/* join the network to a link */

int joinintnettolink(int link)
{
    struct clientt *client;
    struct uchannelt *chan;
    struct uchannelusert *chanuser;
    struct stringarray *bans;
    char modeline[1024];
    char paramline[1024];
    int modes;
    pcontext;
    client=clients;
    while(client!=NULL)
    {
	sendtolink(link,"USER %s %s %s :%s",client->nick,client->ident,client->host,client->server);
	client=client->next;
    }        
    chan=intchan;
    while(chan!=NULL)
    {
	chanuser=chan->users;
	ap_snprintf(modeline,sizeof(modeline),":%s-psybnc.net MODE %s +",me,chan->name);
	paramline[0]=0;
	modes=0;
	while(chanuser!=NULL)
	{
	    sendtolink(link,":%s!%s@%s JOIN :%s",chanuser->nick,chanuser->ident,chanuser->host,chan->name);
	    if(chanuser->mode[0]=='@' || chanuser->mode[0]=='+')
	    {
		if(modes==3)
		{
		    sendtolink(link,"%s %s",modeline,paramline);		
		    ap_snprintf(modeline,sizeof(modeline),":%s-psybnc.net MODE %s +",me,chan->name);
		    paramline[0]=0;
		    modes=0;
		}
		if(chanuser->mode[0]=='@')
		    strcat(modeline,"o");
		else    
		    strcat(modeline,"v");
		if(strlen(paramline)+strlen(chanuser->nick)+1<sizeof(paramline))
		{
		    strcat(paramline,chanuser->nick);
		    modes++;
		    if(modes!=3) strcat(paramline," ");
		}
	    }
	    chanuser=chanuser->next;
	}
	if(modes!=0)
	{
	    sendtolink(link,"%s %s",modeline,paramline);		
	}
	ap_snprintf(modeline,sizeof(modeline),":%s-psybnc.net MODE %s +",me,chan->name);
	paramline[0]=0;
	modes=0;
	bans=chan->bans;
	while(bans!=NULL)
	{
	    if(modes==3)
	    {
		sendtolink(link,"%s %s",modeline,paramline);		
		ap_snprintf(modeline,sizeof(modeline),":%s-psybnc.net MODE %s +",me,chan->name);
		paramline[0]=0;
		modes=0;	    
	    }
	    if(strlen(modeline)+1<sizeof(modeline))
		strcat(modeline,"b");
	    if(strlen(paramline)+strlen(bans->entry)+1<sizeof(paramline))
	    {
		strcat(paramline,bans->entry);
		strcat(paramline," ");
	    }
	    modes++;
	    bans=bans->next;
	}
	if(modes!=0)
	{
	    sendtolink(link,"%s %s",modeline,paramline);		
	    modes=0;	    
	}
	sendtolink(link,":%s-psybnc.net MODE %s %s",me,chan->name,chan->modes);
	chan=chan->next;
    }
    pcontext;
    return 0x0;
}

/* remove all specified users of a lost link from the network */

int removeinternal(char *server)
{
    char tmpnick[64];
    struct topologyt *topo;
    struct clientt *client,*eclient;
    client=clients;
    if(strmcmp(server,me)==1) return 0x0; /* dont remove ourselves */
    while(client!=NULL)
    {
	eclient=client->next;
	if(strmcmp(client->server,server)==1)
	{
	    strmncpy(tmpnick,client->nick,sizeof(tmpnick));
	    sendtochannelsofnick(tmpnick,0,":%s!%s@%s QUIT :%s %s",client->nick,client->ident,client->host,me,server);
	    removeclient(tmpnick);	
	    removenickfromallchannels(-1,tmpnick);
	} else {
	    /* collect garbage, extremely needed */
	    topo=gettopology(client->server);
	    if(topo==NULL)
	    {
		strmncpy(tmpnick,client->nick,sizeof(tmpnick));
		sendtochannelsofnick(tmpnick,0,":%s!%s@%s QUIT :%s %s",client->nick,client->ident,client->host,me,server);
		removeclient(tmpnick);	
		removenickfromallchannels(-1,tmpnick);
	    }
	}
	client=eclient;
    }
    return 0x0;
}


#endif