/* NickServ auto-join module.
 * Written by Yusuf Iskenderoglu <uhc0@stud.uni-karlsruhe.de>
 * Idea taken from PTlink Services.
 *
 * IRC Services is copyright (c) 1996-2002 Andrew Church.
 *     E-mail: <achurch@achurch.org>
 * Parts written by Andrew Kempe and others.
 * This program is free but copyrighted software; see the file COPYING for
 * details.
 */

#include "services.h"
#include "modules.h"
#include "conffile.h"
#include "language.h"
#include "commands.h"
#include "nickserv.h"
#include "modules/operserv/operserv.h"

/*************************************************************************/

static Module *module;
static Module *module_nickserv;

static int NSAutojoinMax;

/*************************************************************************/

static void do_ajoin(User *u);

static Command cmds[] = {
    { "AJOIN",       do_ajoin, NULL,  NICK_HELP_AJOIN,
		-1, NICK_OPER_HELP_AJOIN },
    { NULL }
};

/*************************************************************************/

/* Send autojoin commands for an identified user. */

static int do_identified(User *u, int unused)
{
    NickGroupInfo *ngi = u->ngi;
    int i;

#ifdef CLEAN_COMPILE
    unused = unused;
#endif

    ARRAY_FOREACH (i, ngi->ajoin) {
	struct u_chanlist *uc;
	LIST_SEARCH(u->chans, chan->name, ngi->ajoin[i], irc_stricmp, uc);
	if (!uc)
	    send_cmd(ServerName, "SVSJOIN %s %s", u->nick, ngi->ajoin[i]);
    }
    return 0;
}

/*************************************************************************/
/*************************** Command functions ***************************/
/*************************************************************************/

void do_ajoin(User *u)
{
    char *cmd = strtok(NULL, " ");
    char *chan = strtok(NULL, " ");
    NickGroupInfo *ngi = u->ngi;
    int i;

    if (cmd && chan && stricmp(cmd,"LIST") == 0 && is_services_admin(u)) {
	NickInfo *ni = get_nickinfo(chan);

	if (!ni) {
	    notice_lang(s_NickServ, u, NICK_X_NOT_REGISTERED, chan);
	} else if (ni->status & NS_VERBOTEN) {
	    notice_lang(s_NickServ, u, NICK_X_FORBIDDEN, chan);
	} else if (!(ngi = get_ngi(ni))) {
	    notice_lang(s_NickServ, u, INTERNAL_ERROR);
	} else if (!ngi->ajoin_count) {
	    notice_lang(s_NickServ, u, NICK_AJOIN_LIST_X_EMPTY, chan);
	} else {
	    notice_lang(s_NickServ, u, NICK_AJOIN_LIST_X, chan);
	    ARRAY_FOREACH (i, ngi->ajoin)
		notice(s_NickServ, u->nick, "    %s", ngi->ajoin[i]);
	}

    } else if (!cmd || ((stricmp(cmd,"LIST")==0) && chan)) {
	syntax_error(s_NickServ, u, "AJOIN", NICK_AJOIN_SYNTAX);

    } else if (!valid_ngi(u)) {
	notice_lang(s_NickServ, u, NICK_NOT_REGISTERED);

    } else if (!user_identified(u)) {
	notice_lang(s_NickServ, u, NICK_IDENTIFY_REQUIRED, s_NickServ);

    } else if (stricmp(cmd, "ADD") == 0) {
	if (!chan || *chan != '#') {
	    syntax_error(s_NickServ, u, "AJOIN", NICK_AJOIN_ADD_SYNTAX);
	    return;
	}
	if (!valid_chan(chan)) {
	    notice_lang(s_NickServ, u, CHAN_INVALID, chan);
	    return;
	}
	if (ngi->ajoin_count + 1 > NSAutojoinMax) {
	    notice_lang(s_NickServ, u, NICK_AJOIN_LIST_FULL, NSAutojoinMax);
	    return;
	}
	ARRAY_FOREACH (i, ngi->ajoin) {
	    if (stricmp(ngi->ajoin[i], chan) == 0) {
		notice_lang(s_NickServ, u,
			NICK_AJOIN_ALREADY_PRESENT, ngi->ajoin[i]);
		return;
	    }
	}
	ARRAY_EXTEND(ngi->ajoin);
	ngi->ajoin[ngi->ajoin_count-1] = sstrdup(chan);
	put_nickgroupinfo(ngi);
	notice_lang(s_NickServ, u, NICK_AJOIN_ADDED, chan);

   } else if (stricmp(cmd, "DEL") == 0) {
	if (!chan || *chan != '#') {
	    syntax_error(s_NickServ, u, "AJOIN", NICK_AJOIN_DEL_SYNTAX);
	    return;
	}
	ARRAY_SEARCH_PLAIN(ngi->ajoin, chan, strcmp, i);
	if (i == ngi->ajoin_count)
	    ARRAY_SEARCH_PLAIN(ngi->ajoin, chan, stricmp, i);
	if (i == ngi->ajoin_count) {
	    notice_lang(s_NickServ, u, NICK_AJOIN_NOT_FOUND, chan);
	    return;
	}
	notice_lang(s_NickServ, u, NICK_AJOIN_DELETED, chan);
	free(ngi->ajoin[i]);
	ARRAY_REMOVE(ngi->ajoin, i);

    } else if (stricmp(cmd, "LIST") == 0) {
	if (!ngi->ajoin_count) {
	    notice_lang(s_NickServ, u, NICK_AJOIN_LIST_EMPTY);
	} else {
	    notice_lang(s_NickServ, u, NICK_AJOIN_LIST);
	    ARRAY_FOREACH (i, ngi->ajoin)
		notice(s_NickServ, u->nick, "    %s", ngi->ajoin[i]);
	}

    } else {
	syntax_error(s_NickServ, u, "AJOIN", NICK_AJOIN_SYNTAX);
    }
}

/*************************************************************************/
/***************************** Module stuff ******************************/
/*************************************************************************/

const int32 module_version = MODULE_VERSION_CODE;

ConfigDirective module_config[] = {
    { "NSAutojoinMax",   { { CD_POSINT, CF_DIRREQ, &NSAutojoinMax } } },
    { NULL }
};


/*************************************************************************/

int init_module(Module *module_)
{
    module = module_;

    if (!(protocol_features & PF_SVSJOIN)) {
	module_log("SVSJOIN not supported by this IRC server (%s)",
		   protocol_name);
	return 0;
    }

    module_nickserv = find_module("nickserv/main");
    if (!module_nickserv) {
	module_log("Main NickServ module not loaded");
	return 0;
    }
    use_module(module_nickserv);

    if (!register_commands(module_nickserv, cmds)) {
	module_log("Unable to register commands");
	exit_module(0);
	return 0;
    }

    if (!add_callback(module_nickserv, "identified", do_identified)) {
	module_log("Unable to add callbacks");
	exit_module(0);
	return 0;
    }
    return 1;
}

/*************************************************************************/

int exit_module(int shutdown_unused)
{
#ifdef CLEAN_COMPILE
    shutdown_unused = shutdown_unused;
#endif

    if (module_nickserv) {
	remove_callback(module_nickserv, "identified", do_identified);
	unregister_commands(module_nickserv, cmds);
	unuse_module(module_nickserv);
	module_nickserv = NULL;
    }

    return 1;
}

/*************************************************************************/
