1 /* OperServ 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 CommandOSMode : public Command
15 {
16  public:
CommandOSMode(Module * creator)17 	CommandOSMode(Module *creator) : Command(creator, "operserv/mode", 2, 3)
18 	{
19 		this->SetDesc(_("Change channel modes"));
20 		this->SetSyntax(_("\037channel\037 \037modes\037"));
21 		this->SetSyntax(_("\037channel\037 CLEAR [ALL]"));
22 	}
23 
Execute(CommandSource & source,const std::vector<Anope::string> & params)24 	void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
25 	{
26 		const Anope::string &target = params[0];
27 		const Anope::string &modes = params[1];
28 
29 		Reference<Channel> c = Channel::Find(target);
30 		if (!c)
31 			source.Reply(CHAN_X_NOT_IN_USE, target.c_str());
32 		else if (c->bouncy_modes)
33 			source.Reply(_("Services is unable to change modes. Are your servers' U:lines configured correctly?"));
34 		else if (modes.equals_ci("CLEAR"))
35 		{
36 			bool all = params.size() > 2 && params[2].equals_ci("ALL");
37 
38 			const Channel::ModeList chmodes = c->GetModes();
39 			for (Channel::ModeList::const_iterator it = chmodes.begin(), it_end = chmodes.end(); it != it_end && c; ++it)
40 				c->RemoveMode(c->ci->WhoSends(), it->first, it->second, false);
41 
42 			if (!c)
43 			{
44 				source.Reply(_("Modes cleared on %s and the channel destroyed."), target.c_str());
45 				return;
46 			}
47 
48 			if (all)
49 			{
50 				for (Channel::ChanUserList::iterator it = c->users.begin(), it_end = c->users.end(); it != it_end; ++it)
51 				{
52 					ChanUserContainer *uc = it->second;
53 
54 					if (uc->user->HasMode("OPER"))
55 						continue;
56 
57 					for (size_t i = uc->status.Modes().length(); i > 0; --i)
58 						c->RemoveMode(c->ci->WhoSends(), ModeManager::FindChannelModeByChar(uc->status.Modes()[i - 1]), uc->user->GetUID(), false);
59 				}
60 
61 				source.Reply(_("All modes cleared on %s."), c->name.c_str());
62 			}
63 			else
64 				source.Reply(_("Non-status modes cleared on %s."), c->name.c_str());
65 		}
66 		else
67 		{
68 			spacesepstream sep(modes + (params.size() > 2 ? " " + params[2] : ""));
69 			Anope::string mode;
70 			int add = 1;
71 			Anope::string log_modes, log_params;
72 
73 			sep.GetToken(mode);
74 			for (unsigned i = 0; i < mode.length() && c; ++i)
75 			{
76 				char ch = mode[i];
77 
78 				if (ch == '+')
79 				{
80 					add = 1;
81 					log_modes += "+";
82 					continue;
83 				}
84 				else if (ch == '-')
85 				{
86 					add = 0;
87 					log_modes += "-";
88 					continue;
89 				}
90 
91 				ChannelMode *cm = ModeManager::FindChannelModeByChar(ch);
92 				if (!cm)
93 					continue;
94 
95 				Anope::string param, param_log;
96 				if (cm->type != MODE_REGULAR)
97 				{
98 					if (cm->type == MODE_PARAM && !add && anope_dynamic_static_cast<ChannelModeParam *>(cm)->minus_no_arg)
99 						;
100 					else if (!sep.GetToken(param))
101 						continue;
102 
103 					param_log = param;
104 
105 					if (cm->type == MODE_STATUS)
106 					{
107 						User *targ = User::Find(param, true);
108 						if (targ == NULL || c->FindUser(targ) == NULL)
109 							continue;
110 						param = targ->GetUID();
111 					}
112 				}
113 
114 				log_modes += cm->mchar;
115 				if (!param.empty())
116 					log_params += " " + param_log;
117 
118 				if (add)
119 					c->SetMode(source.service, cm, param, false);
120 				else
121 					c->RemoveMode(source.service, cm, param, false);
122 			}
123 
124 			if (!log_modes.replace_all_cs("+", "").replace_all_cs("-", "").empty())
125 				Log(LOG_ADMIN, source, this) << log_modes << log_params << " on " << (c ? c->name : target);
126 		}
127 	}
128 
OnHelp(CommandSource & source,const Anope::string & subcommand)129 	bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
130 	{
131 		this->SendSyntax(source);
132 		source.Reply(" ");
133 		source.Reply(_("Allows Services Operators to change modes for any channel.\n"
134 				"Parameters are the same as for the standard /MODE command.\n"
135 				"Alternatively, CLEAR may be given to clear all modes on the channel.\n"
136 				"If CLEAR ALL is given then all modes, including user status, is removed."));
137 		return true;
138 	}
139 };
140 
141 class CommandOSUMode : public Command
142 {
143  public:
CommandOSUMode(Module * creator)144 	CommandOSUMode(Module *creator) : Command(creator, "operserv/umode", 2, 2)
145 	{
146 		this->SetDesc(_("Change user modes"));
147 		this->SetSyntax(_("\037user\037 \037modes\037"));
148 	}
149 
Execute(CommandSource & source,const std::vector<Anope::string> & params)150 	void Execute(CommandSource &source, const std::vector<Anope::string> &params) anope_override
151 	{
152 		const Anope::string &target = params[0];
153 		const Anope::string &modes = params[1];
154 
155 		User *u2 = User::Find(target, true);
156 		if (!u2)
157 			source.Reply(NICK_X_NOT_IN_USE, target.c_str());
158 		else
159 		{
160 			u2->SetModes(source.service, "%s", modes.c_str());
161 			source.Reply(_("Changed usermodes of \002%s\002 to %s."), u2->nick.c_str(), modes.c_str());
162 
163 			u2->SendMessage(source.service, _("\002%s\002 changed your usermodes to %s."), source.GetNick().c_str(), modes.c_str());
164 
165 			Log(LOG_ADMIN, source, this) << modes << " on " << target;
166 		}
167 	}
168 
OnHelp(CommandSource & source,const Anope::string & subcommand)169 	bool OnHelp(CommandSource &source, const Anope::string &subcommand) anope_override
170 	{
171 		this->SendSyntax(source);
172 		source.Reply(" ");
173 		source.Reply(_("Allows Services Operators to change modes for any user.\n"
174 				"Parameters are the same as for the standard /MODE command."));
175 		return true;
176 	}
177 };
178 
179 class OSMode : public Module
180 {
181 	CommandOSMode commandosmode;
182 	CommandOSUMode commandosumode;
183 
184  public:
OSMode(const Anope::string & modname,const Anope::string & creator)185 	OSMode(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, VENDOR),
186 		commandosmode(this), commandosumode(this)
187 	{
188 
189 	}
190 };
191 
192 MODULE_INIT(OSMode)
193