/* NickServ auto-join module.
* Written by Yusuf Iskenderoglu <uhc0@stud.uni-karlsruhe.de>
* Idea taken from PTlink Services.
*
* IRC Services is copyright (c) 1996-2007 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"
#include "modules/chanserv/chanserv.h"
/*************************************************************************/
static Module *module;
static Module *module_nickserv;
static Module *module_chanserv;
static typeof(check_access_cmd) *check_access_cmd_p;
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) {
Channel *c = get_channel(ngi->ajoin[i]);
if (c && (c->mode & CMODE_i)
&& c->ci && check_access_cmd_p
&& (*check_access_cmd_p)(u, c->ci, "INVITE", NULL) > 0
) {
send_cmd(s_NickServ, "INVITE %s %s", u->nick, ngi->ajoin[i]);
}
send_cmd(ServerName, "SVSJOIN %s %s", u->nick, ngi->ajoin[i]);
}
}
return 0;
}
/*************************************************************************/
/* Handle autojoin help. */
static int do_help(User *u, const char *param)
{
if (stricmp(param, "AJOIN") == 0) {
Module *mod;
notice_help(s_NickServ, u, NICK_HELP_AJOIN);
if ((mod = find_module("chanserv/main")) != NULL) {
const char *my_s_ChanServ;
const char **ptr = get_module_symbol(mod, "s_ChanServ");
if (ptr) {
my_s_ChanServ = *ptr;
} else {
static int warned = 0;
if (!warned) {
module_log("HELP AJOIN: cannot retrieve symbol"
" `s_ChanServ' from module `chanserv/main'");
warned = 1;
}
my_s_ChanServ = "ChanServ";
}
notice_help(s_NickServ, u, NICK_HELP_AJOIN_END_CHANSERV,
my_s_ChanServ);
} else {
notice_help(s_NickServ, u, NICK_HELP_AJOIN_END);
}
return 1;
}
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 (readonly) {
notice_lang(s_NickServ, u, NICK_AJOIN_DISABLED);
return;
}
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 (readonly) {
notice_lang(s_NickServ, u, NICK_AJOIN_DISABLED);
return;
}
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, irc_stricmp, i);
if (i == ngi->ajoin_count) {
notice_lang(s_NickServ, u, NICK_AJOIN_NOT_FOUND, chan);
return;
}
free(ngi->ajoin[i]);
ARRAY_REMOVE(ngi->ajoin, i);
notice_lang(s_NickServ, u, NICK_AJOIN_DELETED, chan);
} 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 }
};
/*************************************************************************/
static int do_load_module(Module *mod, const char *name)
{
if (strcmp(name,"chanserv/main") == 0) {
module_chanserv = mod;
if (!(check_access_cmd_p = get_module_symbol(mod,"check_access_cmd"))){
module_log("Unable to resolve symbol `check_access_cmd' in"
" module `chanserv/main', auto-inviting disabled");
}
}
return 0;
}
/*************************************************************************/
static int do_unload_module(Module *mod)
{
if (mod == module_chanserv) {
check_access_cmd_p = NULL;
module_chanserv = NULL;
}
return 0;
}
/*************************************************************************/
int init_module(Module *module_)
{
Module *mod;
module = module_;
if (!(protocol_features & PF_SVSJOIN)) {
if (protocol_features & PF_UNSET) {
module_log("No protocol module loaded--you must load a"
" protocol module before loading this module");
} else {
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(NULL, "load module", do_load_module)
|| !add_callback(NULL, "unload module", do_unload_module)
|| !add_callback(module_nickserv, "identified", do_identified)
|| !add_callback(module_nickserv, "HELP", do_help)
) {
module_log("Unable to add callbacks");
exit_module(0);
return 0;
}
mod = find_module("chanserv/main");
if (mod)
do_load_module(mod, "chanserv/main");
return 1;
}
/*************************************************************************/
int exit_module(int shutdown_unused)
{
#ifdef CLEAN_COMPILE
shutdown_unused = shutdown_unused;
#endif
if (module_chanserv)
do_unload_module(module_chanserv);
if (module_nickserv) {
remove_callback(module_nickserv, "HELP", do_help);
remove_callback(module_nickserv, "identified", do_identified);
unregister_commands(module_nickserv, cmds);
unuse_module(module_nickserv);
module_nickserv = NULL;
}
remove_callback(NULL, "unload module", do_unload_module);
remove_callback(NULL, "load module", do_load_module);
return 1;
}
/*************************************************************************/
syntax highlighted by Code2HTML, v. 0.9.1