ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/repos/FreeBSDAdmin/IRC/smart_ison.cpp
Revision: 1268
Committed: 2010-03-22T14:11:11-07:00 (15 years, 3 months ago) by douglas
File size: 7097 byte(s)
Log Message:
Don't accidentally double count duplicate nicks in calculating ISON size.

File Contents

# Content
1 // Smart ISON
2 //
3 // Douglas Thrift
4 //
5 // $Id$
6
7 #include <main.h>
8 #include <Modules.h>
9 #include <Chan.h>
10 #include <User.h>
11 #include <znc.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", "Smart ISON") {}
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", "Version");
82 table.SetCell("Description", "Display module version");
83
84 PutModule(table);
85 }
86 else if (theCommand.Equals("Nicks"))
87 if (nicks_.empty())
88 PutModule("Nick status list empty");
89 else
90 {
91 CTable table;
92
93 table.AddColumn("Nick");
94 table.AddColumn("Status");
95
96 typedef std::map<CString, bool, Compare> NickMap;
97
98 _foreach (const NickMap, nick, nicks_)
99 {
100 table.AddRow();
101 table.SetCell("Nick", nick->first);
102 table.SetCell("Status", nick->second ? "Online" : "Offline");
103 }
104
105 PutModule(table);
106 }
107 else if (theCommand.Equals("Queue"))
108 if (queue_.empty())
109 PutModule("Nick queue empty");
110 else
111 {
112 CTable table;
113
114 table.AddColumn("Nick");
115
116 _foreach (const std::deque<CString>, nick, queue_)
117 {
118 table.AddRow();
119 table.SetCell("Nick", *nick);
120 }
121
122 PutModule(table);
123 }
124 else if (theCommand.Equals("Version"))
125 PutModule("$Id$");
126 else
127 PutModule("Unknown command [" + theCommand + "] try 'Help'");
128 }
129
130 virtual void OnModCTCP(const CString &message)
131 {
132 CString command(message.Token(0));
133
134 if (command.Equals("PING"))
135 PutModNotice("\001PING " + message.Token(1, true) + "\001");
136 else if (command.Equals("Version"))
137 PutModNotice("\001VERSION $Id$\001");
138 }
139
140 virtual void OnNick(const CNick &nick, const CString &newNick, const std::vector<CChan *> &chans)
141 {
142 const CString &oldNick(nick.GetNick());
143
144 nicks_[oldNick] = false;
145 nicks_[newNick] = true;
146 }
147
148 virtual void OnPart(const CNick &nick, CChan &chan)
149 {
150 queue_.push_front(nick.GetNick());
151 }
152
153 virtual EModRet OnPrivAction(CNick &nick, CString &message)
154 {
155 nicks_[nick.GetNick()] = true;
156
157 return CONTINUE;
158 }
159
160 virtual EModRet OnPrivCTCP(CNick &nick, CString &message)
161 {
162 nicks_[nick.GetNick()] = true;
163
164 return CONTINUE;
165 }
166
167 virtual EModRet OnPrivMsg(CNick &nick, CString &message)
168 {
169 nicks_[nick.GetNick()] = true;
170
171 return CONTINUE;
172 }
173
174 virtual EModRet OnPrivNotice(CNick &nick, CString &message)
175 {
176 nicks_[nick.GetNick()] = true;
177
178 return CONTINUE;
179 }
180
181 virtual void OnQuit(const CNick &nick, const CString &message, const std::vector<CChan *> &chans)
182 {
183 const CString &theNick(nick.GetNick());
184
185 nicks_[theNick] = false;
186 }
187
188 virtual EModRet OnRaw(CString &line)
189 {
190 if (line.Token(1) == "303")
191 {
192 typedef std::set<CString, Compare> NickSet;
193
194 _foreach (NickSet, nick, request_)
195 nicks_[*nick] = false;
196
197 std::vector<CString> nicks;
198
199 line.Token(3, true).TrimLeft_n(":").Split(" ", nicks, false);
200
201 _foreach (std::vector<CString>, nick, nicks)
202 nicks_[*nick] = true;
203
204 return HALT;
205 }
206
207 return CONTINUE;
208 }
209
210 virtual EModRet OnUserRaw(CString &line);
211
212 private:
213 template <typename Type>
214 Type CheckChans()
215 {
216 Type nicks;
217
218 _foreach (const std::vector<CChan *>, chan, GetUser()->GetChans())
219 {
220 typedef std::map<CString, CNick *> NickMap;
221
222 _foreach (const NickMap, nick, (*chan)->GetNicks())
223 {
224 nicks_[nick->first] = true;
225 nicks.insert(nick->first);
226 }
227 }
228
229 return nicks;
230 }
231
232 friend void SmartISONTimer::RunJob();
233 };
234
235 struct SmartISONVoid
236 {
237 inline void insert(const CString &value) {}
238 };
239
240 void SmartISONTimer::RunJob()
241 {
242 SmartISON *module(static_cast<SmartISON *>(GetModule()));
243
244 module->request_.clear();
245
246 std::set<CString, SmartISON::Compare> online(module->CheckChans<std::set<CString, SmartISON::Compare> >());
247 size_t size(6);
248
249 while (module->queue_.size())
250 {
251 CString nick(module->queue_.front());
252
253 if (!online.count(nick) && !module->request_.count(nick))
254 {
255 if ((size += nick.size() + 1) > 512)
256 break;
257
258 module->request_.insert(nick);
259 }
260
261 module->queue_.pop_front();
262 }
263
264 if (module->request_.size())
265 {
266 CString request("ISON");
267
268 typedef std::set<CString, SmartISON::Compare> NickSet;
269
270 _foreach (NickSet, nick, module->request_)
271 request += " " + *nick;
272
273 module->PutIRC(request);
274 }
275
276 if (module->queue_.empty())
277 {
278 typedef std::map<CString, bool, SmartISON::Compare> NickMap;
279
280 _foreach (NickMap, nick, module->nicks_)
281 module->queue_.push_back(nick->first);
282 }
283 }
284
285 template <>
286 void SmartISON::CheckChans()
287 {
288 CheckChans<SmartISONVoid>();
289 }
290
291 CModule::EModRet SmartISON::OnUserRaw(CString &line)
292 {
293 if (line.Token(0).Equals("ISON"))
294 {
295 CheckChans<void>();
296
297 std::vector<CString> nicks;
298
299 line.Token(1, true).TrimLeft_n(":").Split(" ", nicks, false);
300
301 if (nicks.empty())
302 {
303 PutUser(":znc.in 461 " + GetUser()->GetIRCNick().GetNick() + " :Not enough parameters");
304 }
305 else
306 {
307 CString response(":znc.in 303 " + GetUser()->GetIRCNick().GetNick() + " :");
308
309 _foreach (std::vector<CString>, nick, nicks)
310 {
311 CString prefix(GetUser()->GetStatusPrefix());
312
313 if (nick->Equals(prefix, false, prefix.size()))
314 {
315 CString modNick(nick->substr(prefix.size()));
316 CModule *module(NULL);
317
318 if (modNick.Equals("status") || (module = GetUser()->GetModules().FindModule(modNick)) || (module = CZNC::Get().GetModules().FindModule(modNick)))
319 {
320 response += (module ? module->GetModNick() : prefix + "status") + " ";
321 continue;
322 }
323 }
324
325 std::map<CString, bool, Compare>::iterator theNick(nicks_.find(*nick));
326
327 if (theNick == nicks_.end())
328 {
329 nicks_[*nick] = false;
330
331 queue_.push_front(*nick);
332 }
333 else if (theNick->second)
334 response += theNick->first + " ";
335 }
336
337 PutUser(response);
338 }
339
340 return HALT;
341 }
342
343 return CONTINUE;
344 }
345
346 MODULEDEFS(SmartISON, "Smart ISON");

Properties

Name Value
svn:keywords Id