ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/repos/FreeBSDAdmin/IRC/smart_ison.cpp
Revision: 1449
Committed: 2012-12-02T14:05:43-08:00 (12 years, 6 months ago) by douglas
File size: 8788 byte(s)
Log Message:
Fix for ZNC 1.0.


File Contents

# Content
1 // Smart ISON
2 //
3 // Douglas Thrift
4 //
5 // $Id$
6
7 #include <znc/main.h>
8 #include <znc/Modules.h>
9 #include <znc/Chan.h>
10 #include <znc/IRCNetwork.h>
11 #include <znc/User.h>
12
13 #include <deque>
14 #include <map>
15 #include <set>
16
17 #include "foreach.hpp"
18
19 #pragma GCC diagnostic ignored "-Wshadow"
20
21 struct SmartISONTimer : public CTimer
22 {
23 SmartISONTimer(CModule *module) : CTimer(module, 15, 0, "Smart ISON", "Keeps track of online and offline nicks so ISON requests from Pidgin are not truncated") {}
24 virtual ~SmartISONTimer() {}
25
26 virtual void RunJob();
27 };
28
29 class SmartISON : public CModule
30 {
31 struct Compare
32 {
33 inline bool operator()(const CString &one, const CString &two) const
34 {
35 return one.AsLower() < two.AsLower();
36 }
37 };
38
39 std::map<CString, bool, Compare> nicks_;
40 std::deque<CString> queue_;
41 std::set<CString, Compare> request_;
42
43 public:
44 MODCONSTRUCTOR(SmartISON) {}
45 virtual ~SmartISON() {}
46
47 virtual EModRet OnCTCPReply(CNick &nick, CString &message)
48 {
49 nicks_[nick.GetNick()] = true;
50
51 return CONTINUE;
52 }
53
54 virtual void OnKick(const CNick &nick, const CString &opNick, CChan &chan, const CString &message)
55 {
56 queue_.push_front(nick.GetNick());
57 }
58
59 virtual bool OnLoad(const CString &args, CString &message)
60 {
61 return AddTimer(new SmartISONTimer(this));
62 }
63
64 virtual void OnModCommand(const CString &command)
65 {
66 CString theCommand(command.Token(0));
67
68 if (theCommand.Equals("Help"))
69 {
70 CTable table;
71
72 table.AddColumn("Command");
73 table.AddColumn("Description");
74 table.AddRow();
75 table.SetCell("Command", "Nicks");
76 table.SetCell("Description", "List nick statuses");
77 table.AddRow();
78 table.SetCell("Command", "Queue");
79 table.SetCell("Description", "List the nick status queue");
80 table.AddRow();
81 table.SetCell("Command", "Request");
82 table.SetCell("Description", "List the last nick request");
83 table.AddRow();
84 table.SetCell("Command", "Stats");
85 table.SetCell("Description", "List nick and queue statistics");
86 table.AddRow();
87 table.SetCell("Command", "Version");
88 table.SetCell("Description", "Display module version");
89
90 PutModule(table);
91 }
92 else if (theCommand.Equals("Nicks"))
93 if (nicks_.empty())
94 PutModule("Nick status list empty");
95 else
96 {
97 CTable table;
98
99 table.AddColumn("Nick");
100 table.AddColumn("Status");
101
102 typedef std::map<CString, bool, Compare> NickMap;
103
104 _foreach (const NickMap, nick, nicks_)
105 {
106 table.AddRow();
107 table.SetCell("Nick", nick->first);
108 table.SetCell("Status", nick->second ? "Online" : "Offline");
109 }
110
111 PutModule(table);
112 }
113 else if (theCommand.Equals("Queue"))
114 if (queue_.empty())
115 PutModule("Nick queue empty");
116 else
117 {
118 CTable table;
119
120 table.AddColumn("Nick");
121
122 _foreach (const std::deque<CString>, nick, queue_)
123 {
124 table.AddRow();
125 table.SetCell("Nick", *nick);
126 }
127
128 PutModule(table);
129 }
130 else if (theCommand.Equals("Request"))
131 if (request_.empty())
132 PutModule("Last nick request empty");
133 else
134 {
135 CTable table;
136
137 table.AddColumn("Nick");
138
139 typedef std::set<CString, Compare> NickSet;
140
141 _foreach (NickSet, nick, request_)
142 {
143 table.AddRow();
144 table.SetCell("Nick", *nick);
145 }
146
147 PutModule(table);
148 }
149 else if (theCommand.Equals("Stats"))
150 {
151 CTable table;
152
153 table.AddColumn("Item");
154 table.AddColumn("Count");
155 table.AddRow();
156 table.SetCell("Item", "Nicks");
157 table.SetCell("Count", CString(nicks_.size()));
158
159 typedef std::map<CString, bool, Compare> NickMap;
160 size_t online(0), offline(0);
161
162 _foreach (NickMap, nick, nicks_)
163 if (nick->second)
164 ++online;
165 else
166 ++offline;
167
168 table.AddRow();
169 table.SetCell("Item", "Online");
170 table.SetCell("Count", CString(online));
171 table.AddRow();
172 table.SetCell("Item", "Offline");
173 table.SetCell("Count", CString(offline));
174 table.AddRow();
175 table.SetCell("Item", "Queue");
176 table.SetCell("Count", CString(queue_.size()));
177 table.AddRow();
178 table.SetCell("Item", "Request");
179 table.SetCell("Count", CString(request_.size()));
180
181 PutModule(table);
182 }
183 else if (theCommand.Equals("Version"))
184 PutModule("$Id$");
185 else
186 PutModule("Unknown command [" + theCommand + "] try 'Help'");
187 }
188
189 virtual void OnModCTCP(const CString &message)
190 {
191 CString command(message.Token(0));
192
193 if (command.Equals("PING"))
194 PutModNotice("\001PING " + message.Token(1, true) + "\001");
195 else if (command.Equals("Version"))
196 PutModNotice("\001VERSION $Id$\001");
197 }
198
199 virtual void OnNick(const CNick &nick, const CString &newNick, const std::vector<CChan *> &chans)
200 {
201 const CString &oldNick(nick.GetNick());
202
203 nicks_[oldNick] = false;
204 nicks_[newNick] = true;
205 }
206
207 virtual void OnPart(const CNick &nick, CChan &chan, const CString &message)
208 {
209 queue_.push_front(nick.GetNick());
210 }
211
212 virtual EModRet OnPrivAction(CNick &nick, CString &message)
213 {
214 nicks_[nick.GetNick()] = true;
215
216 return CONTINUE;
217 }
218
219 virtual EModRet OnPrivCTCP(CNick &nick, CString &message)
220 {
221 nicks_[nick.GetNick()] = true;
222
223 return CONTINUE;
224 }
225
226 virtual EModRet OnPrivMsg(CNick &nick, CString &message)
227 {
228 nicks_[nick.GetNick()] = true;
229
230 return CONTINUE;
231 }
232
233 virtual EModRet OnPrivNotice(CNick &nick, CString &message)
234 {
235 nicks_[nick.GetNick()] = true;
236
237 return CONTINUE;
238 }
239
240 virtual void OnQuit(const CNick &nick, const CString &message, const std::vector<CChan *> &chans)
241 {
242 const CString &theNick(nick.GetNick());
243
244 nicks_[theNick] = false;
245 }
246
247 virtual EModRet OnRaw(CString &line)
248 {
249 if (line.Token(1) == "303")
250 {
251 typedef std::set<CString, Compare> NickSet;
252
253 _foreach (NickSet, nick, request_)
254 nicks_[*nick] = false;
255
256 std::vector<CString> nicks;
257
258 line.Token(3, true).TrimLeft_n(":").Split(" ", nicks, false);
259
260 _foreach (std::vector<CString>, nick, nicks)
261 nicks_[*nick] = true;
262
263 return HALT;
264 }
265
266 return CONTINUE;
267 }
268
269 virtual EModRet OnUserRaw(CString &line);
270
271 private:
272 template <typename Type>
273 Type CheckChans()
274 {
275 Type nicks;
276
277 _foreach (const std::vector<CChan *>, chan, GetNetwork()->GetChans())
278 {
279 typedef std::map<CString, CNick> NickMap;
280
281 _foreach (const NickMap, nick, (*chan)->GetNicks())
282 {
283 nicks_[nick->first] = true;
284 nicks.insert(nick->first);
285 }
286 }
287
288 return nicks;
289 }
290
291 friend void SmartISONTimer::RunJob();
292 };
293
294 struct SmartISONVoid
295 {
296 inline void insert(const CString &value) {}
297 };
298
299 void SmartISONTimer::RunJob()
300 {
301 SmartISON *module(static_cast<SmartISON *>(GetModule()));
302
303 module->request_.clear();
304
305 std::set<CString, SmartISON::Compare> online(module->CheckChans<std::set<CString, SmartISON::Compare> >());
306 size_t size(6);
307
308 while (module->queue_.size())
309 {
310 CString nick(module->queue_.front());
311
312 if (!online.count(nick) && !module->request_.count(nick))
313 {
314 if ((size += nick.size() + 1) > 512)
315 break;
316
317 module->request_.insert(nick);
318 }
319
320 module->queue_.pop_front();
321 }
322
323 if (module->request_.size())
324 {
325 CString request("ISON");
326
327 typedef std::set<CString, SmartISON::Compare> NickSet;
328
329 _foreach (NickSet, nick, module->request_)
330 request += " " + *nick;
331
332 module->PutIRC(request);
333 }
334
335 if (module->queue_.empty())
336 {
337 typedef std::map<CString, bool, SmartISON::Compare> NickMap;
338
339 _foreach (NickMap, nick, module->nicks_)
340 module->queue_.push_back(nick->first);
341 }
342 }
343
344 template <>
345 void SmartISON::CheckChans()
346 {
347 CheckChans<SmartISONVoid>();
348 }
349
350 CModule::EModRet SmartISON::OnUserRaw(CString &line)
351 {
352 if (line.Token(0).Equals("ISON"))
353 {
354 CheckChans<void>();
355
356 std::vector<CString> nicks;
357
358 line.Token(1, true).TrimLeft_n(":").Split(" ", nicks, false);
359
360 if (nicks.empty())
361 {
362 PutUser(":znc.in 461 " + GetNetwork()->GetIRCNick().GetNick() + " :Not enough parameters");
363 }
364 else
365 {
366 CString response(":znc.in 303 " + GetNetwork()->GetIRCNick().GetNick() + " :");
367
368 _foreach (std::vector<CString>, nick, nicks)
369 {
370 CString prefix(GetUser()->GetStatusPrefix());
371
372 if (nick->Equals(prefix, false, prefix.size()))
373 {
374 CString modNick(nick->substr(prefix.size()));
375 CModule *module(NULL);
376
377 if (modNick.Equals("status") || (module = GetUser()->GetModules().FindModule(modNick)) || (module = CZNC::Get().GetModules().FindModule(modNick)))
378 {
379 response += (module ? module->GetModNick() : prefix + "status") + " ";
380 continue;
381 }
382 }
383
384 std::map<CString, bool, Compare>::iterator theNick(nicks_.find(*nick));
385
386 if (theNick == nicks_.end())
387 {
388 nicks_[*nick] = false;
389
390 queue_.push_front(*nick);
391 }
392 else if (theNick->second)
393 response += theNick->first + " ";
394 }
395
396 PutUser(response);
397 }
398
399 return HALT;
400 }
401
402 return CONTINUE;
403 }
404
405 MODULEDEFS(SmartISON, "Keeps track of online and offline nicks so ISON requests from Pidgin are not truncated");
406
407 // vim: noexpandtab tabstop=4

Properties

Name Value
svn:keywords Id