#include "module.h" #include #define AUTHOR "SGR" #define VERSION "1.01" /* ----------------------------------------------------------- * Name: cs_freeze * Author: SGR * Date: 21/09/2004 * ----------------------------------------------------------- * Limitations: NONE KNOWN. * Tested: Unreal(3.2), Viagra, Bahamut, Plexus * ----------------------------------------------------------- * All IRCd's should be compatible with this module. * * Please set the config options below. * * To DISABLE the notices comment out the #DEFINE lines. * #define JOIN_CHANNEL_IS_FROZEN1-6 "Notice text". * i.e * #define JOIN_CHANNEL_IS_FROZEN1 "notice text" becomes */ // #define JOIN_CHANNEL_IS_FROZEN1 "notice text" /* ----------------------------------------------------------- * ChangeLog * * 1) Works - hopefully :P * 2) Added checking to prevent a crash on JOIN 0, reported by * Certus. * 3) Added Much Improved Anope-1.7.x (Revision 370+) support * -----------------------------------------------------------*/ /* ---------------------------------------------------------------------- */ /* START OF CONFIGURATION BLOCK - please read the comments :) */ /* ---------------------------------------------------------------------- */ /* ----------------------------------------------*/ /* ONLY NICKGE WHAT IS INSIDE THE "speach marks" */ /* and limit each line to 400 characters. */ /* ----------------------------------------------*/ /* [REQUIRED] If you are using Anope-1.7.x or later, leave this alone. * Otherwise change it to '#undef ANOPE17x' (no quotes). * * THIS IS IMPORTANT * */ #define ANOPE17x /* [OPTIONAL] These notices (when defined) will be sent to a user when * they join a channel that is FROZEN. Upto 6 notices can be defined. */ //#define JOIN_CHANNEL_IS_FROZEN1 " Blah " //#define JOIN_CHANNEL_IS_FROZEN2 " Blah " //#define JOIN_CHANNEL_IS_FROZEN3 " Blah " //#define JOIN_CHANNEL_IS_FROZEN4 " Blah " //#define JOIN_CHANNEL_IS_FROZEN5 " Blah " #define JOIN_CHANNEL_IS_FROZEN6 "The channel %s has been frozen. ChanServ will not function on this channel.", fc->chan /* [OPTIONAL] These notices (when defined) will be sent to a user when * they attempt to change the settings on a channel that is FROZEN. * Upto 6 notices can be defined. If none are used the standard * 'ACCESS DENIED' message is returned. */ //#define THIS_CHANNEL_IS_FROZEN1 " Blah " //#define THIS_CHANNEL_IS_FROZEN2 " Blah " //#define THIS_CHANNEL_IS_FROZEN3 " Blah " //#define THIS_CHANNEL_IS_FROZEN4 " Blah " #define THIS_CHANNEL_IS_FROZEN5 "The channel %s is FROZEN. This means you", fc->chan #define THIS_CHANNEL_IS_FROZEN6 "cannot change any of its %s settings. ", s_ChanServ /* [OPTIONAL] -- If ADD_TO_CHAN_INFO is defined, the line * 'Channel is FROZEN' * will appear at the end of a channels /ChanServ INFO output. */ #define ADD_TO_CHAN_INFO /* [OPTIONAL] -- If UPDATE_ON_EDIT is defined, the Frozen Channels * database will be updated everytime a frozen channel is added or * removed. */ #define UPDATE_ON_EDIT /* ---------------------------------------------------------------------- * Advanced settings. * ---------------------------------------------------------------------- */ #define FC_DB_NAME "frozenchans.db" #define FC_DB_VERSION 1 #define FC_DB_UPDATE "5m" #define FREEZETABLESIZE 512 /* ---------------------------------------------------------------------- */ /* DO NOT EDIT BELOW THIS LINE UNLESS YOU KNOW WHAT YOU ARE DOING */ /* ---------------------------------------------------------------------- */ /* When a channel is frozen: * * - BotServ bots are unassigned from it * - All users on the channel are set -(q)(a)ohv, all bans and exceptions * etc. are removed. * - All ChanServ and BotServ commands that can be used for the channel * are disabled for it (for non-opers / Services Admins). * - If a ChanServ OP or VOICE command [etc.] is used, modes are * revoked immiedialy after they are set for a user on the channel. * - 'Channel [chan] is FROZEN' will appear in /CS INFO [Chan] * - ChanServ will not 'auto-op' etc. when people join the channel. * - AKICKs etc. won't function on FROZEN channels. * * When a channel is 'UNFROZEN', the above is reversed, except the * setting of modes and replacing of bans / exceptions etc. */ #ifndef ANOPE17x #include "../datafiles.h" #else #include "../../include/datafiles.h" #endif typedef struct FreezeChan_ FreezeChan; struct FreezeChan_ { FreezeChan *next; FreezeChan *prev; char *chan; char *by; char *reason; time_t time; char *botnick; }; FreezeChan *freezechanhash[FREEZETABLESIZE]; unsigned int freezenumber = 0; User *last_join_user = NULL; int save_freezechan_database(int argc, char **argv); int load_freezechan_database(void); static void add_entry(FreezeChan *fc); static int del_entry(FreezeChan *fc); static FreezeChan *create_entry(char *chan, char *reason, NickAlias *na, char *botnick); static FreezeChan *find_freezechan_entry(char *chan); int my_cs_privmsg_frozen_check(char *source, int ac, char **av); int my_frozen_check(char *source, int argc, char **argv, char *from); int my_cs_cs_frozen_check(char *source, int ac, char **av); int my_cs_bs_frozen_check(char *source, int ac, char **av); int my_cs_add_freeze(User *u, char *chan, char *reason); int my_cs_del_freeze(User *u, char *chan); int my_cs_list_freeze(User *u); int my_cs_info_freeze(User *u, char *chan); int on_post_join_freeze_ignore(char *source, int ac, char **av); int on_join_freeze_ignore(char *source, int ac, char **av); int on_sjoin_freeze_ignore(char *source, int ac, char **av); void send_frozen_join_notices(User *u, char *from, FreezeChan *fc); void send_frozen_nochange_notices(User *u, char *from, FreezeChan *fc); void my_cs_freeze_checkanddelifneedbe(char *chan); int my_cs_forbid_freeze_check(User *u); int my_cs_drop_freeze_check(User *u); int my_cs_suspend_freeze_check(User *u); int my_cs_unsetmodes_ifneedbe(User *u, int id); int my_cs_freeze_do_op(User *u); int my_cs_needfreeze_check(User *u); int my_cs_freeze_do_voice(User *u); int my_cs_freeze_do_halfop(User *u); int my_cs_freeze_do_protect(User *u); int my_update_on_osupdate(User *u); int my_cs_freeze(User *u); int my_cs_freeze_identify(User *u); int my_cs_freeze_appendinfo(User *u); void my_cs_freeze_clearallmodes(Channel *c); void SGR_Module_Help_CHANSERV_FREEZE(User *u); int SGR_Module_Help_CHANSERV_FREEZE_FULL(User *u); int AnopeInit(int argc, char **argv) { Message *msg1; Message *msg2; Message *msg3; Message *msg4; Message *msg5; Message *msg6; Command *c1; Command *c2; Command *c3; Command *c4; Command *c5; Command *c6; Command *c7; Command *c8; Command *c9; Command *c10; Command *c11; Command *c12; Command *c13; Command *c14; Command *c15; alog("Loading module cs_freeze.so"); msg1 = createMessage("JOIN",on_join_freeze_ignore); moduleAddMessage(msg1,MOD_HEAD); msg2 = createMessage("JOIN",on_post_join_freeze_ignore); moduleAddMessage(msg2,MOD_TAIL); msg3 = createMessage("SJOIN",on_sjoin_freeze_ignore); moduleAddMessage(msg3,MOD_HEAD); msg4 = createMessage("SJOIN",on_post_join_freeze_ignore); moduleAddMessage(msg4,MOD_TAIL); msg5 = createMessage("PRIVMSG",my_cs_privmsg_frozen_check); moduleAddMessage(msg5,MOD_HEAD); msg5 = createMessage("CS",my_cs_cs_frozen_check); moduleAddMessage(msg5,MOD_HEAD); msg6 = createMessage("BS",my_cs_bs_frozen_check); moduleAddMessage(msg6,MOD_HEAD); c1 = createCommand("FORBID", my_cs_needfreeze_check, NULL, -1, -1, -1, -1, -1); moduleAddCommand(CHANSERV, c1, MOD_TAIL); c2 = createCommand("SUSPEND", my_cs_needfreeze_check, NULL, -1, -1, -1, -1, -1); moduleAddCommand(CHANSERV, c2, MOD_TAIL); c3 = createCommand("DROP", my_cs_needfreeze_check, NULL, -1, -1, -1, -1, -1); moduleAddCommand(CHANSERV, c3, MOD_TAIL); c4 = createCommand("UNSUSPEND", my_cs_needfreeze_check, NULL, -1, -1, -1, -1, -1); moduleAddCommand(CHANSERV, c4, MOD_TAIL); c5 = createCommand("OP", my_cs_freeze_do_op, NULL, -1, -1, -1, -1, -1); moduleAddCommand(CHANSERV, c5, MOD_TAIL); c6 = createCommand("VOICE", my_cs_freeze_do_voice, NULL, -1, -1, -1, -1, -1); moduleAddCommand(CHANSERV, c6, MOD_TAIL); #ifdef HAS_HALFOP c7 = createCommand("HALFOP", my_cs_freeze_do_halfop, NULL, -1, -1, -1, -1, -1); moduleAddCommand(CHANSERV, c7, MOD_TAIL); #endif #if defined(IRC_UNREAL) || defined(IRC_ULTIMATE3) || defined(IRC_VIAGRA) c8 = createCommand("PROTECT", my_cs_freeze_do_protect, NULL, -1, -1, -1, -1, -1); moduleAddCommand(CHANSERV, c8, MOD_TAIL); #endif c9 = createCommand("UPDATE", my_update_on_osupdate, is_services_admin, -1, -1, -1, -1, -1); moduleAddCommand(OPERSERV, c9, MOD_TAIL); c10 = createCommand("SHUTDOWN", my_update_on_osupdate, is_services_admin, -1, -1, -1, -1, -1); moduleAddCommand(OPERSERV, c10, MOD_HEAD); c11 = createCommand("RESTART", my_update_on_osupdate, is_services_admin, -1, -1, -1, -1, -1); moduleAddCommand(OPERSERV, c11, MOD_HEAD); c12 = createCommand("FREEZE", my_cs_freeze, is_services_admin, -1, -1, -1, -1, -1); moduleAddCommand(CHANSERV, c12, MOD_UNIQUE); c13 = createCommand("IDENTIFY", my_cs_freeze_identify, NULL, -1, -1, -1, -1, -1); moduleAddCommand(NICKSERV, c13, MOD_TAIL); c15 = createCommand("INFO", my_cs_freeze_appendinfo, NULL, -1, -1, -1, -1, -1); moduleAddCommand(CHANSERV, c15, MOD_TAIL); c14 = createCommand("ID", my_cs_freeze_identify, NULL, -1, -1, -1, -1, -1); moduleAddCommand(NICKSERV, c14, MOD_TAIL); moduleAddHelp(c12,SGR_Module_Help_CHANSERV_FREEZE_FULL); moduleSetChanHelp(SGR_Module_Help_CHANSERV_FREEZE); moduleAddAuthor(AUTHOR); moduleAddVersion(VERSION); load_freezechan_database(); alog("[cs_freeze] Yayness!(tm) - MODULE LOADED AND ACTIVE"); return MOD_CONT; } void AnopeFini(void) { FreezeChan *fc; int i = 0; save_freezechan_database(0, NULL); if (freezenumber) { for (fc = freezechanhash[i]; fc; fc = fc->next, i++) { freezenumber--; free(freezechanhash[i]); free(fc->chan); free(fc->by); free(fc->reason); free(fc->botnick); free(fc); } i = 0; } return; } /******************************************************************/ /******************************************************************/ /* Command Hooks - FORBID, SUSPEND, FREEZE, DROP etc. */ /******************************************************************/ /******************************************************************/ void SGR_Module_Help_CHANSERV_FREEZE(User *u) { if (is_services_admin(u)) { notice(s_ChanServ,u->nick, " FREEZE Freeze/Release a channels settings."); } return; } int SGR_Module_Help_CHANSERV_FREEZE_FULL(User *u) { if (is_services_admin(u)) { notice(s_ChanServ, u->nick, "------------------------------------------------------------------------"); notice(s_ChanServ, u->nick, " Syntax: FREEZE ADD #chan "); notice(s_ChanServ, u->nick, " Syntax: FREEZE DEL #chan"); notice(s_ChanServ, u->nick, " Syntax: FREEZE INFO #chan"); notice(s_ChanServ, u->nick, " Syntax: FREEZE LIST"); notice(s_ChanServ, u->nick, " "); notice(s_ChanServ, u->nick, " The FREEZE command locks a registered channels %s settings.", s_ChanServ); notice(s_ChanServ, u->nick, " When a channel is FROZEN, none of the channels settings (for example"); notice(s_ChanServ, u->nick, " AKICKS, Access Lists, SET options [e.g MLOCK, SECUREOPs etc.] and so"); notice(s_ChanServ, u->nick, " on are able to be changed by non-services admins. Additionally, users"); notice(s_ChanServ, u->nick, " who are on the given channels access list will not recieve the modes "); notice(s_ChanServ, u->nick, " they would normally be given when joining said channel."); notice(s_ChanServ, u->nick, " "); notice(s_ChanServ, u->nick, " When FROZEN, all modes on the channel are revoked and any %s bots", s_BotServ); notice(s_ChanServ, u->nick, " assigned to the channel are un-assigned untill the the FREEZE is lifted."); notice(s_ChanServ, u->nick, " "); notice(s_ChanServ, u->nick, " A reason is mandatory when adding a channel FREEZE."); notice(s_ChanServ, u->nick, "-----------------------------------------------------------------------"); } return MOD_CONT; } int my_cs_freeze(User *u) { char *arg1 = strtok(NULL, " "); /* ADD, DEL, INFO, LIST */ char *arg2 = strtok(NULL, " "); /* #Chan */ char *arg3 = strtok(NULL, ""); /* Reason */ if (!arg1) { notice(s_ChanServ, u->nick, "Syntax: FREEZE [LIST]"); notice(s_ChanServ, u->nick, "Syntax: FREEZE [ADD] "); notice(s_ChanServ, u->nick, "Syntax: FREEZE [DEL|INFO] "); return MOD_CONT; } if (stricmp(arg1,"list")==0) { return my_cs_list_freeze(u); } else if (stricmp(arg1,"info")==0) { return my_cs_info_freeze(u,(arg2 ? arg2 : NULL)); } else if (stricmp(arg1,"add")==0) { return my_cs_add_freeze(u, (arg2 ? arg2 : NULL), (arg3 ? arg3 : NULL)); } else if (stricmp(arg1,"del")==0) { return my_cs_del_freeze(u, (arg2 ? arg2 : NULL)); } else { notice(s_ChanServ, u->nick, "Syntax: FREEZE [LIST]"); notice(s_ChanServ, u->nick, "Syntax: FREEZE [ADD] "); notice(s_ChanServ, u->nick, "Syntax: FREEZE [DEL|INFO] "); } return MOD_CONT; } int my_cs_freeze_identify(User *u) { if (NSModeOnID && nick_recognized(u)) { return my_cs_unsetmodes_ifneedbe(u, 1); } return MOD_CONT; } int my_cs_freeze_appendinfo(User *u) { char *mainbuf = moduleGetLastBuffer(); char *arg1 = strtok(mainbuf, " "); FreezeChan *fc; if (arg1) { if ((fc = find_freezechan_entry(arg1))) { notice(s_ChanServ, u->nick, "The channel %s is FROZEN", arg1); } free(mainbuf); } return MOD_CONT; } int my_cs_needfreeze_check(User *u) { char *mainbuf = moduleGetLastBuffer(); char *arg1 = strtok(mainbuf, " "); if (arg1) { my_cs_freeze_checkanddelifneedbe(arg1); free(mainbuf); } return MOD_CONT; } int my_cs_freeze_do_op(User *u) { return my_cs_unsetmodes_ifneedbe(u, 0); } int my_cs_freeze_do_voice(User *u) { return my_cs_unsetmodes_ifneedbe(u, 0); } #ifdef HAS_HALFOP int my_cs_freeze_do_halfop(User *u) { return my_cs_unsetmodes_ifneedbe(u, 0); } #endif #if defined(IRC_UNREAL) || defined(IRC_ULTIMATE3) || defined(IRC_VIAGRA) int my_cs_freeze_do_protect(User *u) { return my_cs_unsetmodes_ifneedbe(u, 0); } #endif int my_cs_unsetmodes_ifneedbe(User *u, int id) { ChannelInfo *ci; FreezeChan *fc; struct u_chanlist *uc; char *argv[6]; for (uc = u->chans; uc; uc = uc->next) { if (!uc->chan || !uc->chan->name) { continue; } if ((ci = uc->chan->ci) && (fc = find_freezechan_entry(uc->chan->name))) { int n = 0; if (!chan_has_user_status(uc->chan, u, CUS_OP) && !chan_has_user_status(uc->chan, u, CUS_VOICE) #if defined(IRC_UNREAL) || defined(IRC_ULTIMATE3) || defined(IRC_VIAGRA) || defined(IRC_PTLINK) && !chan_has_user_status(uc->chan, u, CUS_PROTECT) #endif #if defined(IRC_UNREAL) || defined(IRC_VIAGRA) && !chan_has_user_status(uc->chan, u, CUS_OWNER) #endif #ifdef HAS_HALFOP && !chan_has_user_status(uc->chan, u, CUS_HALFOP) #endif ) { continue; /* They have no modes */ } #if defined(IRC_UNREAL) || defined(IRC_VIAGRA) argv[0] = sstrdup("-qahov"); argv[1] = sstrdup(u->nick); argv[2] = sstrdup(u->nick); argv[3] = sstrdup(u->nick); argv[4] = sstrdup(u->nick); argv[5] = sstrdup(u->nick); #ifndef ANOPE17x send_cmd(s_ChanServ, "MODE %s %s %s %s %s %s %s", uc->chan->name, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]); #else anope_cmd_mode(s_ChanServ, uc->chan->name, "%s %s %s %s %s %s", argv[0], argv[1], argv[2], argv[3], argv[4], arg[5]); #endif chan_set_modes(s_ChanServ, uc->chan, 6, argv, 0); for (n = 0; n < 6; n++) { free(argv[n]); } #elif defined(IRC_ULTIMATE3) || defined(IRC_PTLINK) argv[0] = sstrdup("-aohv"); argv[1] = sstrdup(u->nick); argv[2] = sstrdup(u->nick); argv[3] = sstrdup(u->nick); argv[4] = sstrdup(u->nick); #ifndef ANOPE17x send_cmd(s_ChanServ, "MODE %s %s %s %s %s %s", uc->chan->name, argv[0], argv[1], argv[2], argv[3], argv[4]); #else anope_cmd_mode(s_ChanServ, uc->chan->name, "%s %s %s %s %s", argv[0], argv[1], argv[2], argv[3], argv[4]); #endif chan_set_modes(s_ChanServ, uc->chan, 5, argv, 0); for (n = 0; n < 5; n++) { free(argv[n]); } #elif defined(HAS_HALFOP) argv[0] = sstrdup("-hov"); argv[1] = sstrdup(u->nick); argv[2] = sstrdup(u->nick); argv[3] = sstrdup(u->nick); #ifndef ANOPE17x send_cmd(s_ChanServ, "MODE %s %s %s %s %s", uc->chan->name, argv[0], argv[1], argv[2], argv[3]); #else anope_cmd_mode(s_ChanServ, uc->chan->name, "%s %s %s %s", argv[0], argv[1], argv[2], argv[3]); #endif chan_set_modes(s_ChanServ, uc->chan, 4, argv, 0); for (n = 0; n < 4; n++) { free(argv[n]); } #else argv[0] = sstrdup("-ov"); argv[1] = sstrdup(u->nick); argv[2] = sstrdup(u->nick); #ifndef ANOPE17x send_cmd(s_ChanServ, "MODE %s %s %s %s", uc->chan->name, argv[0], argv[1], argv[2]); #else anope_cmd_mode(s_ChanServ, uc->chan->name, "%s %s %s", argv[0], argv[1], argv[2]); #endif chan_set_modes(s_ChanServ, uc->chan, 3, argv, 0); for (n = 0; n < 3; n++) { free(argv[n]); } #endif } } return MOD_CONT; } int my_update_on_osupdate(User *u) { save_freezechan_database(0, NULL); return MOD_CONT; } /******************************************************************/ /******************************************************************/ /* Add/Del/List/Info functions [called by main FREEZE handler] */ /******************************************************************/ /******************************************************************/ int my_cs_del_freeze(User *u, char *chan) { FreezeChan *fc; if (!u) { return MOD_CONT; } if (!chan || (chan[0] != '#')) { notice(s_ChanServ, u->nick, "A valid channel name and reason must be provided"); return MOD_CONT; } if ((fc = find_freezechan_entry(chan))) { notice(s_ChanServ, u->nick, "Channel \002%s\002 is no longer frozen.", chan); del_entry(fc); #ifdef UPDATE_ON_EDIT save_freezechan_database(0, NULL); #endif } else { notice(s_ChanServ, u->nick, "Could not find a FROZEN channel named %s", chan); } return MOD_CONT; } int my_cs_add_freeze(User *u, char *chan, char *reason) { NickAlias *na; BotInfo *bi; ChannelInfo *ci; Channel *c; FreezeChan *fc; if (!u) { return MOD_CONT; } if (!chan || !reason || (chan[0] != '#')) { notice(s_ChanServ, u->nick, "A valid channel name and reason must be provided"); return MOD_CONT; } if (!(na = findnick(u->nick))) { notice(s_ChanServ, u->nick, "ERROR"); return MOD_CONT; } if (!(ci = cs_findchan(chan))) { notice(s_ChanServ, u->nick, "%s is not registered, thus cannot be FROZEN. Use FORBID.", chan); return MOD_CONT; } if ((fc = find_freezechan_entry(chan))) { notice(s_ChanServ, u->nick, "%s is already FROZEN. See \002/%s FREEZE INFO %s\002 for more info.", chan, s_ChanServ, chan); return MOD_CONT; } bi = ci->bi; fc = create_entry(chan, reason, na, (bi ? bi->nick : "*")); if (fc) { if ((c = ci->c)) { my_cs_freeze_clearallmodes(c); } if (bi) { if (ci->c && (ci->c->usercount >= BSMinUsers)) { send_cmd(ci->bi->nick, "PART %s :This channel has been FROZEN by %s.", ci->name, u->nick); } ci->bi->chancount--; ci->bi = NULL; } notice(s_ChanServ, u->nick, "Channel \002%s\002 is now frozen", chan); #ifdef UPDATE_ON_EDIT save_freezechan_database(0, NULL); #endif } else { notice(s_ChanServ, u->nick, "An ERROR occured. Perhaps we're running out of memory?"); } return MOD_CONT; } int my_cs_list_freeze(User *u) { int i = 0; FreezeChan *fc; int count = 0; if (!u) { return MOD_CONT; } if (!freezenumber) { notice(s_ChanServ, u->nick, "No channels are frozen."); return MOD_CONT; } notice(s_ChanServ, u->nick, " Num. Channel. Froze By"); for (i = 0; i < FREEZETABLESIZE; i++) { for (fc = freezechanhash[i]; fc; fc = fc->next) { count++; notice(s_ChanServ, u->nick, "Entry: %-3d %-15s %s", count, fc->chan, fc->by); if (count > FREEZETABLESIZE) { break; } } } notice(s_ChanServ, u->nick, "Total Forzen Channels: %d", count); return MOD_CONT; } int my_cs_info_freeze(User *u, char *chan) { char *time; FreezeChan *fc; if (!u) { return MOD_CONT; } if (!freezenumber) { notice(s_ChanServ, u->nick, "No channels are frozen."); return MOD_CONT; } if (!chan || (chan[0] != '#')) { notice(s_ChanServ, u->nick, "A valid channel name must be provided."); return MOD_CONT; } if ((fc = find_freezechan_entry(chan))) { notice(s_ChanServ, u->nick, "Channel %s Freeze Info:", chan); notice(s_ChanServ, u->nick, " Frozen By: %s", fc->by); notice(s_ChanServ, u->nick, " Reason : %s", fc->reason); time = asctime(localtime(&fc->time)); notice(s_ChanServ, u->nick, " Frozen At: %s", time); notice(s_ChanServ, u->nick, "End of %s Freeze Info.", chan); } else { notice(s_ChanServ, u->nick, "No channel called \002%s\002 is forbidden", chan); } return MOD_CONT; } /******************************************************************/ /******************************************************************/ /* JOIN, SJOIN, PRIVMSG, and CS and BS Functions */ /******************************************************************/ /******************************************************************/ int my_cs_privmsg_frozen_check(char *source, int ac, char **av) { char *s = NULL; char *t = NULL; User *u = NULL; FreezeChan *fc = NULL; if (ac != 2) { return MOD_CONT; } u = finduser(source); /* No source user OR message is to a channel OR no '#' in main text */ if (!u || ((*av[0] == '#')) || (!(t = strchr(av[1], '#')))) { return MOD_CONT; } /* If a server is specified (nick@server format), make sure it matches us, and strip it off. */ s = strchr(av[0], '@'); if (s) { *s++ = 0; if (stricmp(s, ServerName) != 0) { return MOD_CONT; } } /* Message is to BotServ or ChanServ */ if (((stricmp(av[0], s_ChanServ) == 0) || (s_ChanServAlias && (stricmp(av[0], s_ChanServAlias) == 0))) || ((stricmp(av[0], s_BotServ) == 0) || (s_BotServAlias && (stricmp(av[0], s_BotServAlias) == 0)))) { if (!is_oper(u) && !is_services_oper(u)) { int i = 0; char moo[66] = { '\0' }; /* dunno any chans over 64 characters */ for (i = 0; i < FREEZETABLESIZE; i++) { for (fc = freezechanhash[i]; fc; fc = fc->next) { snprintf(moo, 66, " %s ", fc->chan); /* #x IS IN the string #xxx. However, ' #x ' is not in * ' #xxx ' ... See, i'm not just a pretty face ... (and * sexy body, witty mind, charasmatic personality etc.) */ if (stristr(av[1],moo)) { send_frozen_nochange_notices(u, av[0], fc); return MOD_STOP; } } } } } return MOD_CONT; } int my_cs_cs_frozen_check(char *source, int ac, char **av) { return my_frozen_check(source, ac, av, s_ChanServ); } int my_cs_bs_frozen_check(char *source, int ac, char **av) { return my_frozen_check(source, ac, av, s_BotServ); } int my_frozen_check(char *source, int argc, char **argv, char *from) { User *u; FreezeChan *fc; if (argc < 1) { return MOD_CONT; } u = finduser(source); /* No source user OR message is to a channel OR no '#' in main text */ if (!u) { return MOD_CONT; } if (!is_oper(u) && !is_services_oper(u)) { int i = 0; char moo[66] = { '\0' }; for (i = 0; i < FREEZETABLESIZE; i++) { for (fc = freezechanhash[i]; fc; fc = fc->next) { snprintf(moo, 66, " %s ", fc->chan); if (stristr(argv[0],moo)) { send_frozen_nochange_notices(u, from, fc); return MOD_STOP; } } } } return MOD_CONT; } int on_sjoin_freeze_ignore(char *source, int ac, char **av) { User *u; FreezeChan *fc; Channel *c; u = finduser(source); if (u && (ac > 0)) { if (get_ignore(u->nick) != 0) { /* If the nick is already ignored, don't over-ride it */ last_join_user = NULL; /* as otherwise it'll get removed post-JOIN */ } else { if (!stricmp(av[1],"0")) { return MOD_CONT; }; if ((fc = find_freezechan_entry(av[1]))) { last_join_user = u; add_ignore(u->nick, 120); } } } return MOD_CONT; } int on_join_freeze_ignore(char *source, int ac, char **av) { char *s; char *t; User *u; FreezeChan *fc; Channel *c; u = finduser(source); t = av[0]; if (u && t) { while (*(s = t)) { t = s + strcspn(s, ","); if (*t) { *t++ = 0; } if (!stricmp(s,"0")) { continue; }; if ((fc = find_freezechan_entry(s))) { last_join_user = u; add_ignore(u->nick, 120); } } } return MOD_CONT; } int on_post_join_freeze_ignore(char *source, int ac, char **av) { User *u = last_join_user; if (u && (get_ignore(u->nick) != 0)) { delete_ignore(u->nick); } /* This is the 1st user joining the channel. IRCd would normally * give mode +o here, if the user is on the access list for the * channel this might not get revoked. So, force-revoke it. */ return MOD_CONT; } /******************************************************************/ /******************************************************************/ /* Notice about FREEZE functions */ /******************************************************************/ /******************************************************************/ void send_frozen_join_notices(User *u, char *from, FreezeChan *fc) { if (u) { #ifdef JOIN_CHANNEL_IS_FROZEN1 notice(from, u->nick, JOIN_CHANNEL_IS_FROZEN1); #endif #ifdef JOIN_CHANNEL_IS_FROZEN2 notice(from, u->nick, JOIN_CHANNEL_IS_FROZEN2); #endif #ifdef JOIN_CHANNEL_IS_FROZEN3 notice(from, u->nick, JOIN_CHANNEL_IS_FROZEN3); #endif #ifdef JOIN_CHANNEL_IS_FROZEN4 notice(from, u->nick, JOIN_CHANNEL_IS_FROZEN4); #endif #ifdef JOIN_CHANNEL_IS_FROZEN5 notice(from, u->nick, JOIN_CHANNEL_IS_FROZEN5); #endif #ifdef JOIN_CHANNEL_IS_FROZEN6 notice(from, u->nick, JOIN_CHANNEL_IS_FROZEN6); #endif } } void send_frozen_nochange_notices(User *u, char *from, FreezeChan *fc) { if (u) { #ifdef THIS_CHANNEL_IS_FROZEN1 notice(from, u->nick, THIS_CHANNEL_IS_FROZEN1); #endif #ifdef THIS_CHANNEL_IS_FROZEN2 notice(from, u->nick, THIS_CHANNEL_IS_FROZEN2); #endif #ifdef THIS_CHANNEL_IS_FROZEN3 notice(from, u->nick, THIS_CHANNEL_IS_FROZEN3); #endif #ifdef THIS_CHANNEL_IS_FROZEN4 notice(from, u->nick, THIS_CHANNEL_IS_FROZEN4); #endif #ifdef THIS_CHANNEL_IS_FROZEN5 notice(from, u->nick, THIS_CHANNEL_IS_FROZEN5); #endif #ifdef THIS_CHANNEL_IS_FROZEN6 notice(from, u->nick, THIS_CHANNEL_IS_FROZEN6); #endif } } /******************************************************************/ /******************************************************************/ /* Struct Functions */ /******************************************************************/ /******************************************************************/ static int del_entry(FreezeChan *fc) { BotInfo *bi; ChannelInfo *ci; char *botnick = fc->botnick; if (fc->next) { fc->next->prev = fc->prev; } if (fc->prev) { fc->prev->next = fc->next; } else { freezechanhash[tolower(*fc->chan)] = fc->next; } if ((stricmp(fc->botnick,"*") != 0) && (bi = findbot(botnick))) { ci = cs_findchan(fc->chan); ci->bi = bi; bi->chancount++; if (ci->c && ci->c->usercount >= BSMinUsers) { bot_join(ci); } } freezenumber--; if (fc->chan) { free(fc->chan); } if (fc->reason) { free(fc->reason); } if (fc->by) { free(fc->by); } if (fc->botnick) { free(fc->botnick); } free(fc); return 1; } FreezeChan *find_freezechan_entry(char *chan) { FreezeChan *fc; if (!chan || !*chan || !freezenumber || *chan != '#') { return NULL; } for (fc = freezechanhash[tolower(*chan)]; fc; fc = fc->next) { if (!stricmp(chan, fc->chan)) { return fc; } } return NULL; } static FreezeChan *create_entry(char *chan, char *reason, NickAlias *na, char *botnick) { FreezeChan *fc; fc = scalloc(sizeof(FreezeChan), 1); if (fc == NULL) { alog("[cs_freeze] WARNING: COULD NOT ADD CHANNEL FREEZE RECORD! [Out of memory?]"); return NULL; } fc->chan = sstrdup(chan); fc->reason = sstrdup(reason); fc->by = sstrdup(na->nc->display); fc->botnick = sstrdup(botnick); fc->time = time(NULL); add_entry(fc); freezenumber++; return fc; } static void add_entry(FreezeChan *fc) { FreezeChan *next, *prev; for (prev = NULL, next = freezechanhash[tolower(*fc->chan)]; next != NULL && stricmp(next->chan, fc->chan) < 0; prev = next, next = next->next); fc->prev = prev; fc->next = next; if (!prev) { freezechanhash[tolower(*fc->chan)] = fc; } else { prev->next = fc; } if (next) { next->prev = fc; } return; } void my_cs_freeze_checkanddelifneedbe(char *chan) { FreezeChan *fc; ChannelInfo *ci; if ((!(ci = cs_findchan(chan))) || ((ci->flags & CI_VERBOTEN) || (ci->flags & CI_SUSPENDED))) { if ((fc = find_freezechan_entry(chan))) { del_entry(fc); } } return; } /******************************************************************/ /******************************************************************/ /* Database Functions */ /******************************************************************/ /******************************************************************/ #define SAFE(x) do { \ if ((x) < 0) { \ if (!forceload) \ fatal("Read error on %s", FC_DB_NAME); \ failed = 1; \ break; \ } \ } while (0) int load_freezechan_database(void) { dbFILE *f; FreezeChan *fc; int i = 0; int c = 0; int ver = 0; int failed = 0; int32 tmp32; if (!(f = open_db(s_ChanServ, FC_DB_NAME, "r", FC_DB_VERSION))) { return -2; } ver = get_file_version(f); for (i = 0; i < 1024 && !failed; i++) { while ((c = getc_db(f)) == 1) { if (c != 1) { alog("Invalid format in %s", FC_DB_NAME); return -1; } fc = scalloc(1, sizeof(FreezeChan)); SAFE(read_string(&fc->chan, f)); SAFE(read_string(&fc->reason, f)); SAFE(read_string(&fc->by, f)); SAFE(read_string(&fc->botnick, f)); SAFE(read_int32(&tmp32, f)); fc->time = tmp32; freezenumber++; add_entry(fc); } } close_db(f); return 0; } #undef SAFE #define SAFE(x) do { \ if ((x) < 0) { \ restore_db(f); \ log_perror("Write error on %s", FC_DB_NAME); \ if (time(NULL) - lastwarn > WarningTimeout) { \ wallops(NULL, "Write error on %s: %s", FC_DB_NAME, \ strerror(errno)); \ lastwarn = time(NULL); \ } \ return -3; \ } \ } while (0) int save_freezechan_database(int argc, char **argv) { dbFILE *f; int i; FreezeChan *fc; static time_t lastwarn = 0; if (!(f = open_db(s_ChanServ, FC_DB_NAME, "w", FC_DB_VERSION))) { return -2; } for (i = 0; i < FREEZETABLESIZE; i++) { for (fc = freezechanhash[i]; fc; fc = fc->next) { SAFE(write_int8(1, f)); SAFE(write_string(fc->chan, f)); SAFE(write_string(fc->reason, f)); SAFE(write_string(fc->by, f)); SAFE(write_string(fc->botnick, f)); SAFE(write_int32(fc->time, f)); SAFE(write_int8(0, f)); } SAFE(write_int8(0, f)); } close_db(f); #ifdef DB_UPDATE moduleAddCallback("FreezeChanSave",time(NULL)+dotime(FC_DB_UPDATE),save_freezechan_database,0,NULL); #endif return 0; } #undef SAFE void my_cs_freeze_clearallmodes(Channel *c) { int i = 0; int n = 0; char *argv[6]; int count; char **bans; int exceptcount; char **excepts; struct c_userlist *cu; struct c_userlist *next; for (cu = c->users; cu; cu = next) { char temp[512]; next = cu->next; if (!chan_has_user_status(c, cu->user, CUS_OP) && !chan_has_user_status(c, cu->user, CUS_VOICE) #if defined(IRC_UNREAL) || defined(IRC_ULTIMATE3) || defined(IRC_VIAGRA) || defined(IRC_PTLINK) && !chan_has_user_status(c, cu->user, CUS_PROTECT) #endif #if defined(IRC_UNREAL) || defined(IRC_VIAGRA) && !chan_has_user_status(c, cu->user, CUS_OWNER) #endif #ifdef HAS_HALFOP && !chan_has_user_status(c, cu->user, CUS_HALFOP) #endif ) { continue; } #if defined(IRC_UNREAL) || defined(IRC_VIAGRA) argv[0] = sstrdup("-qahov"); argv[1] = sstrdup(cu->user->nick); argv[2] = sstrdup(cu->user->nick); argv[3] = sstrdup(cu->user->nick); argv[4] = sstrdup(cu->user->nick); argv[5] = sstrdup(cu->user->nick); #ifndef ANOPE17x send_cmd(s_ChanServ, "MODE %s %s %s %s %s %s %s", c->name, argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]); #else anope_cmd_mode(s_ChanServ, c->name, "%s %s %s %s %s %s", argv[0], argv[1], argv[2], argv[3], argv[4], arg[5]); #endif chan_set_modes(s_ChanServ, c, 6, argv, 0); for (n = 0; n < 6; n++) { free(argv[n]); } #elif defined(IRC_ULTIMATE3) || defined(IRC_PTLINK) argv[0] = sstrdup("-aohv"); argv[1] = sstrdup(cu->user->nick); argv[2] = sstrdup(cu->user->nick); argv[3] = sstrdup(cu->user->nick); argv[4] = sstrdup(cu->user->nick); #ifndef ANOPE17x send_cmd(s_ChanServ, "MODE %s %s %s %s %s %s", c->name, argv[0], argv[1], argv[2], argv[3], argv[4]); #else anope_cmd_mode(s_ChanServ, c->name, "%s %s %s %s %s", argv[0], argv[1], argv[2], argv[3], argv[4]); #endif chan_set_modes(s_ChanServ, c, 5, argv, 0); for (n = 0; n < 5; n++) { free(argv[n]); } #elif defined(HAS_HALFOP) argv[0] = sstrdup("-hov"); argv[1] = sstrdup(cu->user->nick); argv[2] = sstrdup(cu->user->nick); argv[3] = sstrdup(cu->user->nick); #ifndef ANOPE17x send_cmd(s_ChanServ, "MODE %s %s %s %s %s", c->name, argv[0], argv[1], argv[2], argv[3]); #else anope_cmd_mode(s_ChanServ, c->name, "%s %s %s %s", argv[0], argv[1], argv[2], argv[3]); #endif chan_set_modes(s_ChanServ, c, 4, argv, 0); for (n = 0; n < 4; n++) { free(argv[n]); } #else argv[0] = sstrdup("-ov"); argv[1] = sstrdup(cu->user->nick); argv[2] = sstrdup(cu->user->nick); #ifndef ANOPE17x send_cmd(s_ChanServ, "MODE %s %s %s %s", c->name, argv[0], argv[1], argv[2]); #else anope_cmd_mode(s_ChanServ, c->name, "%s %s %s", argv[0], argv[1], argv[2]); #endif chan_set_modes(s_ChanServ, c, 3, argv, 0); for (n = 0; n < 3; n++) { free(argv[n]); } #endif } /* Clear modes */ #ifndef MODESTOREMOVE #define MODESTOREMOVE ircd->modestoremove #endif argv[0] = sstrdup(MODESTOREMOVE); argv[1] = c->key ? sstrdup(c->key) : NULL; #ifndef ANOPE17x send_cmd(s_OperServ, "MODE %s %s %s", c->name, argv[0], argv[1] ? argv[1] : ""); #else anope_cmd_mode(s_ChanServ, c->name, "%s %s", argv[0], argv[1] ? argv[1] : ""); #endif if (argv[1]) { chan_set_modes(s_ChanServ, c, 2, argv, 0); free(argv[1]); } else { chan_set_modes(s_ChanServ, c, 1, argv, 0); } free(argv[0]); /* Clear bans */ count = c->bancount; bans = scalloc(sizeof(char *) * count, 1); for (i = 0; i < count; i++) { bans[i] = sstrdup(c->bans[i]); } for (i = 0; i < count; i++) { argv[0] = sstrdup("-b"); argv[1] = bans[i]; #ifndef ANOPE17x send_cmd(s_ChanServ, "MODE %s -b %s", c->name, argv[1]); #else anope_cmd_mode(s_ChanServ, c->name, "%s %s", argv[0], argv[1]); #endif chan_set_modes(s_ChanServ, c, 2, argv, 0); free(argv[1]); free(argv[0]); } free(bans); #ifdef ANOPE17x if (!ircd->except) { return; } #endif exceptcount = c->exceptcount; excepts = scalloc(sizeof(char *) * exceptcount, 1); for (i = 0; i < exceptcount; i++) { excepts[i] = sstrdup(c->excepts[i]); } for (i = 0; i < exceptcount; i++) { argv[0] = sstrdup("-e"); argv[1] = excepts[i]; #ifndef ANOPE17x send_cmd(s_ChanServ, "MODE %s -e %s", c->name, argv[1]); #else anope_cmd_mode(s_ChanServ, c->name, "%s %s", argv[0], argv[1]); #endif chan_set_modes(s_ChanServ, c, 2, argv, 0); free(argv[1]); free(argv[0]); } free(excepts); }