1 /* BotServ core functions
2  *
3  * (C) 2003-2020 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 CommandBSAssign : public Command
15 {
16  public:
CommandBSAssign(Module * creator)17 	CommandBSAssign(Module *creator) : Command(creator, "botserv/assign", 2, 2)
18 	{
19 		this->SetDesc(_("Assigns a bot to a channel"));
20 		this->SetSyntax(_("\037channel\037 \037nick\037"));
21 	}
22 
Execute(CommandSource & source,const std::vector<Anope::string> & params)23 	void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
24 	{
25 		const Anope::string &chan = params[0];
26 		const Anope::string &nick = params[1];
27 
28 		if (Anope::ReadOnly)
29 		{
30 			source.Reply(_("Sorry, bot assignment is temporarily disabled."));
31 			return;
32 		}
33 
34 		ChannelInfo *ci = ChannelInfo::Find(params[0]);
35 		if (ci == NULL)
36 		{
37 			source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str());
38 			return;
39 		}
40 
41 		BotInfo *bi = BotInfo::Find(nick, true);
42 		if (!bi)
43 		{
44 			source.Reply(BOT_DOES_NOT_EXIST, nick.c_str());
45 			return;
46 		}
47 
48 		AccessGroup access = source.AccessFor(ci);
49 		if (ci->HasExt("BS_NOBOT") || (!access.HasPriv("ASSIGN") && !source.HasPriv("botserv/administration")))
50 		{
51 			source.Reply(ACCESS_DENIED);
52 			return;
53 		}
54 
55 		if (bi->oper_only && !source.HasPriv("botserv/administration"))
56 		{
57 			source.Reply(ACCESS_DENIED);
58 			return;
59 		}
60 
61 		if (ci->bi == bi)
62 		{
63 			source.Reply(_("Bot \002%s\002 is already assigned to channel \002%s\002."), ci->bi->nick.c_str(), chan.c_str());
64 			return;
65 		}
66 
67 		bool override = !access.HasPriv("ASSIGN");
68 		Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "for " << bi->nick;
69 
70 		bi->Assign(source.GetUser(), ci);
71 		source.Reply(_("Bot \002%s\002 has been assigned to %s."), bi->nick.c_str(), ci->name.c_str());
72 	}
73 
OnHelp(CommandSource & source,const Anope::string & subcommand)74 	bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
75 	{
76 		this->SendSyntax(source);
77 		source.Reply(" ");
78 		source.Reply(_("Assigns the specified bot to a channel. You\n"
79 				"can then configure the bot for the channel so it fits\n"
80 				"your needs."));
81 		return true;
82 	}
83 };
84 
85 class CommandBSUnassign : public Command
86 {
87  public:
CommandBSUnassign(Module * creator)88 	CommandBSUnassign(Module *creator) : Command(creator, "botserv/unassign", 1, 1)
89 	{
90 		this->SetDesc(_("Unassigns a bot from a channel"));
91 		this->SetSyntax(_("\037channel\037"));
92 	}
93 
Execute(CommandSource & source,const std::vector<Anope::string> & params)94 	void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
95 	{
96 		if (Anope::ReadOnly)
97 		{
98 			source.Reply(_("Sorry, bot assignment is temporarily disabled."));
99 			return;
100 		}
101 
102 		ChannelInfo *ci = ChannelInfo::Find(params[0]);
103 		if (ci == NULL)
104 		{
105 			source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str());
106 			return;
107 		}
108 
109 		AccessGroup access = source.AccessFor(ci);
110 		if (!source.HasPriv("botserv/administration") && !access.HasPriv("ASSIGN"))
111 		{
112 			source.Reply(ACCESS_DENIED);
113 			return;
114 		}
115 
116 		if (!ci->bi)
117 		{
118 			source.Reply(BOT_NOT_ASSIGNED);
119 			return;
120 		}
121 
122 		if (ci->HasExt("PERSIST") && !ModeManager::FindChannelModeByName("PERM"))
123 		{
124 			source.Reply(_("You cannot unassign bots while persist is set on the channel."));
125 			return;
126 		}
127 
128 		bool override = !access.HasPriv("ASSIGN");
129 		Log(override ? LOG_OVERRIDE : LOG_COMMAND, source, this, ci) << "for " << ci->bi->nick;
130 
131 		ci->bi->UnAssign(source.GetUser(), ci);
132 		source.Reply(_("There is no bot assigned to %s anymore."), ci->name.c_str());
133 	}
134 
OnHelp(CommandSource & source,const Anope::string & subcommand)135 	bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
136 	{
137 		this->SendSyntax(source);
138 		source.Reply(" ");
139 		source.Reply(_("Unassigns a bot from a channel. When you use this command,\n"
140 				"the bot won't join the channel anymore. However, bot\n"
141 				"configuration for the channel is kept, so you will always\n"
142 				"be able to reassign a bot later without having to reconfigure\n"
143 				"it entirely."));
144 		return true;
145 	}
146 };
147 
148 class CommandBSSetNoBot : public Command
149 {
150  public:
CommandBSSetNoBot(Module * creator,const Anope::string & sname="botserv/set/nobot")151 	CommandBSSetNoBot(Module *creator, const Anope::string &sname = "botserv/set/nobot") : Command(creator, sname, 2, 2)
152 	{
153 		this->SetDesc(_("Prevent a bot from being assigned to a channel"));
154 		this->SetSyntax(_("\037channel\037 {\037ON|OFF\037}"));
155 	}
156 
Execute(CommandSource & source,const std::vector<Anope::string> & params)157 	void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
158 	{
159 		ChannelInfo *ci = ChannelInfo::Find(params[0]);
160 		const Anope::string &value = params[1];
161 
162 		if (Anope::ReadOnly)
163 		{
164 			source.Reply(_("Sorry, bot modification is temporarily disabled."));
165 			return;
166 		}
167 
168 		if (ci == NULL)
169 		{
170 			source.Reply(CHAN_X_NOT_REGISTERED, params[0].c_str());
171 			return;
172 		}
173 
174 		if (value.equals_ci("ON"))
175 		{
176 			Log(LOG_ADMIN, source, this, ci) << "to enable nobot";
177 
178 			ci->Extend<bool>("BS_NOBOT");
179 			if (ci->bi)
180 				ci->bi->UnAssign(source.GetUser(), ci);
181 			source.Reply(_("No-bot mode is now \002on\002 on channel %s."), ci->name.c_str());
182 		}
183 		else if (value.equals_ci("OFF"))
184 		{
185 			Log(LOG_ADMIN, source, this, ci) << "to disable nobot";
186 
187 			ci->Shrink<bool>("BS_NOBOT");
188 			source.Reply(_("No-bot mode is now \002off\002 on channel %s."), ci->name.c_str());
189 		}
190 		else
191 			this->OnSyntaxError(source, source.command);
192 	}
193 
OnHelp(CommandSource & source,const Anope::string &)194 	bool OnHelp(CommandSource &source, const Anope::string &) anope_override
195 	{
196 		this->SendSyntax(source);
197 		source.Reply(_(" \n"
198 				"This option makes a channel unassignable. If a bot\n"
199 				"is already assigned to the channel, it is unassigned\n"
200 				"automatically when you enable it."));
201 		return true;
202 	}
203 };
204 
205 class BSAssign : public Module
206 {
207 	ExtensibleItem<bool> nobot;
208 
209 	CommandBSAssign commandbsassign;
210 	CommandBSUnassign commandbsunassign;
211 	CommandBSSetNoBot commandbssetnobot;
212 
213  public:
BSAssign(const Anope::string & modname,const Anope::string & creator)214 	BSAssign(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
215 		nobot(this, "BS_NOBOT"),
216 		commandbsassign(this), commandbsunassign(this), commandbssetnobot(this)
217 	{
218 	}
219 
OnInvite(User * source,Channel * c,User * targ)220 	void OnInvite(User *source, Channel *c, User *targ) anope_override
221 	{
222 		BotInfo *bi;
223 		if (Anope::ReadOnly || !c->ci || targ->server != Me || !(bi = dynamic_cast<BotInfo *>(targ)))
224 			return;
225 
226 		AccessGroup access = c->ci->AccessFor(source);
227 		if (nobot.HasExt(c->ci) || (!access.HasPriv("ASSIGN") && !source->HasPriv("botserv/administration")))
228 		{
229 			targ->SendMessage(bi, ACCESS_DENIED);
230 			return;
231 		}
232 
233 		if (bi->oper_only && !source->HasPriv("botserv/administration"))
234 		{
235 			targ->SendMessage(bi, ACCESS_DENIED);
236 			return;
237 		}
238 
239 		if (c->ci->bi == bi)
240 		{
241 			targ->SendMessage(bi, _("Bot \002%s\002 is already assigned to channel \002%s\002."), c->ci->bi->nick.c_str(), c->name.c_str());
242 			return;
243 		}
244 
245 		bi->Assign(source, c->ci);
246 		targ->SendMessage(bi, _("Bot \002%s\002 has been assigned to %s."), bi->nick.c_str(), c->name.c_str());
247 	}
248 
OnBotInfo(CommandSource & source,BotInfo * bi,ChannelInfo * ci,InfoFormatter & info)249 	void OnBotInfo(CommandSource &source, BotInfo *bi, ChannelInfo *ci, InfoFormatter &info) anope_override
250 	{
251 		if (nobot.HasExt(ci))
252 			info.AddOption(_("No bot"));
253 	}
254 };
255 
256 MODULE_INIT(BSAssign)
257