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