/************************************************************************                 
 *   IRC - Internet Relay Chat, chanmodes/cm_key.c
 *
 *   Copyright (C)2000-2003 TR-IRCD Development
 *   Copyright (C) 1990 Jarkko Oikarinen and
 *                      University of Oulu, Co Center
 *                      
 *   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 2, 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.  
 */

#include "struct.h"
#include "common.h"
#include "sys.h"
#include "numeric.h"
#include "channel.h"
#include "h.h"
#include "msg.h"
#include "hook.h"
#include "s_conf.h"
#include "chanmode.h"

static int set_channel_key(int adl, aChannel *chptr, int nmodes,
		   int *argnum, int *pidx, int *mbix, char *mbuf, char *pbuf,
		   aClient *cptr, aClient *sptr, int parc, char **parv)
{

    char *pptr;			/* temporary paramater pointer */
    char *morig = mbuf;		/* beginning of mbuf */

    int prelen = strlen(cptr->name) + strlen(chptr->chname) + 16;

    int fargnum = *argnum;
    int fmbix = *mbix;
    int fpidx = *pidx;

    if (parv[fargnum] == NULL)
	return nmodes;

    /* Do not allow keys ':' '\0' '*' */

    if (*parv[fargnum] == ':' || *parv[fargnum] == '\0' || *parv[fargnum] == '*') {
	send_me_numeric(sptr, ERR_NEEDMOREPARAMS, MSG_MODE);
	fargnum++;
	*argnum = fargnum;
	return nmodes;
    }

    /*
     * if we're going to overflow our mode buffer,
     * * drop the change instead
     */

    if ((prelen + (mbuf - morig) + fpidx + KEYLEN + 2) > REALMODEBUFLEN) {
	fargnum++;
	*argnum = fargnum;
	return nmodes;
    }

    if (adl == CMODE_ADD) {
	parv[fargnum][KEYLEN] = '\0';
	chptr->mode.mode |= MODE_KEY;
	strlcpy_irc(chptr->mode.key, parv[fargnum], KEYLEN);
	pptr = chptr->mode.key;
	if (fpidx)
	    pbuf[fpidx++] = ' ';
	while (*pptr)
	    pbuf[fpidx++] = *pptr++;
    }

    if (adl == CMODE_DEL) {
	pptr = chptr->mode.key;
	chptr->mode.mode &= ~MODE_KEY;
	if (fpidx)
	    pbuf[fpidx++] = ' ';
	while (*pptr)
	    pbuf[fpidx++] = *pptr++;
	chptr->mode.key[0] = '\0';
    }

    mbuf[fmbix++] = 'k';
    fargnum++;
    nmodes++;

    *mbix = fmbix;
    *pidx = fpidx;
    *argnum = fargnum;

    return nmodes;
}

static int sk_service(int adl, aChannel *chptr, int nmodes,
		      int *argnum, int *pidx, int *mbix, char *mbuf, char *pbuf,
		      aClient *cptr, aClient *sptr, int parc, char **parv)
{
    if (MyClient(sptr))
	send_me_numeric(sptr, ERR_CHANOPRIVSNEEDED, chptr);
    else
	ircstp->is_fake++;
    return nmodes;
}

static int sk_server(int adl, aChannel *chptr, int nmodes,
		     int *argnum, int *pidx, int *mbix, char *mbuf, char *pbuf,
		     aClient *cptr, aClient *sptr, int parc, char **parv)
{
    return set_channel_key(adl, chptr, nmodes, argnum, pidx, mbix, mbuf, pbuf, cptr, sptr, parc, parv);
}

static int sk_uline(int adl, aChannel *chptr, int nmodes,
		    int *argnum, int *pidx, int *mbix, char *mbuf, char *pbuf,
		    aClient *cptr, aClient *sptr, int parc, char **parv)
{
    return set_channel_key(adl, chptr, nmodes, argnum, pidx, mbix, mbuf, pbuf, cptr, sptr, parc, parv);
}

static int sk_oper(int adl, aChannel *chptr, int nmodes,
		   int *argnum, int *pidx, int *mbix, char *mbuf, char *pbuf,
		   aClient *cptr, aClient *sptr, int parc, char **parv)
{
    if (IsChanUser(sptr, chptr, CHFL_CHANOP) || IsOperMode(sptr) || IsServer(cptr)) {
        
        return set_channel_key(adl, chptr, nmodes, argnum, pidx, mbix, mbuf, pbuf, cptr, sptr, parc, parv);
    } else
	send_me_numeric(sptr, ERR_CHANOPRIVSNEEDED, chptr);
    return nmodes;
}

static int sk_user(int adl, aChannel *chptr, int nmodes,
		   int *argnum, int *pidx, int *mbix, char *mbuf, char *pbuf,
		   aClient *cptr, aClient *sptr, int parc, char **parv)
{
    if (IsChanUser(sptr, chptr, CHFL_CHANOP))
	return set_channel_key(adl, chptr, nmodes, argnum, pidx, mbix, mbuf, pbuf, cptr, sptr, parc, parv);
    else
	send_me_numeric(sptr, ERR_CHANOPRIVSNEEDED, chptr);
    return nmodes;
}

static struct ChanMode mode_key[] = {
    {MODE_KEY, 1, MFLG_PARAMSTR, CMTYPE_PARAMETRIC | CMTYPE_REMWPARA,
     sk_user, sk_oper, sk_uline, sk_server, sk_service}
};

static int do_can_join(struct hook_data *thisdata)
{ 
    aChannel *chptr = thisdata->channel;
    char *key = thisdata->data;

    if (*chptr->mode.key && (BadPtr(key) || irc_strcmp(chptr->mode.key, key)))
        return ERR_BADCHANNELKEY;

    return 0;
}


#ifndef STATIC_MODULES
int _persistent = 1;
void _modinit(void)
#else
void key_modinit(void)
#endif
{
    modetab[(int) 'k'] = mode_key[0];
    GeneralOpts.lists_created = 0;
    hook_add_hook("can join", (hookfn *) do_can_join);
}


syntax highlighted by Code2HTML, v. 0.9.1