Implement threadsafe banlist and make maintenance of bans cleaner
[clinton/bobotpp.git] / source / Channel.C
CommitLineData
cb21075d 1// Channel.C -*- C++ -*-
2// Copyright (c) 1997, 1998 Etienne BERNARD
55f2215d 3// Copyright (C) 2002,2005,2008 Clinton Ebadi
cb21075d 4
5// This program is free software; you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation; either version 2 of the License, or
8// any later version.
9
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14
15// You should have received a copy of the GNU General Public License
16// along with this program; if not, write to the Free Software
7b564711 17// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18// 02110-1301, USA.
cb21075d 19
20#ifdef HAVE_CONFIG_H
21#include "config.h"
22#endif
23
cfa82921 24#include "Channel.H"
25
55f2215d 26#include <cstdlib>
27
cfa82921 28#include "BanEntry.H"
29#include "Bot.H"
cb21075d 30#include "Macros.H"
f9723c92 31#include "Mask.H"
cfa82921 32#include "Person.H"
33#include "ServerConnection.H"
34#include "ShitEntry.H"
35#include "ShitList.H"
cb21075d 36#include "StringTokenizer.H"
cfa82921 37#include "User.H"
38#include "Utils.H"
39
cb21075d 40#ifdef USESCRIPTS
41#include "Interp.H"
42#endif
43
44Channel::Channel(ServerConnection *c,
45 String name, String wanted = "")
46 : channelName(name.toLower()), channelTopic(""),
47 lockedTopic(false), channelMode(0), channelLimit(0),
48 channelKey(""), keepModes(DEFAULT_KEEPMODES), wantedModes(wanted), count(0),
49 countOp(0), joined(false), doMode(true), gotWho(false), cnx(c)
50{
51#ifdef HAVE_STL_CLEAR
52 channelMemory.clear();
cb21075d 53#endif
54 if (c->bot->wantedChannels[channelName])
55 {
56 if (c->bot->wantedChannels[channelName]->keep != "")
57 keepModes = c->bot->wantedChannels[channelName]->keep;
58
59 if (c->bot->wantedChannels[channelName]->mode != "")
60 wantedModes = c->bot->wantedChannels[channelName]->mode;
61 }
62}
63
64Channel::~Channel()
65{
66 User *u;
67 std::map<String, User *, std::less<String> >::iterator it;
68
69 while (channelMemory.size() != 0) {
70 it = channelMemory.begin();
71 u = (*it).second;
72 if (u && u->userListItem && u->userListItem->identified > 0)
73 u->userListItem->identified--;
74 channelMemory.erase(it);
75 delete u;
76 }
cb21075d 77}
78
79void
80Channel::addNick(String n, String uh, int mode, UserList *ul,
81 bool names)
82{
83 if (User * u = getUser(n.toLower())) {
84 count--;
85 if (u->mode & User::OP_MODE)
86 countOp--;
87 channelMemory.erase(n.toLower());
88 delete u;
89 }
90
91 User *u;
92
93 if (names)
94 u = new User(n, mode);
95 else
96 u = new User(n, uh, channelName, mode, ul);
97
98 channelMemory[n.toLower()] = u;
99
100 if (u->userListItem) {
101 if (u->userListItem->identified)
102 u->userListItem->identified++;
103 else {
104 if (u->userListItem->passwd == "")
105 u->userListItem->identified = 1;
106 }
107 }
108
109 count++;
110 if (u->mode & User::OP_MODE)
111 countOp++;
112}
113
114void
115Channel::delNick(String n)
116{
117 n = n.toLower();
118 User *u = getUser(n);
119
120 if (!u)
121 return;
122
123 if (channelMemory[n]!=0) {
124 channelMemory.erase(n);
125 }
126
127 count--;
128 if (u->mode & User::OP_MODE)
129 countOp--;
130 if (u->userListItem && u->userListItem->identified > 0)
131 u->userListItem->identified--;
132 delete u;
133}
134
135void
136Channel::changeNick(String on, String nn)
137{
138 on = on.toLower();
139 User *u = getUser(on);
140 channelMemory.erase(on);
141 channelMemory[nn.toLower()] = u;
142}
143
144bool
145Channel::hasNick(String n)
146{
147 return getUser(n.toLower()) != 0;
148}
149
150User *
151Channel::getUser(String n)
152{
153 User *u;
154
155 n = n.toLower();
156
157 if ((u = channelMemory[n]) == 0) {
158 channelMemory.erase(n);
159 return 0;
160 }
161
162 return u;
163}
164
165void
f9723c92 166Channel::addBan(const Mask & mask, std::time_t expiration)
cb21075d 167{
f9723c92 168 if (channelBanlist.add (mask, expiration))
169 cnx->queue->sendChannelMode (channelName, "+b", mask.getMask ());
cb21075d 170}
171
172void
f9723c92 173Channel::delBan(const Mask & mask)
cb21075d 174{
f9723c92 175 BanList::MatchList matches = channelBanlist.find_matches (mask);
176
177 for (BanList::MatchList::const_iterator it = matches.begin ();
178 it != matches.end ();
179 ++it)
180 {
181 if (channelBanlist.del (*it))
182 cnx->queue->sendChannelMode (channelName, "-b", mask.getMask ());
cb21075d 183 }
184}
185
f9723c92 186void Channel::purge_expired_bans ()
187{
188 BanList::MatchList expired = channelBanlist.delete_expired_x ();
189
190 for (BanList::MatchList::const_iterator it = expired.begin ();
191 it != expired.end ();
192 ++it)
193 cnx->queue->sendChannelMode (channelName, "-b", (*it).getMask ());
194}
195
cb21075d 196void
197Channel::resynchModes()
198{
199 cnx->queue->sendChannelMode(String("MODE ") + channelName +
200 " +" + cnx->bot->wantedChannels[channelName]->mode);
201}
202
203void
204Channel::parseMode(Person *from, String mode)
205{
206 char sign = '-';
207 StringTokenizer st(mode);
a6339323 208 String m = st.next_token(), n;
cb21075d 209 User *u = 0;
210 if (from)
211 u = getUser(from->getNick());
212 // u == 0 if it's a server mode
213 bool doNotObey = !u || (u->getProt() <= User::NO_PROT);
214 if (!gotWho)
215 doNotObey = false;
216
217 for (int i = 0; i < m.length(); i++)
218 switch(m[i]) {
219 case '+':
220 case '-':
221 sign = m[i];
222 break;
223 case 'p': sign =='+' ? channelMode |= PRIVATE :
224 channelMode &= ~PRIVATE;
225 if (keepModes.find('p') != -1 && doNotObey) {
226 if (sign == '-' && wantedModes.find('p') != -1)
227 cnx->queue->sendChannelMode(channelName, "+p", "");
228 else
229 cnx->queue->sendChannelMode(channelName, "-p", "");
230 }
231 break;
232 case 's': sign =='+' ? channelMode |= SECRET :
233 channelMode &= ~SECRET;
234 if (keepModes.find('s') != -1 && doNotObey) {
235 if (sign == '-' && wantedModes.find('s') != -1)
236 cnx->queue->sendChannelMode(channelName, "+s", "");
237 else
238 cnx->queue->sendChannelMode(channelName, "-s", "");
239 }
240 break;
241 case 'i': sign =='+' ? channelMode |= INVITE_ONLY :
242 channelMode &= ~INVITE_ONLY;
243 if (keepModes.find('i') != -1 && doNotObey) {
244 if (sign == '-' && wantedModes.find('i') != -1)
245 cnx->queue->sendChannelMode(channelName, "+i", "");
246 else
247 cnx->queue->sendChannelMode(channelName, "-i", "");
248 }
249 break;
250 case 't': sign =='+' ? channelMode |= TOPIC_RESTRICTED :
251 channelMode &= ~TOPIC_RESTRICTED;
252 if (keepModes.find('t') != -1 && doNotObey) {
253 if (sign == '-' && wantedModes.find('t') != -1)
254 cnx->queue->sendChannelMode(channelName, "+t", "");
255 else
256 cnx->queue->sendChannelMode(channelName, "-t", "");
257 }
258 break;
259 case 'n': sign =='+' ? channelMode |= EXTMSG_RESTRICTED :
260 channelMode &= ~EXTMSG_RESTRICTED;
261 if (keepModes.find('n') != -1 && doNotObey) {
262 if (sign == '-' && wantedModes.find('n') != -1)
263 cnx->queue->sendChannelMode(channelName, "+n", "");
264 else
265 cnx->queue->sendChannelMode(channelName, "-n", "");
266 }
267 break;
268 case 'm': sign =='+' ? channelMode |= MODERATED :
269 channelMode &= ~MODERATED;
270 if (keepModes.find('m') != -1 && doNotObey) {
271 if (sign == '-' && wantedModes.find('m') != -1)
272 cnx->queue->sendChannelMode(channelName, "+m", "");
273 else
274 cnx->queue->sendChannelMode(channelName, "-m", "");
275 }
276 break;
277 case 'l':
278 if (keepModes.find('l') != -1 && doNotObey) {
279 if (sign == '-' && wantedModes.find('l') != -1)
280 cnx->queue->sendChannelMode(channelName, "+l",
281 String((long)channelLimit));
282 else
283 cnx->queue->sendChannelMode(channelName, "-l", "");
284 }
a6339323 285 channelLimit = (sign == '+' ? std::atoi(st.next_token().c_str()) :
cb21075d 286 channelLimit = 0);
287 break;
288 case 'k':
a6339323 289 channelKey = st.next_token();
cb21075d 290 if (keepModes.find('k') != -1 && doNotObey) {
291 if (sign == '-' && wantedModes.find('k') != -1)
292 cnx->queue->sendChannelMode(channelName, "+k", channelKey);
293 else
294 cnx->queue->sendChannelMode(channelName, "-k", channelKey);
295 }
296 cnx->bot->wantedChannels[channelName]->key = (sign == '+' ? channelKey :
297 String(""));
298 break;
299 case 'o':
a6339323 300 n = st.next_token();
cb21075d 301 u = getUser(n);
302 if (joined)
303 sign == '+' ? countOp++ : countOp--;
304 if (!u)
305 break;
306 sign == '+' ? (u->mode |= User::OP_MODE) :
307 (u->mode &= ~User::OP_MODE);
308 if (sign == '-' && u->getProt() >= User::NO_DEOP) {
309 String fromNick = from->getNick();
310 User * v = getUser(fromNick);
311 if (u == v)
312 return;
313 if (v->getProt() < User::NO_DEOP)
314 cnx->queue->sendChannelMode(channelName, "-o", fromNick);
315 cnx->queue->sendChannelMode(channelName, "+o", n);
316 }
317 if (sign == '+') {
318 if (doNotObey && !from &&
319 u->getProt() < User::NO_DEOP && !u->getAop())
320 cnx->queue->sendChannelMode(channelName, "-o", n);
321 ShitEntry * se =
322 cnx->bot->shitList->getShit(n+"!"+cnx->bot->getUserhost(channelName, n),
323 channelName);
324 if (se && se->isStillValid() &&
325 se->getShitLevel() >= ShitEntry::SHIT_NOOP)
326 cnx->queue->sendChannelMode(channelName, "-o", n);
327 if (n.toLower() == cnx->bot->nickName.toLower() && doMode) {
328 doMode = false;
329 resynchModes();
330 }
331 }
332 break;
333 case 'v':
a6339323 334 u = getUser(st.next_token());
cb21075d 335 u->mode = (sign == '+' ? u->mode |= User::VOICE_MODE :
336 u->mode &= ~User::VOICE_MODE);
337 break;
338 case 'b':
a6339323 339 String m = st.next_token();
f9723c92 340 if (sign == '+')
341 channelBanlist.add (m);
342 if (sign == '-')
343 {
344 ShitEntry * se = cnx->bot->shitList->getShit(m, channelName);
345
346 if (se && se->isStillValid() &&
347 se->getShitLevel() >= ShitEntry::SHIT_NODEBAN)
cb21075d 348 cnx->queue->sendChannelMode(channelName, "+b", m);
f9723c92 349 else
350 channelBanlist.del (m);
351
352 }
cb21075d 353 }
354}