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