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

#define P_UCHANNEL

#include <p_global.h>

/* bring the channel modes into the right order, return formulated mode */

char returnmode[300];

char *ordermodes(struct uchannelt *channel)
{
    int i;
    char *pt;
    char known[]="spmntilk";
    char mm[2];
    char newmode[30];
    char param[200];
    char limit[10];
    newmode[0]=0;mm[1]=0;
    param[0]=0;
    for(i=0;i<strlen(known);i++)
    {
	mm[0]=known[i];
	pt=strchr(channel->modes,known[i]);
	if(pt!=NULL)
	{
	    if(*pt=='k')
	    {
		if(strlen(param)+strlen(channel->key)+2<199)
		{
		    strcat(param,channel->key);
		    strcat(param," ");
		}
	    }
	    if(*pt=='l')
	    {
		ap_snprintf(limit,sizeof(limit),"%d",channel->limit);
		if(strlen(param)+strlen(limit)+2<199)
		{
		    strcat(param,limit);
		    strcat(param," ");
		}
	    }
	    if(strlen(newmode)<29) strcat(newmode,mm);
	    *pt=' ';
	}
    }
    pt=channel->modes;
    if(channel->usern!=-1)
    {
	while(*pt!=0)
	{
	    if(*pt!=' ')
	    {
		mm[0]=*pt;
		if(strlen(newmode)<29)
		    strcat(newmode,mm);
	    }
	pt++;
	}
    }
    strmncpy(channel->modes,newmode,sizeof(channel->modes));
    ap_snprintf(returnmode,sizeof(returnmode),"+%s %s",newmode,param);
    return returnmode;
}

/* Add a channel to a user structure or return the existent channel */

struct uchannelt *addchanneltouser(int usern, char *channel,int nowrite)
{
    struct uchannelt *lkm,*llkm=NULL;
    char uc[255],uc1[255];
    char cfg[]="ENTRY%d";
    char bf[400];
    pcontext;
    strmncpy(uc,channel,sizeof(uc));
    ucase(uc);
#ifdef INTNET
    if(usern==-1)
	lkm=intchan;
    else
#endif
	lkm=user(usern)->channels;
    while(lkm!=NULL)
    {
	strmncpy(uc1,lkm->name,sizeof(uc1));
	ucase(uc1);
	if(strmcmp(uc1,uc)==1)
	    return lkm;
	llkm=lkm;
	lkm=lkm->next;
    }
    if(llkm==NULL)
    {
#ifdef INTNET
	if(usern==-1)
	{
	    intchan=(struct uchannelt *)pmalloc(sizeof(struct uchannelt));
	    llkm=intchan;
	}
	else
	{
#endif
	    user(usern)->channels=(struct uchannelt *)pmalloc(sizeof(struct uchannelt));
	    llkm=user(usern)->channels;
#ifdef INTNET
	}
#endif
    } else {
	llkm->next=(struct uchannelt *)pmalloc(sizeof(struct uchannelt));
	llkm=llkm->next;
    }
    strmncpy(llkm->name,channel,sizeof(llkm->name));
    strcpy(llkm->modes,"nt"); /* standardmodes */
    llkm->usern=usern;
    /* write to config */
#ifdef INTNET
    if(usern==-1) return llkm;
#endif
    if(nowrite==1) return llkm;
    ap_snprintf(bf,sizeof(bf),"USER%d",usern);
    countconfentries("CHANNELS","ENTRY%d",bf);
    llkm->isentry=lastfree;
    ap_snprintf(bf,sizeof(bf),"USER%d",usern);
    ap_snprintf(uc,sizeof(uc),"ENTRY%d",lastfree);
    pcontext;
    writeini("CHANNELS",uc,bf,channel);
    flushconfig(); /* this was missing, result: channels where not saved in time */
    pcontext;
    return llkm;
}

/* Get a channel from a user structure */

struct uchannelt *getuserchannel(int usern, char *channel)
{
    struct uchannelt *lkm,*llkm=NULL;
    char uc[255],uc1[255];
    strmncpy(uc,channel,sizeof(uc));
    ucase(uc);
#ifdef INTNET
    if(usern==-1)
	lkm=intchan;
    else
#endif
	lkm=user(usern)->channels;
    while(lkm!=NULL)
    {
	strmncpy(uc1,lkm->name,sizeof(uc1));
	ucase(uc1);
	if(strmcmp(uc1,uc)==1)
	    return lkm;
	llkm=lkm;
	lkm=lkm->next;
    }
    return NULL;
}

/* get a nickname of a userlist from a channel of a user */

struct uchannelusert *getchannelnick(struct uchannelt *channel, char *nick)
{
    struct uchannelusert *ukm;
    char uu[64],uu1[64];
    ukm=channel->users;
    strmncpy(uu,nick,sizeof(uu));
    ucase(uu);
    while(ukm!=NULL)
    {
	strmncpy(uu1,ukm->nick,sizeof(uu1));
	ucase(uu1);
	if (strmcmp(uu,uu1)==1)
	{
	    return ukm;
	}
	ukm=ukm->next;
    }
    return NULL;
}

/* add a nick to a channel of a user (on join) */

struct uchannelusert *addnicktochannel(struct uchannelt *chan, char *nick, char *ident, char *host)
{
    struct uchannelusert *chanuser,*scu;
    chanuser=getchannelnick(chan,nick);
    if(chanuser!=NULL)
    {
	scu=chanuser;
    } else {
	chanuser=chan->users;
	scu=chanuser;
        while(chanuser!=NULL)
        {
	    scu=chanuser;
	    chanuser=chanuser->next;
	}
	if(scu==NULL)
	{
	    chan->users=(struct uchannelusert *)pmalloc(sizeof(struct uchannelusert));
	    scu=chan->users;
	} else {
	    scu->next=(struct uchannelusert *)pmalloc(sizeof(struct uchannelusert));
	    scu=scu->next;
	}
    }
    strmncpy(scu->nick,nick,sizeof(scu->nick));
    strmncpy(scu->ident,ident,sizeof(scu->ident));
    strmncpy(scu->host,host,sizeof(scu->host));
    scu->mode[0]=0;
    return scu;
}

/* remove a nick from a channel */

int removenickfromchannel(struct uchannelt *channel, char *nick)
{
    struct uchannelusert *chanuser,*previous=NULL;
    chanuser=channel->users;
    while(chanuser!=NULL)
    {
	if(strmcmp(chanuser->nick,nick)==1)
	{
	    if(previous==NULL)
	    {
		channel->users=chanuser->next;
	    } else {
		previous->next=chanuser->next;
	    }
	    free(chanuser);
	    return 0x0;
	}
	previous=chanuser;
	chanuser=chanuser->next;
    }
    return 0x0;    
}

/* remove a nick from all channels of a user */

int removenickfromallchannels(int usern, char *nick)
{
    struct uchannelt *channel,*echannel;
#ifdef INTNET
    if(usern==-1)
	channel=intchan;
    else
#endif
	channel=user(usern)->channels;
    while(channel!=NULL)
    {
	removenickfromchannel(channel,nick);
	echannel=channel;
	channel=channel->next;
	if(echannel->users==NULL)
	{
	    removechannelfromuser(usern,echannel->name);
	}
    }
    return 0x0;
}

/* nickchange */

int nickchange(int usern, char *oldnick,char *newnick)
{
    struct uchannelt *channel;
    struct uchannelusert *chanuser;
#ifdef INTNET
    if(usern==-1)
	channel=intchan;
    else
#endif
	channel=user(usern)->channels;
    while(channel!=NULL)
    {
	chanuser=getchannelnick(channel,oldnick);
	if(chanuser!=NULL)
	{
	    strmncpy(chanuser->nick,newnick,sizeof(chanuser->nick));
	}
	channel=channel->next;
    }
    return 0x0;
}

/* remove all users from a channel (if the channel was left in any way) */

int removeallusersfromchannel(struct uchannelt *lkm)
{
    struct uchannelusert *ukm,*uukm=NULL;
    ukm=lkm->users;
    while(ukm!=NULL)
    {
	uukm=ukm->next;
	free(ukm);
	ukm=uukm;
    }
    lkm->users=NULL;
    return 0x0;
}

/* remove all channels from the user (for clearing the user) */

int removeallchannelsfromuser(int usern)
{
    struct uchannelt *lkm,*llkm=NULL;
    struct uchannelusert *ukm,*uukm;
#ifdef INTNET
    if(usern==-1)
	lkm=intchan;
    else
#endif
	lkm=user(usern)->channels;
    while(lkm!=NULL)
    {
	llkm=lkm->next;
	ukm=lkm->users;
	while(ukm!=NULL)
	{
	    uukm=ukm->next;
	    free(ukm);
	    ukm=uukm;
	}
	free(lkm);
	lkm=llkm;
    }
    /* we dont need to cleanup conf, this will be done later */
#ifdef INTNET
    if(usern==-1)
	intchan=NULL;
    else
#endif
	user(usern)->channels=NULL;
    return 0x0;
}

/* remove a specific channel from a user */

int removechannelfromuser(int usern, char *channel)
{
    struct uchannelt *lkm,*llkm=NULL;
    struct uchannelusert *ukm,*uukm;
    struct stringarray *l1,*l2;
    char uc[255],uc1[255];
    strmncpy(uc,channel,sizeof(uc));
    ucase(uc);
#ifdef INTNET
    if(usern==-1)
	lkm=intchan;
    else
#endif
	lkm=user(usern)->channels;
    while(lkm!=NULL)
    {
	strmncpy(uc1,lkm->name,sizeof(uc1));
	ucase(uc1);
	if(strmcmp(uc1,uc)==1)
	{
	    if(llkm==NULL)
	    {
#ifdef INTNET
		if(usern==-1)
		    intchan=lkm->next;
		else
#endif
		    user(usern)->channels=lkm->next;
	    } else {
		llkm->next=lkm->next;
	    }
	    ukm=lkm->users;
	    while(ukm!=NULL)
	    {
		uukm=ukm->next;
		free(ukm);
		ukm=uukm;
	    }
	    l1=lkm->bans;
	    while(l1!=NULL)
	    {
		l2=l1->next;
		free(l1->entry);
		free(l1);
		l1=l2;
	    }
	    l1=lkm->invites;
	    while(l1!=NULL)
	    {
		l2=l1->next;
		free(l1->entry);
		free(l1);
		l1=l2;
	    }
	    if(usern!=-1)
	    {
		ap_snprintf(uc,sizeof(uc),"USER%d.CHANNELS.ENTRY%d",usern,lkm->isentry);
		clearsectionconfig(uc);
		ap_snprintf(uc,sizeof(uc),"USER%d.CHANNELS.KEY%d",usern,lkm->isentry);
		clearsectionconfig(uc);
		flushconfig();
	    }
	    free(lkm);
	    lkm=llkm;
	    return 0x0;
	}
	llkm=lkm;
	lkm=lkm->next;
    }
    return 0x0;
}

/* set initial channelmodes */

int setchannelmode(struct uchannelt *lkm,char *mode, char *param)
{
    int i;
    char *par,*pt,*md;
    char sb[20],eb[20];
    strmncpy(lkm->modes,mode,sizeof(lkm->modes));
    par=param;
    md=mode;
    while(*md)
    {
	if(*md==0) return 0x0;
	switch(*md)
	{
	    case 'l':
		if (par==NULL) break;
		pt=strchr(par,' ');
		if(pt!=NULL)
		{
		    *pt=0;
		    pt++;
		}
		lkm->limit=atoi(par);
		par=pt;
		break;
	    case 'k':
		if (par==NULL) break;
		pt=strchr(par,' ');
		if(pt!=NULL)
		{
		    *pt=0;
		    pt++;
		}
		strmncpy(lkm->key,par,sizeof(lkm->key));
		if(lkm->usern>0 && lkm->usern!=-1)
		{
		    ap_snprintf(sb,sizeof(sb),"USER%d",lkm->usern);
		    ap_snprintf(eb,sizeof(eb),"KEY%d",lkm->isentry);
		    writeini("CHANNELS",eb,sb,lkm->key);
		    flushconfig();
		}
		par=pt;
		break;
	}
	md++;
    }
    return 0x0;
}

/* sub: add a mode to a user on a channel */

int addchannelusermode(struct uchannelt *channel, char *nickname, char mode)
{
    struct uchannelusert *chanuser;
    char order[20];
    order[0]=0;
    chanuser=getchannelnick(channel,nickname);
    if(chanuser==NULL) return 0x0;
/* the good old OP */
    if(strchr(chanuser->mode,'@')!=NULL || mode =='o') strcat(order,"@");
    if(strchr(chanuser->mode,'+')!=NULL || mode =='v') strcat(order,"+");
/* rfc noncompliant characters seen in some interesting networks */
    if(strchr(chanuser->mode,'%')!=NULL || mode =='%') strcat(order,"%"); /* halfop */
    if(strchr(chanuser->mode,'^')!=NULL || mode =='^') strcat(order,"^"); /* drop protect */
    strcpy(chanuser->mode,order);
    return 0x0;
}

/* sub: remove a single mode from a user on a channel */

int removechannelusermode(struct uchannelt *channel, char *nickname, char mode)
{
    char temp[20];
    struct uchannelusert *chanuser;
    char *pt;
    char imode;
    imode=mode;
    if(imode=='v') imode='+';
    if(imode=='o') imode='@';
    if(imode=='h') imode='%';
    if(imode=='a') imode='^';
    chanuser=getchannelnick(channel,nickname);
    if(chanuser==NULL) return 0x0;
    strmncpy(temp,chanuser->mode,sizeof(temp));
    pt=strchr(temp,imode);
    if(pt==NULL) return 0x0;
    *pt=0;pt++;
    ap_snprintf(chanuser->mode,sizeof(chanuser->mode),"%s%s",temp,pt);
    return 0x0;
}

/* sub: add a single mode to a channel */

int addmodetochannel(struct uchannelt *channel, char mode)
{
    char mm[2];
    mm[1]=0;
    if(strlen(channel->modes)<sizeof(channel->modes))
    {
	mm[0]=mode;
	if(strstr(channel->modes,mm)==NULL)
    	    strcat(channel->modes,mm);
    }
    return 0x0;
}

/* sub: delete a single mode from a channel */

int deletemodefromchannel(struct uchannelt *channel, char mode)
{
    char buf[60];
    char *pt;
    pt=strchr(channel->modes,mode);
    if(pt!=NULL)
    {
	*pt=0;
	pt++;
	ap_snprintf(buf,sizeof(buf),"%s%s",channel->modes,pt);
	strmncpy(channel->modes,buf,sizeof(channel->modes));
    }
    return 0x0;
}

/* send the names of a channel in a right command syntax to a given userinbound */

int sendnames(int usern, struct uchannelt *chan)
{
    int thsock;
    int userp;
    char token[60];
    char nameline[300];
    char line[1024];
    char mm[2];
    struct uchannelusert *users;
    char uc1[200],uc2[200];
    userp=usern;
    token[0]=0;
    token[1]=0;
    mm[1]=0;
    if(usern<10000)
    {
	if(user(usern)->innames==1)
	{
	    strmncpy(uc1,rtrim(chan->name),sizeof(uc1));
	    ucase(uc1);
	    strmncpy(uc2,rtrim(user(usern)->inchan),sizeof(uc2));
	    ucase(uc2);
	    if(strmcmp(uc1,uc2)==1)
	    {
		user(usern)->innames=2;	
		return 0x0;
	    }
	}
	if(user(usern)->parent!=0) 
	{
	    userp=user(usern)->parent;
	    ap_snprintf(token,sizeof(token),"#%s~",user(usern)->network);
	}
    }
#ifdef INTNET
    if(usern>10000)
    {
	userp=usern-10000;
	ap_snprintf(token,sizeof(token),"#int~");
	usern-=10000;
    }
#endif
    thsock=user(userp)->insock;
    ap_snprintf(nameline,sizeof(nameline),":%s 353 %s = %s%s :",user(usern)->server, user(usern)->nick,token,chan->name);    
    users=chan->users;
    strmncpy(line,nameline,sizeof(line));
    while(users!=NULL)
    {
	if(strlen(line)>500)
	{
	    strcat(line,"\n");
	    writesock(user(userp)->insock,line);
	    strmncpy(line,nameline,sizeof(line));
	} else {
	    if(users->mode[0]!=0)
	    {
		mm[0]=users->mode[0];
		strcat(line,mm);
	    }
	    if(strmcmp(users->nick,user(usern)->nick)==1)
	    {
		strcat(line,user(userp)->nick);
	    } else {
		strcat(line,token+1);
		strcat(line,users->nick);
	    }
	    strcat(line," ");
	    users=users->next;
	}
    }    
    strcat(line,"\n");
    writesock(user(userp)->insock,line);
    ap_snprintf(line,sizeof(line),":%s 366 %s %s%s :End of /NAMES list.\n",user(usern)->server, user(usern)->nick,token,chan->name);
    writesock(user(userp)->insock,line);
    return 0x0;
}

#ifdef SCRIPTING

/* raise a mode event to scripting */

int raisemodeevent(struct uchannelt *chan,char prefix,char mode,char *param)
{
    static char siccontent[4096];
    static char siccontent2[4096];
    strmncpy(siccontent,irccontent,sizeof(siccontent));
    if(param!=NULL)
	ap_snprintf(siccontent2,sizeof(siccontent2),"%c%c %s",prefix,mode,param);
    else
	ap_snprintf(siccontent2,sizeof(siccontent2),"%c%c",prefix,mode);
    strmncpy(irccontent,siccontent2,sizeof(irccontent));
    serverevent(chan->usern);
    strmncpy(irccontent,siccontent,sizeof(irccontent));
    return 0x0;
}

#endif

/* add or delete multiple channelmodes from the userchannel */

int addchannelmode(struct uchannelt *lkm, char *mode, char *param)
{
    char *par,*pt,*md;
    char prefix;
    static char sb[20],eb[20];
    static char mod[200];
    static char pr[4096];
    strmncpy(mod,mode,sizeof(mod));
    strmncpy(pr,param,sizeof(pr));
    prefix='+';
    par=pr;
    md=mod;
    while(*md!=0)
    {
	
	switch(*md)
	{
	    case '+': /* add mode */
		prefix='+';
		break;
	    case '-': /* delete mode */
		prefix='-';
		break;
	    case 'b': /* ban */
		if (par==NULL) break;
		pt=strchr(par,' ');
		if(pt!=NULL)	
		{
		    *pt=0;pt++;
		    if(*pt==0) pt=NULL;
		}
		/* work on a single ban later */
#ifdef SCRIPTING
		if(lkm->usern>0)
		    raisemodeevent(lkm,prefix,*md,par);
#endif
		par=pt;
		break;
	    case 'e': /* exclude */
		if (par==NULL) break;
		pt=strchr(par,' ');
		if(pt!=NULL)	
		{
		    *pt=0;pt++;
		    if(*pt==0) pt=NULL;
		}
		/* work on a single exclude later */
#ifdef SCRIPTING
		if(lkm->usern>0)
		    raisemodeevent(lkm,prefix,*md,par);
#endif
		par=pt;
		break;
	    case 'I': /* Invite */
		if (par==NULL) break;
		pt=strchr(par,' ');
		if(pt!=NULL)	
		{
		    *pt=0;pt++;
		    if(*pt==0) pt=NULL;
		}
		/* work on a single Invitation later */
#ifdef SCRIPTING
		if(lkm->usern>0)
		    raisemodeevent(lkm,prefix,*md,par);
#endif
		par=pt;
		break;
	    case 'v': /* voice */
		if (par==NULL) break;
		pt=strchr(par,' ');
		if(pt!=NULL)	
		{
		    *pt=0;pt++;
		    if(*pt==0) pt=NULL;
		}
		if(prefix=='+')
		    addchannelusermode(lkm,par,*md);
		else
		    removechannelusermode(lkm,par,*md);
#ifdef SCRIPTING
		if(lkm->usern>0)
		    raisemodeevent(lkm,prefix,*md,par);
#endif
		par=pt;
		break;
	    case 'o': /* op */
		if (par==NULL) break;
		pt=strchr(par,' ');
		if(pt!=NULL)	
		{
		    *pt=0;pt++;
		    if(*pt==0) pt=NULL;
		}
		if(prefix=='+')
		    addchannelusermode(lkm,par,*md);
		else
		    removechannelusermode(lkm,par,*md);
#ifdef SCRIPTING
		if(lkm->usern>0)
		    raisemodeevent(lkm,prefix,*md,par);
#endif
		par=pt;
		break;
	    case 'h': /* halfop	 */
		if (par==NULL) break;
		pt=strchr(par,' ');
		if(pt!=NULL)	
		{
		    *pt=0;pt++;
		    if(*pt==0) pt=NULL;
		}
		if(prefix=='+')
		    addchannelusermode(lkm,par,*md);
		else
		    removechannelusermode(lkm,par,*md);
#ifdef SCRIPTING
		if(lkm->usern>0)
		    raisemodeevent(lkm,prefix,*md,par);
#endif
		par=pt;
		break;
	    case 'a': /* kickprot */
		if (par==NULL) break;
		pt=strchr(par,' ');
		if(pt!=NULL)	
		{
		    *pt=0;pt++;
		    if(*pt==0) pt=NULL;
		}
		if(prefix=='+')
		    addchannelusermode(lkm,par,*md);
		else
		    removechannelusermode(lkm,par,*md);
#ifdef SCRIPTING
		if(lkm->usern>0)
		    raisemodeevent(lkm,prefix,*md,par);
#endif
		par=pt;
		break;
	    case 'l': /* limit */
		if(prefix=='+')
		{
		    if (par==NULL) break;
		    pt=strchr(par,' ');
		    if(pt!=NULL)	
		    {
			*pt=0;pt++;
			if(*pt==0) pt=NULL;
		    }
		    lkm->limit=atoi(par);
#ifdef SCRIPTING
		    if(lkm->usern>0)
			raisemodeevent(lkm,prefix,*md,par);
#endif
		    par=pt;
		    addmodetochannel(lkm,*md);
		}
		else
		{
		    deletemodefromchannel(lkm,*md);
#ifdef SCRIPTING
		    if(lkm->usern>0)
			raisemodeevent(lkm,prefix,*md,NULL);
#endif
		}
		break;
	    case 'k': /* key */
		if(prefix=='+')
		{
		    if (par==NULL) break;
		    pt=strchr(par,' ');
		    if(pt!=NULL)	
		    {
			*pt=0;pt++;
			if(*pt==0) pt=NULL;
		    }
		    strmncpy(lkm->key,par,sizeof(lkm->key));
#ifdef SCRIPTING
		    if(lkm->usern>0)
			raisemodeevent(lkm,prefix,*md,lkm->key);
#endif
		    par=pt;
		    if(lkm->usern>0)
		    {
			ap_snprintf(sb,sizeof(sb),"USER%d",lkm->usern);
    			ap_snprintf(eb,sizeof(eb),"KEY%d",lkm->isentry);
			writeini("CHANNELS",eb,sb,lkm->key);
			flushconfig();
		    }
		    addmodetochannel(lkm,*md);
		}
		else
		{
		    if (par==NULL) break;
		    pt=strchr(par,' ');
		    if(pt!=NULL)	
		    {
			*pt=0;pt++;
			if(*pt==0) pt=NULL;
		    }
		    if(lkm->usern>0)
		    {
			ap_snprintf(sb,sizeof(sb),"USER%d",lkm->usern);
    			ap_snprintf(eb,sizeof(eb),"KEY%d",lkm->isentry);
			writeini("CHANNELS",eb,sb,NULL);
			flushconfig();
		    }
		    deletemodefromchannel(lkm,*md);
#ifdef SCRIPTING
		    if(lkm->usern>0)
			raisemodeevent(lkm,prefix,*md,par);
#endif
		    par=pt;
		}
		break;
/* handle private and secret vice versa resetting */
	    case 's': /* secret */
		if(prefix=='+')
		{
		    addmodetochannel(lkm,*md);
		    deletemodefromchannel(lkm,'p');
		}
		else
		    deletemodefromchannel(lkm,*md);
#ifdef SCRIPTING
		if(lkm->usern>0)
		    raisemodeevent(lkm,prefix,*md,NULL);
#endif
		break;
	    case 'p': /* private  */
		if(prefix=='+')
		{
		    addmodetochannel(lkm,*md);
		    deletemodefromchannel(lkm,'s');
		}
		else
		    deletemodefromchannel(lkm,*md);
#ifdef SCRIPTING
		if(lkm->usern>0)
		    raisemodeevent(lkm,prefix,*md,NULL);
#endif
		break;
	    default: /* other channelmodes */
		if(prefix=='+')
		    addmodetochannel(lkm,*md);
		else
		    deletemodefromchannel(lkm,*md);
#ifdef SCRIPTING
		if(lkm->usern>0)
		    raisemodeevent(lkm,prefix,*md,NULL);
#endif
		break;
	}
	md++;
    }
    ordermodes(lkm);
    return 0x0;
}

int setchanneltopic(struct uchannelt *chan, char *topic)
{
    strmncpy(chan->topic,topic,sizeof(chan->topic));
    return 0x0;
}

int convertlastwhois(int usern, char *lastwhois)
{
    char *pt,*ept,*pt2;
    char lastsic[2048];
    int chan=0;
    strmncpy(lastsic,lastwhois,sizeof(lastsic));
    ept=lastsic;
    while(ept!=NULL)
    {
	while(*ept==' ') ept++;
	if(*ept==0) return 0x0;
	pt=strchr(ept,' ');
	if(pt!=NULL)
	    {*pt=0;pt++;}
	pt2=ept+1;
	if(*ept=='@' || *ept=='%' || (*ept=='+' && strchr("&#!",*pt2)!=NULL) || (*ept=='^' && strchr("&#!",*pt2)!=NULL))
	    ept++;
	addchanneltouser(usern,ept,0);
	ept=pt;
    }
    return 0x0;
}

/* reset all channels for a user (on disconnect) */

int resetallchannels(int usern)
{
    struct uchannelt *chan;
    chan=user(usern)->channels;
    while(chan!=NULL)
    {
	removeallusersfromchannel(chan);
	chan->ison=0;
	chan->topic[0]=0;
	chan=chan->next;
    }
    return 0x0;
}

/* load all channels for a user from the config */

int loadchannels(int usern)
{
    char bf[30],bf2[30];
    struct uchannelt *chan;
    int i,rc;
    ap_snprintf(bf,sizeof(bf),"USER%d",usern);
    for(i=0;i<40;i++)
    {
	ap_snprintf(bf2,sizeof(bf2),"ENTRY%d",i);	
	rc=getini("CHANNELS",bf2,bf);
	if(rc==0)
	{
	    chan=addchanneltouser(usern,value,1);
	    ap_snprintf(bf2,sizeof(bf2),"KEY%d",i);
	    rc=getini("CHANNELS",bf2,bf);
	    if(chan!=NULL) 
	    {
		chan->isentry=i;
		if(rc==0)
		{
		    strcpy(chan->modes,"tnk");
		    strmncpy(chan->key,value,sizeof(chan->key));
		}
	    }
	}
    }
}
