anope- supernets anope source code & configuration |
git clone git://git.acid.vegas/anope.git |
Log | Files | Refs | Archive | README |
botserv.cpp (7686B)
1 /* BotServ core functions 2 * 3 * (C) 2003-2022 Anope Team 4 * Contact us at team@anope.org 5 * 6 * Please read COPYING and README for further details. 7 * 8 * Based on the original code of Epona by Lara. 9 * Based on the original code of Services by Andy Church. 10 */ 11 12 #include "module.h" 13 14 class BotServCore : public Module 15 { 16 Reference<BotInfo> BotServ; 17 ExtensibleRef<bool> persist, inhabit; 18 19 public: 20 BotServCore(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, PSEUDOCLIENT | VENDOR), 21 persist("PERSIST"), inhabit("inhabit") 22 { 23 } 24 25 void OnReload(Configuration::Conf *conf) anope_override 26 { 27 const Anope::string &bsnick = conf->GetModule(this)->Get<const Anope::string>("client"); 28 BotServ = BotInfo::Find(bsnick, true); 29 } 30 31 void OnSetCorrectModes(User *user, Channel *chan, AccessGroup &access, bool &give_modes, bool &take_modes) anope_override 32 { 33 /* Do not allow removing bot modes on our service bots */ 34 if (chan->ci && chan->ci->bi == user) 35 { 36 const Anope::string &botmodes = Config->GetModule(this)->Get<const Anope::string>("botmodes"); 37 for (unsigned i = 0; i < botmodes.length(); ++i) 38 chan->SetMode(chan->ci->bi, ModeManager::FindChannelModeByChar(botmodes[i]), chan->ci->bi->GetUID()); 39 } 40 } 41 42 void OnBotAssign(User *sender, ChannelInfo *ci, BotInfo *bi) anope_override 43 { 44 if (ci->c && ci->c->users.size() >= Config->GetModule(this)->Get<unsigned>("minusers")) 45 { 46 ChannelStatus status(Config->GetModule(this)->Get<const Anope::string>("botmodes")); 47 bi->Join(ci->c, &status); 48 } 49 } 50 51 void OnJoinChannel(User *user, Channel *c) anope_override 52 { 53 if (!Config || !IRCD) 54 return; 55 56 BotInfo *bi = user->server == Me ? dynamic_cast<BotInfo *>(user) : NULL; 57 if (bi && Config->GetModule(this)->Get<bool>("smartjoin")) 58 { 59 std::vector<Anope::string> bans = c->GetModeList("BAN"); 60 61 /* We check for bans */ 62 for (unsigned int i = 0; i < bans.size(); ++i) 63 { 64 Entry ban("BAN", bans[i]); 65 if (ban.Matches(user)) 66 c->RemoveMode(NULL, "BAN", ban.GetMask()); 67 } 68 69 Anope::string Limit; 70 unsigned limit = 0; 71 try 72 { 73 if (c->GetParam("LIMIT", Limit)) 74 limit = convertTo<unsigned>(Limit); 75 } 76 catch (const ConvertException &) { } 77 78 /* Should we be invited? */ 79 if (c->HasMode("INVITE") || (limit && c->users.size() >= limit)) 80 { 81 ChannelMode *cm = ModeManager::FindChannelModeByName("OP"); 82 char symbol = cm ? anope_dynamic_static_cast<ChannelModeStatus *>(cm)->symbol : 0; 83 IRCD->SendNotice(bi, (symbol ? Anope::string(symbol) : "") + c->name, "%s invited %s into the channel.", user->nick.c_str(), user->nick.c_str()); 84 } 85 86 ModeManager::ProcessModes(); 87 } 88 89 if (user->server != Me && c->ci && c->ci->bi) 90 { 91 /** 92 * We let the bot join even if it was an ignored user, as if we don't, 93 * and the ignored user doesn't just leave, the bot will never 94 * make it into the channel, leaving the channel botless even for 95 * legit users - Rob 96 **/ 97 /* This is before the user has joined the channel, so check usercount + 1 */ 98 if (c->users.size() + 1 >= Config->GetModule(this)->Get<unsigned>("minusers") && !c->FindUser(c->ci->bi)) 99 { 100 ChannelStatus status(Config->GetModule(this)->Get<const Anope::string>("botmodes")); 101 c->ci->bi->Join(c, &status); 102 } 103 } 104 } 105 106 void OnLeaveChannel(User *u, Channel *c) anope_override 107 { 108 /* Channel is persistent, it shouldn't be deleted and the service bot should stay */ 109 if (c->ci && persist && persist->HasExt(c->ci)) 110 return; 111 112 /* Channel is syncing from a netburst, don't destroy it as more users are probably wanting to join immediately 113 * We also don't part the bot here either, if necessary we will part it after the sync 114 */ 115 if (c->syncing) 116 return; 117 118 /* Additionally, do not delete this channel if ChanServ/a BotServ bot is inhabiting it */ 119 if (inhabit && inhabit->HasExt(c)) 120 return; 121 122 /* This is called prior to removing the user from the channel, so c->users.size() - 1 should be safe */ 123 if (c->ci && c->ci->bi && u != *c->ci->bi && c->users.size() - 1 <= Config->GetModule(this)->Get<unsigned>("minusers") && c->FindUser(c->ci->bi)) 124 c->ci->bi->Part(c->ci->c); 125 } 126 127 EventReturn OnPreHelp(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override 128 { 129 if (!params.empty()) 130 return EVENT_CONTINUE; 131 132 if (source.c) 133 { 134 source.Reply(_("\002%s\002 allows you to execute \"fantasy\" commands in the channel.\n" 135 "Fantasy commands are commands that can be executed from messaging a\n" 136 "channel, and provide a more convenient way to execute commands. Commands that\n" 137 "require a channel as a parameter will automatically have that parameter\n" 138 "given.\n"), source.service->nick.c_str()); 139 const Anope::string &fantasycharacters = Config->GetModule("fantasy")->Get<const Anope::string>("fantasycharacter", "!"); 140 if (!fantasycharacters.empty()) 141 source.Reply(_(" \n" 142 "Fantasy commands may be prefixed with one of the following characters: %s\n"), fantasycharacters.c_str()); 143 source.Reply(_(" \n" 144 "Available commands are:")); 145 } 146 else if (*source.service == BotServ) 147 { 148 source.Reply(_("\002%s\002 allows you to have a bot on your own channel.\n" 149 "It has been created for users that can't host or\n" 150 "configure a bot, or for use on networks that don't\n" 151 "allow user bots. Available commands are listed\n" 152 "below; to use them, type \002%s%s \037command\037\002. For\n" 153 "more information on a specific command, type\n" 154 "\002%s%s %s \037command\037\002.\n"), 155 BotServ->nick.c_str(), Config->StrictPrivmsg.c_str(), BotServ->nick.c_str(), 156 Config->StrictPrivmsg.c_str(), BotServ->nick.c_str(), source.command.c_str()); 157 } 158 159 return EVENT_CONTINUE; 160 } 161 162 void OnPostHelp(CommandSource &source, const std::vector<Anope::string> ¶ms) anope_override 163 { 164 if (!params.empty() || source.c || source.service != *BotServ) 165 return; 166 167 source.Reply(_(" \n" 168 "Bot will join a channel whenever there is at least\n" 169 "\002%d\002 user(s) on it."), Config->GetModule(this)->Get<unsigned>("minusers")); 170 const Anope::string &fantasycharacters = Config->GetModule("fantasy")->Get<const Anope::string>("fantasycharacter", "!"); 171 if (!fantasycharacters.empty()) 172 source.Reply(_("Additionally, if fantasy is enabled fantasy commands\n" 173 "can be executed by prefixing the command name with\n" 174 "one of the following characters: %s"), fantasycharacters.c_str()); 175 } 176 177 EventReturn OnChannelModeSet(Channel *c, MessageSource &source, ChannelMode *mode, const Anope::string ¶m) anope_override 178 { 179 if (source.GetUser() && !source.GetBot() && Config->GetModule(this)->Get<bool>("smartjoin") && mode->name == "BAN" && c->ci && c->ci->bi && c->FindUser(c->ci->bi)) 180 { 181 BotInfo *bi = c->ci->bi; 182 183 Entry ban("BAN", param); 184 if (ban.Matches(bi)) 185 c->RemoveMode(bi, "BAN", param); 186 } 187 188 return EVENT_CONTINUE; 189 } 190 191 void OnCreateChan(ChannelInfo *ci) anope_override 192 { 193 /* Set default bot flags */ 194 spacesepstream sep(Config->GetModule(this)->Get<const Anope::string>("defaults", "greet fantasy")); 195 for (Anope::string token; sep.GetToken(token);) 196 ci->Extend<bool>("BS_" + token.upper()); 197 } 198 199 void OnUserKicked(const MessageSource &source, User *target, const Anope::string &channel, ChannelStatus &status, const Anope::string &kickmsg) anope_override 200 { 201 BotInfo *bi = BotInfo::Find(target->GetUID()); 202 if (bi) 203 /* Bots get rejoined */ 204 bi->Join(channel, &status); 205 } 206 207 void OnCreateBot(BotInfo *bi) anope_override 208 { 209 if (bi->botmodes.empty()) 210 bi->botmodes = Config->GetModule(this)->Get<const Anope::string>("botumodes"); 211 } 212 }; 213 214 MODULE_INIT(BotServCore)