Split user list from Channel into ChannelUserList
[clinton/bobotpp.git] / source / Channel.C
1 // Channel.C -*- C++ -*-
2 // Copyright (c) 1997, 1998 Etienne BERNARD
3 // Copyright (C) 2002,2005,2008,2009 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 "Mask.H"
32 #include "Person.H"
33 #include "ServerConnection.H"
34 #include "ShitEntry.H"
35 #include "ShitList.H"
36 #include "StringTokenizer.H"
37 #include "User.H"
38 #include "Utils.H"
39
40 #ifdef USESCRIPTS
41 #include "Interp.H"
42 #endif
43
44 Channel::Channel(ServerConnection *c,
45 std::string name, std::string wanted = "")
46 : channelName(Utils::to_lower(name)), channelTopic(""),
47 lockedTopic(false), channelMode(0), channelLimit(0),
48 channelKey(""), keepModes(DEFAULT_KEEPMODES), wantedModes(wanted),
49 channelUserlist (name),
50 joined(false), doMode(true), gotWho(false), cnx(c)
51 {
52 if (c->bot->wantedChannels[channelName])
53 {
54 if (c->bot->wantedChannels[channelName]->keep != "")
55 keepModes = c->bot->wantedChannels[channelName]->keep;
56
57 if (c->bot->wantedChannels[channelName]->mode != "")
58 wantedModes = c->bot->wantedChannels[channelName]->mode;
59 }
60 }
61
62 Channel::~Channel()
63 { }
64
65 void
66 Channel::addNick(std::string n, std::string uh, int mode, UserList *ul,
67 bool names)
68 {
69 channelUserlist.add (n, uh, mode, ul, names);
70 }
71
72 void
73 Channel::delNick(std::string n)
74 {
75 channelUserlist.del (n);
76 }
77
78 void
79 Channel::changeNick(std::string on, std::string nn)
80 {
81 channelUserlist.change_nickname (on, nn);
82 }
83
84 bool
85 Channel::hasNick(const std::string &n) const
86 {
87 return channelUserlist.in_channel_p (n);
88 }
89
90 const User
91 Channel::getUser(const std::string &n) const
92 {
93 return channelUserlist.get (n);
94 }
95
96 void
97 Channel::change_user_key (std::string name, std::string key)
98 {
99 channelUserlist.change_user_key (name, key);
100 }
101
102 unsigned int
103 Channel::user_count () const throw ()
104 {
105 return channelUserlist.user_count ();
106 }
107
108 unsigned int
109 Channel::operator_count () const throw ()
110 {
111 return channelUserlist.operator_count ();
112 }
113
114 void
115 Channel::addBan(const Mask & mask, std::time_t expiration)
116 {
117 if (channelBanlist.add (mask, expiration))
118 cnx->queue->sendChannelMode (channelName, "+b", mask.getMask ());
119 }
120
121 void
122 Channel::delBan(const Mask & mask)
123 {
124 BanList::MatchList matches = channelBanlist.find_matches (mask);
125
126 for (BanList::MatchList::const_iterator it = matches.begin ();
127 it != matches.end ();
128 ++it)
129 {
130 if (channelBanlist.del (*it))
131 cnx->queue->sendChannelMode (channelName, "-b", mask.getMask ());
132 }
133 }
134
135 void Channel::purge_expired_bans ()
136 {
137 BanList::MatchList expired = channelBanlist.delete_expired_x ();
138
139 for (BanList::MatchList::const_iterator it = expired.begin ();
140 it != expired.end ();
141 ++it)
142 cnx->queue->sendChannelMode (channelName, "-b", (*it).getMask ());
143 }
144
145 void
146 Channel::resynchModes()
147 {
148 cnx->queue->sendChannelMode(std::string("MODE ") + channelName +
149 " +" + cnx->bot->wantedChannels[channelName]->mode);
150 }
151
152 void
153 Channel::parseMode(Person *from, std::string mode)
154 {
155 char sign = '-';
156 StringTokenizer st(mode);
157 std::string m = st.next_token(), n;
158 bool doNotObey = true; // disobey mode if server or target is protected
159 if (from)
160 try
161 {
162 doNotObey = getUser(from->getNick()).getProt () <= User::NO_PROT;
163 }
164 catch (ChannelUserList::user_not_found&)
165 { }
166
167 if (!gotWho)
168 doNotObey = false;
169
170 for (int i = 0; i < m.length(); i++)
171 switch(m[i]) {
172 case '+':
173 case '-':
174 sign = m[i];
175 break;
176 case 'p': sign =='+' ? channelMode |= PRIVATE :
177 channelMode &= ~PRIVATE;
178 if (keepModes.find('p') != -1 && doNotObey) {
179 if (sign == '-' && wantedModes.find('p') != -1)
180 cnx->queue->sendChannelMode(channelName, "+p", "");
181 else
182 cnx->queue->sendChannelMode(channelName, "-p", "");
183 }
184 break;
185 case 's': sign =='+' ? channelMode |= SECRET :
186 channelMode &= ~SECRET;
187 if (keepModes.find('s') != -1 && doNotObey) {
188 if (sign == '-' && wantedModes.find('s') != -1)
189 cnx->queue->sendChannelMode(channelName, "+s", "");
190 else
191 cnx->queue->sendChannelMode(channelName, "-s", "");
192 }
193 break;
194 case 'i': sign =='+' ? channelMode |= INVITE_ONLY :
195 channelMode &= ~INVITE_ONLY;
196 if (keepModes.find('i') != -1 && doNotObey) {
197 if (sign == '-' && wantedModes.find('i') != -1)
198 cnx->queue->sendChannelMode(channelName, "+i", "");
199 else
200 cnx->queue->sendChannelMode(channelName, "-i", "");
201 }
202 break;
203 case 't': sign =='+' ? channelMode |= TOPIC_RESTRICTED :
204 channelMode &= ~TOPIC_RESTRICTED;
205 if (keepModes.find('t') != -1 && doNotObey) {
206 if (sign == '-' && wantedModes.find('t') != -1)
207 cnx->queue->sendChannelMode(channelName, "+t", "");
208 else
209 cnx->queue->sendChannelMode(channelName, "-t", "");
210 }
211 break;
212 case 'n': sign =='+' ? channelMode |= EXTMSG_RESTRICTED :
213 channelMode &= ~EXTMSG_RESTRICTED;
214 if (keepModes.find('n') != -1 && doNotObey) {
215 if (sign == '-' && wantedModes.find('n') != -1)
216 cnx->queue->sendChannelMode(channelName, "+n", "");
217 else
218 cnx->queue->sendChannelMode(channelName, "-n", "");
219 }
220 break;
221 case 'm': sign =='+' ? channelMode |= MODERATED :
222 channelMode &= ~MODERATED;
223 if (keepModes.find('m') != -1 && doNotObey) {
224 if (sign == '-' && wantedModes.find('m') != -1)
225 cnx->queue->sendChannelMode(channelName, "+m", "");
226 else
227 cnx->queue->sendChannelMode(channelName, "-m", "");
228 }
229 break;
230 case 'l':
231 if (keepModes.find('l') != -1 && doNotObey) {
232 if (sign == '-' && wantedModes.find('l') != -1)
233 cnx->queue->sendChannelMode(channelName, "+l",
234 Utils::long2str(channelLimit));
235 else
236 cnx->queue->sendChannelMode(channelName, "-l", "");
237 }
238 channelLimit = (sign == '+' ? std::atoi(st.next_token().c_str()) :
239 channelLimit = 0);
240 break;
241 case 'k':
242 channelKey = st.next_token();
243 if (keepModes.find('k') != -1 && doNotObey) {
244 if (sign == '-' && wantedModes.find('k') != -1)
245 cnx->queue->sendChannelMode(channelName, "+k", channelKey);
246 else
247 cnx->queue->sendChannelMode(channelName, "-k", channelKey);
248 }
249 cnx->bot->wantedChannels[channelName]->key = (sign == '+' ? channelKey :
250 std::string(""));
251 break;
252 case 'o':
253 try
254 {
255 n = st.next_token();
256 User u = getUser(n);
257 // if (joined)
258 // sign == '+' ? countOp++ : countOp--;
259 channelUserlist.change_user_mode (n, User::OP_MODE, sign != '+');
260
261 if (sign == '-' && u.getProt() >= User::NO_DEOP) {
262 std::string fromNick = from->getNick();
263 User v = getUser(fromNick);
264
265 if (n == fromNick)
266 return;
267
268 if (v.getProt() < User::NO_DEOP)
269 cnx->queue->sendChannelMode(channelName, "-o", fromNick);
270
271 cnx->queue->sendChannelMode(channelName, "+o", n);
272 }
273
274 if (sign == '+') {
275 if (doNotObey && !from &&
276 u.getProt() < User::NO_DEOP && !u.getAop())
277 cnx->queue->sendChannelMode(channelName, "-o", n);
278 ShitEntry * se =
279 cnx->bot->shitList->getShit(n+"!"+cnx->bot->getUserhost(channelName, n),
280 channelName);
281 if (se && se->isStillValid() &&
282 se->getShitLevel() >= ShitEntry::SHIT_NOOP)
283 cnx->queue->sendChannelMode(channelName, "-o", n);
284 if (Utils::to_lower (n) == cnx->bot->nickName.toLower() && doMode) {
285 doMode = false;
286 resynchModes();
287 }
288 }
289 break;
290 }
291 catch (ChannelUserList::user_not_found &)
292 {
293 break;
294 }
295 case 'v':
296 channelUserlist.change_user_mode (st.next_token (),
297 User::VOICE_MODE,
298 sign != '+');
299 break;
300 case 'b':
301 std::string m = st.next_token();
302 if (sign == '+')
303 channelBanlist.add (Mask(m));
304 if (sign == '-')
305 {
306 ShitEntry * se = cnx->bot->shitList->getShit(m, channelName);
307
308 if (se && se->isStillValid() &&
309 se->getShitLevel() >= ShitEntry::SHIT_NODEBAN)
310 cnx->queue->sendChannelMode(channelName, "+b", m);
311 else
312 channelBanlist.del (Mask(m));
313
314 }
315 }
316 }