All pastes #244050 Raw Edit

Unnamed

public c v1 · immutable
#244050 ·published 2006-11-09 06:14 UTC
rendered paste body
/* Main OperServ module. * * IRC Services is copyright (c) 1996-2006 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 "timeout.h"#include "encrypt.h"#include "ignore.h"#include "modules/nickserv/nickserv.h"#ifdef DEBUG_COMMANDS# include "modules/chanserv/chanserv.h"  /* for send_user_info */#endif#include "operserv.h"#include "maskdata.h"#include "akill.h"#include "news.h"/* Maximum depth for SERVERMAP command */#define MAXMAPLEVEL	64/*************************************************************************/static Module *module;static Module *module_akill;static Module *module_nickserv;       char *s_OperServ;static char *desc_OperServ;       char *s_GlobalNoticer;static char *desc_GlobalNoticer;static char *OperDBName;EXPORT_VAR(char *,s_OperServ)EXPORT_VAR(char *,s_GlobalNoticer)       char * ServicesRoot;static int    WallOper;static int    WallBadOS;static int    WallOSChannel;static int    WallSU;static int    KillClonesAutokill;static time_t KillClonesAutokillExpire;static int    AllowRaw;EXPORT_VAR(char *,ServicesRoot)static int cb_command   = -1;static int cb_expire_md = -1;static int cb_help      = -1;static int cb_help_cmds = -1;static int cb_set       = -1;static int cb_stats     = -1;static int cb_stats_all = -1;static int db_opened = 0;/* Services super-user password */static char supass[PASSMAX];/* Is the password currently unset? */static int8 no_supass = 1;/*************************************************************************/static void do_help(User *u);static void do_global(User *u);static void do_stats(User *u);static void do_servermap(User *u);static void do_admin(User *u);static void do_oper(User *u);static void do_os_mode(User *u);static void do_clearmodes(User *u);static void do_clearchan(User *u);static void do_os_kick(User *u);static void do_su(User *u);static void do_set(User *u);static void do_jupe(User *u);static void do_raw(User *u);static void do_update(User *u);static void do_os_quit(User *u);static void do_shutdown(User *u);static void do_restart(User *u);static void do_rehash(User *u);static void do_listignore(User *u);static void do_killclones(User *u);#ifdef DEBUG_COMMANDSstatic void send_server_list(User *u);static void send_channel_list(User *u);static void send_channel_users(User *u);static void send_user_list(User *u);static void send_user_info(User *u);static void do_matchwild(User *u);static void do_setcmode(User *u);#endif/*************************************************************************/static Command cmds[] = {    {"HELP",      do_help,      NULL,             -1,                  -1,-1},    {"GLOBAL",    do_global,    NULL,             OPER_HELP_GLOBAL,    -1,-1},    {"STATS",     do_stats,     NULL,             OPER_HELP_STATS,     -1,-1},    {"UPTIME",    do_stats,     NULL,             OPER_HELP_STATS,     -1,-1},    {"SERVERMAP", do_servermap, NULL,             OPER_HELP_SERVERMAP, -1,-1},    /* Anyone can use the LIST option to the ADMIN and OPER commands; those     * routines check privileges to ensure that only authorized users     * modify the list. */    {"ADMIN",     do_admin,     NULL,             OPER_HELP_ADMIN,     -1,-1},    {"OPER",      do_oper,      NULL,             OPER_HELP_OPER,      -1,-1},    /* Commands for Services opers: */    {"MODE",      do_os_mode,   is_services_oper, OPER_HELP_MODE,      -1,-1},    {"KICK",      do_os_kick,   is_services_oper, OPER_HELP_KICK,      -1,-1},    {"CLEARMODES",do_clearmodes,is_services_oper, OPER_HELP_CLEARMODES,-1,-1},    {"CLEARCHAN", do_clearchan, is_services_oper, OPER_HELP_CLEARCHAN, -1,-1},    {"KILLCLONES",do_killclones,is_services_oper, OPER_HELP_KILLCLONES,-1,-1},    /* Commands for Services admins: */    {"SU",        do_su,        NULL,             OPER_HELP_SU,        -1,-1},    {"SET",       do_set,       is_services_admin,OPER_HELP_SET,       -1,-1},    {"SET READONLY",NULL,       NULL,           OPER_HELP_SET_READONLY,-1,-1},    {"SET DEBUG", NULL,         NULL,             OPER_HELP_SET_DEBUG, -1,-1},    {"SET SUPASS",NULL,         NULL,             OPER_HELP_SET_SUPASS,-1,-1},    {"JUPE",      do_jupe,      is_services_admin,OPER_HELP_JUPE,      -1,-1},    {"UPDATE",    do_update,    is_services_admin,OPER_HELP_UPDATE,    -1,-1},    {"QUIT",      do_os_quit,   is_services_admin,OPER_HELP_QUIT,      -1,-1},    {"SHUTDOWN",  do_shutdown,  is_services_admin,OPER_HELP_SHUTDOWN,  -1,-1},    {"RESTART",   do_restart,   is_services_admin,OPER_HELP_RESTART,   -1,-1},    {"REHASH",    do_rehash,    is_services_admin,OPER_HELP_REHASH,    -1,-1,		IRCSERVICES_CONF },    {"LISTIGNORE",do_listignore,is_services_admin,-1,                  -1,-1},    /* Commands for Services super-user: */    {"RAW",       do_raw,       is_services_root, OPER_HELP_RAW,       -1,-1},#ifdef DEBUG_COMMANDS    {"LISTSERVERS", send_server_list,   is_services_root, -1,-1,-1},    {"LISTCHANS",   send_channel_list,  is_services_root, -1,-1,-1},    {"LISTCHAN",    send_channel_users, is_services_root, -1,-1,-1},    {"LISTUSERS",   send_user_list,     is_services_root, -1,-1,-1},    {"LISTUSER",    send_user_info,     is_services_root, -1,-1,-1},    {"LISTTIMERS",  send_timeout_list,  is_services_root, -1,-1,-1},    {"MATCHWILD",   do_matchwild,       is_services_root, -1,-1,-1},    {"SETCMODE",    do_setcmode,        is_services_root, -1,-1,-1},#endif    /* Fencepost: */    { NULL }};/*************************************************************************//*************************** NickServ imports ****************************//*************************************************************************//* This is somewhat inefficient, but since it's not called often it should * do for the time being.  FIXME: find a more general way to implement * intermodule function imports. (cf. database/version4's extsyms.[ch]) */#define _get_ngi local__get_ngistatic NickGroupInfo *local__get_ngi(NickInfo *ni, const char *file, int line){    typeof(_get_ngi) *p__get_ngi;    if (!module_nickserv)	return NULL;    p__get_ngi = get_module_symbol(module_nickserv, "_get_ngi");    if (!p__get_ngi) {	module_log("Unable to find symbol `_get_ngi' in module"		   " `nickserv/main' (called from %s:%d)", file, line);	return NULL;    }    return p__get_ngi(ni, file, line);}/*************************************************************************//***************************** Main routines *****************************//*************************************************************************//* Introduce the OperServ pseudoclient and related clients. */static int introduce_operserv(const char *nick){    if (!nick || irc_stricmp(nick, s_OperServ) == 0) {	char modebuf[BUFSIZE];	snprintf(modebuf, sizeof(modebuf), "oi%s", pseudoclient_modes);	send_nick(s_OperServ, ServiceUser, ServiceHost, ServerName,		  desc_OperServ, modebuf);	if (nick)	    return 1;    }    if (!nick || irc_stricmp(nick, s_GlobalNoticer) == 0) {	char modebuf[BUFSIZE];	snprintf(modebuf, sizeof(modebuf), "oi%s", pseudoclient_modes);	send_nick(s_GlobalNoticer, ServiceUser, ServiceHost, ServerName,		  desc_GlobalNoticer, modebuf);	if (nick)	    return 1;    }    return 0;}/*************************************************************************//* Main OperServ routine. */static int operserv(const char *source, const char *target, char *buf){    char *cmd;    const char *s;    User *u = get_user(source);    if (irc_stricmp(target, s_OperServ) != 0)	return 0;    if (!u) {	module_log("user record for %s not found", source);	notice(s_OperServ, source, "Access denied.");	if (WallBadOS)	    wallops(s_OperServ, "Denied access to %s from %s (user record"	                        " missing)", s_OperServ, source);	return 1;    }    if (!is_oper(u)) {	notice_lang(s_OperServ, u, ACCESS_DENIED);	if (WallBadOS)	    wallops(s_OperServ, "Denied access to %s from %s (non-oper)",		    s_OperServ, source);	module_log("Non-oper %s!%s@%s sent: %s",		   u->nick, u->username, u->host, buf);	return 1;    }    /* Don't log stuff that might be passwords */    if (strnicmp(buf, "SU ", 3) == 0) {	module_log("%s: SU xxxxxx", source);    } else if (strnicmp(buf, "SET ", 4) == 0	       && (s = stristr(buf, "SUPASS")) != NULL	       && strspn(buf+4, " ") == s-(buf+4)) {	/* All that was needed to make sure someone doesn't fool us with	 * "SET READONLY ON SUPASS".  Which wouldn't work anyway, but we	 * ought to log it properly... */	module_log("%s: SET SUPASS xxxxxx", source);    } else {	module_log("%s: %s", source, buf);    }    cmd = strtok(buf, " ");    if (!cmd) {	return 1;    } else if (stricmp(cmd, "\1PING") == 0) {	if (!(s = strtok(NULL, "")))	    s = "\1";	notice(s_OperServ, source, "\1PING %s", s);    } else {	if (call_callback_2(module, cb_command, u, cmd) <= 0)	    run_cmd(s_OperServ, u, module, cmd);    }    return 1;}/*************************************************************************//* Return a /WHOIS response for OperServ or the global noticer. */static int operserv_whois(const char *source, char *who, char *extra){    if (irc_stricmp(who, s_OperServ) == 0) {	send_cmd(ServerName, "311 %s %s %s %s * :%s", source, who,		 ServiceUser, ServiceHost, desc_OperServ);    } else if (irc_stricmp(who, s_GlobalNoticer) == 0) {	send_cmd(ServerName, "311 %s %s %s %s * :%s", source, who,		 ServiceUser, ServiceHost, desc_GlobalNoticer);    } else {	return 0;    }    send_cmd(ServerName, "312 %s %s %s :%s", source, who,	     ServerName, ServerDesc);    send_cmd(ServerName, "313 %s %s :is a network service", source, who);    send_cmd(ServerName, "318 %s %s End of /WHOIS response.", source, who);    return 1;}/*************************************************************************//* Watch for umode +o and send wallops.  This callback is only activated if * WallOper is specified in modules.conf. */static int wall_oper_callback(User *u, int modechar, int add){    if (modechar == 'o' && add)	wallops(s_OperServ, "\2%s\2 is now an IRC operator.", u->nick);    return 0;}/*************************************************************************//* Callback for saving data. */static int do_save_data(void){    sync_operserv_db(OperDBName);    return 0;}/*************************************************************************//* Callback for NickServ REGISTER/LINK check; we disallow * registration/linking of the OperServ pseudoclient nickname. */static int do_reglink_check(const User *u, const char *nick,			    const char *pass, const char *email){    return irc_stricmp(nick, s_OperServ) == 0	|| irc_stricmp(nick, s_GlobalNoticer) == 0;}/*************************************************************************//**************************** Privilege checks ***************************//*************************************************************************//* Does the given user have Services super-user privileges? */EXPORT_FUNC(is_services_root)int is_services_root(User *u){    NickInfo *ni;    int rootid;    static int warned_ni = 0, warned_id = 0;    if (u->flags & UF_SERVROOT)	return 1;    if (!(ni = get_nickinfo(ServicesRoot))) {	if (!warned_ni) {	    wallops(s_OperServ, "Warning: Services super-user nickname %s"		    " is not registered", ServicesRoot);	    warned_ni = 1;	}	module_log("warning: ServicesRoot nickname not registered");	return 0;    }    warned_ni = 0;    if (!(rootid = ni->nickgroup)) {	if (!warned_id) {	    wallops(s_OperServ, "Warning: Services super-user nickname %s"		    " is forbidden or not properly registered", ServicesRoot);	    warned_id = 1;	}	module_log("warning: ServicesRoot nickname forbidden or registered"		   " data corrupt");	return 0;    }    if (!is_oper(u) || !u->ni || u->ni->nickgroup != rootid)	return 0;    if (user_identified(u))	return 1;    return 0;}/*************************************************************************//* Does the given user have Services admin privileges? */EXPORT_FUNC(is_services_admin)int is_services_admin(User *u){    if (!is_oper(u) || !user_identified(u))	return 0;    if (is_services_root(u))	return 1;    return u->ngi && u->ngi != NICKGROUPINFO_INVALID		  && u->ngi->os_priv >= NP_SERVADMIN;}/*************************************************************************//* Does the given user have Services oper privileges? */EXPORT_FUNC(is_services_oper)int is_services_oper(User *u){    if (!is_oper(u) || !user_identified(u))	return 0;    if (is_services_root(u))	return 1;    return u->ngi && u->ngi != NICKGROUPINFO_INVALID		  && u->ngi->os_priv >= NP_SERVOPER;}/*************************************************************************//* Is the given nick a Services admin/root nick? *//* NOTE: Do not use this to check if a user who is online is a services * admin or root. This function only checks if a user has the ABILITY to be * a services admin. Rather use is_services_admin(User *u). -TheShadow */EXPORT_FUNC(nick_is_services_admin)int nick_is_services_admin(NickInfo *ni){    NickGroupInfo *ngi;    if (!ni || !(ngi = get_ngi(ni)))	return 0;    if (stricmp(ni->nick, ServicesRoot) == 0)	return 1;    return ngi->os_priv >= NP_SERVADMIN;}/*************************************************************************//********************** Admin/oper list modification *********************//*************************************************************************/#define LIST_ADMIN	0#define LIST_OPER	1#define MSG_EXISTS	0#define MSG_EXISTS_NEXT	1#define MSG_ADDED	2#define MSG_TOOMANY	3#define MSG_REMOVED	4#define MSG_NOTFOUND	5static int privlist_msgs[2][6] = {    { OPER_ADMIN_EXISTS,      0,      OPER_ADMIN_ADDED,      OPER_ADMIN_TOO_MANY,      OPER_ADMIN_REMOVED,      OPER_ADMIN_NOT_FOUND,    },    { OPER_OPER_EXISTS,      OPER_ADMIN_EXISTS,      OPER_OPER_ADDED,      OPER_OPER_TOO_MANY,      OPER_OPER_REMOVED,      OPER_OPER_NOT_FOUND,    },};/*************************************************************************//* Add a nick to the Services admin/oper list.  u is the command sender. */static void privlist_add(User *u, int listid, const char *nick){    int16 level = (listid==LIST_ADMIN ? NP_SERVADMIN : NP_SERVOPER);    int16 nextlevel = (listid==LIST_ADMIN ? 0 : NP_SERVADMIN);    int *msgs = privlist_msgs[listid];    NickInfo *ni;    NickGroupInfo *ngi;    if (!(ni = get_nickinfo(nick))) {	notice_lang(s_OperServ, u, NICK_X_NOT_REGISTERED, nick);	return;    }    if (!(ngi = get_ngi(ni))) {	notice_lang(s_OperServ, u, INTERNAL_ERROR);	return;    }    if (nextlevel && ngi->os_priv >= nextlevel) {	notice_lang(s_OperServ, u, msgs[MSG_EXISTS_NEXT], nick);	return;    } else if (ngi->os_priv >= level) {	notice_lang(s_OperServ, u, msgs[MSG_EXISTS], nick);	return;    }    ngi->os_priv = level;    put_nickgroupinfo(ngi);    notice_lang(s_OperServ, u, msgs[MSG_ADDED], nick);    if (readonly)	notice_lang(s_OperServ, u, READ_ONLY_MODE);    else	put_nickgroupinfo(ngi);}/*************************************************************************//* Remove a nick from the Services admin/oper list. */static void privlist_rem(User *u, int listid, const char *nick){    int16 level = (listid==LIST_ADMIN ? NP_SERVADMIN : NP_SERVOPER);    int16 nextlevel = (listid==LIST_ADMIN ? 0 : NP_SERVADMIN);    int *msgs = privlist_msgs[listid];    NickInfo *ni;    NickGroupInfo *ngi;    if (!(ni = get_nickinfo(nick))) {	notice_lang(s_OperServ, u, NICK_X_NOT_REGISTERED, nick);	return;    }    if (!(ngi = get_ngi(ni))) {	notice_lang(s_OperServ, u, INTERNAL_ERROR);	return;    }    if (ngi->os_priv < level || (nextlevel && ngi->os_priv >= nextlevel)) {	notice_lang(s_OperServ, u, msgs[MSG_NOTFOUND], nick);	return;    }    ngi->os_priv = 0;    put_nickgroupinfo(ngi);    notice_lang(s_OperServ, u, msgs[MSG_REMOVED], nick);    if (readonly)	notice_lang(s_OperServ, u, READ_ONLY_MODE);    else	put_nickgroupinfo(ngi);}/*************************************************************************//*********************** OperServ command functions **********************//*************************************************************************//* HELP command. */static void do_help(User *u){    char *cmd = strtok_remaining();    Module *mod;    if (!cmd) {	notice_help(s_OperServ, u, OPER_HELP);    } else if (call_callback_2(module, cb_help, u, cmd) > 0) {	return;    } else if (stricmp(cmd, "COMMANDS") == 0) {	notice_help(s_OperServ, u, OPER_HELP_COMMANDS);	call_callback_2(module, cb_help_cmds, u, 0);	notice_help(s_OperServ, u, OPER_HELP_COMMANDS_SERVOPER);	if ((mod = find_module("operserv/akill"))) {	    int *p_EnableExclude;	    notice_help(s_OperServ, u, OPER_HELP_COMMANDS_AKILL);	    p_EnableExclude = get_module_symbol(mod, "EnableExclude");	    if (p_EnableExclude && *p_EnableExclude)		notice_help(s_OperServ, u, OPER_HELP_COMMANDS_EXCLUDE);	}	if (find_module("operserv/sline"))	    notice_help(s_OperServ, u, OPER_HELP_COMMANDS_SLINE);	if (find_module("operserv/sessions"))	    notice_help(s_OperServ, u, OPER_HELP_COMMANDS_SESSION);	if (find_module("operserv/news"))	    notice_help(s_OperServ, u, OPER_HELP_COMMANDS_NEWS);	call_callback_2(module, cb_help_cmds, u, 1);	notice_help(s_OperServ, u, OPER_HELP_COMMANDS_SERVADMIN);	call_callback_2(module, cb_help_cmds, u, 2);	notice_help(s_OperServ, u, OPER_HELP_COMMANDS_SERVROOT);	if (AllowRaw)	    notice_help(s_OperServ, u, OPER_HELP_COMMANDS_RAW);	call_callback_2(module, cb_help_cmds, u, 3);    } else {	help_cmd(s_OperServ, u, module, cmd);    }}/*************************************************************************//* Global notice sending via GlobalNoticer. */static void do_global(User *u){    char *msg = strtok_remaining();    if (!msg) {	syntax_error(s_OperServ, u, "GLOBAL", OPER_GLOBAL_SYNTAX);	return;    }    notice_all(s_GlobalNoticer, "%s", msg);}/*************************************************************************//* STATS command. */static void do_stats(User *u){    time_t uptime = time(NULL) - start_time;    char *extra = strtok_remaining();    int days = uptime/86400, hours = (uptime/3600)%24,        mins = (uptime/60)%60, secs = uptime%60;    char timebuf[BUFSIZE];    if (extra && stricmp(extra, "UPTIME") == 0)	extra = NULL;    if (extra && stricmp(extra, "ALL") != 0) {	if (stricmp(extra, "RESET") == 0) {	    int i;	    maxusercnt = usercnt;	    maxusertime = time(NULL);	    notice_lang(s_OperServ, u, OPER_STATS_RESET_USER_COUNT);	    if ((i = OSDATA_MAXUSERCNT,  !put_operserv_data(i, &maxusercnt))	     || (i = OSDATA_MAXUSERTIME, !put_operserv_data(i, &maxusertime))	    ) {		module_log("STATS RESET: put_operserv_data(%d) failed", i);		wallops(s_OperServ, "Unable to update OperServ data!");	    }	} else if (call_callback_2(module, cb_stats, u, extra) > 0) {	    /* nothing */	} else if (stricmp(extra, "NETWORK") == 0) {	    uint32 read, written, socksize, totalsize;	    int ratio1, ratio2;	    sock_rwstat(servsock, &read, &written);	    sock_bufstat(servsock, &socksize, &totalsize, &ratio1, &ratio2);	    socksize /= 1024;	    totalsize /= 1024;	    notice_lang(s_OperServ, u, OPER_STATS_KBYTES_READ, read);	    notice_lang(s_OperServ, u, OPER_STATS_KBYTES_WRITTEN, written);	    if (ratio1)		notice_lang(s_OperServ, u, OPER_STATS_NETBUF_SOCK_PERCENT,			    socksize, ratio1);	    else		notice_lang(s_OperServ, u, OPER_STATS_NETBUF_SOCK, socksize);	    if (ratio2)		notice_lang(s_OperServ, u, OPER_STATS_NETBUF_TOTAL_PERCENT,			    totalsize, ratio2);	    else		notice_lang(s_OperServ, u, OPER_STATS_NETBUF_TOTAL, totalsize);	} else {	    notice_lang(s_OperServ, u, OPER_STATS_UNKNOWN_OPTION,			strupper(extra));	}	return;    }    notice_lang(s_OperServ, u, OPER_STATS_CURRENT_USERS, usercnt, opcnt);    strftime_lang(timebuf, sizeof(timebuf), u->ngi,		  STRFTIME_DATE_TIME_FORMAT, maxusertime);    notice_lang(s_OperServ, u, OPER_STATS_MAX_USERS, maxusercnt, timebuf);    if (days >= 1) {	const char *str = getstring(u->ngi, days!=1 ? STR_DAYS : STR_DAY);	notice_lang(s_OperServ, u, OPER_STATS_UPTIME_DHMS,		days, str, hours, mins, secs);    } else {	notice_lang(s_OperServ, u, OPER_STATS_UPTIME_HM_MS,		    maketime(u->ngi, uptime, MT_DUALUNIT|MT_SECONDS));    }    if (extra && stricmp(extra, "ALL") == 0 && is_services_admin(u)) {	long count, mem;	get_user_stats(&count, &mem);	notice_lang(s_OperServ, u, OPER_STATS_ALL_USER_MEM,			count, (mem+512) / 1024);	get_channel_stats(&count, &mem);	notice_lang(s_OperServ, u, OPER_STATS_ALL_CHANNEL_MEM,			count, (mem+512) / 1024);	get_server_stats(&count, &mem);	notice_lang(s_OperServ, u, OPER_STATS_ALL_SERVER_MEM,			count, (mem+512) / 1024);	call_callback_2(module, cb_stats_all, u, s_OperServ);    }}/*************************************************************************//* Server map display. */static void map_server(User *u, Server *s, int level);  /* defined below */static void do_servermap(User *u){    Server *root = get_server("");    if (!root) {	module_log("BUG: root server not found for SERVERMAP");	notice_lang(s_OperServ, u, INTERNAL_ERROR);	return;    }    map_server(u, root, 0);}/* Recursively print the server map.  This routine prints the given server * at level `level' of indentation (0 = left margin), then prints its * children in child->sibling->sibling... order. */static void map_server(User *u, Server *s, int level){    static int need_bar[MAXMAPLEVEL]; /* which levs need a continuation bar? */    static const char *indentstr = "  +-- ";    static const char *barstr    = "  |   ";    static const char *nobarstr  = "      ";    char buf[BUFSIZE], *ptr;    int i;    ptr = buf;    *ptr = 0;    i = 0;    while (i < level-1) {	ptr += snprintf(ptr, sizeof(buf)-(ptr-buf), "%s",			need_bar[i] ? barstr : nobarstr);	i++;    }    if (level)	ptr += snprintf(ptr, sizeof(buf)-(ptr-buf), "%s", indentstr);    notice(s_OperServ, u->nick, "%s%s%s", buf,	   s ? (*s->name ? s->name : ServerName) : "...",	   (s && s->fake) ? "(*)" : "");    if (s && s->child) {	if (level+1 >= MAXMAPLEVEL) {	    map_server(u, NULL, level+1);	    return;	}	for (s = s->child; s; s = s->sibling) {	    need_bar[level] = (s->sibling != NULL);	    map_server(u, s, level+1);	}    }}/*************************************************************************//* Channel mode changing (MODE command). */static void do_os_mode(User *u){    int argc;    char **argv;    char *s = strtok_remaining();    char *chan, *modes;    Channel *c;    if (!s) {	syntax_error(s_OperServ, u, "MODE", OPER_MODE_SYNTAX);	return;    }    chan = s;    s += strcspn(s, " ");    if (!*s) {	syntax_error(s_OperServ, u, "MODE", OPER_MODE_SYNTAX);	return;    }    *s = 0;    modes = (s+1) + strspn(s+1, " ");    if (!*modes) {	syntax_error(s_OperServ, u, "MODE", OPER_MODE_SYNTAX);	return;    }    if (!(c = get_channel(chan))) {	notice_lang(s_OperServ, u, CHAN_X_NOT_IN_USE, chan);    } else if (c->bouncy_modes) {	notice_lang(s_OperServ, u, OPER_BOUNCY_MODES);	return;    } else {	send_cmd(s_OperServ, "MODE %s %s", chan, modes);	if (WallOSChannel)	    wallops(s_OperServ, "%s used MODE %s on %s", u->nick, modes, chan);	*s = ' ';	argc = split_buf(chan, &argv, 1);	do_cmode(s_OperServ, argc, argv);    }}/*************************************************************************//* Clear all modes from a channel. */static void do_clearmodes(User *u){    char *s;    char *chan = strtok(NULL, " ");    Channel *c;    int all = 0;    if (!chan) {	syntax_error(s_OperServ, u, "CLEARMODES", OPER_CLEARMODES_SYNTAX);    } else if (!(c = get_channel(chan))) {	notice_lang(s_OperServ, u, CHAN_X_NOT_IN_USE, chan);    } else if (c->bouncy_modes) {	notice_lang(s_OperServ, u, OPER_BOUNCY_MODES);	return;    } else {	s = strtok(NULL, " ");	if (s) {	    if (stricmp(s, "ALL") == 0) {		all = 1;	    } else {		syntax_error(s_OperServ,u,"CLEARMODES",OPER_CLEARMODES_SYNTAX);		return;	    }	}	if (WallOSChannel)	    wallops(s_OperServ, "%s used CLEARMODES%s on %s",			u->nick, all ? " ALL" : "", chan);	if (all) {	    clear_channel(c, CLEAR_UMODES, (void *)MODE_ALL);	    clear_channel(c, CLEAR_CMODES, NULL);	    notice_lang(s_OperServ, u, OPER_CLEARMODES_ALL_DONE, chan);	} else {	    clear_channel(c, CLEAR_CMODES, NULL);	    notice_lang(s_OperServ, u, OPER_CLEARMODES_DONE, chan);	}    }}/*************************************************************************//* Remove all users from a channel. */static void do_clearchan(User *u){    char *chan = strtok(NULL, " ");    Channel *c;    char buf[BUFSIZE];    if (!chan) {	syntax_error(s_OperServ, u, "CLEARCHAN", OPER_CLEARCHAN_SYNTAX);    } else if (!(c = get_channel(chan))) {	notice_lang(s_OperServ, u, CHAN_X_NOT_IN_USE, chan);    } else if (c->bouncy_modes) {	notice_lang(s_OperServ, u, OPER_BOUNCY_MODES);	return;    } else {	if (WallOSChannel)	    wallops(s_OperServ, "%s used CLEARCHAN on %s", u->nick, chan);	snprintf(buf, sizeof(buf), "CLEARCHAN by %s", u->nick);	clear_channel(c, CLEAR_USERS, buf);	notice_lang(s_OperServ, u, OPER_CLEARCHAN_DONE, chan);    }}/*************************************************************************//* Kick a user from a channel (KICK command). */static void do_os_kick(User *u){    char *argv[3];    char *chan, *nick, *s;    Channel *c;    chan = strtok(NULL, " ");    nick = strtok(NULL, " ");    s = strtok_remaining();    if (!chan || !nick || !s) {	syntax_error(s_OperServ, u, "KICK", OPER_KICK_SYNTAX);	return;    }    if (!(c = get_channel(chan))) {	notice_lang(s_OperServ, u, CHAN_X_NOT_IN_USE, chan);    } else if (c->bouncy_modes) {	notice_lang(s_OperServ, u, OPER_BOUNCY_MODES);	return;    }    send_cmd(s_OperServ, "KICK %s %s :%s (%s)", chan, nick, u->nick, s);    if (WallOSChannel)	wallops(s_OperServ, "%s used KICK on %s/%s", u->nick, nick, chan);    argv[0] = chan;    argv[1] = nick;    argv[2] = s;    do_kick(s_OperServ, 3, argv);}/*************************************************************************//* Services admin list viewing/modification. */static void do_admin(User *u){    const char *cmd, *nick;    if (!module_nickserv) {	notice_lang(s_OperServ, u, OPER_ADMIN_NO_NICKSERV);	return;    }    cmd = strtok(NULL, " ");    if (!cmd)	cmd = "";    if (stricmp(cmd, "ADD") == 0) {	if (!is_services_root(u)) {	    notice_lang(s_OperServ, u, PERMISSION_DENIED);	    return;	}	nick = strtok(NULL, " ");	if (nick)	    privlist_add(u, LIST_ADMIN, nick);	else	    syntax_error(s_OperServ, u, "ADMIN", OPER_ADMIN_ADD_SYNTAX);    } else if (stricmp(cmd, "DEL") == 0) {	if (!is_services_root(u)) {	    notice_lang(s_OperServ, u, PERMISSION_DENIED);	    return;	}	nick = strtok(NULL, " ");	if (nick)	    privlist_rem(u, LIST_ADMIN, nick);	else	    syntax_error(s_OperServ, u, "ADMIN", OPER_ADMIN_DEL_SYNTAX);    } else if (stricmp(cmd, "LIST") == 0) {	NickGroupInfo *ngi;	notice_lang(s_OperServ, u, OPER_ADMIN_LIST_HEADER);	for (ngi = first_nickgroupinfo(); ngi; ngi = next_nickgroupinfo()) {	    if (ngi->os_priv >= NP_SERVADMIN)		notice(s_OperServ, u->nick, "%s", ngi_mainnick(ngi));	}    } else {	syntax_error(s_OperServ, u, "ADMIN", OPER_ADMIN_SYNTAX);    }}/*************************************************************************//* Services oper list viewing/modification. */static void do_oper(User *u){    const char *cmd, *nick;    if (!module_nickserv) {	notice_lang(s_OperServ, u, OPER_OPER_NO_NICKSERV);	return;    }    cmd = strtok(NULL, " ");    if (!cmd)	cmd = "";    if (stricmp(cmd, "ADD") == 0) {	if (!is_services_admin(u)) {	    notice_lang(s_OperServ, u, PERMISSION_DENIED);	    return;	}	nick = strtok(NULL, " ");	if (nick)	    privlist_add(u, LIST_OPER, nick);	else	    syntax_error(s_OperServ, u, "OPER", OPER_OPER_ADD_SYNTAX);    } else if (stricmp(cmd, "DEL") == 0) {	if (!is_services_admin(u)) {	    notice_lang(s_OperServ, u, PERMISSION_DENIED);	    return;	}	nick = strtok(NULL, " ");	if (nick)	    privlist_rem(u, LIST_OPER, nick);	else	    syntax_error(s_OperServ, u, "OPER", OPER_OPER_DEL_SYNTAX);    } else if (stricmp(cmd, "LIST") == 0) {	NickGroupInfo *ngi;	notice_lang(s_OperServ, u, OPER_OPER_LIST_HEADER);	for (ngi = first_nickgroupinfo(); ngi; ngi = next_nickgroupinfo()) {	    if (ngi->os_priv >= NP_SERVOPER && ngi->os_priv < NP_SERVADMIN)		notice(s_OperServ, u->nick, "%s", ngi_mainnick(ngi));	}    } else {	syntax_error(s_OperServ, u, "OPER", OPER_OPER_SYNTAX);    }}/*************************************************************************//* Obtain Services root privileges.  We check permissions here instead of * letting run_cmd() do it for us so we can send out warnings when a * non-admin tries to use the command, and allow anyone to use it when * NickServ isn't loaded. */static void do_su(User *u){    char *password = strtok_remaining();    int res;    if (module_nickserv && !is_services_admin(u)) {	wallops(s_OperServ, "\2NOTICE:\2 %s!%s@%s attempted to use SU "		"command (not Services admin)",		u->nick, u->username, u->host);	notice_lang(s_OperServ, u, PERMISSION_DENIED);	return;    }    if (!password) {	syntax_error(s_OperServ, u, "SU", OPER_SU_SYNTAX);    } else if (no_supass) {	notice_lang(s_OperServ, u, OPER_SU_NO_PASSWORD);    } else if ((res = check_password(password, supass)) < 0) {	notice_lang(s_OperServ, u, OPER_SU_FAILED);    } else if (res == 0) {	module_log("Failed SU by %s!%s@%s", u->nick, u->username, u->host);	wallops(s_OperServ, "\2NOTICE:\2 Failed SU by %s!%s@%s",		u->nick, u->username, u->host);	bad_password(s_OperServ, u, "Services root");    } else {	u->flags |= UF_SERVROOT;	if (WallSU)	    wallops(s_OperServ,		    "%s!%s@%s obtained Services super-user privileges",		    u->nick, u->username, u->host);	notice_lang(s_OperServ, u, OPER_SU_SUCCEEDED);    }}/*************************************************************************//* Set various Services runtime options. */static void do_set(User *u){    char *option = strtok(NULL, " ");    char *setting = strtok_remaining();    if (!option || (!setting && stricmp(option, "SUPASS") != 0)) {	syntax_error(s_OperServ, u, "SET", OPER_SET_SYNTAX);	return;    }    if (call_callback_3(module, cb_set, u, option, setting) > 0)	return;    if (stricmp(option, "IGNORE") == 0) {	if (stricmp(setting, "on") == 0) {	    allow_ignore = 1;	    notice_lang(s_OperServ, u, OPER_SET_IGNORE_ON);	} else if (stricmp(setting, "off") == 0) {	    allow_ignore = 0;	    notice_lang(s_OperServ, u, OPER_SET_IGNORE_OFF);	} else {	    notice_lang(s_OperServ, u, OPER_SET_IGNORE_ERROR);	}    } else if (stricmp(option, "READONLY") == 0) {	if (stricmp(setting, "on") == 0) {	    readonly = 1;	    log("Read-only mode activated");	    close_log();	    notice_lang(s_OperServ, u, OPER_SET_READONLY_ON);	} else if (stricmp(setting, "off") == 0) {	    readonly = 0;	    open_log();	    log("Read-only mode deactivated");	    notice_lang(s_OperServ, u, OPER_SET_READONLY_OFF);	} else {	    notice_lang(s_OperServ, u, OPER_SET_READONLY_ERROR);	}    } else if (stricmp(option, "DEBUG") == 0) {	if (stricmp(setting, "on") == 0) {	    debug = 1;	    log("Debug mode activated");	    notice_lang(s_OperServ, u, OPER_SET_DEBUG_ON);	} else if (stricmp(setting, "off") == 0 ||				(*setting == '0' && atoi(setting) == 0)) {	    log("Debug mode deactivated");	    debug = 0;	    notice_lang(s_OperServ, u, OPER_SET_DEBUG_OFF);	} else if (isdigit(*setting) && atoi(setting) > 0) {	    debug = atoi(setting);	    log("Debug mode activated (level %d)", debug);	    notice_lang(s_OperServ, u, OPER_SET_DEBUG_LEVEL, debug);	} else {	    notice_lang(s_OperServ, u, OPER_SET_DEBUG_ERROR);	}    } else if (stricmp(option, "SUPASS") == 0) {	int len;	char newpass[PASSMAX];	if (!is_services_root(u)) {	    notice_lang(s_OperServ, u, PERMISSION_DENIED);	    return;	}	if (!setting) {	    no_supass = 1;	    put_operserv_data(OSDATA_SUPASS, NULL);	    notice_lang(s_OperServ, u, OPER_SET_SUPASS_NONE);	    return;	}	len = strlen(setting);	if (len >= PASSMAX) {	    memset(setting+PASSMAX-1, 0, len-(PASSMAX-1));	    len = PASSMAX-1;	    notice_lang(s_OperServ, u, PASSWORD_TRUNCATED, len);	}	if (encrypt(setting, len, newpass, PASSMAX) < 0) {	    notice_lang(s_OperServ, u, OPER_SET_SUPASS_FAILED);	} else {	    no_supass = 0;	    memcpy(supass, newpass, PASSMAX);	    put_operserv_data(OSDATA_SUPASS, supass);	    notice_lang(s_OperServ, u, OPER_SET_SUPASS_OK);	}    } else {	notice_lang(s_OperServ, u, OPER_SET_UNKNOWN_OPTION, option);    }}/*************************************************************************/static void do_jupe(User *u){    char *jserver = strtok(NULL, " ");    char *reason = strtok_remaining();    char buf[BUFSIZE];    Server *server;    if (!jserver) {	syntax_error(s_OperServ, u, "JUPE", OPER_JUPE_SYNTAX);    } else if (!strchr(jserver, '.')) {	notice_lang(s_OperServ, u, OPER_JUPE_INVALID_NAME);    } else if ((server = get_server(jserver)) != NULL && server->fake) {	notice_lang(s_OperServ, u, OPER_JUPE_ALREADY_JUPED, jserver);    } else {	wallops(s_OperServ, "\2Juping\2 %s by request of \2%s\2.",		jserver, u->nick);	if (reason)	    snprintf(buf, sizeof(buf), "%s (%s)", reason, u->nick);	else	    snprintf(buf, sizeof(buf), "Jupitered by %s", u->nick);	if (server) {	    char *argv[2];	    argv[0] = jserver;	    argv[1] = buf;	    send_cmd(ServerName, "SQUIT %s :%s", jserver, buf);	    do_squit(ServerName, 2, argv);	}	send_server_remote(jserver, buf);	do_server("", -1, &jserver);    }}/*************************************************************************/static void do_raw(User *u){    char *text = strtok_remaining();    if (!text)	syntax_error(s_OperServ, u, "RAW", OPER_RAW_SYNTAX);    else	send_cmd(NULL, "%s", text);}/*************************************************************************//* Callback and data used to send "update complete" message */static int do_update_complete(int successful);static User *update_sender = NULL;static void do_update(User *u){    char *param = strtok_remaining();    if (param && *param) {	if (stricmp(param, "FORCE") != 0) {	    syntax_error(s_OperServ, u, "UPDATE", OPER_UPDATE_SYNTAX);	    return;	} else if (!is_services_admin(u)) {	    notice_lang(s_OperServ, u, PERMISSION_DENIED);	    return;	}	switch (is_data_locked()) {	  case 1:	    if (!unlock_data()) {		module_log_perror("UPDATE FORCE lock removal failed");		notice_lang(s_OperServ, u, OPER_UPDATE_FORCE_FAILED);		return;	    }	    break;	  case -1:	    module_log_perror("UPDATE FORCE lock check failed");	    break;	}    }    notice_lang(s_OperServ, u, OPER_UPDATING);    save_data = 1;    update_sender = u;  /* to send to when the update completes--it's safe			 * to save this pointer since no more data will be			 * processed before we use it again */    add_callback(NULL, "save data complete", do_update_complete);}static int do_update_complete(int successful){    if (update_sender) {	if (successful)	    notice_lang(s_OperServ, update_sender, OPER_UPDATE_COMPLETE);	else	    notice_lang(s_OperServ, update_sender, OPER_UPDATE_FAILED);	update_sender = NULL;    } else {	log("BUG: no sender in do_update_complete()");    }    remove_callback(NULL, "save data complete", do_update_complete);    return 0;}/*************************************************************************/static void do_os_quit(User *u){    snprintf(quitmsg, sizeof(quitmsg),	     "QUIT command received from %s", u->nick);    quitting = 1;}/*************************************************************************/static void do_shutdown(User *u){    snprintf(quitmsg, sizeof(quitmsg),	    "SHUTDOWN command received from %s", u->nick);    save_data = 1;    delayed_quit = 1;}/*************************************************************************/static void do_restart(User *u){    snprintf(quitmsg, sizeof(quitmsg),	     "RESTART command received from %s", u->nick);    save_data = 1;    delayed_quit = 2;}/*************************************************************************/static void do_rehash(User *u){    /* Don't let ourselves be unloaded */    modules_allow_use_self++;    use_module(module);    notice_lang(s_OperServ, u, OPER_REHASHING);    wallops(NULL, "Rehashing configuration files (REHASH from %s)", u->nick);    if (reconfigure())	notice_lang(s_OperServ, u, OPER_REHASHED);    else	notice_lang(s_OperServ, u, OPER_REHASH_ERROR);    /* Restore normal module behavior */    unuse_module(module);    modules_allow_use_self--;}/*************************************************************************/static void do_listignore(User *u){    int sent_header = 0;    IgnoreData *id;    for (id = first_ignore(); id; id = next_ignore()) {	if (!sent_header) {	    notice_lang(s_OperServ, u, OPER_IGNORE_LIST);	    sent_header = 1;	}	notice(s_OperServ, u->nick, "%ld %s", (long)id->time, id->who);    }    if (!sent_header)	notice_lang(s_OperServ, u, OPER_IGNORE_LIST_EMPTY);}/*************************************************************************//* Kill all users matching a certain host.  The host is obtained from the * supplied nick.  The raw hostmask is not supplied with the command in an * effort to prevent abuse and mistakes from being made--which might cause * *.com to be killed. It also makes it very quick and simple to use--which * is usually what you want when someone starts loading numerous clones.  In * addition to killing the clones, we add a temporary autokill to prevent * them from immediately reconnecting. * Syntax: KILLCLONES nick * -TheShadow (29 Mar 1999) * * Added KillClonesAutokill support  --AC */static void do_killclones(User *u){    char *clonenick = strtok(NULL, " ");    User *cloneuser;    typeof(create_akill) *p_create_akill =	module_akill ? get_module_symbol(module_akill,"create_akill") : NULL;    if (!clonenick) {	notice_lang(s_OperServ, u, OPER_KILLCLONES_SYNTAX);    } else if (!(cloneuser = get_user(clonenick))) {	notice_lang(s_OperServ, u, OPER_KILLCLONES_UNKNOWN_NICK, clonenick);    } else {	char clonemask[BUFSIZE];	User *user;	int count = 0;	snprintf(clonemask, sizeof(clonemask), "*!*@%s", cloneuser->host);	for (user = first_user(); user; user = next_user()) {	    if (match_usermask(clonemask, user) != 0) {		char killreason[32];		count++;		snprintf(killreason, sizeof(killreason),			 "Cloning [%d]", count);		kill_user(NULL, user->nick, killreason);	    }	}	module_log("KILLCLONES: %d clone(s) matching %s killed.",		   count, clonemask);	if (KillClonesAutokill && p_create_akill) {	    /* Add autokill if it doesn't exist.  Use get_matching_maskdata()	     * so that we find both exact matches and more general masks. */	    if (!get_matching_maskdata(MD_AKILL, clonemask+2)) {		/* No mask fits these clones, so add a new one. */		const char akillreason[] = "Temporary KILLCLONES akill.";		p_create_akill(clonemask+2, akillreason, u->nick,			       time(NULL) + KillClonesAutokillExpire);		wallops(s_OperServ,			getstring(NULL,OPER_KILLCLONES_KILLED_AKILL),			u->nick, clonemask, count, clonemask+2);	    } else {		/* There's already a matching mask, so don't add a new one. */		wallops(s_OperServ, getstring(NULL,OPER_KILLCLONES_KILLED),			u->nick, clonemask, count);	    }	} else {	    /* Autokill option not set or module not available. */	    wallops(s_OperServ, getstring(NULL,OPER_KILLCLONES_KILLED),		    u->nick, clonemask, count);	}    }}/*************************************************************************/#ifdef DEBUG_COMMANDS/* All commands from here down are enabled only when DEBUG_COMMANDS is * also enabled. *//*************************************************************************//* Send the current list of servers to the given user. */void send_server_list(User *user){    Server *server;    for (server = first_server(); server; server = next_server()) {	notice(s_OperServ, user->nick, "%s fake:%d hub:%s child:%s sibling:%s",	       server->name, server->fake,	       server->hub ? server->hub->name : "-",	       server->child ? server->child->name : "-",	       server->sibling ? server->sibling->name : "-");    }}/*************************************************************************//* Send the current list of channels to the named user. */static void send_channel_list(User *user){    Channel *c;    char buf[BUFSIZE], *end;    struct c_userlist *u;    const char *source = user->nick;    for (c = first_channel(); c; c = next_channel()) {	notice(s_OperServ, source, "%s %ld +%s %d %s :%s",	       c->name, (long)c->creation_time,	       mode_flags_to_string(c->mode, MODE_CHANNEL),	       c->limit, c->key ? c->key : "-",	       c->topic ? c->topic : "");	end = buf;	end += snprintf(end, sizeof(buf)-(end-buf), "%s", c->name);	LIST_FOREACH (u, c->users) {	    end += snprintf(end, sizeof(buf)-(end-buf), " +%s/%s",			    mode_flags_to_string(u->mode,MODE_CHANUSER),			    u->user->nick);	}	notice(s_OperServ, source, buf);    }}/*************************************************************************//* Send list of users on a single channel, taken from strtok(). */static void send_channel_users(User *user){    char *chan = strtok(NULL, " ");    Channel *c = chan ? get_channel(chan) : NULL;    struct c_userlist *u;    const char *source = user->nick;    if (!c) {	notice(s_OperServ, source, "Channel %s not found!",		chan ? chan : "(null)");	return;    }    notice(s_OperServ, source, "Channel %s users:", chan);    LIST_FOREACH (u, c->users)	notice(s_OperServ, source, "%x/%s", u->mode, u->user->nick);}/*************************************************************************//* Send the current list of users to the given user. */static void send_user_list(User *user){    User *u;    const char *source = user->nick;    for (u = first_user(); u; u = next_user()) {	char buf[5];	if (u->ni)	    snprintf(buf, sizeof(buf), "%04X", u->ni->status & 0xFFFF);	else	    strcpy(buf, "-");	notice(s_OperServ, source, "%s!%s@%s %s %s +%s %ld %u %s %s :%s",	       u->nick, u->username, u->host, u->fakehost ? u->fakehost : "-",	       u->ipaddr ? u->ipaddr : "-",	       mode_flags_to_string(u->mode, MODE_USER), (long)u->signon,	       u->servicestamp, u->server->name, buf, u->realname);    }}/*************************************************************************//* Send information about a single user to the given user.  Target nick is * taken from strtok(). */static void send_user_info(User *user){    char *nick = strtok(NULL, " ");    User *u = nick ? get_user(nick) : NULL;    char buf[BUFSIZE], *s;    struct u_chanlist *c;    struct u_chaninfolist *ci;    const char *source = user->nick;    if (!u) {	notice(s_OperServ, source, "User %s not found!",		nick ? nick : "(null)");	return;    }    if (u->ni)	snprintf(buf, sizeof(buf), "%04X", u->ni->status & 0xFFFF);    else	strcpy(buf, "-");    notice(s_OperServ, source, "%s!%s@%s %s %s +%s %ld %u %s %s :%s",	   u->nick, u->username, u->host, u->fakehost ? u->fakehost : "-",	   u->ipaddr, mode_flags_to_string(u->mode, MODE_USER),	   (long)u->signon, u->servicestamp, u->server->name, buf,	   u->realname);    buf[0] = 0;    s = buf;    LIST_FOREACH (c, u->chans)	s += snprintf(s, sizeof(buf)-(s-buf), " %s", c->chan->name);    notice(s_OperServ, source, "%s%s", u->nick, buf);    buf[0] = 0;    s = buf;    LIST_FOREACH (ci, u->id_chans)	s += snprintf(s, sizeof(buf)-(s-buf), " %s", ci->chan);    notice(s_OperServ, source, "%s%s", u->nick, buf);}/*************************************************************************//* Perform a wildcard match and report the result (either 0 or 1) to the * given user. */static void do_matchwild(User *u){    char *pat = strtok(NULL, " ");    char *str = strtok(NULL, " ");    if (pat && str)	notice(s_OperServ, u->nick, "%d", match_wild(pat, str));    else	notice(s_OperServ, u->nick, "Syntax error.");}/*************************************************************************//* Call set_cmode() with ServerName and parameters taken from strtok() (up * to SETCMODE_NPARAMS). */#define SETCMODE_NPARAMS	10static void do_setcmode(User *u){    char *channame, *params[SETCMODE_NPARAMS];    Channel *channel;    int i;    channame = strtok(NULL, " ");    for (i = 0; i < SETCMODE_NPARAMS; i++)	params[i] = strtok(NULL, " ");    if (!channame) {	notice(s_OperServ, u->nick, "SETCMODE: not enough parameters");	return;    }    if (strcmp(channame, "-") == 0) {	channel = NULL;    } else {	channel = get_channel(channame);	if (!channel) {	    notice(s_OperServ, u->nick, "SETCMODE: channel not found (%s)",		   channame);	    return;	}    }    set_cmode(channel ? ServerName : NULL, channel,	      params[0], params[1], params[2], params[3], params[4],	      params[5], params[6], params[7], params[8], params[9]);    notice(s_OperServ, u->nick, "SETCMODE: done");}/*************************************************************************/#endif	/* DEBUG_COMMANDS *//*************************************************************************//*********** MaskData expiration check (for database modules) ************//*************************************************************************//* Check for expiration of a MaskData; delete it and return 1 if expired, * and return 0 if not expired. */EXPORT_FUNC(check_expire_maskdata)int check_expire_maskdata(uint8 type, MaskData *md){    if (md->expires && md->expires <= time(NULL)) {	call_callback_2(module, cb_expire_md, type, md);	del_maskdata(type, md);	return 1;    }    return 0;}/*************************************************************************//***************************** Module stuff ******************************//*************************************************************************/const int32 module_version = MODULE_VERSION_CODE;ConfigDirective module_config[] = {    { "AllowRaw",         { { CD_SET, 0, &AllowRaw } } },    { "GlobalName",       { { CD_STRING, CF_DIRREQ, &s_GlobalNoticer },                            { CD_STRING, 0, &desc_GlobalNoticer } } },    { "KillClonesAutokill",{{ CD_SET, 0, &KillClonesAutokill },			    { CD_TIME, 0, &KillClonesAutokillExpire } } },    { "OperServDB",       { { CD_STRING, CF_DIRREQ, &OperDBName } } },    { "OperServName",     { { CD_STRING, CF_DIRREQ, &s_OperServ },                            { CD_STRING, 0, &desc_OperServ } } },    { "ServicesRoot",     { { CD_STRING, CF_DIRREQ, &ServicesRoot } } },    { "WallBadOS",        { { CD_SET, 0, &WallBadOS } } },    { "WallOper",         { { CD_SET, 0, &WallOper } } },    { "WallOSChannel",    { { CD_SET, 0, &WallOSChannel } } },    { "WallSU",           { { CD_SET, 0, &WallSU } } },    { NULL }};/* For enabling/disabling RAW command (AllowRaw) */static Command *cmd_RAW = NULL;/* Previous value of clear_channel() sender */static char old_clearchan_sender[NICKMAX];static int old_clearchan_sender_set = 0;/*************************************************************************/static int do_load_module(Module *mod, const char *modname){    if (strcmp(modname, "operserv/akill") == 0) {	module_akill = mod;    } else if (strcmp(modname, "nickserv/main") == 0) {	char **p_s_NickServ;	Command *cmd;	module_nickserv = mod;	p_s_NickServ = get_module_symbol(mod, "s_NickServ");	if (p_s_NickServ) {	    cmd = lookup_cmd(module, "ADMIN");	    if (cmd)		cmd->help_param1 = *p_s_NickServ;	    cmd = lookup_cmd(module, "OPER");	    if (cmd)		cmd->help_param1 = *p_s_NickServ;	} else {	    module_log("Unable to resolve NickServ symbol `s_NickServ'");	}	if (!add_callback(mod, "REGISTER/LINK check", do_reglink_check))	    module_log("Unable to register NickServ REGISTER/LINK check"		       " callback");    }    return 0;}/*************************************************************************/static int do_unload_module(Module *mod){    if (mod == module_akill) {	module_akill = NULL;    } else if (mod == module_nickserv) {	Command *cmd;	cmd = lookup_cmd(module, "ADMIN");	if (cmd)	    cmd->help_param1 = "NickServ";	cmd = lookup_cmd(module, "OPER");	if (cmd)	    cmd->help_param1 = "NickServ";	remove_callback(module_nickserv, "REGISTER/LINK check",			do_reglink_check);	module_nickserv = NULL;    }    return 0;}/*************************************************************************/static int do_reconfigure(int after_configure){    static char old_s_OperServ[NICKMAX];    static char *old_desc_OperServ = NULL;    static char *old_OperDBName    = NULL;    if (!after_configure) {	/* Before reconfiguration: save old values. */	free(old_desc_OperServ);  /* these might be non-NULL if a */	free(old_OperDBName);     /* previous reconfigure failed  */	strscpy(old_s_OperServ, s_OperServ, NICKMAX);	old_desc_OperServ = strdup(desc_OperServ);	old_OperDBName    = strdup(OperDBName);    } else {	Command *cmd;	/* After reconfiguration: handle value changes. */	if (strcmp(old_s_OperServ, s_OperServ) != 0) {	    if (strcmp(set_clear_channel_sender(PTR_INVALID),old_s_OperServ)==0)		set_clear_channel_sender(s_OperServ);	    send_nickchange(old_s_OperServ, s_OperServ);	}	if (!old_desc_OperServ || strcmp(old_desc_OperServ,desc_OperServ) != 0)	    send_namechange(s_OperServ, desc_OperServ);	if (!old_OperDBName || strcmp(old_OperDBName, OperDBName) != 0) {	    module_log("reconfigure: new database name will only take"		       " effect after restart");	    /* Restore the old database name */	    free(OperDBName);	    OperDBName = old_OperDBName;	    /* Make sure the old name isn't freed below */	    old_OperDBName = NULL;	}	/* Free and clear old values */	free(old_desc_OperServ);	free(old_OperDBName);	old_desc_OperServ = NULL;	old_OperDBName = NULL;	/* Activate/deactivate commands */	if (cmd_RAW) {	    if (AllowRaw)		cmd_RAW->name = "RAW";	    else		cmd_RAW->name = "";	}	/* Update command help parameters */	if (module_nickserv) {	    char **p_s_NickServ;	    p_s_NickServ = get_module_symbol(module_nickserv, "s_NickServ");	    if (p_s_NickServ) {		cmd = lookup_cmd(module, "ADMIN");		if (cmd)		    cmd->help_param1 = *p_s_NickServ;		cmd = lookup_cmd(module, "OPER");		if (cmd)		    cmd->help_param1 = *p_s_NickServ;	    } else {		module_log("reconfigure: Unable to resolve NickServ symbol:"			   " s_NickServ");	    }	}	cmd = lookup_cmd(module, "GLOBAL");	if (cmd)	    cmd->help_param1 = s_GlobalNoticer;    }  /* if (!after_configure) */    return 0;}/*************************************************************************/int init_module(Module *module_){    Command *cmd;    int i;    char *supass_ret;    module = module_;    if (!new_commandlist(module) || !register_commands(module, cmds)) {	module_log("Unable to register commands");	exit_module(0);	return 0;    }    cb_command   = register_callback(module, "command");    cb_expire_md = register_callback(module, "expire maskdata");    cb_help      = register_callback(module, "HELP");    cb_help_cmds = register_callback(module, "HELP COMMANDS");    cb_set       = register_callback(module, "SET");    cb_stats     = register_callback(module, "STATS");    cb_stats_all = register_callback(module, "STATS ALL");    if (cb_command < 0 || cb_help < 0 || cb_help_cmds < 0 || cb_set < 0     || cb_stats < 0 || cb_stats_all < 0    ) {	module_log("Unable to register callbacks");	exit_module(0);	return 0;    }    if (!add_callback(NULL, "load module", do_load_module)     || !add_callback(NULL, "unload module", do_unload_module)     || !add_callback(NULL, "reconfigure", do_reconfigure)     || !add_callback(NULL, "save data", do_save_data)     || !add_callback(NULL, "introduce_user", introduce_operserv)     || !add_callback(NULL, "m_privmsg", operserv)     || !add_callback(NULL, "m_whois", operserv_whois)     || (WallOper && !add_callback(NULL, "user MODE", wall_oper_callback))    ) {	module_log("Unable to add callbacks");	exit_module(0);	return 0;    }    if ((i = -1, !open_operserv_db(OperDBName))     || (i = OSDATA_MAXUSERCNT,  !get_operserv_data(i, &maxusercnt))     || (i = OSDATA_MAXUSERTIME, !get_operserv_data(i, &maxusertime))     || (i = OSDATA_SUPASS,      !get_operserv_data(i, &supass_ret))    ) {	module_log("Unable to read from database! (code %d)", i);	exit_module(0);	return 0;    }    if (supass_ret) {	no_supass = 0;	memcpy(supass, supass_ret, PASSMAX);    } else {	no_supass = 1;    }    db_opened = 1;    cmd_RAW = lookup_cmd(module, "RAW");    if (cmd_RAW && !AllowRaw)	cmd_RAW->name = "";    cmd = lookup_cmd(module, "GLOBAL");    if (cmd)	cmd->help_param1 = s_GlobalNoticer;    if (linked)	introduce_operserv(NULL);    strscpy(old_clearchan_sender, set_clear_channel_sender(s_OperServ),	    sizeof(old_clearchan_sender));    old_clearchan_sender_set = 1;    return 1;}/*************************************************************************/int exit_module(int shutdown_unused){#ifdef CLEAN_COMPILE    shutdown_unused = shutdown_unused;#endif    if (old_clearchan_sender_set) {	set_clear_channel_sender(old_clearchan_sender);	old_clearchan_sender_set = 0;    }    if (linked) {	send_cmd(s_OperServ, "QUIT :");	send_cmd(s_GlobalNoticer, "QUIT :");    }    if (cmd_RAW)	cmd_RAW->name = "RAW";    if (db_opened)	close_operserv_db(OperDBName);    if (module_nickserv)	do_unload_module(module_nickserv);    if (module_akill)	do_unload_module(module_akill);    remove_callback(NULL, "user MODE", wall_oper_callback);    remove_callback(NULL, "m_whois", operserv_whois);    remove_callback(NULL, "m_privmsg", operserv);    remove_callback(NULL, "introduce_user", introduce_operserv);    remove_callback(NULL, "save data", do_save_data);    remove_callback(NULL, "reconfigure", do_reconfigure);    remove_callback(NULL, "unload module", do_unload_module);    remove_callback(NULL, "load module", do_load_module);    unregister_callback(module, cb_stats_all);    unregister_callback(module, cb_stats);    unregister_callback(module, cb_set);    unregister_callback(module, cb_help_cmds);    unregister_callback(module, cb_help);    unregister_callback(module, cb_expire_md);    unregister_callback(module, cb_command);    unregister_commands(module, cmds);    del_commandlist(module);    return 1;}/*************************************************************************/