/************************************************************************
 *   IRC - Internet Relay Chat, chanmodes/cm_invites.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 char modebuf[REALMODEBUFLEN], parabuf[REALMODEBUFLEN];

static int add_invites_id(aClient *cptr, aChannel *chptr, char *id)
{
    int r = 0;

    r = add_id(cptr, chptr, id, MAXINVITES, &(chptr->invitelist));

    return r;
}

static int del_invites_id(aClient *cptr, aChannel *chptr, char *id)
{
    int r = 0;

    r = del_id(id, &(chptr->invitelist));

    return r;
}

static int kill_invites_list(struct hook_data *data)
{
    aClient *cptr = data->client_p;
    aChannel *chptr = data->channel;

    remove_nuh_list(cptr, chptr, &chptr->invitelist, 'I');

    return 0;
}

static int send_invites_list(struct hook_data *data)
{
    aClient *cptr = data->client_p;
    aChannel *chptr = data->channel;

    *parabuf = '\0';
    *modebuf = '+';
    modebuf[1] = '\0';
    send_nuh_list(cptr, chptr, &chptr->invitelist, 'I', modebuf, parabuf);
    return 0;
}

static int remove_matching_invites(struct hook_data *data)
{
    aChannel *chptr = data->channel;
    aClient *cptr = data->client_p;
    aClient *from = data->source_p;
    char letter = data->statchar;
    if (letter == 'I')
	remove_matching_nuhs(chptr, cptr, from, &chptr->invitelist, letter);
    return 0;	
}


static int clear_invites(struct hook_data *data)
{
    aChannel *chptr = data->channel;
    dlink_node *nuhptr, *next_ptr;
    aNUH *nuh;

    for (nuhptr = chptr->invitelist.head; nuhptr; nuhptr = next_ptr) {
        next_ptr = nuhptr->next;
        nuh = nuhptr->data;
        MyFree(nuh->nuhstr);
        MyFree(nuh->who);
        MyFree(nuh);
        dlinkDeleteNode(nuhptr, &(chptr->invitelist));
    }
    return 0;
}

/* 
 * adl : add|del|list :P -TimeMr14C 
 */

static int set_invite(int adl, aChannel *chptr, int nmodes,
		      int *argnum, int *pidx, int *mbix, char *mbuf, char *pbuf,
		      aClient *cptr, aClient *sptr, int parc, char **parv)
{
    aNUH *nuhptr = NULL;
    dlink_node *l;

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

    char nuhbuf[NICKLEN + USERLEN + HOSTLEN + 6];

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

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

    if (adl == CMODE_LIST) {
        for (l = chptr->invitelist.head; l; l = l->next) {
            nuhptr = l->data;
            if (nuhptr->nuhstr)
                send_me_numeric(sptr, RPL_INVITELIST, chptr, nuhptr->nuhstr, nuhptr->who, nuhptr->when);
        }
	send_me_numeric(cptr, RPL_ENDOFINVITELIST, chptr);
	return nmodes;
    }

    if (parv[fargnum] == NULL) {
	return set_invite(CMODE_LIST, chptr, nmodes, argnum, pidx, mbix,
			  mbuf, pbuf, cptr, sptr, parc, parv);
    }

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

    strlcpy_irc(nuhbuf, collapse(pretty_mask(parv[fargnum])), NICKLEN + USERLEN + HOSTLEN + 6);
    parv[fargnum] = nuhbuf;
    if ((prelen + (mbuf - morig) + fpidx + NICKLEN + USERLEN + HOSTLEN + 6 + 1) > REALMODEBUFLEN) {
	fargnum++;
	*argnum = fargnum;
	return nmodes;
    }

    if ((adl == CMODE_ADD) && !add_invites_id(sptr, chptr, parv[fargnum])) {
	fargnum++;
	*argnum = fargnum;
	return -1;
    }
    if ((adl == CMODE_DEL) && !del_invites_id(sptr, chptr, parv[fargnum])) {
	fargnum++;
	*argnum = fargnum;
	return -1;
    }

    mbuf[fmbix++] = 'I';

    pptr = parv[fargnum];
    if (fpidx)
	pbuf[fpidx++] = ' ';
    while (*pptr)
	pbuf[fpidx++] = *pptr++;
    fargnum++;
    nmodes++;

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

    return nmodes;
}

static int si_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 si_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_invite(adl, chptr, nmodes, argnum, pidx, mbix, mbuf, pbuf, cptr, sptr, parc, parv);
}

static int si_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_invite(adl, chptr, nmodes, argnum, pidx, mbix, mbuf, pbuf, cptr, sptr, parc, parv);
}

static int si_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) || (adl == 0)) {
        return set_invite(adl, chptr, nmodes, argnum, pidx, mbix, mbuf, pbuf, cptr, sptr, parc, parv);
    } else
	send_me_numeric(sptr, ERR_CHANOPRIVSNEEDED, chptr);
    return nmodes;
}

static int si_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) || (adl == 0))
	return set_invite(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_invite[] = {
    {MDFL_INVITE, 1, MFLG_LISTABLE | MFLG_IGNORE, CMTYPE_LIST | CMTYPE_PARAMETRIC,
     si_user, si_oper, si_uline, si_server, si_service}
};

#ifndef STATIC_MODULES
int _persistent = 1;
void _modinit(void)
#else
void invites_modinit(void)
#endif
{
    hook_add_hook("send mode list", (hookfn *) send_invites_list);
    hook_add_hook("sub1 from channel", (hookfn *) clear_invites);
    hook_add_hook("kill paramode list", (hookfn *) kill_invites_list);
    hook_add_hook("channel svsmode", (hookfn *) remove_matching_invites);
    modetab[(int) 'I'] = mode_invite[0];
    GeneralOpts.lists_created = 0;
}


syntax highlighted by Code2HTML, v. 0.9.1