summaryrefslogtreecommitdiff
path: root/src/modules/m_remove.cpp
blob: 89b3234ec842f028ff852cbe9a380826c91424fc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
/* Support for a dancer-style /remove command, an alternative to /kick to try and avoid auto-rejoin-on-kick scripts */
/* Written by Om, 25-03-05 */

using namespace std;

#include <stdio.h>
#include <string>
#include "users.h"
#include "channels.h"
#include "modules.h"
#include "helperfuncs.h"

/* $ModDesc: Provides a /remove command, this is mostly an alternative to /kick, except makes users appear to have parted the channel */

/*	
 * This module supports the use of the +q and +a usermodes, but should work without them too.
 * Usage of the command is restricted to +hoaq, and you cannot remove a user with a "higher" level than yourself.
 * eg: +h can remove +hv and users with no modes. +a can remove +aohv and users with no modes.
*/

static Server *Srv;

/* This little function just converts a chanmode character (~ & @ & +) into an integer (5 4 3 2 1) */
/* XXX - this could be handy in the core, so it can be used elsewhere */
int chartolevel(std::string &privs)
{
	const char* n = privs.c_str();

	switch (*n)
	{
		case '~':
			return 5;
		break;
		case '&':
			return 4;
		break;
		case '@':
			return 3;
		break;
		case '%':
			return 2;
		break;
		default:
			return 1;
		break;
	}
	return 1;
}

class cmd_remove : public command_t
{
 public:
	cmd_remove () : command_t("REMOVE", 0, 2)
	{
		this->source = "m_remove.so";
	}

	void Handle (char **parameters, int pcnt, userrec *user)
	{
		/* Look up the user we're meant to be removing from the channel */
		userrec* target = Srv->FindNick(std::string(parameters[0]));
		/* And the channel we're meant to be removing them from */
		chanrec* channel = Srv->FindChannel(std::string(parameters[1]));

		/* Fix by brain - someone needs to learn to validate their input! */
		if (!target || !channel)
		{
			WriteServ(user->fd,"401 %s %s :No such nick/channel",user->nick, !target ? parameters[0] : parameters[1]);
			return;
		}

		/* And see if the person calling the command has access to use it on the channel */
		std::string privs = Srv->ChanMode(user, channel);
		/* Check what privs the person being removed has */
		std::string targetprivs = Srv->ChanMode(target, channel);

		int tlevel;
		int ulevel;
		int n = 2;
		std::string result;
		
		/* This turns all the parameters after the first two into a single string, so the part reason can be multi-word */
		while (n < pcnt)
		{
			result=result + std::string(" ") + std::string(parameters[n]);
			n++;
		}
		
		/* If the target nick exists... */
		if (target && channel)
		{
			for (unsigned int x = 0; x < strlen(parameters[1]); x++)
			{
					if ((parameters[1][0] != '#') || (parameters[1][x] == ' ') || (parameters[1][x] == ','))
					{
						Srv->SendTo(NULL,user,"NOTICE "+std::string(user->nick)+" :*** Invalid characters in channel name");
						return;
					}
			}
			
			/* This is adding support for the +q and +a channel modes, basically if they are enabled, and the remover has them set. */
			/* Then we change the @|%|+ to & if they are +a, or ~ if they are +q */
			if (user->GetExt("cm_protect_"+std::string(channel->name)))
				privs = std::string("&");
			if (user->GetExt("cm_founder_"+std::string(channel->name)))
				privs = std::string("~");
				
			/* Now it's the same idea, except for the target */
			if (target->GetExt("cm_protect_"+std::string(channel->name)))
				targetprivs = std::string("&");
			if (target->GetExt("cm_founder_"+std::string(channel->name)))
				targetprivs = std::string("~");
				
			tlevel = chartolevel(targetprivs);
			ulevel = chartolevel(privs);
			
			/* If the user calling the command is either an admin, owner, operator or a half-operator on the channel */
			if(ulevel > 1)
			{
				/* For now, we'll let everyone remove their level and below, eg ops can remove ops, halfops, voices, and those with no mode (no moders actually are set to 1) */
				if(ulevel >= tlevel)
				{
					Srv->PartUserFromChannel(target,std::string(parameters[1]), "Removed by "+std::string(user->nick)+":"+result);
					Srv->SendTo(NULL,user,"NOTICE "+std::string(channel->name)+" : "+std::string(user->nick)+" removed "+std::string(target->nick)+ " from the channel");
					Srv->SendTo(NULL,target,"NOTICE "+std::string(target->nick)+" :*** "+std::string(user->nick)+" removed you from "+std::string(channel->name)+" with the message:"+std::string(result));
				}
				else
				{
					Srv->SendTo(NULL,user,"NOTICE "+std::string(user->nick)+" :*** You do not have access to remove "+std::string(target->nick)+" from the "+std::string(channel->name));
				}
			}
			else
			{
				Srv->SendTo(NULL,user,"NOTICE "+std::string(user->nick)+" :*** You do not have access to use /remove on "+std::string(channel->name));
			}
		}
	}
};

class ModuleRemove : public Module
{
	cmd_remove* mycommand;
 public:
	ModuleRemove(Server* Me)
		: Module::Module(Me)
	{
		Srv = Me;
		mycommand = new cmd_remove();
		Srv->AddCommand(mycommand);
	}

	void Implements(char* List)
	{
		List[I_On005Numeric] = 1;
	}

        virtual void On005Numeric(std::string &output)
        {
                output = output + std::string(" REMOVE");
        }
	
	virtual ~ModuleRemove()
	{
	}
	
	virtual Version GetVersion()
	{
		return Version(1,0,0,1,VF_VENDOR);
	}
	
};

// stuff down here is the module-factory stuff. For basic modules you can ignore this.

class ModuleRemoveFactory : public ModuleFactory
{
 public:
	ModuleRemoveFactory()
	{
	}
	
	~ModuleRemoveFactory()
	{
	}
	
	virtual Module * CreateModule(Server* Me)
	{
		return new ModuleRemove(Me);
	}
	
};


extern "C" void * init_module( void )
{
	return new ModuleRemoveFactory;
}