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