]> jfr.im git - irc/rizon/znc.git/blame - Modules.cpp
Write forceserver and webircpassword to conf
[irc/rizon/znc.git] / Modules.cpp
CommitLineData
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 84CTimer::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
96CTimer::~CTimer() {
97 m_pModule->UnlinkTimer(this);
98}
99
100void CTimer::SetModule(CModule* p) { m_pModule = p; }
beb5b49b 101void CTimer::SetDescription(const CString& s) { m_sDescription = s; }
538d3ece 102CModule* CTimer::GetModule() const { return m_pModule; }
beb5b49b 103const CString& CTimer::GetDescription() const { return m_sDescription; }
538d3ece 104/////////////////// !Timer ///////////////////
105
c48f13a4 106
620c72a2 107CModule::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 122CModule::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 134CModule::~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 146void CModule::SetUser(CUser* pUser) { m_pUser = pUser; }
a490f62d 147void CModule::SetClient(CClient* pClient) { m_pClient = pClient; }
44d38ec4 148
8e59f751
US
149const CString& CModule::GetSavePath() const {
150 if (!CFile::Exists(m_sSavePath)) {
151 CDir::MakeDir(m_sSavePath);
152 }
153 return m_sSavePath;
154}
155
44d38ec4 156bool 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 161bool 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 166bool 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 175CString 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 185bool 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 201bool CModule::ClearNV(bool bWriteToDisk) {
202 m_mssRegistry.clear();
203
204 if (bWriteToDisk) {
205 return SaveRegistry();
206 }
207 return true;
208}
209
538d3ece 210bool 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 224bool 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 231bool 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 238bool CModule::RemTimer(const CString& sLabel) {
03f3e348 239 CTimer *pTimer = FindTimer(sLabel);
240 if (!pTimer)
241 return false;
242 return RemTimer(pTimer);
538d3ece 243}
244
245bool 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 257CTimer* 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
269void 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 296bool CModule::AddSocket(CSocket* pSocket) {
297 if (!pSocket) {
298 return false;
299 }
300
c88ec5f9 301 m_sSockets.insert(pSocket);
c48f13a4 302 return true;
303}
304
305bool 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 318bool 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
333bool 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 345CSocket* 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
357void 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
393bool 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
406bool 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
412void CModule::AddHelpCommand()
413{
39f97a88 414 AddCommand("Help", &CModule::HandleHelpCommand, "search", "Generate this output");
ebd7e53d
US
415}
416
417bool CModule::RemCommand(const CString& sCmd)
418{
419 return m_mCommands.erase(sCmd) > 0;
420}
421
422const 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
433bool 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
447void 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 462CString CModule::GetModNick() const { return ((m_pUser) ? m_pUser->GetStatusPrefix() : "*") + m_sModName; }
538d3ece 463
ad92c58c 464// Webmods
437eef7f 465bool CModule::OnWebPreRequest(CWebSock& WebSock, const CString& sPageName) { return false; }
ad92c58c 466bool CModule::OnWebRequest(CWebSock& WebSock, const CString& sPageName, CTemplate& Tmpl) { return false; }
dffabfed 467bool CModule::OnEmbeddedWebRequest(CWebSock& WebSock, const CString& sPageName, CTemplate& Tmpl) { return false; }
ad92c58c 468// !Webmods
469
ee350ab7 470bool CModule::OnLoad(const CString& sArgs, CString& sMessage) { sMessage = ""; return true; }
538d3ece 471bool CModule::OnBoot() { return true; }
dde7921e 472void CModule::OnPreRehash() {}
473void CModule::OnPostRehash() {}
538d3ece 474void CModule::OnIRCDisconnected() {}
475void CModule::OnIRCConnected() {}
d0a38e41 476CModule::EModRet CModule::OnIRCConnecting(CIRCSock *IRCSock) { return CONTINUE; }
7162b011 477void CModule::OnIRCConnectionError(CIRCSock *IRCSock) {}
c7156510 478CModule::EModRet CModule::OnIRCRegistration(CString& sPass, CString& sNick, CString& sIdent, CString& sRealName) { return CONTINUE; }
8e3c57a1 479CModule::EModRet CModule::OnBroadcast(CString& sMessage) { return CONTINUE; }
538d3ece 480
1437f279 481void CModule::OnChanPermission(const CNick& OpNick, const CNick& Nick, CChan& Channel, unsigned char uMode, bool bAdded, bool bNoChange) {}
482void CModule::OnOp(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) {}
483void CModule::OnDeop(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) {}
484void CModule::OnVoice(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) {}
485void CModule::OnDevoice(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) {}
486void CModule::OnRawMode(const CNick& OpNick, CChan& Channel, const CString& sModes, const CString& sArgs) {}
219ae6a5 487void CModule::OnMode(const CNick& OpNick, CChan& Channel, char uMode, const CString& sArg, bool bAdded, bool bNoChange) {}
538d3ece 488
44d38ec4 489CModule::EModRet CModule::OnRaw(CString& sLine) { return CONTINUE; }
538d3ece 490
94f6e2cf 491CModule::EModRet CModule::OnStatusCommand(CString& sCommand) { return CONTINUE; }
beb5b49b 492void CModule::OnModNotice(const CString& sMessage) {}
493void CModule::OnModCTCP(const CString& sMessage) {}
538d3ece 494
8e59fb95
US
495void CModule::OnModCommand(const CString& sCommand) {
496 HandleCommand(sCommand);
497}
498void 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 508void CModule::OnQuit(const CNick& Nick, const CString& sMessage, const vector<CChan*>& vChans) {}
509void CModule::OnNick(const CNick& Nick, const CString& sNewNick, const vector<CChan*>& vChans) {}
1437f279 510void CModule::OnKick(const CNick& Nick, const CString& sKickedNick, CChan& Channel, const CString& sMessage) {}
511void CModule::OnJoin(const CNick& Nick, CChan& Channel) {}
a0c0b735 512void CModule::OnPart(const CNick& Nick, CChan& Channel, const CString& sMessage) {}
538d3ece 513
dd6c9a07 514CModule::EModRet CModule::OnChanBufferStarting(CChan& Chan, CClient& Client) { return CONTINUE; }
515CModule::EModRet CModule::OnChanBufferEnding(CChan& Chan, CClient& Client) { return CONTINUE; }
516CModule::EModRet CModule::OnChanBufferPlayLine(CChan& Chan, CClient& Client, CString& sLine) { return CONTINUE; }
517CModule::EModRet CModule::OnPrivBufferPlayLine(CClient& Client, CString& sLine) { return CONTINUE; }
518
db21f885 519void CModule::OnClientLogin() {}
520void CModule::OnClientDisconnect() {}
fb9a062f 521CModule::EModRet CModule::OnUserRaw(CString& sLine) { return CONTINUE; }
6d27d1c0 522CModule::EModRet CModule::OnUserCTCPReply(CString& sTarget, CString& sMessage) { return CONTINUE; }
6d27d1c0 523CModule::EModRet CModule::OnUserCTCP(CString& sTarget, CString& sMessage) { return CONTINUE; }
f601db2c 524CModule::EModRet CModule::OnUserAction(CString& sTarget, CString& sMessage) { return CONTINUE; }
fb9a062f 525CModule::EModRet CModule::OnUserMsg(CString& sTarget, CString& sMessage) { return CONTINUE; }
526CModule::EModRet CModule::OnUserNotice(CString& sTarget, CString& sMessage) { return CONTINUE; }
527CModule::EModRet CModule::OnUserJoin(CString& sChannel, CString& sKey) { return CONTINUE; }
528CModule::EModRet CModule::OnUserPart(CString& sChannel, CString& sMessage) { return CONTINUE; }
442ef47c 529CModule::EModRet CModule::OnUserTopic(CString& sChannel, CString& sTopic) { return CONTINUE; }
0316c6a1 530CModule::EModRet CModule::OnUserTopicRequest(CString& sChannel) { return CONTINUE; }
fb9a062f 531
532CModule::EModRet CModule::OnCTCPReply(CNick& Nick, CString& sMessage) { return CONTINUE; }
49d71a9b 533CModule::EModRet CModule::OnPrivCTCP(CNick& Nick, CString& sMessage) { return CONTINUE; }
534CModule::EModRet CModule::OnChanCTCP(CNick& Nick, CChan& Channel, CString& sMessage) { return CONTINUE; }
f601db2c 535CModule::EModRet CModule::OnPrivAction(CNick& Nick, CString& sMessage) { return CONTINUE; }
536CModule::EModRet CModule::OnChanAction(CNick& Nick, CChan& Channel, CString& sMessage) { return CONTINUE; }
49d71a9b 537CModule::EModRet CModule::OnPrivMsg(CNick& Nick, CString& sMessage) { return CONTINUE; }
538CModule::EModRet CModule::OnChanMsg(CNick& Nick, CChan& Channel, CString& sMessage) { return CONTINUE; }
49d71a9b 539CModule::EModRet CModule::OnPrivNotice(CNick& Nick, CString& sMessage) { return CONTINUE; }
540CModule::EModRet CModule::OnChanNotice(CNick& Nick, CChan& Channel, CString& sMessage) { return CONTINUE; }
0a5d3013 541CModule::EModRet CModule::OnTopic(CNick& Nick, CChan& Channel, CString& sTopic) { return CONTINUE; }
9952e8d2 542CModule::EModRet CModule::OnTimerAutoJoin(CChan& Channel) { return CONTINUE; }
538d3ece 543
83db7684 544bool CModule::OnServerCapAvailable(const CString& sCap) { return false; }
a3bc3f68 545void CModule::OnServerCapResult(const CString& sCap, bool bSuccess) {}
83db7684 546
beb5b49b 547bool CModule::PutIRC(const CString& sLine) {
538d3ece 548 return (m_pUser) ? m_pUser->PutIRC(sLine) : false;
549}
beb5b49b 550bool CModule::PutUser(const CString& sLine) {
a490f62d 551 return (m_pUser) ? m_pUser->PutUser(sLine, m_pClient) : false;
538d3ece 552}
beb5b49b 553bool CModule::PutStatus(const CString& sLine) {
a490f62d 554 return (m_pUser) ? m_pUser->PutStatus(sLine, m_pClient) : false;
538d3ece 555}
6bc36d17 556unsigned 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 566bool 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 571bool 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 580CModule::EModRet CGlobalModule::OnAddUser(CUser& User, CString& sErrorRet) { return CONTINUE; }
57fb9fc8 581CModule::EModRet CGlobalModule::OnDeleteUser(CUser& User) { return CONTINUE; }
46b70f65 582void CGlobalModule::OnClientConnect(CZNCSock* pClient, const CString& sHost, unsigned short uPort) {}
97fd4d0c 583CModule::EModRet CGlobalModule::OnLoginAttempt(CSmartPtr<CAuthBase> Auth) { return CONTINUE; }
d91109d7 584void CGlobalModule::OnFailedLogin(const CString& sUsername, const CString& sRemoteIP) {}
47a5ab37 585CModule::EModRet CGlobalModule::OnUnknownUserRaw(CString& sLine) { return CONTINUE; }
9d99e4cc 586void CGlobalModule::OnClientCapLs(SCString& ssCaps) {}
587bool CGlobalModule::IsClientCapSupported(const CString& sCap, bool bState) { return false; }
47a5ab37 588void CGlobalModule::OnClientCapRequest(const CString& sCap, bool bState) {}
ffcd4223 589CModule::EModRet CGlobalModule::OnModuleLoading(const CString& sModName, const CString& sArgs,
590 bool& bSuccess, CString& sRetMsg) { return CONTINUE; }
591CModule::EModRet CGlobalModule::OnModuleUnloading(CModule* pModule, bool& bSuccess, CString& sRetMsg) {
592 return CONTINUE;
593}
594CModule::EModRet CGlobalModule::OnGetModInfo(CModInfo& ModInfo, const CString& sModule,
595 bool& bSuccess, CString& sRetMsg) { return CONTINUE; }
596void CGlobalModule::OnGetAvailableMods(set<CModInfo>& ssMods, bool bGlobal) {}
97fd4d0c 597
c041a6e1 598
89e5079c 599CModules::CModules() {
3dde793e 600 m_pUser = NULL;
5fa8d03d 601 m_pClient = NULL;
3dde793e 602}
603
3e35a073 604CModules::~CModules() {
605 UnloadAll();
606}
538d3ece 607
608void CModules::UnloadAll() {
609 while (size()) {
beb5b49b 610 CString sRetMsg;
b5043eb8 611 CString sModName = back()->GetModName();
538d3ece 612 UnloadModule(sModName, sRetMsg);
613 }
614}
615
538d3ece 616bool 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 632bool CModules::OnPreRehash() { MODUNLOADCHK(OnPreRehash()); return false; }
633bool CModules::OnPostRehash() { MODUNLOADCHK(OnPostRehash()); return false; }
b740d7cc 634bool CModules::OnIRCConnected() { MODUNLOADCHK(OnIRCConnected()); return false; }
d0a38e41 635bool CModules::OnIRCConnecting(CIRCSock *pIRCSock) { MODHALTCHK(OnIRCConnecting(pIRCSock)); }
7162b011 636bool CModules::OnIRCConnectionError(CIRCSock *pIRCSock) { MODUNLOADCHK(OnIRCConnectionError(pIRCSock)); return false; }
c7156510 637bool CModules::OnIRCRegistration(CString& sPass, CString& sNick, CString& sIdent, CString& sRealName) { MODHALTCHK(OnIRCRegistration(sPass, sNick, sIdent, sRealName)); }
fb9a062f 638bool CModules::OnBroadcast(CString& sMessage) { MODHALTCHK(OnBroadcast(sMessage)); }
b740d7cc 639bool CModules::OnIRCDisconnected() { MODUNLOADCHK(OnIRCDisconnected()); return false; }
b740d7cc 640bool 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; }
641bool CModules::OnOp(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) { MODUNLOADCHK(OnOp(OpNick, Nick, Channel, bNoChange)); return false; }
642bool CModules::OnDeop(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) { MODUNLOADCHK(OnDeop(OpNick, Nick, Channel, bNoChange)); return false; }
643bool CModules::OnVoice(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) { MODUNLOADCHK(OnVoice(OpNick, Nick, Channel, bNoChange)); return false; }
644bool CModules::OnDevoice(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) { MODUNLOADCHK(OnDevoice(OpNick, Nick, Channel, bNoChange)); return false; }
645bool CModules::OnRawMode(const CNick& OpNick, CChan& Channel, const CString& sModes, const CString& sArgs) { MODUNLOADCHK(OnRawMode(OpNick, Channel, sModes, sArgs)); return false; }
219ae6a5 646bool 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 647bool CModules::OnRaw(CString& sLine) { MODHALTCHK(OnRaw(sLine)); }
648
db21f885 649bool CModules::OnClientLogin() { MODUNLOADCHK(OnClientLogin()); return false; }
650bool CModules::OnClientDisconnect() { MODUNLOADCHK(OnClientDisconnect()); return false; }
fb9a062f 651bool CModules::OnUserRaw(CString& sLine) { MODHALTCHK(OnUserRaw(sLine)); }
652bool CModules::OnUserCTCPReply(CString& sTarget, CString& sMessage) { MODHALTCHK(OnUserCTCPReply(sTarget, sMessage)); }
653bool CModules::OnUserCTCP(CString& sTarget, CString& sMessage) { MODHALTCHK(OnUserCTCP(sTarget, sMessage)); }
f601db2c 654bool CModules::OnUserAction(CString& sTarget, CString& sMessage) { MODHALTCHK(OnUserAction(sTarget, sMessage)); }
fb9a062f 655bool CModules::OnUserMsg(CString& sTarget, CString& sMessage) { MODHALTCHK(OnUserMsg(sTarget, sMessage)); }
656bool CModules::OnUserNotice(CString& sTarget, CString& sMessage) { MODHALTCHK(OnUserNotice(sTarget, sMessage)); }
657bool CModules::OnUserJoin(CString& sChannel, CString& sKey) { MODHALTCHK(OnUserJoin(sChannel, sKey)); }
658bool CModules::OnUserPart(CString& sChannel, CString& sMessage) { MODHALTCHK(OnUserPart(sChannel, sMessage)); }
442ef47c 659bool CModules::OnUserTopic(CString& sChannel, CString& sTopic) { MODHALTCHK(OnUserTopic(sChannel, sTopic)); }
0316c6a1 660bool CModules::OnUserTopicRequest(CString& sChannel) { MODHALTCHK(OnUserTopicRequest(sChannel)); }
fb9a062f 661
b740d7cc 662bool CModules::OnQuit(const CNick& Nick, const CString& sMessage, const vector<CChan*>& vChans) { MODUNLOADCHK(OnQuit(Nick, sMessage, vChans)); return false; }
663bool CModules::OnNick(const CNick& Nick, const CString& sNewNick, const vector<CChan*>& vChans) { MODUNLOADCHK(OnNick(Nick, sNewNick, vChans)); return false; }
664bool CModules::OnKick(const CNick& Nick, const CString& sKickedNick, CChan& Channel, const CString& sMessage) { MODUNLOADCHK(OnKick(Nick, sKickedNick, Channel, sMessage)); return false; }
665bool CModules::OnJoin(const CNick& Nick, CChan& Channel) { MODUNLOADCHK(OnJoin(Nick, Channel)); return false; }
a0c0b735 666bool CModules::OnPart(const CNick& Nick, CChan& Channel, const CString& sMessage) { MODUNLOADCHK(OnPart(Nick, Channel, sMessage)); return false; }
dd6c9a07 667bool CModules::OnChanBufferStarting(CChan& Chan, CClient& Client) { MODHALTCHK(OnChanBufferStarting(Chan, Client)); }
668bool CModules::OnChanBufferEnding(CChan& Chan, CClient& Client) { MODHALTCHK(OnChanBufferEnding(Chan, Client)); }
669bool CModules::OnChanBufferPlayLine(CChan& Chan, CClient& Client, CString& sLine) { MODHALTCHK(OnChanBufferPlayLine(Chan, Client, sLine)); }
670bool CModules::OnPrivBufferPlayLine(CClient& Client, CString& sLine) { MODHALTCHK(OnPrivBufferPlayLine(Client, sLine)); }
fb9a062f 671bool CModules::OnCTCPReply(CNick& Nick, CString& sMessage) { MODHALTCHK(OnCTCPReply(Nick, sMessage)); }
672bool CModules::OnPrivCTCP(CNick& Nick, CString& sMessage) { MODHALTCHK(OnPrivCTCP(Nick, sMessage)); }
673bool CModules::OnChanCTCP(CNick& Nick, CChan& Channel, CString& sMessage) { MODHALTCHK(OnChanCTCP(Nick, Channel, sMessage)); }
f601db2c 674bool CModules::OnPrivAction(CNick& Nick, CString& sMessage) { MODHALTCHK(OnPrivAction(Nick, sMessage)); }
675bool CModules::OnChanAction(CNick& Nick, CChan& Channel, CString& sMessage) { MODHALTCHK(OnChanAction(Nick, Channel, sMessage)); }
fb9a062f 676bool CModules::OnPrivMsg(CNick& Nick, CString& sMessage) { MODHALTCHK(OnPrivMsg(Nick, sMessage)); }
677bool CModules::OnChanMsg(CNick& Nick, CChan& Channel, CString& sMessage) { MODHALTCHK(OnChanMsg(Nick, Channel, sMessage)); }
678bool CModules::OnPrivNotice(CNick& Nick, CString& sMessage) { MODHALTCHK(OnPrivNotice(Nick, sMessage)); }
679bool CModules::OnChanNotice(CNick& Nick, CChan& Channel, CString& sMessage) { MODHALTCHK(OnChanNotice(Nick, Channel, sMessage)); }
0a5d3013 680bool CModules::OnTopic(CNick& Nick, CChan& Channel, CString& sTopic) { MODHALTCHK(OnTopic(Nick, Channel, sTopic)); }
9952e8d2 681bool CModules::OnTimerAutoJoin(CChan& Channel) { MODHALTCHK(OnTimerAutoJoin(Channel)); }
94f6e2cf 682bool CModules::OnStatusCommand(CString& sCommand) { MODHALTCHK(OnStatusCommand(sCommand)); }
b740d7cc 683bool CModules::OnModCommand(const CString& sCommand) { MODUNLOADCHK(OnModCommand(sCommand)); return false; }
684bool CModules::OnModNotice(const CString& sMessage) { MODUNLOADCHK(OnModNotice(sMessage)); return false; }
685bool CModules::OnModCTCP(const CString& sMessage) { MODUNLOADCHK(OnModCTCP(sMessage)); return false; }
538d3ece 686
83db7684 687// Why MODHALTCHK works only with functions returning EModRet ? :(
688bool 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 714bool CModules::OnServerCapResult(const CString& sCap, bool bSuccess) { MODUNLOADCHK(OnServerCapResult(sCap, bSuccess)); return false; }
83db7684 715
c041a6e1 716////////////////////
717// CGlobalModules //
718////////////////////
28022ca7 719bool CGlobalModules::OnAddUser(CUser& User, CString& sErrorRet) {
720 GLOBALMODHALTCHK(OnAddUser(User, sErrorRet));
721}
722
57fb9fc8 723bool CGlobalModules::OnDeleteUser(CUser& User) {
724 GLOBALMODHALTCHK(OnDeleteUser(User));
725}
726
9ae959b8 727bool 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 732bool CGlobalModules::OnLoginAttempt(CSmartPtr<CAuthBase> Auth) {
733 GLOBALMODHALTCHK(OnLoginAttempt(Auth));
734}
735
9ae959b8 736bool CGlobalModules::OnFailedLogin(const CString& sUsername, const CString& sRemoteIP) {
d91109d7 737 GLOBALMODCALL(OnFailedLogin(sUsername, sRemoteIP));
9ae959b8 738 return false;
d91109d7 739}
740
47a5ab37 741bool CGlobalModules::OnUnknownUserRaw(CString& sLine) {
742 GLOBALMODHALTCHK(OnUnknownUserRaw(sLine));
d84b9c6e 743}
744
9ae959b8 745bool CGlobalModules::OnClientCapLs(SCString& ssCaps) {
9d99e4cc 746 GLOBALMODCALL(OnClientCapLs(ssCaps));
9ae959b8 747 return false;
9d99e4cc 748}
749
750// Maybe create new macro for this?
751bool 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 777bool CGlobalModules::OnClientCapRequest(const CString& sCap, bool bState) {
778 GLOBALMODCALL(OnClientCapRequest(sCap, bState));
9ae959b8 779 return false;
9d99e4cc 780}
781
ffcd4223 782bool CGlobalModules::OnModuleLoading(const CString& sModName, const CString& sArgs,
783 bool& bSuccess, CString& sRetMsg) {
784 GLOBALMODHALTCHK(OnModuleLoading(sModName, sArgs, bSuccess, sRetMsg));
785}
786
787bool CGlobalModules::OnModuleUnloading(CModule* pModule, bool& bSuccess, CString& sRetMsg) {
788 GLOBALMODHALTCHK(OnModuleUnloading(pModule, bSuccess, sRetMsg));
789}
790
791bool CGlobalModules::OnGetModInfo(CModInfo& ModInfo, const CString& sModule,
792 bool& bSuccess, CString& sRetMsg) {
793 GLOBALMODHALTCHK(OnGetModInfo(ModInfo, sModule, bSuccess, sRetMsg));
794}
795
796bool CGlobalModules::OnGetAvailableMods(set<CModInfo>& ssMods, bool bGlobal) {
797 GLOBALMODCALL(OnGetAvailableMods(ssMods, bGlobal));
798 return false;
799}
800
9d99e4cc 801
f6f438a5 802CModule* 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 812bool 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 889bool CModules::UnloadModule(const CString& sModule) {
890 CString s;
891 return UnloadModule(sModule, s);
892}
893
beb5b49b 894bool 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 929bool 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 944bool 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
958bool 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 978void 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 1009bool 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 1032CModules::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 1056ModHandle 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
1108CModCommand::CModCommand()
1109 : m_sCmd(), m_pFunc(NULL), m_sArgs(), m_sDesc()
1110{
1111}
1112
1113CModCommand::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
1118CModCommand::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
1123CModCommand& 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
1132void CModCommand::InitHelp(CTable& Table) {
1133 Table.AddColumn("Command");
1134 Table.AddColumn("Arguments");
1135 Table.AddColumn("Description");
1136}
1137
1138void CModCommand::AddHelp(CTable& Table) const {
1139 Table.AddRow();
1140 Table.SetCell("Command", GetCommand());
1141 Table.SetCell("Arguments", GetArgs());
1142 Table.SetCell("Description", GetDescription());
1143}