ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/repos/FreeBSDAdmin/IRC/smart_ison.cpp
(Generate patch)

Comparing FreeBSDAdmin/IRC/smart_ison.cpp (file contents):
Revision 1262 by douglas, 2010-03-20T20:07:58-07:00 vs.
Revision 1295 by douglas, 2010-04-09T05:48:07-07:00

# Line 8 | Line 8
8   #include <Modules.h>
9   #include <Chan.h>
10   #include <User.h>
11 + #include <znc.h>
12  
13 < #include <ext/hash_set>
13 > #include <deque>
14 > #include <map>
15 > #include <set>
16  
17   #include "foreach.hpp"
18  
19   #pragma GCC diagnostic ignored "-Wshadow"
20  
21 < namespace __gnu_cxx
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 < template <>
22 < struct hash<CString>
23 < {
24 <        size_t operator()(const CString &x) const { return __stl_hash_string(x.c_str()); }
26 >        virtual void RunJob();
27   };
28  
29 < }
28 <
29 < namespace ext { using namespace __gnu_cxx; }
30 <
31 < class CSmartISON : public CModule
29 > class SmartISON : public CModule
30   {
31 <        CString online_;
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(CSmartISON) {}
45 <        virtual ~CSmartISON() {}
44 >        MODCONSTRUCTOR(SmartISON) {}
45 >        virtual ~SmartISON() {}
46  
47 <        virtual EModRet OnRaw(CString &line)
47 >        virtual EModRet OnCTCPReply(CNick &nick, CString &message)
48          {
49 <                DEBUG("smart_ison: OnRaw() " << line.Token(1));
49 >                nicks_[nick.GetNick()] = true;
50  
51                  return CONTINUE;
52          }
53  
54 <        virtual EModRet OnUserRaw(CString &line)
54 >        virtual void OnKick(const CNick &nick, const CString &opNick, CChan &chan, const CString &message)
55          {
56 <                if (line.Token(0).Equals("ISON"))
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 <                        ext::hash_set<CString> known;
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 <                        _foreach (std::vector<CChan *>, channel, GetUser()->GetChans())
90 >                        PutModule(table);
91 >                }
92 >                else if (theCommand.Equals("Nicks"))
93 >                        if (nicks_.empty())
94 >                                PutModule("Nick status list empty");
95 >                        else
96                          {
97 <                                typedef std::map<CString, CNick *> NickMap;
97 >                                CTable table;
98 >
99 >                                table.AddColumn("Nick");
100 >                                table.AddColumn("Status");
101 >
102 >                                typedef std::map<CString, bool, Compare> NickMap;
103  
104 <                                _foreach (NickMap, nick, (*channel)->GetNicks())
105 <                                        known.insert(nick->first);
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 <                        VCString nicks;
120 >                                table.AddColumn("Nick");
121  
122 <                        line.Token(1, true).TrimLeft_n(":").Split(" ", nicks, false);
122 >                                _foreach (const std::deque<CString>, nick, queue_)
123 >                                {
124 >                                        table.AddRow();
125 >                                        table.SetCell("Nick", *nick);
126 >                                }
127  
128 <                        CString online, unknown("ISON");
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 <                        _foreach (VCString, nick, nicks)
67 <                                ((known.find(*nick) != known.end()) ? online : unknown) += " " + *nick;
137 >                                table.AddColumn("Nick");
138  
139 <                        online_ = online.TrimLeft_n(" ");
139 >                                typedef std::set<CString, Compare> NickSet;
140  
141 <                        if (unknown != "ISON")
142 <                                line = unknown;
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)
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, GetUser()->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 < MODULEDEFS(CSmartISON, "Smart ISON");
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 " + GetUser()->GetIRCNick().GetNick() + " :Not enough parameters");
363 >                }
364 >                else
365 >                {
366 >                        CString response(":znc.in 303 " + GetUser()->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");

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines