Make rate limiting penalties less severe
[clinton/bobotpp.git] / source / ServerQueue.C
CommitLineData
cb21075d 1// ServerQueue.C -*- C++ -*-
2// Copyright (c) 1997, 1998 Etienne BERNARD
46af1667 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
c99c411a 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
4ce3a244 24#include <limits>
cb21075d 25#include "ServerQueue.H"
fd7440f1 26#include "Utils.H"
cb21075d 27
0b062618 28int ServerQueue::max_penalty = 20;
29
cb21075d 30ServerQueue::ServerQueue(Socket * s, bool d)
31 : Queue(s,d), penalty(0)
32{
33#ifdef HAVE_STL_CLEAR
34 serverQueue.clear();
35#endif
36}
37
38ServerQueue::~ServerQueue()
39{
4ce3a244 40 penalty = std::numeric_limits<int>::min ();
cb21075d 41 flush();
42}
43
44void
45ServerQueue::addItem(ServerQueueItem *sqi)
46{
cd5342f5 47 BotLock queue_lock (queue_mutex);
cb21075d 48 std::list<ServerQueueItem *>::iterator it, it2;
49
c99c411a 50 for (it = serverQueue.begin(); it != serverQueue.end(); ++it)
51 {
94a03421 52 if (**it < *sqi)
c99c411a 53 {
54 break;
55 }
56 }
57
58 it2 = it;
59 --it2;
60 if (it2 != serverQueue.end() && *it2)
61 {
62 // All right, we try to merge this item to the previous
63 if ((*it2)->merge(sqi))
64 {
65 delete sqi;
66 return;
67 }
cb21075d 68 }
c99c411a 69
cb21075d 70 serverQueue.insert(it, sqi);
71}
72
73void
74ServerQueue::addLine(String l, int pr, int pen, int t)
75{
76 ServerQueueOtherItem * sqoi =
77 new ServerQueueOtherItem(l, pr, pen, t);
78 addItem(sqoi);
79}
80
81bool
82ServerQueue::flush()
83{
cd5342f5 84 // Locking around the entire queue flush prevents another thread
85 // from spamming the queue and preventing lower priority messages
86 // from ever being sent
87 BotLock flush_lock (queue_mutex);
88
cb21075d 89 // Called every second, we decrement the penalty
90 if (penalty > 0)
c99c411a 91 {
92 penalty--;
93 }
94
0b062618 95 while (!serverQueue.empty() && (penalty < max_penalty))
c99c411a 96 {
cd5342f5 97 ServerQueueItem * sqi = serverQueue.front ();
0b062618 98 penalty += sqi->penalty + sqi->getLine().length()/100;
c99c411a 99
100 bool res = sendLine(sqi->getLine());
cd5342f5 101
102 serverQueue.pop_front ();
c99c411a 103 delete sqi;
104
105 if (!res)
106 {
107 return false;
108 }
109 }
110
cb21075d 111 return true;
112}
113
fd7440f1 114#define MNICK (Interp::bot->nickName + "!" + Interp::bot->userHost)
cb21075d 115void
116ServerQueue::sendCTCP(String to, String command,
117 String message)
118{
119 sendPrivmsg(to, String("\001") + command + " " + message + "\001");
fd7440f1 120
fd7440f1 121#ifdef USESCRIPTS
122 if (command == "ACTION")
123 {
fed59248 124 Interp::bot->botInterp->RunHooks (Hook::SEND_ACTION,
125 MNICK + " " + to +
fd7440f1 126 " " + message,
46af1667 127 scm_list_n (Utils::
a6339323 128 str2scm (MNICK),
fd7440f1 129 Utils::
a6339323 130 str2scm (to),
fd7440f1 131 Utils::
a6339323 132 str2scm (message),
fd7440f1 133 SCM_UNDEFINED));
134 }
fed59248 135 else
136 Interp::bot->botInterp->RunHooks (Hook::SEND_CTCP,
c99c411a 137 MNICK + " " + to + " " +
138 command + " " + message,
46af1667 139 scm_list_n (Utils::
c99c411a 140 str2scm (MNICK),
141 Utils::
142 str2scm (to),
143 Utils::
144 str2scm
145 (command),
146 Utils::
147 str2scm (message),
148 SCM_UNDEFINED));
fd7440f1 149#endif
150
cb21075d 151}
fd7440f1 152#undef MNICK
cb21075d 153
154void
155ServerQueue::sendCTCPReply(String to, String command,
156 String message)
157{
158 sendNotice(to, String("\001") + command + " " +
159 message + "\001");
160}
161
162void
163ServerQueue::sendChannelMode(String mode)
164{
165 addLine(mode, CHANNELMODE_PRIORITY, CHANNELMODE_PENALTY,
166 ServerQueueItem::CHANNELMODE);
167}
168
169void
170ServerQueue::sendChannelMode(String channel, String mode, String parameters)
171{
172 ServerQueueChannelModeItem * sqcmi =
173 new ServerQueueChannelModeItem(channel, mode, parameters);
174 addItem(sqcmi);
175}
176
177void
178ServerQueue::sendInvite(String channel, String nick)
179{
180 addLine(String("INVITE ") + nick + " " + channel,
181 INVITE_PRIORITY, INVITE_PENALTY, ServerQueueItem::INVITE);
182}
183
184void
185ServerQueue::sendJoin(String channel, String key)
186{
187 addLine(String("JOIN ") + channel + " " + key,
188 JOIN_PRIORITY, JOIN_PENALTY, ServerQueueItem::JOIN);
189}
190
191void
192ServerQueue::sendKick(String channel, String nick, String reason)
193{
194 ServerQueueKickItem * sqki =
195 new ServerQueueKickItem(channel, nick, reason);
196 addItem(sqki);
197}
198
199void
200ServerQueue::sendNick(String nick)
201{
202 addLine(String("NICK ") + nick,
203 NICK_PRIORITY, NICK_PENALTY, ServerQueueItem::NICK);
204}
205
206void
207ServerQueue::sendNotice(String to, String message)
208{
209 ServerQueueNoticeItem *sqni =
210 new ServerQueueNoticeItem(to, message);
211 addItem(sqni);
212}
213
214void
215ServerQueue::sendPart(String channel)
216{
217 addLine(String("PART ") + channel,
218 PART_PRIORITY, PART_PENALTY, ServerQueueItem::PART);
219}
220
221void
222ServerQueue::sendPass(String pass)
223{
224 addLine(String("PASS ") + pass,
225 NICK_PRIORITY, NICK_PENALTY, ServerQueueItem::PASS);
226}
227
228void
229ServerQueue::sendPing(String server)
230{
231 addLine(String("PING :") + server,
232 PING_PRIORITY, PING_PENALTY, ServerQueueItem::PING);
233}
234
235void
236ServerQueue::sendPong(String crap)
237{
238 addLine(String("PONG ") + crap,
239 PONG_PRIORITY, PONG_PENALTY, ServerQueueItem::PONG);
240}
241
242void
243ServerQueue::sendPrivmsg(String dest, String message)
244{
245 addLine(String("PRIVMSG ") + dest + " :" + message,
246 PRIVMSG_PRIORITY, PRIVMSG_PENALTY, ServerQueueItem::PRIVMSG);
fd7440f1 247 // hook stuff
248#ifdef USESCRIPTS
249 if (message[0] != '\001')
a6339323 250 if (Utils::channel_p (dest))
fed59248 251 Interp::bot->botInterp->RunHooks (Hook::SEND_PUBLIC,
fd7440f1 252 Interp::bot->nickName + " " + dest +
253 " " + message,
46af1667 254 scm_list_n
c99c411a 255 (Utils::str2scm
256 (Interp::bot->nickName),
257 Utils::str2scm (dest),
258 Utils::str2scm (message),
259 SCM_UNDEFINED));
fd7440f1 260 else
ae97d6ec 261 Interp::bot->botInterp->RunHooks
262 (Hook::SEND_MESSAGE,
263 Interp::bot->nickName + " " + dest +
264 message,
46af1667 265 scm_list_n (Utils::str2scm (Interp::bot->nickName),
ae97d6ec 266 Utils::str2scm (dest),
267 Utils::str2scm
268 (message), SCM_UNDEFINED));
fd7440f1 269#endif
cb21075d 270}
271
272void
273ServerQueue::sendQuit(String reason)
274{
275 addLine(String("QUIT :") + reason,
276 QUIT_PRIORITY, QUIT_PENALTY, ServerQueueItem::QUIT);
277}
278
279void
280ServerQueue::sendTopic(String channel, String topic)
281{
282 addLine(String("TOPIC ") + channel + " :" + topic,
283 TOPIC_PRIORITY, TOPIC_PENALTY, ServerQueueItem::TOPIC);
284}
285
286void
287ServerQueue::sendUser(String username, String ircname)
288{
439869bf 289 addLine(String("USER ") + username + " 0 * :" + ircname,
cb21075d 290 NICK_PRIORITY, NICK_PENALTY, ServerQueueItem::USER);
291}
292
293void
294ServerQueue::sendUserMode(String nick, String mode)
295{
296 addLine(String("MODE ") + nick + " " + mode,
297 USERMODE_PRIORITY, USERMODE_PENALTY,
298 ServerQueueItem::USERMODE);
299}
300
301void
302ServerQueue::sendUserhost(String nick)
303{
304 addLine(String("USERHOST ") + nick,
305 USERHOST_PRIORITY, USERHOST_PENALTY, ServerQueueItem::USERHOST);
306}
307
308void
309ServerQueue::sendWho(String who)
310{
311 addLine(String("WHO ") + who,
312 WHO_PRIORITY, WHO_PENALTY, ServerQueueItem::WHO);
528799bd 313
314#ifdef USESCRIPTS
315 Interp::bot->botInterp->RunHooks (Hook::SEND_WHO,
316 who,
317 scm_list_n (Utils::
318 str2scm (who),
319 SCM_UNDEFINED));
320#endif
cb21075d 321}
322
323void
324ServerQueue::sendWhois(String nick)
325{
326 addLine(String("WHOIS ") + nick,
327 NICK_PRIORITY, WHOIS_PENALTY, ServerQueueItem::WHOIS);
528799bd 328
329#ifdef USESCRIPTS
330 Interp::bot->botInterp->RunHooks (Hook::SEND_WHOIS,
331 nick,
332 scm_list_n (Utils::
333 str2scm (nick),
334 SCM_UNDEFINED));
335#endif
cb21075d 336}