/************************************************************************                  
 *   IRC - Internet Relay Chat, chanmodes/cm_singles.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 "hook.h"
#include "s_conf.h"
#include "chanmode.h"

static int set_single_mode(int adl, aChannel *chptr, int nmodes,
			   int *mbix, char *mbuf, int flag, char letter)
{
    int fmbix = *mbix;

    if (adl == CMODE_ADD)
	chptr->mode.mode |= flag;
    if (adl == CMODE_DEL)
	chptr->mode.mode &= ~flag;

    mbuf[fmbix++] = letter;

    *mbix = fmbix;

    return nmodes;
}

static int ssm_service(int adl, aChannel *chptr, int nmodes, int *mbix,
		       int flag, char letter, aClient *sptr, char *mbuf)
{
    nmodes++;
    if (MyClient(sptr))
	send_me_numeric(sptr, ERR_CHANOPRIVSNEEDED, chptr);
    else
	ircstp->is_fake++;
    return nmodes;
}

static int ssm_server(int adl, aChannel *chptr, int nmodes, int *mbix, int flag,
		      char letter, aClient *sptr, char *mbuf)
{
    nmodes++;
    return set_single_mode(adl, chptr, nmodes, mbix, mbuf, flag, letter);
}

static int ssm_uline(int adl, aChannel *chptr, int nmodes, int *mbix, int flag,
		     char letter, aClient *sptr, char *mbuf)
{
    nmodes++;
    return set_single_mode(adl, chptr, nmodes, mbix, mbuf, flag, letter);
}

static int ssm_oper(int adl, aChannel *chptr, int nmodes, int *mbix, int flag,
		    char letter, aClient *sptr, char *mbuf)
{
    nmodes++;
    if (IsChanUser(sptr, chptr, CHFL_CHANOP) || IsOperMode(sptr) || IsServer(sptr->from)) {
	
	return set_single_mode(adl, chptr, nmodes, mbix, mbuf, flag, letter);
    } else
	send_me_numeric(sptr, ERR_CHANOPRIVSNEEDED, chptr);
    return nmodes;
}

static int ssm_user(int adl, aChannel *chptr, int nmodes, int *mbix, int flag,
		    char letter, aClient *sptr, char *mbuf)
{
    nmodes++;
    if (IsChanUser(sptr, chptr, CHFL_CHANOP))
	return set_single_mode(adl, chptr, nmodes, mbix, mbuf, flag, letter);
    else
	send_me_numeric(sptr, ERR_CHANOPRIVSNEEDED, chptr);
    return nmodes;
}

static int ssm_user_halfop(int adl, aChannel *chptr, int nmodes, int *mbix,
			   int flag, char letter, aClient *sptr, char *mbuf)
{
    nmodes++;
    if (IsChanUser(sptr, chptr, CHFL_CHANOP) || IsChanUser(sptr, chptr, CHFL_HALFOP))
	return set_single_mode(adl, chptr, nmodes, mbix, mbuf, flag, letter);
    else
	send_me_numeric(sptr, ERR_CHANOPRIVSNEEDED, chptr);
    return nmodes;
}

static int ssm_service_nocolor(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 ssm_service(adl, chptr, nmodes, mbix, MODE_NOCOLOR, 'c', sptr, mbuf);
}

static int ssm_service_noctcp(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 ssm_service(adl, chptr, nmodes, mbix, MODE_NOCTCP, 'C', sptr, mbuf);
}

static int ssm_service_inviteonly(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 ssm_service(adl, chptr, nmodes, mbix, MODE_INVITEONLY, 'i', sptr, mbuf);
}

static int ssm_service_moderated(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 ssm_service(adl, chptr, nmodes, mbix, MODE_MODERATED, 'm', sptr, mbuf);
}

static int ssm_service_noprivmsgs(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 ssm_service(adl, chptr, nmodes, mbix, MODE_NOPRIVMSGS, 'n', sptr, mbuf);
}

static int ssm_service_operonly(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 ssm_service(adl, chptr, nmodes, mbix, MODE_OPERONLY, 'O', sptr, mbuf);
}

static int ssm_service_private(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 ssm_service(adl, chptr, nmodes, mbix, MODE_PRIVATE, 'p', sptr, mbuf);
}

static int ssm_service_registered(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 ssm_service(adl, chptr, nmodes, mbix, MODE_REGISTERED, 'r', sptr, mbuf);
}

static int ssm_service_regonly(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 ssm_service(adl, chptr, nmodes, mbix, MODE_REGONLY, 'R', sptr, mbuf);
}

static int ssm_service_secret(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 ssm_service(adl, chptr, nmodes, mbix, MODE_SECRET, 's', sptr, mbuf);
}

static int ssm_service_namesonlymembers(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 ssm_service(adl, chptr, nmodes, mbix, MODE_NAMESONLYMEMBERS, 'j', sptr, mbuf);
}

static int ssm_service_topiclimit(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 ssm_service(adl, chptr, nmodes, mbix, MODE_TOPICLIMIT, 't', sptr, mbuf);
}

static int ssm_service_extopic(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 ssm_service(adl, chptr, nmodes, mbix, MODE_EXTOPIC, 'T', sptr, mbuf);
}

static int ssm_service_hideops(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 ssm_service(adl, chptr, nmodes, mbix, MODE_HIDEOPS, 'x', sptr, mbuf);
}

static int ssm_service_no_nonres(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 ssm_service(adl, chptr, nmodes, mbix, MODE_NONONRES, 'N', sptr, mbuf);
}

static int ssm_service_sendrego(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 ssm_service(adl, chptr, nmodes, mbix, MODE_SENDREGONLY, 'g', sptr, mbuf);
}

static int ssm_service_no_quitpart(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 ssm_service(adl, chptr, nmodes, mbix, MODE_HIDEPARTQUIT, 'd', sptr, mbuf);
}

static int ssm_service_noknock(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 ssm_service(adl, chptr, nmodes, mbix, MODE_NOKNOCK, 'K', sptr, mbuf);
}

static int ssm_anonymous(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 ssm_service(adl, chptr, nmodes, mbix, MODE_ANONYMOUS, 'q', sptr, mbuf);
}

static int ssm_server_nocolor(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 ssm_server(adl, chptr, nmodes, mbix, MODE_NOCOLOR, 'c', sptr, mbuf);
}

static int ssm_server_noctcp(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 ssm_server(adl, chptr, nmodes, mbix, MODE_NOCTCP, 'C', sptr, mbuf);
}

static int ssm_server_inviteonly(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 (adl == CMODE_DEL) {
    dlink_node *ptr;
	ptr = chptr->invites.head;
	while (ptr) {
	    del_invite(ptr->data, chptr);
	    ptr = ptr->next;
	}
    }
    return ssm_server(adl, chptr, nmodes, mbix, MODE_INVITEONLY, 'i', sptr, mbuf);
}

static int ssm_server_moderated(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 ssm_server(adl, chptr, nmodes, mbix, MODE_MODERATED, 'm', sptr, mbuf);
}

static int ssm_server_noprivmsgs(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 ssm_server(adl, chptr, nmodes, mbix, MODE_NOPRIVMSGS, 'n', sptr, mbuf);
}

static int ssm_server_operonly(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 ssm_server(adl, chptr, nmodes, mbix, MODE_OPERONLY, 'O', sptr, mbuf);
}

static int ssm_server_private(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 ssm_server(adl, chptr, nmodes, mbix, MODE_PRIVATE, 'p', sptr, mbuf);
}

static int ssm_server_registered(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 ssm_server(adl, chptr, nmodes, mbix, MODE_REGISTERED, 'r', sptr, mbuf);
}

static int ssm_server_regonly(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 ssm_server(adl, chptr, nmodes, mbix, MODE_REGONLY, 'R', sptr, mbuf);
}

static int ssm_server_secret(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 ssm_server(adl, chptr, nmodes, mbix, MODE_SECRET, 's', sptr, mbuf);
}

static int ssm_server_namesonlymembers(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 ssm_server(adl, chptr, nmodes, mbix, MODE_NAMESONLYMEMBERS, 'j', sptr, mbuf);
}

static int ssm_server_topiclimit(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 ssm_server(adl, chptr, nmodes, mbix, MODE_TOPICLIMIT, 't', sptr, mbuf);
}

static int ssm_server_extopic(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 ssm_server(adl, chptr, nmodes, mbix, MODE_EXTOPIC, 'T', sptr, mbuf);
}

static int ssm_server_hideops(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 ssm_server(adl, chptr, nmodes, mbix, MODE_HIDEOPS, 'x', sptr, mbuf);
}

static int ssm_server_no_nonres(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 ssm_server(adl, chptr, nmodes, mbix, MODE_NONONRES, 'N', sptr, mbuf);            
}

static int ssm_server_sendrego(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 ssm_server(adl, chptr, nmodes, mbix, MODE_SENDREGONLY, 'g', sptr, mbuf);
}

static int ssm_server_no_quitpart(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 ssm_server(adl, chptr, nmodes, mbix, MODE_HIDEPARTQUIT, 'd', sptr, mbuf);
}

static int ssm_server_noknock(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 ssm_server(adl, chptr, nmodes, mbix, MODE_NOKNOCK, 'K', sptr, mbuf);
}

static int ssm_uline_nocolor(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 ssm_uline(adl, chptr, nmodes, mbix, MODE_NOCOLOR, 'c', sptr, mbuf);
}

static int ssm_uline_noctcp(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 ssm_uline(adl, chptr, nmodes, mbix, MODE_NOCTCP, 'C', sptr, mbuf);
}

static int ssm_uline_inviteonly(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 (adl == CMODE_DEL) {
    dlink_node *ptr;
	ptr = chptr->invites.head;
	while (ptr) {
	    del_invite(ptr->data, chptr);
	    ptr = ptr->next;
	}
    }
    return ssm_uline(adl, chptr, nmodes, mbix, MODE_INVITEONLY, 'i', sptr, mbuf);
}

static int ssm_uline_moderated(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 ssm_uline(adl, chptr, nmodes, mbix, MODE_MODERATED, 'm', sptr, mbuf);
}

static int ssm_uline_noprivmsgs(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 ssm_uline(adl, chptr, nmodes, mbix, MODE_NOPRIVMSGS, 'n', sptr, mbuf);
}

static int ssm_uline_operonly(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 ssm_uline(adl, chptr, nmodes, mbix, MODE_OPERONLY, 'O', sptr, mbuf);
}

static int ssm_uline_private(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 ssm_uline(adl, chptr, nmodes, mbix, MODE_PRIVATE, 'p', sptr, mbuf);
}

static int ssm_uline_registered(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 ssm_uline(adl, chptr, nmodes, mbix, MODE_REGISTERED, 'r', sptr, mbuf);
}

static int ssm_uline_regonly(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 ssm_uline(adl, chptr, nmodes, mbix, MODE_REGONLY, 'R', sptr, mbuf);
}

static int ssm_uline_secret(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 ssm_uline(adl, chptr, nmodes, mbix, MODE_SECRET, 's', sptr, mbuf);
}

static int ssm_uline_namesonlymembers(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 ssm_uline(adl, chptr, nmodes, mbix, MODE_NAMESONLYMEMBERS, 'j', sptr, mbuf);
}

static int ssm_uline_topiclimit(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 ssm_uline(adl, chptr, nmodes, mbix, MODE_TOPICLIMIT, 't', sptr, mbuf);
}

static int ssm_uline_extopic(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 ssm_uline(adl, chptr, nmodes, mbix, MODE_EXTOPIC, 'T', sptr, mbuf);
}

static int ssm_uline_hideops(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 ssm_uline(adl, chptr, nmodes, mbix, MODE_HIDEOPS, 'x', sptr, mbuf);
}

static int ssm_uline_no_nonres(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 ssm_uline(adl, chptr, nmodes, mbix, MODE_NONONRES, 'N', sptr, mbuf);            
}

static int ssm_uline_sendregon(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 ssm_uline(adl, chptr, nmodes, mbix, MODE_SENDREGONLY, 'g', sptr, mbuf);
}

static int ssm_uline_no_quitpart(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 ssm_uline(adl, chptr, nmodes, mbix, MODE_HIDEPARTQUIT, 'd', sptr, mbuf);
}

static int ssm_uline_noknock(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 ssm_uline(adl, chptr, nmodes, mbix, MODE_NOKNOCK, 'K', sptr, mbuf);
}

static int ssm_oper_nocolor(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 ssm_oper(adl, chptr, nmodes, mbix, MODE_NOCOLOR, 'c', sptr, mbuf);
}

static int ssm_oper_noctcp(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 ssm_oper(adl, chptr, nmodes, mbix, MODE_NOCTCP, 'C', sptr, mbuf);
}

static int ssm_oper_inviteonly(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 (adl == CMODE_DEL) {
    dlink_node *ptr;
	ptr = chptr->invites.head;
	while (ptr) {
	    del_invite(ptr->data, chptr);
	    ptr = ptr->next;
	}
    }
    return ssm_oper(adl, chptr, nmodes, mbix, MODE_INVITEONLY, 'i', sptr, mbuf);
}

static int ssm_oper_moderated(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 ssm_oper(adl, chptr, nmodes, mbix, MODE_MODERATED, 'm', sptr, mbuf);
}

static int ssm_oper_noprivmsgs(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 ssm_oper(adl, chptr, nmodes, mbix, MODE_NOPRIVMSGS, 'n', sptr, mbuf);
}

static int ssm_oper_operonly(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 ssm_oper(adl, chptr, nmodes, mbix, MODE_OPERONLY, 'O', sptr, mbuf);
}

static int ssm_oper_private(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 ssm_oper(adl, chptr, nmodes, mbix, MODE_PRIVATE, 'p', sptr, mbuf);
}

static int ssm_oper_registered(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_NOPRIVILEGES, chptr);
    else
	ircstp->is_fake++;
    return nmodes;
}

static int ssm_oper_regonly(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 ssm_oper(adl, chptr, nmodes, mbix, MODE_REGONLY, 'R', sptr, mbuf);
}

static int ssm_oper_secret(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 ssm_oper(adl, chptr, nmodes, mbix, MODE_SECRET, 's', sptr, mbuf);
}

static int ssm_oper_namesonlymembers(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 ssm_oper(adl, chptr, nmodes, mbix, MODE_NAMESONLYMEMBERS, 'j', sptr, mbuf);
}

static int ssm_oper_topiclimit(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 ssm_oper(adl, chptr, nmodes, mbix, MODE_TOPICLIMIT, 't', sptr, mbuf);
}

static int ssm_oper_extopic(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 ssm_oper(adl, chptr, nmodes, mbix, MODE_EXTOPIC, 'T', sptr, mbuf);
}

static int ssm_oper_hideops(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 ssm_oper(adl, chptr, nmodes, mbix, MODE_HIDEOPS, 'x', sptr, mbuf);
}

static int ssm_oper_no_nonres(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 ssm_oper(adl, chptr, nmodes, mbix, MODE_NONONRES, 'N', sptr, mbuf);            
}

static int ssm_oper_sendregonly(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 ssm_oper(adl, chptr, nmodes, mbix, MODE_SENDREGONLY, 'g', sptr, mbuf);
}

static int ssm_oper_no_quitpart(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 ssm_oper(adl, chptr, nmodes, mbix, MODE_HIDEPARTQUIT, 'd', sptr, mbuf);
}

static int ssm_oper_noknock(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 ssm_oper(adl, chptr, nmodes, mbix, MODE_NOKNOCK, 'K', sptr, mbuf);
}

static int ssm_nocolor(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 ssm_user(adl, chptr, nmodes, mbix, MODE_NOCOLOR, 'c', sptr, mbuf);
}

static int ssm_noctcp(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 ssm_user(adl, chptr, nmodes, mbix, MODE_NOCTCP, 'C', sptr, mbuf);
}

static int ssm_inviteonly(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 (adl == CMODE_DEL) {
    dlink_node *ptr;
	ptr = chptr->invites.head;
	while (ptr) {
	    del_invite(ptr->data, chptr);
	    ptr = ptr->next;
	}
    }
    return ssm_user_halfop(adl, chptr, nmodes, mbix, MODE_INVITEONLY, 'i', sptr, mbuf);
}

static int ssm_moderated(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 ssm_user(adl, chptr, nmodes, mbix, MODE_MODERATED, 'm', sptr, mbuf);
}

static int ssm_noprivmsgs(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 ssm_user(adl, chptr, nmodes, mbix, MODE_NOPRIVMSGS, 'n', sptr, mbuf);
}

static int ssm_operonly(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_NOPRIVILEGES, chptr);
    else
	ircstp->is_fake++;
    return nmodes;
}

static int ssm_private(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 ssm_user(adl, chptr, nmodes, mbix, MODE_PRIVATE, 'p', sptr, mbuf);
}

static int ssm_registered(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_NOPRIVILEGES, chptr);
    else
	ircstp->is_fake++;
    return nmodes;
}

static int ssm_regonly(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 ssm_user_halfop(adl, chptr, nmodes, mbix, MODE_REGONLY, 'R', sptr, mbuf);
}

static int ssm_secret(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 ssm_user(adl, chptr, nmodes, mbix, MODE_SECRET, 's', sptr, mbuf);
}

static int ssm_namesonlymembers(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 ssm_user(adl, chptr, nmodes, mbix, MODE_NAMESONLYMEMBERS, 'j', sptr, mbuf);
}

static int ssm_topiclimit(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 ssm_user(adl, chptr, nmodes, mbix, MODE_TOPICLIMIT, 't', sptr, mbuf);
}

static int ssm_extopic(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_NOPRIVILEGES, chptr);
    else
	ircstp->is_fake++;
    return nmodes;
}

static int ssm_hideops(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 ssm_user(adl, chptr, nmodes, mbix, MODE_HIDEOPS, 'x', sptr, mbuf);
}

static int ssm_no_nonres(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 ssm_user(adl, chptr, nmodes, mbix, MODE_NONONRES, 'N', sptr, mbuf);            
}

static int ssm_sendregonly(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 ssm_user(adl, chptr, nmodes, mbix, MODE_SENDREGONLY, 'g', sptr, mbuf);
}

static int ssm_no_quitpart(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 ssm_user(adl, chptr, nmodes, mbix, MODE_HIDEPARTQUIT, 'd', sptr, mbuf);
}

static int ssm_noknock(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 ssm_user(adl, chptr, nmodes, mbix, MODE_NOKNOCK, 'K', sptr, mbuf);
}

static struct ChanMode mode_anonymous[] = {
    {MODE_ANONYMOUS, 1, 0, CMTYPE_SINGLE, ssm_anonymous,
     ssm_anonymous, ssm_anonymous, ssm_anonymous, 
     ssm_anonymous}
};

static struct ChanMode mode_sendregonly[] = {
    {MODE_SENDREGONLY, 1, 0, CMTYPE_SINGLE, 
     ssm_sendregonly, ssm_oper_sendregonly, ssm_uline_sendregon,
     ssm_server_sendrego, ssm_service_sendrego}
};

static struct ChanMode mode_nocolor[] = {
    {MODE_NOCOLOR, 1, 0, CMTYPE_SINGLE, 
     ssm_nocolor, ssm_oper_nocolor, ssm_uline_nocolor,
     ssm_server_nocolor, ssm_service_nocolor}
};

static struct ChanMode mode_noctcp[] = {
    {MODE_NOCTCP, 1, 0, CMTYPE_SINGLE, 
     ssm_noctcp, ssm_oper_noctcp, ssm_uline_noctcp,
     ssm_server_noctcp, ssm_service_noctcp}
};

static struct ChanMode mode_inviteonly[] = {
    {MODE_INVITEONLY, 1, 0, CMTYPE_SINGLE, 
     ssm_inviteonly, ssm_oper_inviteonly, ssm_uline_inviteonly,
     ssm_server_inviteonly, ssm_service_inviteonly}
};

static struct ChanMode mode_moderated[] = {
    {MODE_MODERATED, 1, 0, CMTYPE_SINGLE, 
     ssm_moderated, ssm_oper_moderated, ssm_uline_moderated,
     ssm_server_moderated, ssm_service_moderated}
};

static struct ChanMode mode_noprivmsgs[] = {
    {MODE_NOPRIVMSGS, 1, 0, CMTYPE_SINGLE, 
     ssm_noprivmsgs, ssm_oper_noprivmsgs, ssm_uline_noprivmsgs,
     ssm_server_noprivmsgs, ssm_service_noprivmsgs}
};

static struct ChanMode mode_operonly[] = {
    {MODE_OPERONLY, 1, 0, CMTYPE_SINGLE, 
     ssm_operonly, ssm_oper_operonly, ssm_uline_operonly,
     ssm_server_operonly, ssm_service_operonly}
};

static struct ChanMode mode_private[] = {
    {MODE_PRIVATE, 1, 0, CMTYPE_SINGLE, 
     ssm_private, ssm_oper_private, ssm_uline_private,
     ssm_server_private, ssm_service_private}
};

static struct ChanMode mode_registered[] = {
    {MODE_REGISTERED, 1, 0, CMTYPE_SINGLE, 
     ssm_registered, ssm_oper_registered, ssm_uline_registered,
     ssm_server_registered, ssm_service_registered}
};

static struct ChanMode mode_regonly[] = {
    {MODE_REGONLY, 1, 0, CMTYPE_SINGLE, 
     ssm_regonly, ssm_oper_regonly, ssm_uline_regonly,
     ssm_server_regonly, ssm_service_regonly}
};

static struct ChanMode mode_secret[] = {
    {MODE_SECRET, 1, 0, CMTYPE_SINGLE, 
     ssm_secret, ssm_oper_secret, ssm_uline_secret,
     ssm_server_secret, ssm_service_secret}
};

static struct ChanMode mode_namesonlymembers[] = {
    {MODE_NAMESONLYMEMBERS, 1, 0, CMTYPE_SINGLE,
     ssm_namesonlymembers, ssm_oper_namesonlymembers, ssm_uline_namesonlymembers,
     ssm_server_namesonlymembers, ssm_service_namesonlymembers}
};

static struct ChanMode mode_topiclimit[] = {
    {MODE_TOPICLIMIT, 1, 0, CMTYPE_SINGLE, 
     ssm_topiclimit, ssm_oper_topiclimit, ssm_uline_topiclimit,
     ssm_server_topiclimit, ssm_service_topiclimit}
};

static struct ChanMode mode_extopic[] = {
    {MODE_EXTOPIC, 1, 0, CMTYPE_SINGLE, 
     ssm_extopic, ssm_oper_extopic, ssm_uline_extopic,
     ssm_server_extopic, ssm_service_extopic}
};

static struct ChanMode mode_hideops[] = {
    {MODE_HIDEOPS, 1, 0, CMTYPE_SINGLE, 
     ssm_hideops, ssm_oper_hideops, ssm_uline_hideops,
     ssm_server_hideops, ssm_service_hideops}
};

static struct ChanMode mode_no_nonres[] = {
    {MODE_NONONRES, 1, 0, CMTYPE_SINGLE, 
     ssm_no_nonres, ssm_oper_no_nonres, ssm_uline_no_nonres,
     ssm_server_no_nonres, ssm_service_no_nonres}
};

static struct ChanMode mode_no_quitpart[] = {
    {MODE_HIDEPARTQUIT, 1, 0, CMTYPE_SINGLE, ssm_no_quitpart, ssm_oper_no_quitpart,
     ssm_uline_no_quitpart, ssm_server_no_quitpart, ssm_service_no_quitpart}
};

static struct ChanMode mode_noknock[] = {
    {MODE_NOKNOCK, 1, 0, CMTYPE_SINGLE, ssm_noknock, ssm_oper_noknock,
     ssm_uline_noknock, ssm_server_noknock, ssm_service_noknock}
};

static int do_can_send(struct hook_data *thisdata)
{
    int member = thisdata->check;
    aChannel *chptr = thisdata->channel;
    aClient *cptr = thisdata->client_p;
    char *msg = thisdata->data;  

    if (!member) {
	if (IsChanModerated(chptr))
            return ERR_CANNOTSENDTOCHAN;
        if (IsChanNoNonres(chptr) && IsNonResolved(cptr))
            return ERR_IPNOTRESOLVED;
        if (IsChanNoPriv(chptr))
            return ERR_CANNOTSENDTOCHAN;
        if (IsChanRegOnly(chptr) && !IsRegNick(cptr))
            return ERR_NEEDREGGEDNICK;
        if (IsChanNoColor(chptr) && msg_has_colors(msg))
            return ERR_NOCOLORSONCHAN;
    	return 0;
    } else {
        if (IsChanModerated(chptr))
            return ERR_CANNOTSENDTOCHAN;
        if (IsChanRegOnly(chptr) && !IsRegNick(cptr))
            return ERR_NEEDREGGEDNICK;
        if (IsChanSendRegOnly(chptr) && !IsRegNick(cptr))
            return ERR_NEEDREGGEDNICK;
        if (IsChanNoColor(chptr) && msg_has_colors(msg))
            return ERR_NOCOLORSONCHAN;
        if (IsChanNoNonres(chptr) && IsNonResolved(cptr))
            return ERR_IPNOTRESOLVED;
	return 0;
    }
}

static int do_can_join(struct hook_data *thisdata)
{ 
    aChannel *chptr = thisdata->channel;
    aClient *sptr = thisdata->source_p;

    if (IsChanInviteonly(chptr))
        return ERR_INVITEONLYCHAN;
    if (IsChanRegOnly(chptr) && !IsRegNick(sptr))
        return ERR_NEEDREGGEDNICK;
    if (IsChanOperOnly(chptr) && !IsAnOper(sptr))
        return ERR_NOPRIVILEGES;
    if (IsChanNoNonres(chptr) && IsNonResolved(sptr))
        return ERR_BANNEDFROMCHAN;
    return 0;
}

#ifndef STATIC_MODULES
int _persistent = 1;
void _modinit(void)
#else
void singles_modinit(void)
#endif
{
    modetab[(int) 'c'] = mode_nocolor[0];
    modetab[(int) 'i'] = mode_inviteonly[0];
    modetab[(int) 'm'] = mode_moderated[0];
    modetab[(int) 'n'] = mode_noprivmsgs[0];
    modetab[(int) 'O'] = mode_operonly[0];
    modetab[(int) 'p'] = mode_private[0];
    modetab[(int) 'q'] = mode_anonymous[0];
    modetab[(int) 'r'] = mode_registered[0];
    modetab[(int) 'R'] = mode_regonly[0];
    modetab[(int) 's'] = mode_secret[0];
    modetab[(int) 't'] = mode_topiclimit[0];
    modetab[(int) 'T'] = mode_extopic[0];
    modetab[(int) 'x'] = mode_hideops[0];
    modetab[(int) 'N'] = mode_no_nonres[0];
    modetab[(int) 'C'] = mode_noctcp[0];
    modetab[(int) 'g'] = mode_sendregonly[0];
    modetab[(int) 'd'] = mode_no_quitpart[0];
    modetab[(int) 'j'] = mode_namesonlymembers[0];
    modetab[(int) 'K'] = mode_noknock[0];
    GeneralOpts.lists_created = 0;
    hook_add_hook("can send", (hookfn *) do_can_send);
    hook_add_hook("can join", (hookfn *) do_can_join); 
}


syntax highlighted by Code2HTML, v. 0.9.1