/************************************************************************
 *   psybnc2.3, src/p_network.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_network.c, v 2.3 2001/07/13 02:03:00 psychoid Exp $";
#endif

#define P_NETWORK

#include <p_global.h>

/* check parent users */

int checkparents(int usernum)
{
   int uparent;    
   pcontext;
   if (user(usernum)->parent != 0)
   {
       uparent=user(usernum)->parent;
       if (user(uparent)->instate == STD_NOUSE)
       {
           deluser(usernum);
	   loaduser(usernum);
       } else {
	   strmncpy(user(usernum)->login,user(uparent)->login,sizeof(user(usernum)->login));
	   strmncpy(user(usernum)->user,user(uparent)->user,sizeof(user(usernum)->user));
	   strmncpy(user(usernum)->pass,user(uparent)->pass,sizeof(user(usernum)->pass));
	   user(usernum)->insock=user(uparent)->insock;
	   user(usernum)->instate=user(uparent)->instate;    
	   user(usernum)->rights=user(uparent)->rights;
       }
   }    
}

/* converting a outbounded input string to the nick of the parent */

int parentnick(int usern)
{
    char *pt;
    char *pt1;
    char *pt2;
    int uparent;
    char tmpbuf[8192];
    int intnet=0;
    char nicktmp[70];
#ifdef INTNET
    if(usern>10000)
    {
	usern-=10000;
    	intnet=1;
    }
    else
#endif
	if (user(usern)->parent==0) return 0x0;
    pcontext;
    uparent=user(usern)->parent;
    if (strmcmp(user(usern)->nick,user(uparent)->nick)==1) return 0x0;

    if (ircbuf[0]==':')
    {

	ap_snprintf(nicktmp,sizeof(nicktmp),":%s!",user(usern)->nick);
	pt=strstr(ircbuf,nicktmp);
	if (pt==ircbuf) {
	    pt=ircbuf+strlen(nicktmp);
	    if(intnet==1)
		ap_snprintf(tmpbuf,sizeof(tmpbuf),gettxt(637),user(usern)->nick,pt);
	    else
		ap_snprintf(tmpbuf,sizeof(tmpbuf),gettxt(638),user(uparent)->nick,pt);

	    strmncpy(ircbuf,tmpbuf,sizeof(ircbuf));
	}
    }

    ap_snprintf(nicktmp,sizeof(nicktmp)," %s ",user(usern)->nick);
    if (strlen(ircbuf)<1) return 0x0;
    pt=ircbuf;
    pt2=strchr(pt+1,':');
    while (1)
    {
	pt=strstr(pt+1,nicktmp);
	if (pt==NULL) break;
	if (pt>pt2 && pt2 != NULL) break;
	/* its the nick */
	pt1=pt+strlen(nicktmp);
	pt1--;
	*pt1=0;
	pt1++;
	*pt=0;
	if(intnet==1)
	    ap_snprintf(tmpbuf,sizeof(tmpbuf),gettxt(639),ircbuf,user(usern)->nick,pt1);
	else
	    ap_snprintf(tmpbuf,sizeof(tmpbuf),gettxt(640),ircbuf,user(uparent)->nick,pt1);
	strmncpy(ircbuf,tmpbuf,sizeof(ircbuf));
    }
}

/* this routine checks for a network token - phew */

int checknetwork(int usern)
{
    struct usernodes *th;
    char tmpircbuf[8192];
    int i;
    char *pt;
    char *pt1;
    char *pt2;
    pcontext;
    th=usernode;
    strmncpy(tmpircbuf,ircbuf,sizeof(tmpircbuf));
    pt=strchr(tmpircbuf,'~');
    if (pt!=NULL) 
    {
	pt1=pt;
	pt1--;
	if (*pt1=='*' || *pt1=='!') { /* if its a userflag, try next item */
	    pt1=pt;pt1++;
	    pt=strchr(pt1,'~');
	    if (pt==NULL) return usern;
	}
	pt1=tmpircbuf+1;
	pt1=strchr(pt1,':');
	if (pt1 != NULL && pt>pt1 && ifcommand("NICK")==0) /* if network specified in content, bye */
	    return usern;
	pt1=pt;
	while (pt1!=tmpircbuf && *pt1!=' ' && *pt1!=':') pt1--;
	if (pt1==tmpircbuf) return usern; /* at start of the buffer ? nah */
	/* in pt1 = start of networktoken, in pt = end of network token */
	*pt1=0; /* buffer part 1 */
	*pt=0; /* buffer part 2 */
	pt2=pt;pt2++;pt1++;
	if (*pt1=='#') pt1++; /* filtering the channels */
#ifdef INTNET
	if(strmcmp(pt1,"int")==1)
	{
	    i=usern+10000;
            ap_snprintf(ircbuf,sizeof(ircbuf),gettxt(641),tmpircbuf,pt2);    
	    return i;
	} else {
#endif
	    while (th!=NULL)
	    {
		i=th->uid;
		if (user(i)->parent==usern)
		{
		    if (strmcmp(user(i)->network,pt1)==1) 
		    {
			/* ok, we got it. its a valid network. Network user is in i
		           pt2 has the second part of the buffer, tmpircbuf is terminated
		           before start of network token. Lets craft the untokened ircbuf now */
		        ap_snprintf(ircbuf,sizeof(ircbuf),gettxt(642),tmpircbuf,pt2);    
		        /* setting parents inbound flags to child */
		        if(i<10000)
		        {
			    user(i)->insock=user(usern)->insock;
		    	    user(i)->instate=user(usern)->instate;
		        }
		        /* returning the network uid */
		        return i;
		    }
		}
		th=th->next;
	    }
	    /* interesting network token, but not existent, telling the user its unknown */
	    ssnprintf(user(usern)->insock,gettxt(643),pt1);
	    /* clearing ircbuf */
	    ircbuf[0]=0;
#ifdef INTNET
	}
#endif
    }
    return usern;
}

/* this is a bitch -> adding the network token to the currents network-Users-
   Inbound 									*/

int addtoken(int usern)
{
    char *pt;
    char *pt1;
    char *pt2;
    char tmpircbuf[8192];
    char tmpircbuf2[8192];
    char nameline[512];
    char netname[20];
    char myparentnick[64];
    char l;
    int intnet=0;
    char flg;
    int broken;
    int eflg;
    int sku=0;
    char mm[2];
    pcontext;
    eflg=0;
#ifdef INTNET
    if(usern>10000)
    {
	strmncpy(netname,"int",sizeof(netname));
	usern=usern-10000;
	intnet=10000;
	strmncpy(myparentnick,user(usern)->nick,sizeof(myparentnick));
    } else {
#endif
	strmncpy(netname,user(usern)->network,sizeof(netname));
	strmncpy(myparentnick,user(user(usern)->parent)->nick,sizeof(myparentnick));
#ifdef INTNET
    }
#endif
    /* skip nick message, if we are already changed */
    if(ifcommand("NICK") && strmcmp(user(usern)->nick,ircto)==1) 
    {
	*ircbuf=0;
	return 0x0;
    }
    /* parsing channels */
    pt1=strstr(ircbuf,ircto);
    if (pt1!=NULL && *ircto!=0 && !ifcommand("QUIT")) 
    {
	pt2=strchr(ircbuf+1,':');
        if (ifcommand("JOIN") || ifcommand("PART") || ifcommand("NICK")) pt2=NULL;
        pt=strchr(pt1,'#');
        if (pt==NULL) pt=strchr(pt1,'+');
        if (pt==NULL) pt=strchr(pt1,'&');
        if (pt==NULL) pt=strchr(pt1,'!');
        pcontext;
        if (pt!=NULL)
        {
    	    if (pt>pt2 && pt2!=NULL) 
	    {
		sku=0;
	    } else {
		pt=strstr(ircbuf,pt);
		/* a channel. We preceed the 'to' parameter */
		if (pt!= NULL)
		{
		    pt--;
		    l=*pt;
		    *pt=0;
		    pt++;
		    ap_snprintf(tmpircbuf,sizeof(tmpircbuf),gettxt(644),ircbuf,l,netname,pt);
		    strmncpy(ircbuf,tmpircbuf,sizeof(ircbuf));
		}
		sku=1;
	    }
	}
    } 
    if(sku==0)
    {
	/* no, its a user ! */
        /* checking, if we are the dest */
        pcontext;
        if (ifcommand("NICK"))
        {
	    ap_snprintf(tmpircbuf,sizeof(tmpircbuf)," :%s",ircto);
	    pt=strstr(ircbuf,tmpircbuf);
	    if (pt!=NULL)
	    {
		pt++;
		*pt=0;
		pt++;
		ap_snprintf(tmpircbuf,sizeof(tmpircbuf),gettxt(645),ircbuf,netname,pt);
		strmncpy(ircbuf,tmpircbuf,sizeof(ircbuf));
    	    }
	}
    }
    pcontext;
    /* parsing Users */
    if (strchr(ircfrom,'@') != NULL) { /* if theres a @ in the from, its a user */
	if (strmcmp(ircnick,user(usern)->nick)!=1)
	{
	    ap_snprintf(tmpircbuf,sizeof(tmpircbuf),gettxt(646),*ircbuf,netname,ircbuf+1);
	    strmncpy(ircbuf,tmpircbuf,sizeof(ircbuf));
	}
    }
    pcontext;
    if(intnet==0)
	parentnick(usern);
    /* special content parsing has to be done on NAMES and WHO */
    broken=0;
    if (ifcommand("353"))
    { /* names */
	pt=ircbuf;
	pt++;
	pt=strchr(pt,':');
	if (pt!=NULL) 
	{
	    pt++;
	    l=*pt;
	    *pt=0;
	    strmncpy(tmpircbuf,ircbuf,sizeof(tmpircbuf));
	    strmncpy(nameline,ircbuf,sizeof(nameline));
	    *pt=l;
	    /* now the hard stuff.. we precede every Nick */
	    while(eflg==0)
	    {
		pt1=strchr(pt,' ');
		if (pt1!=NULL) {
		    *pt1=0;l=32;
		} else {
		    eflg=1;l=0;
		}
		flg=0;
		/* the modes */
		if (*pt=='@' || *pt=='+' || *pt=='%') {
		    flg=*pt;
		    pt++;
		}
		/* if its us, we dont parse */
		if (strmcmp(pt,user(usern)->nick))
		{
		    if(flg!=0)
			ap_snprintf(tmpircbuf2,sizeof(tmpircbuf2),gettxt(647),tmpircbuf,flg,myparentnick,l);
		    else
			ap_snprintf(tmpircbuf2,sizeof(tmpircbuf2),gettxt(648),tmpircbuf,myparentnick,l);
		} else {
		    if (l==0)
 			ap_snprintf(tmpircbuf2,sizeof(tmpircbuf2),gettxt(649),tmpircbuf,pt,l);
		    else
		    {
			if(flg!=0)
 			    ap_snprintf(tmpircbuf2,sizeof(tmpircbuf2),gettxt(650),tmpircbuf,flg,netname,pt,l);
			else
 			    ap_snprintf(tmpircbuf2,sizeof(tmpircbuf2),gettxt(651),tmpircbuf,netname,pt,l);
		    }
		}
		strmncpy(tmpircbuf,tmpircbuf2,sizeof(tmpircbuf));
		/* avoiding the limit exceed */
		if (strlen(tmpircbuf)>500)
		{
		    /* sending the result up to here */
		    writesock(user(usern)->insock,tmpircbuf);
		    /* building new names line */
		    strmncpy(tmpircbuf,nameline,sizeof(tmpircbuf));
		}
		pt=pt1+1;
	    }
	    strmncpy(ircbuf,tmpircbuf,sizeof(ircbuf));
	}
    }
    pcontext;
    if (ifcommand("311") || ifcommand("312") || ifcommand("313") || ifcommand("318") || ifcommand("319"))
    {   /* the whois answers */
	pt=strchr(ircbuf,' ');
	if(pt!=NULL)
	{
	    pt++;
	    pt=strchr(pt,' ');
	    if(pt!=NULL)
	    {
		pt++;
		pt=strchr(pt,' ');
		if(pt!=NULL)
		{
		    *pt=0;
		    pt++;
		    ap_snprintf(tmpircbuf,sizeof(tmpircbuf),gettxt(652),ircbuf,netname,pt);
		    strmncpy(ircbuf,tmpircbuf,sizeof(ircbuf));
		}
	    }
	}    
    }
    pcontext;
    if (ifcommand("319"))
    {  /* the channel answer of whois */
	ap_snprintf(tmpircbuf,sizeof(tmpircbuf)," :%s",irccontent);
	pt=strstr(ircbuf,tmpircbuf);
	if(pt!=NULL)
	{
	    *pt=0; /* cutting */
	    /* and now: the channels: */
	    pt=irccontent;
	    tmpircbuf2[0]=0;
	    mm[0]=0;mm[1]=0;
	    while(pt!=NULL)
	    {
		pt2=strchr(pt,' ');
		if(pt2!=NULL)
		{
		    *pt2=0;pt2++;
		}
		flg=0;
		if(*pt=='+' || *pt=='^' || *pt=='@' || *pt=='%')
		{
		     flg=*pt;
    		     pt++;
		}
		if(strlen(tmpircbuf2)+strlen(netname)+6+strlen(pt)<sizeof(tmpircbuf2) && *pt!=' ' && *pt!=0)
		{
		    if(flg!=0)
		    {
			mm[0]=flg;
			strcat(tmpircbuf2,mm);
		    }
		    strcat(tmpircbuf2,"#");
		    strcat(tmpircbuf2,netname);
		    strcat(tmpircbuf2,"~");
		    strcat(tmpircbuf2,pt);
		    strcat(tmpircbuf2," ");
		}
		pt=pt2;
	    }
	    ap_snprintf(tmpircbuf,sizeof(tmpircbuf),gettxt(653),ircbuf,tmpircbuf2);
	    strmncpy(ircbuf,tmpircbuf,sizeof(ircbuf));
	}		    
    }
    pcontext;
    if (ifcommand("352"))
    { /* who */
	pt=ircbuf;
	for (eflg=0;eflg<7;eflg++)
	{
	   pt=strchr(pt+1,' ');if (pt==NULL) return 0x0;
	}
	*pt=0;
	pt++;
	pt2=strchr(pt,' ');
	if (pt2==NULL) return 0x0;
	*pt2=0;
	pt2++;
	/* here also, we skip us */
	if (strstr(user(usern)->nick,pt) && strlen(pt)==strlen(user(usern)->nick)) {
	   ap_snprintf(tmpircbuf,sizeof(tmpircbuf),gettxt(654),ircbuf,myparentnick,pt2);
	} else {
	   ap_snprintf(tmpircbuf,sizeof(tmpircbuf),gettxt(655),ircbuf,netname,pt,pt2);
	}
	strmncpy(ircbuf,tmpircbuf,sizeof(ircbuf));
    }
    pcontext;
    if (ifcommand("MODE"))
    { /* this is funny. we have to decide, that a parameter is no hostmask and preceed it */
	pt=strchr(ircbuf,' ');
	if (pt==NULL) return 0x0;
	pt=strchr(pt+1,' ');
	if (pt==NULL) return 0x0;
	pt++;
	if (*pt == '#' || *pt == '&' || *pt == '+' || *pt == '!')
	{ /* a channel, ok, check the parameters */
	    pt=strchr(pt,' ');
	    if (pt==NULL) return 0x0;
	    /* million of ircds, thousands of networks.. we cant parse the modes
	       we parse the parameters */
	    pt++;
	    pt=strchr(pt,' ');
	    if (pt==NULL) return 0x0;
	    /* now the parameters. Its no nick, if: @ is in, no user.
	       if first character is numeric, no user. Problem is:
	       Channel Key. Events Client side on NickBan.              */
	    *pt=0;
	    ap_snprintf(tmpircbuf,sizeof(tmpircbuf),"%s ",ircbuf);
	    pt++;
	    eflg=0;
	    /* "bleh!blah@bloh MODE #x +o Irgs  " */
	    while (eflg==0)
	    {
		pt2=strchr(pt,' ');
		if (pt2!=NULL) 
		{
		    l=*pt2;
		    *pt2=0;
		    pt2++;
		} else {
		    l=0;eflg=1;
		}
		if (strchr(gettxt(656),*pt) == NULL && strchr(pt,'@')==NULL && strlen(pt)>0 && *pt!=' ' && *pt!=0 && pt!=pt2-1)
		{
		    /* fixed for v2.2 - modes for us, no parse */
		    if ((strstr(pt,user(usern)->nick) && strlen(pt)==strlen(user(usern)->nick)) || *pt==' ')
		    {
			ap_snprintf(tmpircbuf2,sizeof(tmpircbuf2),gettxt(657),tmpircbuf,pt,l);
		    } else {
			ap_snprintf(tmpircbuf2,sizeof(tmpircbuf2),gettxt(658),tmpircbuf,netname,pt,l);
		    }
		} else {
		    ap_snprintf(tmpircbuf2,sizeof(tmpircbuf2),gettxt(659),tmpircbuf,pt,l);
		}
		strmncpy(tmpircbuf,tmpircbuf2,sizeof(tmpircbuf));
		pt=pt2;
	    }
	    strmncpy(ircbuf,tmpircbuf,sizeof(ircbuf));
	}	
    }
    pcontext;
    if (ifcommand(gettxt(660)))
    {  /* the content */
	ap_snprintf(tmpircbuf,sizeof(tmpircbuf)," :%s",irccontent);
	pt=strstr(ircbuf,tmpircbuf);
	if(pt!=NULL)
	{
	    *pt=0;
	    ap_snprintf(tmpircbuf2,sizeof(tmpircbuf2),gettxt(661),ircbuf,netname,irccontent);
	    strmncpy(ircbuf,tmpircbuf2,sizeof(ircbuf));
	}
    }
    pcontext;
    if (ifcommand("KICK"))
    { /* a kick. we need to preceed the victim */
	pt=strchr(ircbuf,' ');
	if (pt==NULL) return 0x0;
	pt++;
	pt=strchr(pt,' ');
	if (pt==NULL) return 0x0;
	pt++;
	pt=strchr(pt,' ');
	if (pt==NULL) return 0x0;
	*pt=0;
	pt++;
	/* the victim */
	pt2=strchr(pt,' ');
	if (pt2==NULL) return 0x0;
	*pt2=0;
	pt2++;
	if (strmcmp(myparentnick,pt)==1)
	{
	   ap_snprintf(tmpircbuf,sizeof(tmpircbuf),gettxt(662),ircbuf,pt,pt2);
	} else {
	   ap_snprintf(tmpircbuf,sizeof(tmpircbuf),gettxt(663),ircbuf,netname,pt,pt2);
	}
	strmncpy(ircbuf,tmpircbuf,sizeof(ircbuf));
    }
    return 0x0;
}

/* checking, if network exists for a user */
int checkusernetwork(int usern)
{
    struct usernodes *th;
    int uind;
    pcontext;
#ifdef INTNET
    if(strmcmp(user(uind)->network,"int")==1) return 0x0;
#endif
    th=usernode;
    while(th!=NULL)
    {
	uind=th->uid;
	if (user(uind)->parent==usern) {
	    if (strmcmp(user(uind)->network,irccontent)) return uind;
	}
	th=th->next;
    }
    return 0;
}
