1.4.1
by Patrick Matthäi
Import upstream version 1.0 |
1 |
/*
|
2 |
* Copyright (C) 2004-2012 See the AUTHORS file for details.
|
|
3 |
*
|
|
4 |
* This program is free software; you can redistribute it and/or modify it
|
|
5 |
* under the terms of the GNU General Public License version 2 as published
|
|
6 |
* by the Free Software Foundation.
|
|
7 |
*/
|
|
8 |
||
9 |
#include <znc/Modules.h> |
|
10 |
#include <znc/FileUtils.h> |
|
11 |
#include <znc/Template.h> |
|
12 |
#include <znc/User.h> |
|
13 |
#include <znc/IRCNetwork.h> |
|
14 |
#include <znc/WebModules.h> |
|
15 |
#include <znc/znc.h> |
|
16 |
#include <dlfcn.h> |
|
17 |
||
18 |
using std::map; |
|
19 |
using std::set; |
|
20 |
using std::vector; |
|
21 |
||
22 |
bool ZNC_NO_NEED_TO_DO_ANYTHING_ON_MODULE_CALL_EXITER; |
|
23 |
||
24 |
#ifndef RTLD_LOCAL
|
|
25 |
# define RTLD_LOCAL 0
|
|
26 |
# warning "your crap box doesnt define RTLD_LOCAL !?"
|
|
27 |
#endif
|
|
28 |
||
29 |
#define MODUNLOADCHK(func) \
|
|
30 |
for (unsigned int a = 0; a < size(); a++) { \
|
|
31 |
try { \
|
|
32 |
CModule* pMod = (CModule *) (*this)[a]; \
|
|
33 |
CClient* pOldClient = pMod->GetClient(); \
|
|
34 |
pMod->SetClient(m_pClient); \
|
|
35 |
CUser* pOldUser = NULL; \
|
|
36 |
if (m_pUser) { \
|
|
37 |
pOldUser = pMod->GetUser(); \
|
|
38 |
pMod->SetUser(m_pUser); \
|
|
39 |
} \
|
|
40 |
CIRCNetwork* pNetwork = NULL; \
|
|
41 |
if (m_pNetwork) { \
|
|
42 |
pNetwork = pMod->GetNetwork(); \
|
|
43 |
pMod->SetNetwork(m_pNetwork); \
|
|
44 |
} \
|
|
45 |
pMod->func; \
|
|
46 |
if (m_pUser) \
|
|
47 |
pMod->SetUser(pOldUser); \
|
|
48 |
if (m_pNetwork) \
|
|
49 |
pMod->SetNetwork(pNetwork); \
|
|
50 |
pMod->SetClient(pOldClient); \
|
|
51 |
} catch (CModule::EModException e) { \
|
|
52 |
if (e == CModule::UNLOAD) { \
|
|
53 |
UnloadModule((*this)[a]->GetModName()); \
|
|
54 |
} \
|
|
55 |
} \
|
|
56 |
}
|
|
57 |
||
58 |
||
59 |
#define MODHALTCHK(func) \
|
|
60 |
bool bHaltCore = false; \
|
|
61 |
for (unsigned int a = 0; a < size(); a++) { \
|
|
62 |
try { \
|
|
63 |
CModule* pMod = (CModule*) (*this)[a]; \
|
|
64 |
CModule::EModRet e = CModule::CONTINUE; \
|
|
65 |
CClient* pOldClient = pMod->GetClient(); \
|
|
66 |
pMod->SetClient(m_pClient); \
|
|
67 |
CUser* pOldUser = NULL; \
|
|
68 |
if (m_pUser) { \
|
|
69 |
pOldUser = pMod->GetUser(); \
|
|
70 |
pMod->SetUser(m_pUser); \
|
|
71 |
} \
|
|
72 |
CIRCNetwork* pNetwork = NULL; \
|
|
73 |
if (m_pNetwork) { \
|
|
74 |
pNetwork = pMod->GetNetwork(); \
|
|
75 |
pMod->SetNetwork(m_pNetwork); \
|
|
76 |
} \
|
|
77 |
e = pMod->func; \
|
|
78 |
if (m_pUser) \
|
|
79 |
pMod->SetUser(pOldUser); \
|
|
80 |
if (m_pNetwork) \
|
|
81 |
pMod->SetNetwork(pNetwork); \
|
|
82 |
pMod->SetClient(pOldClient); \
|
|
83 |
if (e == CModule::HALTMODS) { \
|
|
84 |
break; \
|
|
85 |
} else if (e == CModule::HALTCORE) { \
|
|
86 |
bHaltCore = true; \
|
|
87 |
} else if (e == CModule::HALT) { \
|
|
88 |
bHaltCore = true; \
|
|
89 |
break; \
|
|
90 |
} \
|
|
91 |
} catch (CModule::EModException e) { \
|
|
92 |
if (e == CModule::UNLOAD) { \
|
|
93 |
UnloadModule((*this)[a]->GetModName()); \
|
|
94 |
} \
|
|
95 |
} \
|
|
96 |
} \
|
|
97 |
return bHaltCore;
|
|
98 |
||
99 |
/////////////////// Timer ///////////////////
|
|
100 |
CTimer::CTimer(CModule* pModule, unsigned int uInterval, unsigned int uCycles, const CString& sLabel, const CString& sDescription) : CCron() { |
|
101 |
SetName(sLabel); |
|
102 |
m_sDescription = sDescription; |
|
103 |
m_pModule = pModule; |
|
104 |
||
105 |
if (uCycles) { |
|
106 |
StartMaxCycles(uInterval, uCycles); |
|
107 |
} else { |
|
108 |
Start(uInterval); |
|
109 |
}
|
|
110 |
}
|
|
111 |
||
112 |
CTimer::~CTimer() { |
|
113 |
m_pModule->UnlinkTimer(this); |
|
114 |
}
|
|
115 |
||
116 |
void CTimer::SetModule(CModule* p) { m_pModule = p; } |
|
117 |
void CTimer::SetDescription(const CString& s) { m_sDescription = s; } |
|
118 |
CModule* CTimer::GetModule() const { return m_pModule; } |
|
119 |
const CString& CTimer::GetDescription() const { return m_sDescription; } |
|
120 |
/////////////////// !Timer ///////////////////
|
|
121 |
||
122 |
||
123 |
CModule::CModule(ModHandle pDLL, CUser* pUser, CIRCNetwork* pNetwork, const CString& sModName, const CString& sDataDir) { |
|
124 |
m_pDLL = pDLL; |
|
125 |
m_pManager = &(CZNC::Get().GetManager());; |
|
126 |
m_pUser = pUser; |
|
127 |
m_pNetwork = pNetwork; |
|
128 |
m_pClient = NULL; |
|
129 |
m_sModName = sModName; |
|
130 |
m_sDataDir = sDataDir; |
|
131 |
||
132 |
if (m_pNetwork) { |
|
133 |
m_sSavePath = m_pNetwork->GetNetworkPath() + "/moddata/" + m_sModName; |
|
134 |
} else if (m_pUser) { |
|
135 |
m_sSavePath = m_pUser->GetUserPath() + "/moddata/" + m_sModName; |
|
136 |
} else { |
|
137 |
m_sSavePath = CZNC::Get().GetZNCPath() + "/moddata/" + m_sModName; |
|
138 |
}
|
|
139 |
LoadRegistry(); |
|
140 |
}
|
|
141 |
||
142 |
CModule::~CModule() { |
|
143 |
while (!m_sTimers.empty()) { |
|
144 |
RemTimer(*m_sTimers.begin()); |
|
145 |
}
|
|
146 |
||
147 |
while (!m_sSockets.empty()) { |
|
148 |
RemSocket(*m_sSockets.begin()); |
|
149 |
}
|
|
150 |
||
151 |
SaveRegistry(); |
|
152 |
}
|
|
153 |
||
154 |
void CModule::SetUser(CUser* pUser) { m_pUser = pUser; } |
|
155 |
void CModule::SetNetwork(CIRCNetwork* pNetwork) { m_pNetwork = pNetwork; } |
|
156 |
void CModule::SetClient(CClient* pClient) { m_pClient = pClient; } |
|
157 |
||
158 |
const CString& CModule::GetSavePath() const { |
|
159 |
if (!CFile::Exists(m_sSavePath)) { |
|
160 |
CDir::MakeDir(m_sSavePath); |
|
161 |
}
|
|
162 |
return m_sSavePath; |
|
163 |
}
|
|
164 |
||
165 |
CString CModule::GetWebPath() { |
|
166 |
switch (m_eType) { |
|
167 |
case CModInfo::GlobalModule: return "/mods/global/" + GetModName() + "/"; |
|
168 |
case CModInfo::UserModule: return "/mods/user/" + GetModName() + "/"; |
|
169 |
case CModInfo::NetworkModule: return "/mods/network/" + m_pNetwork->GetName() + "/" + GetModName() + "/"; |
|
170 |
default: return "/"; |
|
171 |
}
|
|
172 |
}
|
|
173 |
||
174 |
CString CModule::GetWebFilesPath() { |
|
175 |
switch (m_eType) { |
|
176 |
case CModInfo::GlobalModule: return "/modfiles/global/" + GetModName() + "/"; |
|
177 |
case CModInfo::UserModule: return "/modfiles/user/" + GetModName() + "/"; |
|
178 |
case CModInfo::NetworkModule: return "/modfiles/network/" + m_pNetwork->GetName() + "/" + GetModName() + "/"; |
|
179 |
default: return "/"; |
|
180 |
}
|
|
181 |
}
|
|
182 |
||
183 |
bool CModule::LoadRegistry() { |
|
184 |
//CString sPrefix = (m_pUser) ? m_pUser->GetUserName() : ".global";
|
|
185 |
return (m_mssRegistry.ReadFromDisk(GetSavePath() + "/.registry") == MCString::MCS_SUCCESS); |
|
186 |
}
|
|
187 |
||
188 |
bool CModule::SaveRegistry() const { |
|
189 |
//CString sPrefix = (m_pUser) ? m_pUser->GetUserName() : ".global";
|
|
190 |
return (m_mssRegistry.WriteToDisk(GetSavePath() + "/.registry", 0600) == MCString::MCS_SUCCESS); |
|
191 |
}
|
|
192 |
||
193 |
bool CModule::SetNV(const CString & sName, const CString & sValue, bool bWriteToDisk) { |
|
194 |
m_mssRegistry[sName] = sValue; |
|
195 |
if (bWriteToDisk) { |
|
196 |
return SaveRegistry(); |
|
197 |
}
|
|
198 |
||
199 |
return true; |
|
200 |
}
|
|
201 |
||
202 |
CString CModule::GetNV(const CString & sName) const { |
|
203 |
MCString::const_iterator it = m_mssRegistry.find(sName); |
|
204 |
||
205 |
if (it != m_mssRegistry.end()) { |
|
206 |
return it->second; |
|
207 |
}
|
|
208 |
||
209 |
return ""; |
|
210 |
}
|
|
211 |
||
212 |
bool CModule::DelNV(const CString & sName, bool bWriteToDisk) { |
|
213 |
MCString::iterator it = m_mssRegistry.find(sName); |
|
214 |
||
215 |
if (it != m_mssRegistry.end()) { |
|
216 |
m_mssRegistry.erase(it); |
|
217 |
} else { |
|
218 |
return false; |
|
219 |
}
|
|
220 |
||
221 |
if (bWriteToDisk) { |
|
222 |
return SaveRegistry(); |
|
223 |
}
|
|
224 |
||
225 |
return true; |
|
226 |
}
|
|
227 |
||
228 |
bool CModule::ClearNV(bool bWriteToDisk) { |
|
229 |
m_mssRegistry.clear(); |
|
230 |
||
231 |
if (bWriteToDisk) { |
|
232 |
return SaveRegistry(); |
|
233 |
}
|
|
234 |
return true; |
|
235 |
}
|
|
236 |
||
237 |
bool CModule::AddTimer(CTimer* pTimer) { |
|
238 |
if ((!pTimer) || (!pTimer->GetName().empty() && FindTimer(pTimer->GetName()))) { |
|
239 |
delete pTimer; |
|
240 |
return false; |
|
241 |
}
|
|
242 |
||
243 |
if (!m_sTimers.insert(pTimer).second) |
|
244 |
// Was already added
|
|
245 |
return true; |
|
246 |
||
247 |
m_pManager->AddCron(pTimer); |
|
248 |
return true; |
|
249 |
}
|
|
250 |
||
251 |
bool CModule::AddTimer(FPTimer_t pFBCallback, const CString& sLabel, u_int uInterval, u_int uCycles, const CString& sDescription) { |
|
252 |
CFPTimer *pTimer = new CFPTimer(this, uInterval, uCycles, sLabel, sDescription); |
|
253 |
pTimer->SetFPCallback(pFBCallback); |
|
254 |
||
255 |
return AddTimer(pTimer); |
|
256 |
}
|
|
257 |
||
258 |
bool CModule::RemTimer(CTimer* pTimer) { |
|
259 |
if (m_sTimers.erase(pTimer) == 0) |
|
260 |
return false; |
|
261 |
m_pManager->DelCronByAddr(pTimer); |
|
262 |
return true; |
|
263 |
}
|
|
264 |
||
265 |
bool CModule::RemTimer(const CString& sLabel) { |
|
266 |
CTimer *pTimer = FindTimer(sLabel); |
|
267 |
if (!pTimer) |
|
268 |
return false; |
|
269 |
return RemTimer(pTimer); |
|
270 |
}
|
|
271 |
||
272 |
bool CModule::UnlinkTimer(CTimer* pTimer) { |
|
273 |
set<CTimer*>::iterator it; |
|
274 |
for (it = m_sTimers.begin(); it != m_sTimers.end(); ++it) { |
|
275 |
if (pTimer == *it) { |
|
276 |
m_sTimers.erase(it); |
|
277 |
return true; |
|
278 |
}
|
|
279 |
}
|
|
280 |
||
281 |
return false; |
|
282 |
}
|
|
283 |
||
284 |
CTimer* CModule::FindTimer(const CString& sLabel) { |
|
285 |
if (sLabel.empty()) { |
|
286 |
return NULL; |
|
287 |
}
|
|
288 |
||
289 |
set<CTimer*>::iterator it; |
|
290 |
for (it = m_sTimers.begin(); it != m_sTimers.end(); ++it) { |
|
291 |
CTimer* pTimer = *it; |
|
292 |
if (pTimer->GetName().Equals(sLabel)) { |
|
293 |
return pTimer; |
|
294 |
}
|
|
295 |
}
|
|
296 |
||
297 |
return NULL; |
|
298 |
}
|
|
299 |
||
300 |
void CModule::ListTimers() { |
|
301 |
if (m_sTimers.empty()) { |
|
302 |
PutModule("You have no timers running."); |
|
303 |
return; |
|
304 |
}
|
|
305 |
||
306 |
CTable Table; |
|
307 |
Table.AddColumn("Name"); |
|
308 |
Table.AddColumn("Secs"); |
|
309 |
Table.AddColumn("Cycles"); |
|
310 |
Table.AddColumn("Description"); |
|
311 |
||
312 |
set<CTimer*>::iterator it; |
|
313 |
for (it = m_sTimers.begin(); it != m_sTimers.end(); ++it) { |
|
314 |
CTimer* pTimer = *it; |
|
315 |
unsigned int uCycles = pTimer->GetCyclesLeft(); |
|
316 |
timeval Interval = pTimer->GetInterval(); |
|
317 |
||
318 |
Table.AddRow(); |
|
319 |
Table.SetCell("Name", pTimer->GetName()); |
|
320 |
Table.SetCell("Secs", CString(Interval.tv_sec) + "seconds" + (Interval.tv_usec ? " " + CString(Interval.tv_usec) + " microseconds" : "")); |
|
321 |
Table.SetCell("Cycles", ((uCycles) ? CString(uCycles) : "INF")); |
|
322 |
Table.SetCell("Description", pTimer->GetDescription()); |
|
323 |
}
|
|
324 |
||
325 |
PutModule(Table); |
|
326 |
}
|
|
327 |
||
328 |
bool CModule::AddSocket(CSocket* pSocket) { |
|
329 |
if (!pSocket) { |
|
330 |
return false; |
|
331 |
}
|
|
332 |
||
333 |
m_sSockets.insert(pSocket); |
|
334 |
return true; |
|
335 |
}
|
|
336 |
||
337 |
bool CModule::RemSocket(CSocket* pSocket) { |
|
338 |
set<CSocket*>::iterator it; |
|
339 |
for (it = m_sSockets.begin(); it != m_sSockets.end(); ++it) { |
|
340 |
if (*it == pSocket) { |
|
341 |
m_sSockets.erase(it); |
|
342 |
m_pManager->DelSockByAddr(pSocket); |
|
343 |
return true; |
|
344 |
}
|
|
345 |
}
|
|
346 |
||
347 |
return false; |
|
348 |
}
|
|
349 |
||
350 |
bool CModule::RemSocket(const CString& sSockName) { |
|
351 |
set<CSocket*>::iterator it; |
|
352 |
for (it = m_sSockets.begin(); it != m_sSockets.end(); ++it) { |
|
353 |
CSocket* pSocket = *it; |
|
354 |
||
355 |
if (pSocket->GetSockName().Equals(sSockName)) { |
|
356 |
m_sSockets.erase(it); |
|
357 |
m_pManager->DelSockByAddr(pSocket); |
|
358 |
return true; |
|
359 |
}
|
|
360 |
}
|
|
361 |
||
362 |
return false; |
|
363 |
}
|
|
364 |
||
365 |
bool CModule::UnlinkSocket(CSocket* pSocket) { |
|
366 |
set<CSocket*>::iterator it; |
|
367 |
for (it = m_sSockets.begin(); it != m_sSockets.end(); ++it) { |
|
368 |
if (pSocket == *it) { |
|
369 |
m_sSockets.erase(it); |
|
370 |
return true; |
|
371 |
}
|
|
372 |
}
|
|
373 |
||
374 |
return false; |
|
375 |
}
|
|
376 |
||
377 |
CSocket* CModule::FindSocket(const CString& sSockName) { |
|
378 |
set<CSocket*>::iterator it; |
|
379 |
for (it = m_sSockets.begin(); it != m_sSockets.end(); ++it) { |
|
380 |
CSocket* pSocket = *it; |
|
381 |
if (pSocket->GetSockName().Equals(sSockName)) { |
|
382 |
return pSocket; |
|
383 |
}
|
|
384 |
}
|
|
385 |
||
386 |
return NULL; |
|
387 |
}
|
|
388 |
||
389 |
void CModule::ListSockets() { |
|
390 |
if (m_sSockets.empty()) { |
|
391 |
PutModule("You have no open sockets."); |
|
392 |
return; |
|
393 |
}
|
|
394 |
||
395 |
CTable Table; |
|
396 |
Table.AddColumn("Name"); |
|
397 |
Table.AddColumn("State"); |
|
398 |
Table.AddColumn("LocalPort"); |
|
399 |
Table.AddColumn("SSL"); |
|
400 |
Table.AddColumn("RemoteIP"); |
|
401 |
Table.AddColumn("RemotePort"); |
|
402 |
||
403 |
set<CSocket*>::iterator it; |
|
404 |
for (it = m_sSockets.begin(); it != m_sSockets.end(); ++it) { |
|
405 |
CSocket* pSocket = *it; |
|
406 |
||
407 |
Table.AddRow(); |
|
408 |
Table.SetCell("Name", pSocket->GetSockName()); |
|
409 |
||
410 |
if (pSocket->GetType() == CSocket::LISTENER) { |
|
411 |
Table.SetCell("State", "Listening"); |
|
412 |
} else { |
|
413 |
Table.SetCell("State", (pSocket->IsConnected() ? "Connected" : "")); |
|
414 |
}
|
|
415 |
||
416 |
Table.SetCell("LocalPort", CString(pSocket->GetLocalPort())); |
|
417 |
Table.SetCell("SSL", (pSocket->GetSSL() ? "yes" : "no")); |
|
418 |
Table.SetCell("RemoteIP", pSocket->GetRemoteIP()); |
|
419 |
Table.SetCell("RemotePort", (pSocket->GetRemotePort()) ? CString(pSocket->GetRemotePort()) : CString("")); |
|
420 |
}
|
|
421 |
||
422 |
PutModule(Table); |
|
423 |
}
|
|
424 |
||
425 |
bool CModule::AddCommand(const CModCommand& Command) |
|
426 |
{
|
|
427 |
if (Command.GetFunction() == NULL) |
|
428 |
return false; |
|
429 |
if (Command.GetCommand().find(' ') != CString::npos) |
|
430 |
return false; |
|
431 |
if (FindCommand(Command.GetCommand()) != NULL) |
|
432 |
return false; |
|
433 |
||
434 |
m_mCommands[Command.GetCommand()] = Command; |
|
435 |
return true; |
|
436 |
}
|
|
437 |
||
438 |
bool CModule::AddCommand(const CString& sCmd, CModCommand::ModCmdFunc func, const CString& sArgs, const CString& sDesc) |
|
439 |
{
|
|
440 |
CModCommand cmd(sCmd, func, sArgs, sDesc); |
|
441 |
return AddCommand(cmd); |
|
442 |
}
|
|
443 |
||
444 |
void CModule::AddHelpCommand() |
|
445 |
{
|
|
446 |
AddCommand("Help", &CModule::HandleHelpCommand, "search", "Generate this output"); |
|
447 |
}
|
|
448 |
||
449 |
bool CModule::RemCommand(const CString& sCmd) |
|
450 |
{
|
|
451 |
return m_mCommands.erase(sCmd) > 0; |
|
452 |
}
|
|
453 |
||
454 |
const CModCommand* CModule::FindCommand(const CString& sCmd) const |
|
455 |
{
|
|
456 |
map<CString, CModCommand>::const_iterator it; |
|
457 |
for (it = m_mCommands.begin(); it != m_mCommands.end(); ++it) { |
|
458 |
if (!it->first.Equals(sCmd)) |
|
459 |
continue; |
|
460 |
return &it->second; |
|
461 |
}
|
|
462 |
return NULL; |
|
463 |
}
|
|
464 |
||
465 |
bool CModule::HandleCommand(const CString& sLine) { |
|
466 |
const CString& sCmd = sLine.Token(0); |
|
467 |
const CModCommand* pCmd = FindCommand(sCmd); |
|
468 |
||
469 |
if (pCmd) { |
|
470 |
pCmd->Call(this, sLine); |
|
471 |
return true; |
|
472 |
}
|
|
473 |
||
474 |
OnUnknownModCommand(sLine); |
|
475 |
||
476 |
return false; |
|
477 |
}
|
|
478 |
||
479 |
void CModule::HandleHelpCommand(const CString& sLine) { |
|
480 |
CString sFilter = sLine.Token(1, true); |
|
481 |
CString::size_type iFilterLength = sFilter.size(); |
|
482 |
CTable Table; |
|
483 |
map<CString, CModCommand>::const_iterator it; |
|
484 |
||
485 |
CModCommand::InitHelp(Table); |
|
486 |
for (it = m_mCommands.begin(); it != m_mCommands.end(); ++it) { |
|
487 |
if (sFilter.empty() || (it->second.GetCommand().Equals(sFilter, false, iFilterLength))) { |
|
488 |
it->second.AddHelp(Table); |
|
489 |
}
|
|
490 |
}
|
|
491 |
PutModule(Table); |
|
492 |
}
|
|
493 |
||
494 |
CString CModule::GetModNick() const { return ((m_pUser) ? m_pUser->GetStatusPrefix() : "*") + m_sModName; } |
|
495 |
||
496 |
// Webmods
|
|
497 |
bool CModule::OnWebPreRequest(CWebSock& WebSock, const CString& sPageName) { return false; } |
|
498 |
bool CModule::OnWebRequest(CWebSock& WebSock, const CString& sPageName, CTemplate& Tmpl) { return false; } |
|
499 |
bool CModule::OnEmbeddedWebRequest(CWebSock& WebSock, const CString& sPageName, CTemplate& Tmpl) { return false; } |
|
500 |
// !Webmods
|
|
501 |
||
502 |
bool CModule::OnLoad(const CString& sArgs, CString& sMessage) { sMessage = ""; return true; } |
|
503 |
bool CModule::OnBoot() { return true; } |
|
504 |
void CModule::OnPreRehash() {} |
|
505 |
void CModule::OnPostRehash() {} |
|
506 |
void CModule::OnIRCDisconnected() {} |
|
507 |
void CModule::OnIRCConnected() {} |
|
508 |
CModule::EModRet CModule::OnIRCConnecting(CIRCSock *IRCSock) { return CONTINUE; } |
|
509 |
void CModule::OnIRCConnectionError(CIRCSock *IRCSock) {} |
|
510 |
CModule::EModRet CModule::OnIRCRegistration(CString& sPass, CString& sNick, CString& sIdent, CString& sRealName) { return CONTINUE; } |
|
511 |
CModule::EModRet CModule::OnBroadcast(CString& sMessage) { return CONTINUE; } |
|
512 |
||
513 |
void CModule::OnChanPermission(const CNick& OpNick, const CNick& Nick, CChan& Channel, unsigned char uMode, bool bAdded, bool bNoChange) {} |
|
514 |
void CModule::OnOp(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) {} |
|
515 |
void CModule::OnDeop(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) {} |
|
516 |
void CModule::OnVoice(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) {} |
|
517 |
void CModule::OnDevoice(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) {} |
|
518 |
void CModule::OnRawMode(const CNick& OpNick, CChan& Channel, const CString& sModes, const CString& sArgs) {} |
|
519 |
void CModule::OnMode(const CNick& OpNick, CChan& Channel, char uMode, const CString& sArg, bool bAdded, bool bNoChange) {} |
|
520 |
||
521 |
CModule::EModRet CModule::OnRaw(CString& sLine) { return CONTINUE; } |
|
522 |
||
523 |
CModule::EModRet CModule::OnStatusCommand(CString& sCommand) { return CONTINUE; } |
|
524 |
void CModule::OnModNotice(const CString& sMessage) {} |
|
525 |
void CModule::OnModCTCP(const CString& sMessage) {} |
|
526 |
||
527 |
void CModule::OnModCommand(const CString& sCommand) { |
|
528 |
HandleCommand(sCommand); |
|
529 |
}
|
|
530 |
void CModule::OnUnknownModCommand(const CString& sLine) { |
|
531 |
if (m_mCommands.empty()) |
|
532 |
// This function is only called if OnModCommand wasn't
|
|
533 |
// overriden, so no false warnings for modules which don't use
|
|
534 |
// CModCommand for command handling.
|
|
535 |
PutModule("This module doesn't implement any commands."); |
|
536 |
else
|
|
537 |
PutModule("Unknown command!"); |
|
538 |
}
|
|
539 |
||
540 |
void CModule::OnQuit(const CNick& Nick, const CString& sMessage, const vector<CChan*>& vChans) {} |
|
541 |
void CModule::OnNick(const CNick& Nick, const CString& sNewNick, const vector<CChan*>& vChans) {} |
|
542 |
void CModule::OnKick(const CNick& Nick, const CString& sKickedNick, CChan& Channel, const CString& sMessage) {} |
|
543 |
void CModule::OnJoin(const CNick& Nick, CChan& Channel) {} |
|
544 |
void CModule::OnPart(const CNick& Nick, CChan& Channel, const CString& sMessage) {} |
|
545 |
CModule::EModRet CModule::OnInvite(const CNick& Nick, const CString& sChan) { return CONTINUE; } |
|
546 |
||
547 |
CModule::EModRet CModule::OnChanBufferStarting(CChan& Chan, CClient& Client) { return CONTINUE; } |
|
548 |
CModule::EModRet CModule::OnChanBufferEnding(CChan& Chan, CClient& Client) { return CONTINUE; } |
|
549 |
CModule::EModRet CModule::OnChanBufferPlayLine(CChan& Chan, CClient& Client, CString& sLine) { return CONTINUE; } |
|
550 |
CModule::EModRet CModule::OnPrivBufferPlayLine(CClient& Client, CString& sLine) { return CONTINUE; } |
|
551 |
||
552 |
void CModule::OnClientLogin() {} |
|
553 |
void CModule::OnClientDisconnect() {} |
|
554 |
CModule::EModRet CModule::OnUserRaw(CString& sLine) { return CONTINUE; } |
|
555 |
CModule::EModRet CModule::OnUserCTCPReply(CString& sTarget, CString& sMessage) { return CONTINUE; } |
|
556 |
CModule::EModRet CModule::OnUserCTCP(CString& sTarget, CString& sMessage) { return CONTINUE; } |
|
557 |
CModule::EModRet CModule::OnUserAction(CString& sTarget, CString& sMessage) { return CONTINUE; } |
|
558 |
CModule::EModRet CModule::OnUserMsg(CString& sTarget, CString& sMessage) { return CONTINUE; } |
|
559 |
CModule::EModRet CModule::OnUserNotice(CString& sTarget, CString& sMessage) { return CONTINUE; } |
|
560 |
CModule::EModRet CModule::OnUserJoin(CString& sChannel, CString& sKey) { return CONTINUE; } |
|
561 |
CModule::EModRet CModule::OnUserPart(CString& sChannel, CString& sMessage) { return CONTINUE; } |
|
562 |
CModule::EModRet CModule::OnUserTopic(CString& sChannel, CString& sTopic) { return CONTINUE; } |
|
563 |
CModule::EModRet CModule::OnUserTopicRequest(CString& sChannel) { return CONTINUE; } |
|
564 |
||
565 |
CModule::EModRet CModule::OnCTCPReply(CNick& Nick, CString& sMessage) { return CONTINUE; } |
|
566 |
CModule::EModRet CModule::OnPrivCTCP(CNick& Nick, CString& sMessage) { return CONTINUE; } |
|
567 |
CModule::EModRet CModule::OnChanCTCP(CNick& Nick, CChan& Channel, CString& sMessage) { return CONTINUE; } |
|
568 |
CModule::EModRet CModule::OnPrivAction(CNick& Nick, CString& sMessage) { return CONTINUE; } |
|
569 |
CModule::EModRet CModule::OnChanAction(CNick& Nick, CChan& Channel, CString& sMessage) { return CONTINUE; } |
|
570 |
CModule::EModRet CModule::OnPrivMsg(CNick& Nick, CString& sMessage) { return CONTINUE; } |
|
571 |
CModule::EModRet CModule::OnChanMsg(CNick& Nick, CChan& Channel, CString& sMessage) { return CONTINUE; } |
|
572 |
CModule::EModRet CModule::OnPrivNotice(CNick& Nick, CString& sMessage) { return CONTINUE; } |
|
573 |
CModule::EModRet CModule::OnChanNotice(CNick& Nick, CChan& Channel, CString& sMessage) { return CONTINUE; } |
|
574 |
CModule::EModRet CModule::OnTopic(CNick& Nick, CChan& Channel, CString& sTopic) { return CONTINUE; } |
|
575 |
CModule::EModRet CModule::OnTimerAutoJoin(CChan& Channel) { return CONTINUE; } |
|
576 |
||
577 |
bool CModule::OnServerCapAvailable(const CString& sCap) { return false; } |
|
578 |
void CModule::OnServerCapResult(const CString& sCap, bool bSuccess) {} |
|
579 |
||
580 |
bool CModule::PutIRC(const CString& sLine) { |
|
581 |
return (m_pNetwork) ? m_pNetwork->PutIRC(sLine) : false; |
|
582 |
}
|
|
583 |
bool CModule::PutUser(const CString& sLine) { |
|
584 |
return (m_pNetwork) ? m_pNetwork->PutUser(sLine, m_pClient) : false; |
|
585 |
}
|
|
586 |
bool CModule::PutStatus(const CString& sLine) { |
|
587 |
return (m_pNetwork) ? m_pNetwork->PutStatus(sLine, m_pClient) : false; |
|
588 |
}
|
|
589 |
unsigned int CModule::PutModule(const CTable& table) { |
|
590 |
if (!m_pUser) |
|
591 |
return 0; |
|
592 |
||
593 |
unsigned int idx = 0; |
|
594 |
CString sLine; |
|
595 |
while (table.GetLine(idx++, sLine)) |
|
596 |
PutModule(sLine); |
|
597 |
return idx - 1; |
|
598 |
}
|
|
599 |
bool CModule::PutModule(const CString& sLine) { |
|
600 |
if (m_pClient) { |
|
601 |
m_pClient->PutModule(GetModName(), sLine); |
|
602 |
return true; |
|
603 |
}
|
|
604 |
||
605 |
if (m_pNetwork) { |
|
606 |
return m_pNetwork->PutModule(GetModName(), sLine); |
|
607 |
}
|
|
608 |
||
609 |
if (m_pUser) { |
|
610 |
return m_pUser->PutModule(GetModName(), sLine); |
|
611 |
}
|
|
612 |
||
613 |
return false; |
|
614 |
}
|
|
615 |
bool CModule::PutModNotice(const CString& sLine) { |
|
616 |
if (!m_pUser) |
|
617 |
return false; |
|
618 |
||
619 |
if (m_pClient) { |
|
620 |
m_pClient->PutModNotice(GetModName(), sLine); |
|
621 |
return true; |
|
622 |
}
|
|
623 |
||
624 |
return m_pUser->PutModNotice(GetModName(), sLine); |
|
625 |
}
|
|
626 |
||
627 |
///////////////////
|
|
628 |
// Global Module //
|
|
629 |
///////////////////
|
|
630 |
CModule::EModRet CModule::OnAddUser(CUser& User, CString& sErrorRet) { return CONTINUE; } |
|
631 |
CModule::EModRet CModule::OnDeleteUser(CUser& User) { return CONTINUE; } |
|
632 |
void CModule::OnClientConnect(CZNCSock* pClient, const CString& sHost, unsigned short uPort) {} |
|
633 |
CModule::EModRet CModule::OnLoginAttempt(CSmartPtr<CAuthBase> Auth) { return CONTINUE; } |
|
634 |
void CModule::OnFailedLogin(const CString& sUsername, const CString& sRemoteIP) {} |
|
635 |
CModule::EModRet CModule::OnUnknownUserRaw(CClient* pClient, CString& sLine) { return CONTINUE; } |
|
636 |
void CModule::OnClientCapLs(CClient* pClient, SCString& ssCaps) {} |
|
637 |
bool CModule::IsClientCapSupported(CClient* pClient, const CString& sCap, bool bState) { return false; } |
|
638 |
void CModule::OnClientCapRequest(CClient* pClient, const CString& sCap, bool bState) {} |
|
639 |
CModule::EModRet CModule::OnModuleLoading(const CString& sModName, const CString& sArgs, |
|
640 |
CModInfo::EModuleType eType, bool& bSuccess, CString& sRetMsg) { return CONTINUE; } |
|
641 |
CModule::EModRet CModule::OnModuleUnloading(CModule* pModule, bool& bSuccess, CString& sRetMsg) { |
|
642 |
return CONTINUE; |
|
643 |
}
|
|
644 |
CModule::EModRet CModule::OnGetModInfo(CModInfo& ModInfo, const CString& sModule, |
|
645 |
bool& bSuccess, CString& sRetMsg) { return CONTINUE; } |
|
646 |
void CModule::OnGetAvailableMods(set<CModInfo>& ssMods, CModInfo::EModuleType eType) {} |
|
647 |
||
648 |
||
649 |
CModules::CModules() { |
|
650 |
m_pUser = NULL; |
|
651 |
m_pNetwork = NULL; |
|
652 |
m_pClient = NULL; |
|
653 |
}
|
|
654 |
||
655 |
CModules::~CModules() { |
|
656 |
UnloadAll(); |
|
657 |
}
|
|
658 |
||
659 |
void CModules::UnloadAll() { |
|
660 |
while (size()) { |
|
661 |
CString sRetMsg; |
|
662 |
CString sModName = back()->GetModName(); |
|
663 |
UnloadModule(sModName, sRetMsg); |
|
664 |
}
|
|
665 |
}
|
|
666 |
||
667 |
bool CModules::OnBoot() { |
|
668 |
for (unsigned int a = 0; a < size(); a++) { |
|
669 |
try { |
|
670 |
if (!(*this)[a]->OnBoot()) { |
|
671 |
return true; |
|
672 |
}
|
|
673 |
} catch (CModule::EModException e) { |
|
674 |
if (e == CModule::UNLOAD) { |
|
675 |
UnloadModule((*this)[a]->GetModName()); |
|
676 |
}
|
|
677 |
}
|
|
678 |
}
|
|
679 |
||
680 |
return false; |
|
681 |
}
|
|
682 |
||
683 |
bool CModules::OnPreRehash() { MODUNLOADCHK(OnPreRehash()); return false; } |
|
684 |
bool CModules::OnPostRehash() { MODUNLOADCHK(OnPostRehash()); return false; } |
|
685 |
bool CModules::OnIRCConnected() { MODUNLOADCHK(OnIRCConnected()); return false; } |
|
686 |
bool CModules::OnIRCConnecting(CIRCSock *pIRCSock) { MODHALTCHK(OnIRCConnecting(pIRCSock)); } |
|
687 |
bool CModules::OnIRCConnectionError(CIRCSock *pIRCSock) { MODUNLOADCHK(OnIRCConnectionError(pIRCSock)); return false; } |
|
688 |
bool CModules::OnIRCRegistration(CString& sPass, CString& sNick, CString& sIdent, CString& sRealName) { MODHALTCHK(OnIRCRegistration(sPass, sNick, sIdent, sRealName)); } |
|
689 |
bool CModules::OnBroadcast(CString& sMessage) { MODHALTCHK(OnBroadcast(sMessage)); } |
|
690 |
bool CModules::OnIRCDisconnected() { MODUNLOADCHK(OnIRCDisconnected()); return false; } |
|
691 |
bool CModules::OnChanPermission(const CNick& OpNick, const CNick& Nick, CChan& Channel, unsigned char uMode, bool bAdded, bool bNoChange) { MODUNLOADCHK(OnChanPermission(OpNick, Nick, Channel, uMode, bAdded, bNoChange)); return false; } |
|
692 |
bool CModules::OnOp(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) { MODUNLOADCHK(OnOp(OpNick, Nick, Channel, bNoChange)); return false; } |
|
693 |
bool CModules::OnDeop(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) { MODUNLOADCHK(OnDeop(OpNick, Nick, Channel, bNoChange)); return false; } |
|
694 |
bool CModules::OnVoice(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) { MODUNLOADCHK(OnVoice(OpNick, Nick, Channel, bNoChange)); return false; } |
|
695 |
bool CModules::OnDevoice(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) { MODUNLOADCHK(OnDevoice(OpNick, Nick, Channel, bNoChange)); return false; } |
|
696 |
bool CModules::OnRawMode(const CNick& OpNick, CChan& Channel, const CString& sModes, const CString& sArgs) { MODUNLOADCHK(OnRawMode(OpNick, Channel, sModes, sArgs)); return false; } |
|
697 |
bool CModules::OnMode(const CNick& OpNick, CChan& Channel, char uMode, const CString& sArg, bool bAdded, bool bNoChange) { MODUNLOADCHK(OnMode(OpNick, Channel, uMode, sArg, bAdded, bNoChange)); return false; } |
|
698 |
bool CModules::OnRaw(CString& sLine) { MODHALTCHK(OnRaw(sLine)); } |
|
699 |
||
700 |
bool CModules::OnClientLogin() { MODUNLOADCHK(OnClientLogin()); return false; } |
|
701 |
bool CModules::OnClientDisconnect() { MODUNLOADCHK(OnClientDisconnect()); return false; } |
|
702 |
bool CModules::OnUserRaw(CString& sLine) { MODHALTCHK(OnUserRaw(sLine)); } |
|
703 |
bool CModules::OnUserCTCPReply(CString& sTarget, CString& sMessage) { MODHALTCHK(OnUserCTCPReply(sTarget, sMessage)); } |
|
704 |
bool CModules::OnUserCTCP(CString& sTarget, CString& sMessage) { MODHALTCHK(OnUserCTCP(sTarget, sMessage)); } |
|
705 |
bool CModules::OnUserAction(CString& sTarget, CString& sMessage) { MODHALTCHK(OnUserAction(sTarget, sMessage)); } |
|
706 |
bool CModules::OnUserMsg(CString& sTarget, CString& sMessage) { MODHALTCHK(OnUserMsg(sTarget, sMessage)); } |
|
707 |
bool CModules::OnUserNotice(CString& sTarget, CString& sMessage) { MODHALTCHK(OnUserNotice(sTarget, sMessage)); } |
|
708 |
bool CModules::OnUserJoin(CString& sChannel, CString& sKey) { MODHALTCHK(OnUserJoin(sChannel, sKey)); } |
|
709 |
bool CModules::OnUserPart(CString& sChannel, CString& sMessage) { MODHALTCHK(OnUserPart(sChannel, sMessage)); } |
|
710 |
bool CModules::OnUserTopic(CString& sChannel, CString& sTopic) { MODHALTCHK(OnUserTopic(sChannel, sTopic)); } |
|
711 |
bool CModules::OnUserTopicRequest(CString& sChannel) { MODHALTCHK(OnUserTopicRequest(sChannel)); } |
|
712 |
||
713 |
bool CModules::OnQuit(const CNick& Nick, const CString& sMessage, const vector<CChan*>& vChans) { MODUNLOADCHK(OnQuit(Nick, sMessage, vChans)); return false; } |
|
714 |
bool CModules::OnNick(const CNick& Nick, const CString& sNewNick, const vector<CChan*>& vChans) { MODUNLOADCHK(OnNick(Nick, sNewNick, vChans)); return false; } |
|
715 |
bool CModules::OnKick(const CNick& Nick, const CString& sKickedNick, CChan& Channel, const CString& sMessage) { MODUNLOADCHK(OnKick(Nick, sKickedNick, Channel, sMessage)); return false; } |
|
716 |
bool CModules::OnJoin(const CNick& Nick, CChan& Channel) { MODUNLOADCHK(OnJoin(Nick, Channel)); return false; } |
|
717 |
bool CModules::OnPart(const CNick& Nick, CChan& Channel, const CString& sMessage) { MODUNLOADCHK(OnPart(Nick, Channel, sMessage)); return false; } |
|
718 |
bool CModules::OnInvite(const CNick& Nick, const CString& sChan) { MODHALTCHK(OnInvite(Nick, sChan)); } |
|
719 |
bool CModules::OnChanBufferStarting(CChan& Chan, CClient& Client) { MODHALTCHK(OnChanBufferStarting(Chan, Client)); } |
|
720 |
bool CModules::OnChanBufferEnding(CChan& Chan, CClient& Client) { MODHALTCHK(OnChanBufferEnding(Chan, Client)); } |
|
721 |
bool CModules::OnChanBufferPlayLine(CChan& Chan, CClient& Client, CString& sLine) { MODHALTCHK(OnChanBufferPlayLine(Chan, Client, sLine)); } |
|
722 |
bool CModules::OnPrivBufferPlayLine(CClient& Client, CString& sLine) { MODHALTCHK(OnPrivBufferPlayLine(Client, sLine)); } |
|
723 |
bool CModules::OnCTCPReply(CNick& Nick, CString& sMessage) { MODHALTCHK(OnCTCPReply(Nick, sMessage)); } |
|
724 |
bool CModules::OnPrivCTCP(CNick& Nick, CString& sMessage) { MODHALTCHK(OnPrivCTCP(Nick, sMessage)); } |
|
725 |
bool CModules::OnChanCTCP(CNick& Nick, CChan& Channel, CString& sMessage) { MODHALTCHK(OnChanCTCP(Nick, Channel, sMessage)); } |
|
726 |
bool CModules::OnPrivAction(CNick& Nick, CString& sMessage) { MODHALTCHK(OnPrivAction(Nick, sMessage)); } |
|
727 |
bool CModules::OnChanAction(CNick& Nick, CChan& Channel, CString& sMessage) { MODHALTCHK(OnChanAction(Nick, Channel, sMessage)); } |
|
728 |
bool CModules::OnPrivMsg(CNick& Nick, CString& sMessage) { MODHALTCHK(OnPrivMsg(Nick, sMessage)); } |
|
729 |
bool CModules::OnChanMsg(CNick& Nick, CChan& Channel, CString& sMessage) { MODHALTCHK(OnChanMsg(Nick, Channel, sMessage)); } |
|
730 |
bool CModules::OnPrivNotice(CNick& Nick, CString& sMessage) { MODHALTCHK(OnPrivNotice(Nick, sMessage)); } |
|
731 |
bool CModules::OnChanNotice(CNick& Nick, CChan& Channel, CString& sMessage) { MODHALTCHK(OnChanNotice(Nick, Channel, sMessage)); } |
|
732 |
bool CModules::OnTopic(CNick& Nick, CChan& Channel, CString& sTopic) { MODHALTCHK(OnTopic(Nick, Channel, sTopic)); } |
|
733 |
bool CModules::OnTimerAutoJoin(CChan& Channel) { MODHALTCHK(OnTimerAutoJoin(Channel)); } |
|
734 |
bool CModules::OnStatusCommand(CString& sCommand) { MODHALTCHK(OnStatusCommand(sCommand)); } |
|
735 |
bool CModules::OnModCommand(const CString& sCommand) { MODUNLOADCHK(OnModCommand(sCommand)); return false; } |
|
736 |
bool CModules::OnModNotice(const CString& sMessage) { MODUNLOADCHK(OnModNotice(sMessage)); return false; } |
|
737 |
bool CModules::OnModCTCP(const CString& sMessage) { MODUNLOADCHK(OnModCTCP(sMessage)); return false; } |
|
738 |
||
739 |
// Why MODHALTCHK works only with functions returning EModRet ? :(
|
|
740 |
bool CModules::OnServerCapAvailable(const CString& sCap) { |
|
741 |
bool bResult = false; |
|
742 |
for (unsigned int a = 0; a < size(); ++a) { |
|
743 |
try { |
|
744 |
CModule* pMod = (*this)[a]; |
|
745 |
CClient* pOldClient = pMod->GetClient(); |
|
746 |
pMod->SetClient(m_pClient); |
|
747 |
if (m_pUser) { |
|
748 |
CUser* pOldUser = pMod->GetUser(); |
|
749 |
pMod->SetUser(m_pUser); |
|
750 |
bResult |= pMod->OnServerCapAvailable(sCap); |
|
751 |
pMod->SetUser(pOldUser); |
|
752 |
} else { |
|
753 |
// WTF? Is that possible?
|
|
754 |
bResult |= pMod->OnServerCapAvailable(sCap); |
|
755 |
}
|
|
756 |
pMod->SetClient(pOldClient); |
|
757 |
} catch (CModule::EModException e) { |
|
758 |
if (CModule::UNLOAD == e) { |
|
759 |
UnloadModule((*this)[a]->GetModName()); |
|
760 |
}
|
|
761 |
}
|
|
762 |
}
|
|
763 |
return bResult; |
|
764 |
}
|
|
765 |
||
766 |
bool CModules::OnServerCapResult(const CString& sCap, bool bSuccess) { MODUNLOADCHK(OnServerCapResult(sCap, bSuccess)); return false; } |
|
767 |
||
768 |
////////////////////
|
|
769 |
// Global Modules //
|
|
770 |
////////////////////
|
|
771 |
bool CModules::OnAddUser(CUser& User, CString& sErrorRet) { |
|
772 |
MODHALTCHK(OnAddUser(User, sErrorRet)); |
|
773 |
}
|
|
774 |
||
775 |
bool CModules::OnDeleteUser(CUser& User) { |
|
776 |
MODHALTCHK(OnDeleteUser(User)); |
|
777 |
}
|
|
778 |
||
779 |
bool CModules::OnClientConnect(CZNCSock* pClient, const CString& sHost, unsigned short uPort) { |
|
780 |
MODUNLOADCHK(OnClientConnect(pClient, sHost, uPort)); |
|
781 |
return false; |
|
782 |
}
|
|
783 |
||
784 |
bool CModules::OnLoginAttempt(CSmartPtr<CAuthBase> Auth) { |
|
785 |
MODHALTCHK(OnLoginAttempt(Auth)); |
|
786 |
}
|
|
787 |
||
788 |
bool CModules::OnFailedLogin(const CString& sUsername, const CString& sRemoteIP) { |
|
789 |
MODUNLOADCHK(OnFailedLogin(sUsername, sRemoteIP)); |
|
790 |
return false; |
|
791 |
}
|
|
792 |
||
793 |
bool CModules::OnUnknownUserRaw(CClient* pClient, CString& sLine) { |
|
794 |
MODHALTCHK(OnUnknownUserRaw(pClient, sLine)); |
|
795 |
}
|
|
796 |
||
797 |
bool CModules::OnClientCapLs(CClient* pClient, SCString& ssCaps) { |
|
798 |
MODUNLOADCHK(OnClientCapLs(pClient, ssCaps)); |
|
799 |
return false; |
|
800 |
}
|
|
801 |
||
802 |
// Maybe create new macro for this?
|
|
803 |
bool CModules::IsClientCapSupported(CClient* pClient, const CString& sCap, bool bState) { |
|
804 |
bool bResult = false; |
|
805 |
for (unsigned int a = 0; a < size(); ++a) { |
|
806 |
try { |
|
807 |
CModule* pMod = (CModule*) (*this)[a]; |
|
808 |
CClient* pOldClient = pMod->GetClient(); |
|
809 |
pMod->SetClient(m_pClient); |
|
810 |
if (m_pUser) { |
|
811 |
CUser* pOldUser = pMod->GetUser(); |
|
812 |
pMod->SetUser(m_pUser); |
|
813 |
bResult |= pMod->IsClientCapSupported(pClient, sCap, bState); |
|
814 |
pMod->SetUser(pOldUser); |
|
815 |
} else { |
|
816 |
// WTF? Is that possible?
|
|
817 |
bResult |= pMod->IsClientCapSupported(pClient, sCap, bState); |
|
818 |
}
|
|
819 |
pMod->SetClient(pOldClient); |
|
820 |
} catch (CModule::EModException e) { |
|
821 |
if (CModule::UNLOAD == e) { |
|
822 |
UnloadModule((*this)[a]->GetModName()); |
|
823 |
}
|
|
824 |
}
|
|
825 |
}
|
|
826 |
return bResult; |
|
827 |
}
|
|
828 |
||
829 |
bool CModules::OnClientCapRequest(CClient* pClient, const CString& sCap, bool bState) { |
|
830 |
MODUNLOADCHK(OnClientCapRequest(pClient, sCap, bState)); |
|
831 |
return false; |
|
832 |
}
|
|
833 |
||
834 |
bool CModules::OnModuleLoading(const CString& sModName, const CString& sArgs, |
|
835 |
CModInfo::EModuleType eType, bool& bSuccess, CString& sRetMsg) { |
|
836 |
MODHALTCHK(OnModuleLoading(sModName, sArgs, eType, bSuccess, sRetMsg)); |
|
837 |
}
|
|
838 |
||
839 |
bool CModules::OnModuleUnloading(CModule* pModule, bool& bSuccess, CString& sRetMsg) { |
|
840 |
MODHALTCHK(OnModuleUnloading(pModule, bSuccess, sRetMsg)); |
|
841 |
}
|
|
842 |
||
843 |
bool CModules::OnGetModInfo(CModInfo& ModInfo, const CString& sModule, |
|
844 |
bool& bSuccess, CString& sRetMsg) { |
|
845 |
MODHALTCHK(OnGetModInfo(ModInfo, sModule, bSuccess, sRetMsg)); |
|
846 |
}
|
|
847 |
||
848 |
bool CModules::OnGetAvailableMods(set<CModInfo>& ssMods, CModInfo::EModuleType eType) { |
|
849 |
MODUNLOADCHK(OnGetAvailableMods(ssMods, eType)); |
|
850 |
return false; |
|
851 |
}
|
|
852 |
||
853 |
||
854 |
CModule* CModules::FindModule(const CString& sModule) const { |
|
855 |
for (unsigned int a = 0; a < size(); a++) { |
|
856 |
if (sModule.Equals((*this)[a]->GetModName())) { |
|
857 |
return (*this)[a]; |
|
858 |
}
|
|
859 |
}
|
|
860 |
||
861 |
return NULL; |
|
862 |
}
|
|
863 |
||
864 |
bool CModules::LoadModule(const CString& sModule, const CString& sArgs, CModInfo::EModuleType eType, CUser* pUser, CIRCNetwork *pNetwork, CString& sRetMsg) { |
|
865 |
sRetMsg = ""; |
|
866 |
||
867 |
if (FindModule(sModule) != NULL) { |
|
868 |
sRetMsg = "Module [" + sModule + "] already loaded."; |
|
869 |
return false; |
|
870 |
}
|
|
871 |
||
872 |
bool bSuccess; |
|
873 |
bool bHandled = false; |
|
874 |
_GLOBALMODULECALL(OnModuleLoading(sModule, sArgs, eType, bSuccess, sRetMsg), pUser, pNetwork, NULL, &bHandled); |
|
875 |
if (bHandled) return bSuccess; |
|
876 |
||
877 |
CString sModPath, sDataPath; |
|
878 |
bool bVersionMismatch; |
|
879 |
CModInfo Info; |
|
880 |
||
881 |
if (!FindModPath(sModule, sModPath, sDataPath)) { |
|
882 |
sRetMsg = "Unable to find module [" + sModule + "]"; |
|
883 |
return false; |
|
884 |
}
|
|
885 |
||
886 |
ModHandle p = OpenModule(sModule, sModPath, bVersionMismatch, Info, sRetMsg); |
|
887 |
||
888 |
if (!p) |
|
889 |
return false; |
|
890 |
||
891 |
if (bVersionMismatch) { |
|
892 |
dlclose(p); |
|
893 |
sRetMsg = "Version mismatch, recompile this module."; |
|
894 |
return false; |
|
895 |
}
|
|
896 |
||
897 |
if (!Info.SupportsType(eType)) { |
|
898 |
dlclose(p); |
|
899 |
sRetMsg = "Module [" + sModule + "] does not support module type [" |
|
900 |
+ CModInfo::ModuleTypeToString(eType) + "]."; |
|
901 |
return false; |
|
902 |
}
|
|
903 |
||
904 |
if (!pUser && eType == CModInfo::UserModule) { |
|
905 |
dlclose(p); |
|
906 |
sRetMsg = "Module [" + sModule + "] requires a user."; |
|
907 |
return false; |
|
908 |
}
|
|
909 |
||
910 |
if (!pNetwork && eType == CModInfo::NetworkModule) { |
|
911 |
dlclose(p); |
|
912 |
sRetMsg = "Module [" + sModule + "] requires a network."; |
|
913 |
return false; |
|
914 |
}
|
|
915 |
||
916 |
CModule* pModule = Info.GetLoader()(p, pUser, pNetwork, sModule, sDataPath); |
|
917 |
pModule->SetDescription(Info.GetDescription()); |
|
918 |
pModule->SetType(eType); |
|
919 |
pModule->SetArgs(sArgs); |
|
920 |
pModule->SetModPath(CDir::ChangeDir(CZNC::Get().GetCurPath(), sModPath)); |
|
921 |
push_back(pModule); |
|
922 |
||
923 |
bool bLoaded; |
|
924 |
try { |
|
925 |
bLoaded = pModule->OnLoad(sArgs, sRetMsg); |
|
926 |
} catch (CModule::EModException) { |
|
927 |
bLoaded = false; |
|
928 |
sRetMsg = "Caught an exception"; |
|
929 |
}
|
|
930 |
||
931 |
if (!bLoaded) { |
|
932 |
UnloadModule(sModule, sModPath); |
|
933 |
if (!sRetMsg.empty()) |
|
934 |
sRetMsg = "Module [" + sModule + "] aborted: " + sRetMsg; |
|
935 |
else
|
|
936 |
sRetMsg = "Module [" + sModule + "] aborted."; |
|
937 |
return false; |
|
938 |
}
|
|
939 |
||
940 |
if (!sRetMsg.empty()) { |
|
941 |
sRetMsg += "[" + sRetMsg + "] "; |
|
942 |
}
|
|
943 |
sRetMsg += "[" + sModPath + "]"; |
|
944 |
return true; |
|
945 |
}
|
|
946 |
||
947 |
bool CModules::UnloadModule(const CString& sModule) { |
|
948 |
CString s; |
|
949 |
return UnloadModule(sModule, s); |
|
950 |
}
|
|
951 |
||
952 |
bool CModules::UnloadModule(const CString& sModule, CString& sRetMsg) { |
|
953 |
CString sMod = sModule; // Make a copy incase the reference passed in is from CModule::GetModName() |
|
954 |
CModule* pModule = FindModule(sMod); |
|
955 |
sRetMsg = ""; |
|
956 |
||
957 |
if (!pModule) { |
|
958 |
sRetMsg = "Module [" + sMod + "] not loaded."; |
|
959 |
return false; |
|
960 |
}
|
|
961 |
||
962 |
bool bSuccess; |
|
963 |
bool bHandled = false; |
|
964 |
_GLOBALMODULECALL(OnModuleUnloading(pModule, bSuccess, sRetMsg), pModule->GetUser(), pModule->GetNetwork(), NULL, &bHandled); |
|
965 |
if (bHandled) return bSuccess; |
|
966 |
||
967 |
ModHandle p = pModule->GetDLL(); |
|
968 |
||
969 |
if (p) { |
|
970 |
delete pModule; |
|
971 |
||
972 |
for (iterator it = begin(); it != end(); ++it) { |
|
973 |
if (*it == pModule) { |
|
974 |
erase(it); |
|
975 |
break; |
|
976 |
}
|
|
977 |
}
|
|
978 |
||
979 |
dlclose(p); |
|
980 |
sRetMsg = "Module [" + sMod + "] unloaded"; |
|
981 |
||
982 |
return true; |
|
983 |
}
|
|
984 |
||
985 |
sRetMsg = "Unable to unload module [" + sMod + "]"; |
|
986 |
return false; |
|
987 |
}
|
|
988 |
||
989 |
bool CModules::ReloadModule(const CString& sModule, const CString& sArgs, CUser* pUser, CIRCNetwork* pNetwork, CString& sRetMsg) { |
|
990 |
CString sMod = sModule; // Make a copy incase the reference passed in is from CModule::GetModName() |
|
991 |
CModule *pModule = FindModule(sMod); |
|
992 |
||
993 |
if (!pModule) { |
|
994 |
sRetMsg = "Module [" + sMod + "] not loaded"; |
|
995 |
return false; |
|
996 |
}
|
|
997 |
||
998 |
CModInfo::EModuleType eType = pModule->GetType(); |
|
999 |
pModule = NULL; |
|
1000 |
||
1001 |
sRetMsg = ""; |
|
1002 |
if (!UnloadModule(sMod, sRetMsg)) { |
|
1003 |
return false; |
|
1004 |
}
|
|
1005 |
||
1006 |
if (!LoadModule(sMod, sArgs, eType, pUser, pNetwork, sRetMsg)) { |
|
1007 |
return false; |
|
1008 |
}
|
|
1009 |
||
1010 |
sRetMsg = "Reloaded module [" + sMod + "]"; |
|
1011 |
return true; |
|
1012 |
}
|
|
1013 |
||
1014 |
bool CModules::GetModInfo(CModInfo& ModInfo, const CString& sModule, CString& sRetMsg) { |
|
1015 |
CString sModPath, sTmp; |
|
1016 |
||
1017 |
bool bSuccess; |
|
1018 |
bool bHandled = false; |
|
1019 |
GLOBALMODULECALL(OnGetModInfo(ModInfo, sModule, bSuccess, sRetMsg), &bHandled); |
|
1020 |
if (bHandled) return bSuccess; |
|
1021 |
||
1022 |
if (!FindModPath(sModule, sModPath, sTmp)) { |
|
1023 |
sRetMsg = "Unable to find module [" + sModule + "]"; |
|
1024 |
return false; |
|
1025 |
}
|
|
1026 |
||
1027 |
return GetModPathInfo(ModInfo, sModule, sModPath, sRetMsg); |
|
1028 |
}
|
|
1029 |
||
1030 |
bool CModules::GetModPathInfo(CModInfo& ModInfo, const CString& sModule, const CString& sModPath, CString& sRetMsg) { |
|
1031 |
bool bVersionMismatch; |
|
1032 |
||
1033 |
ModHandle p = OpenModule(sModule, sModPath, bVersionMismatch, ModInfo, sRetMsg); |
|
1034 |
||
1035 |
if (!p) |
|
1036 |
return false; |
|
1037 |
||
1038 |
ModInfo.SetName(sModule); |
|
1039 |
ModInfo.SetPath(sModPath); |
|
1040 |
||
1041 |
if (bVersionMismatch) { |
|
1042 |
ModInfo.SetDescription("--- Version mismatch, recompile this module. ---"); |
|
1043 |
}
|
|
1044 |
||
1045 |
dlclose(p); |
|
1046 |
||
1047 |
return true; |
|
1048 |
}
|
|
1049 |
||
1050 |
void CModules::GetAvailableMods(set<CModInfo>& ssMods, CModInfo::EModuleType eType) { |
|
1051 |
ssMods.clear(); |
|
1052 |
||
1053 |
unsigned int a = 0; |
|
1054 |
CDir Dir; |
|
1055 |
||
1056 |
ModDirList dirs = GetModDirs(); |
|
1057 |
||
1058 |
while (!dirs.empty()) { |
|
1059 |
Dir.FillByWildcard(dirs.front().first, "*.so"); |
|
1060 |
dirs.pop(); |
|
1061 |
||
1062 |
for (a = 0; a < Dir.size(); a++) { |
|
1063 |
CFile& File = *Dir[a]; |
|
1064 |
CString sName = File.GetShortName(); |
|
1065 |
CString sPath = File.GetLongName(); |
|
1066 |
CModInfo ModInfo; |
|
1067 |
sName.RightChomp(3); |
|
1068 |
||
1069 |
CString sIgnoreRetMsg; |
|
1070 |
if (GetModPathInfo(ModInfo, sName, sPath, sIgnoreRetMsg)) { |
|
1071 |
if (ModInfo.SupportsType(eType)) { |
|
1072 |
ssMods.insert(ModInfo); |
|
1073 |
}
|
|
1074 |
}
|
|
1075 |
}
|
|
1076 |
}
|
|
1077 |
||
1078 |
GLOBALMODULECALL(OnGetAvailableMods(ssMods, eType), NOTHING); |
|
1079 |
}
|
|
1080 |
||
1081 |
bool CModules::FindModPath(const CString& sModule, CString& sModPath, |
|
1082 |
CString& sDataPath) { |
|
1083 |
CString sMod = sModule; |
|
1084 |
CString sDir = sMod; |
|
1085 |
if (sModule.find(".") == CString::npos) |
|
1086 |
sMod += ".so"; |
|
1087 |
||
1088 |
ModDirList dirs = GetModDirs(); |
|
1089 |
||
1090 |
while (!dirs.empty()) { |
|
1091 |
sModPath = dirs.front().first + sMod; |
|
1092 |
sDataPath = dirs.front().second; |
|
1093 |
dirs.pop(); |
|
1094 |
||
1095 |
if (CFile::Exists(sModPath)) { |
|
1096 |
sDataPath += sDir; |
|
1097 |
return true; |
|
1098 |
}
|
|
1099 |
}
|
|
1100 |
||
1101 |
return false; |
|
1102 |
}
|
|
1103 |
||
1104 |
CModules::ModDirList CModules::GetModDirs() { |
|
1105 |
ModDirList ret; |
|
1106 |
CString sDir; |
|
1107 |
||
1108 |
#ifdef RUN_FROM_SOURCE
|
|
1109 |
// ./modules
|
|
1110 |
sDir = CZNC::Get().GetCurPath() + "/modules/"; |
|
1111 |
ret.push(std::make_pair(sDir, sDir + "data/")); |
|
1112 |
#endif
|
|
1113 |
||
1114 |
// ~/.znc/modules
|
|
1115 |
sDir = CZNC::Get().GetModPath() + "/"; |
|
1116 |
ret.push(std::make_pair(sDir, sDir)); |
|
1117 |
||
1118 |
// <moduledir> and <datadir> (<prefix>/lib/znc)
|
|
1119 |
ret.push(std::make_pair(_MODDIR_ + CString("/"), _DATADIR_ + CString("/modules/"))); |
|
1120 |
||
1121 |
return ret; |
|
1122 |
}
|
|
1123 |
||
1124 |
ModHandle CModules::OpenModule(const CString& sModule, const CString& sModPath, bool &bVersionMismatch, |
|
1125 |
CModInfo& Info, CString& sRetMsg) { |
|
1126 |
// Some sane defaults in case anything errors out below
|
|
1127 |
bVersionMismatch = false; |
|
1128 |
sRetMsg.clear(); |
|
1129 |
||
1130 |
for (unsigned int a = 0; a < sModule.length(); a++) { |
|
1131 |
if (((sModule[a] < '0') || (sModule[a] > '9')) && ((sModule[a] < 'a') || (sModule[a] > 'z')) && ((sModule[a] < 'A') || (sModule[a] > 'Z')) && (sModule[a] != '_')) { |
|
1132 |
sRetMsg = "Module names can only contain letters, numbers and underscores, [" + sModule + "] is invalid."; |
|
1133 |
return NULL; |
|
1134 |
}
|
|
1135 |
}
|
|
1136 |
||
1137 |
// The second argument to dlopen() has a long history. It seems clear
|
|
1138 |
// that (despite what the man page says) we must include either of
|
|
1139 |
// RTLD_NOW and RTLD_LAZY and either of RTLD_GLOBAL and RTLD_LOCAL.
|
|
1140 |
//
|
|
1141 |
// RTLD_NOW vs. RTLD_LAZY: We use RTLD_NOW to avoid ZNC dying due to
|
|
1142 |
// failed symbol lookups later on. Doesn't really seem to have much of a
|
|
1143 |
// performance impact.
|
|
1144 |
//
|
|
1145 |
// RTLD_GLOBAL vs. RTLD_LOCAL: If perl is loaded with RTLD_LOCAL and later on
|
|
1146 |
// loads own modules (which it apparently does with RTLD_LAZY), we will die in a
|
|
1147 |
// name lookup since one of perl's symbols isn't found. That's worse
|
|
1148 |
// than any theoretical issue with RTLD_GLOBAL.
|
|
1149 |
ModHandle p = dlopen((sModPath).c_str(), RTLD_NOW | RTLD_GLOBAL); |
|
1150 |
||
1151 |
if (!p) { |
|
1152 |
sRetMsg = "Unable to open module [" + sModule + "] [" + dlerror() + "]"; |
|
1153 |
return NULL; |
|
1154 |
}
|
|
1155 |
||
1156 |
typedef bool (*InfoFP)(double, CModInfo&); |
|
1157 |
InfoFP ZNCModInfo = (InfoFP) dlsym(p, "ZNCModInfo"); |
|
1158 |
||
1159 |
if (!ZNCModInfo) { |
|
1160 |
dlclose(p); |
|
1161 |
sRetMsg = "Could not find ZNCModInfo() in module [" + sModule + "]"; |
|
1162 |
return NULL; |
|
1163 |
}
|
|
1164 |
||
1165 |
if (ZNCModInfo(CModule::GetCoreVersion(), Info)) { |
|
1166 |
sRetMsg = ""; |
|
1167 |
bVersionMismatch = false; |
|
1168 |
} else { |
|
1169 |
bVersionMismatch = true; |
|
1170 |
sRetMsg = "Version mismatch, recompile this module."; |
|
1171 |
}
|
|
1172 |
||
1173 |
return p; |
|
1174 |
}
|
|
1175 |
||
1176 |
CModCommand::CModCommand() |
|
1177 |
: m_sCmd(), m_pFunc(NULL), m_sArgs(), m_sDesc() |
|
1178 |
{
|
|
1179 |
}
|
|
1180 |
||
1181 |
CModCommand::CModCommand(const CString& sCmd, ModCmdFunc func, const CString& sArgs, const CString& sDesc) |
|
1182 |
: m_sCmd(sCmd), m_pFunc(func), m_sArgs(sArgs), m_sDesc(sDesc) |
|
1183 |
{
|
|
1184 |
}
|
|
1185 |
||
1186 |
CModCommand::CModCommand(const CModCommand& other) |
|
1187 |
: m_sCmd(other.m_sCmd), m_pFunc(other.m_pFunc), m_sArgs(other.m_sArgs), m_sDesc(other.m_sDesc) |
|
1188 |
{
|
|
1189 |
}
|
|
1190 |
||
1191 |
CModCommand& CModCommand::operator=(const CModCommand& other) |
|
1192 |
{
|
|
1193 |
m_sCmd = other.m_sCmd; |
|
1194 |
m_pFunc = other.m_pFunc; |
|
1195 |
m_sArgs = other.m_sArgs; |
|
1196 |
m_sDesc = other.m_sDesc; |
|
1197 |
return *this; |
|
1198 |
}
|
|
1199 |
||
1200 |
void CModCommand::InitHelp(CTable& Table) { |
|
1201 |
Table.AddColumn("Command"); |
|
1202 |
Table.AddColumn("Arguments"); |
|
1203 |
Table.AddColumn("Description"); |
|
1204 |
}
|
|
1205 |
||
1206 |
void CModCommand::AddHelp(CTable& Table) const { |
|
1207 |
Table.AddRow(); |
|
1208 |
Table.SetCell("Command", GetCommand()); |
|
1209 |
Table.SetCell("Arguments", GetArgs()); |
|
1210 |
Table.SetCell("Description", GetDescription()); |
|
1211 |
}
|