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