/*
 *   m_nochan UnrealIRCD module
 *   (C) 2005 John Brooks (http://john.yarbbles.info/ john@yarbbles.info)
 *
 *   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.
 */

#include "config.h"
#include "struct.h"
#include "common.h"
#include "sys.h"
#include "numeric.h"
#include "msg.h"
#include "proto.h"
#include "channel.h"
#include <time.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
#include <io.h>
#endif
#include <fcntl.h>
#include "h.h"
#ifdef STRIPBADWORDS
#include "badwords.h"
#endif
#ifdef _WIN32
#include "version.h"
#endif

/* Changes of 1.1.0:
 *   Added -r switch to filter out registered users.
 *   Added -o switch to filter out opers
 */

Command *nochan;

void make_status(aClient *sptr, aClient *acptr, char *status);
DLLFUNC int cmd_nochan(aClient *cptr, aClient *sptr, int parc, char *parv[]);
void showncHelp(aClient *sptr);

#define MSG_NOCHAN 	"NOCHAN"	

ModuleHeader MOD_HEADER(m_nochan)
  = {
	"m_nochan",
	"$Id: m_nochan.c,v 1.1.0 2005/03/26 15:16 Special Exp $",
	"command /nochan", 
	"3.2.3",
	NULL 
    };

DLLFUNC int MOD_INIT(m_nochan)(ModuleInfo *modinfo)
{
	nochan = CommandAdd(modinfo->handle, MSG_NOCHAN, NULL, cmd_nochan, MAXPARA, 0);
	if (!nochan)
	{
		sendto_realops("Error while loading 'm_nochan' module: Command could not be added.");
		return MOD_FAILED;
	}
	return MOD_SUCCESS;
}

DLLFUNC int MOD_LOAD(m_nochan)(int module_load)
{
	return MOD_SUCCESS;
}

DLLFUNC int MOD_UNLOAD(m_nochan)(int module_unload)
{
	CommandDel(nochan);
	return MOD_SUCCESS;
}

void showncHelp(aClient *sptr)
{
	sendto_one(sptr, ":%s 334 %s :/NOCHAN [-a] [-o] [-r]", me.name, sptr->name);
	sendto_one(sptr, ":%s 334 %s :Lists all users who are not in any channels.", me.name,
		sptr->name);
	sendto_one(sptr, ":%s 334 %s :Switches:", me.name, sptr->name);
	sendto_one(sptr, ":%s 334 %s :  -a   Hide users who are away", me.name, sptr->name);
	sendto_one(sptr, ":%s 334 %s :  -o   Hide IRCops", me.name, sptr->name);
	sendto_one(sptr, ":%s 334 %s :  -r   Hide registered users", me.name, sptr->name);
	sendto_one(sptr, ":%s 334 %s :Example: /nochan -ao (All users not in any channels that are not away and are not IRCops",
		me.name, sptr->name);
}
DLLFUNC int cmd_nochan(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
	/* Simple: Loop through each user, check the number of channels they
	 * are on (acptr->user->joined), send a who reply (with borrowed code from
	 * m_who), and go on). */
	aClient *acptr;
	int hideReg = 0, hideOper = 0, hideAway = 0, i, j;
	if (!IsAnOper(sptr))
	{
		sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, sptr->name);
		return 0;
	}
	if (parc > 1)
	{
		/* This could be coded a lot more cleanly, but I want it to
		 * allow /nochan -r -o -a AND /nochan -roa (and even /nochan -ro -a).
		 */
		for (i = 0; i < parc; i++)
		{
			if (parv[i][0] == '-')
			{
				for (j = 1; j < strlen(parv[i]); j++)
				{
					if (parv[i][j] == 'r')
					{
						hideReg = 1;
					}
					else if (parv[i][j] == 'o')
					{
						hideOper = 1;
					}
					else if (parv[i][j] == 'a')
					{
						hideAway = 1;
					}
					else
					{
						/* We show them the help if they specify an invalid switch */
						showncHelp(sptr);
						return 0;
					}
				}
			}
		}
	}
	for (acptr = client; acptr; acptr = acptr->next)
	{
		char stat[20];
		if (IsServer(acptr) || IsMe(acptr) || acptr->user->joined > 0)
		{
			continue;
		}
		if (hideReg && IsARegNick(acptr))
		{
			continue;
		}
		if (hideOper && IsAnOper(acptr))
		{
			continue;
		}
		if (hideAway && acptr->user->away)
		{
			continue;
		}
		/* Make the reply.. */
		make_status(sptr, acptr, stat);
		sendto_one(sptr, getreply(RPL_WHOREPLY), me.name, sptr->name,
			"*", /* The channel.. */
			acptr->user->username, /* The username (ident) */
			acptr->user->realhost, /* The hostname */
			acptr->user->server, /* Server name */
			acptr->name, /* Nickname */
			stat, /* Status */
			acptr->hopcount, /* Hops to this server */
			acptr->info /* Real name (Gecos) */
			);
	}
	sendto_one(sptr, getreply(RPL_ENDOFWHO), me.name, sptr->name, sptr->name);
	return 0;
}

void make_status(aClient *sptr, aClient *acptr, char *status)
{
	int i = 0;
	if (acptr->user->away)
	{
		status[i++] = 'G';
	}
	else
	{
		status[i++] = 'H';
	}
	if (IsARegNick(acptr))
	{
		status[i++] = 'r';
	}
	if (acptr->umodes & UMODE_BOT)
	{
		status[i++] = 'B';
	}
	if (IsAnOper(acptr))
	{
		status[i++] = '*';
	}
	status[i] = '\0';
}
