2
* Copyright (C) 2004-2012 See the AUTHORS file for details.
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.
9
#include <znc/Modules.h>
10
#include <znc/FileUtils.h>
11
#include <znc/Template.h>
13
#include <znc/IRCNetwork.h>
14
#include <znc/WebModules.h>
22
bool ZNC_NO_NEED_TO_DO_ANYTHING_ON_MODULE_CALL_EXITER;
26
# warning "your crap box doesnt define RTLD_LOCAL !?"
29
#define MODUNLOADCHK(func) \
30
for (unsigned int a = 0; a < size(); a++) { \
32
CModule* pMod = (CModule *) (*this)[a]; \
33
CClient* pOldClient = pMod->GetClient(); \
34
pMod->SetClient(m_pClient); \
35
CUser* pOldUser = NULL; \
37
pOldUser = pMod->GetUser(); \
38
pMod->SetUser(m_pUser); \
40
CIRCNetwork* pNetwork = NULL; \
42
pNetwork = pMod->GetNetwork(); \
43
pMod->SetNetwork(m_pNetwork); \
47
pMod->SetUser(pOldUser); \
49
pMod->SetNetwork(pNetwork); \
50
pMod->SetClient(pOldClient); \
51
} catch (CModule::EModException e) { \
52
if (e == CModule::UNLOAD) { \
53
UnloadModule((*this)[a]->GetModName()); \
59
#define MODHALTCHK(func) \
60
bool bHaltCore = false; \
61
for (unsigned int a = 0; a < size(); a++) { \
63
CModule* pMod = (CModule*) (*this)[a]; \
64
CModule::EModRet e = CModule::CONTINUE; \
65
CClient* pOldClient = pMod->GetClient(); \
66
pMod->SetClient(m_pClient); \
67
CUser* pOldUser = NULL; \
69
pOldUser = pMod->GetUser(); \
70
pMod->SetUser(m_pUser); \
72
CIRCNetwork* pNetwork = NULL; \
74
pNetwork = pMod->GetNetwork(); \
75
pMod->SetNetwork(m_pNetwork); \
79
pMod->SetUser(pOldUser); \
81
pMod->SetNetwork(pNetwork); \
82
pMod->SetClient(pOldClient); \
83
if (e == CModule::HALTMODS) { \
85
} else if (e == CModule::HALTCORE) { \
87
} else if (e == CModule::HALT) { \
91
} catch (CModule::EModException e) { \
92
if (e == CModule::UNLOAD) { \
93
UnloadModule((*this)[a]->GetModName()); \
99
/////////////////// Timer ///////////////////
100
CTimer::CTimer(CModule* pModule, unsigned int uInterval, unsigned int uCycles, const CString& sLabel, const CString& sDescription) : CCron() {
102
m_sDescription = sDescription;
106
StartMaxCycles(uInterval, uCycles);
113
m_pModule->UnlinkTimer(this);
116
void CTimer::SetModule(CModule* p) { m_pModule = p; }
117
void CTimer::SetDescription(const CString& s) { m_sDescription = s; }
118
CModule* CTimer::GetModule() const { return m_pModule; }
119
const CString& CTimer::GetDescription() const { return m_sDescription; }
120
/////////////////// !Timer ///////////////////
123
CModule::CModule(ModHandle pDLL, CUser* pUser, CIRCNetwork* pNetwork, const CString& sModName, const CString& sDataDir) {
125
m_pManager = &(CZNC::Get().GetManager());;
127
m_pNetwork = pNetwork;
129
m_sModName = sModName;
130
m_sDataDir = sDataDir;
133
m_sSavePath = m_pNetwork->GetNetworkPath() + "/moddata/" + m_sModName;
134
} else if (m_pUser) {
135
m_sSavePath = m_pUser->GetUserPath() + "/moddata/" + m_sModName;
137
m_sSavePath = CZNC::Get().GetZNCPath() + "/moddata/" + m_sModName;
142
CModule::~CModule() {
143
while (!m_sTimers.empty()) {
144
RemTimer(*m_sTimers.begin());
147
while (!m_sSockets.empty()) {
148
RemSocket(*m_sSockets.begin());
154
void CModule::SetUser(CUser* pUser) { m_pUser = pUser; }
155
void CModule::SetNetwork(CIRCNetwork* pNetwork) { m_pNetwork = pNetwork; }
156
void CModule::SetClient(CClient* pClient) { m_pClient = pClient; }
158
const CString& CModule::GetSavePath() const {
159
if (!CFile::Exists(m_sSavePath)) {
160
CDir::MakeDir(m_sSavePath);
165
CString CModule::GetWebPath() {
167
case CModInfo::GlobalModule: return "/mods/global/" + GetModName() + "/";
168
case CModInfo::UserModule: return "/mods/user/" + GetModName() + "/";
169
case CModInfo::NetworkModule: return "/mods/network/" + m_pNetwork->GetName() + "/" + GetModName() + "/";
174
CString CModule::GetWebFilesPath() {
176
case CModInfo::GlobalModule: return "/modfiles/global/" + GetModName() + "/";
177
case CModInfo::UserModule: return "/modfiles/user/" + GetModName() + "/";
178
case CModInfo::NetworkModule: return "/modfiles/network/" + m_pNetwork->GetName() + "/" + GetModName() + "/";
183
bool CModule::LoadRegistry() {
184
//CString sPrefix = (m_pUser) ? m_pUser->GetUserName() : ".global";
185
return (m_mssRegistry.ReadFromDisk(GetSavePath() + "/.registry") == MCString::MCS_SUCCESS);
188
bool CModule::SaveRegistry() const {
189
//CString sPrefix = (m_pUser) ? m_pUser->GetUserName() : ".global";
190
return (m_mssRegistry.WriteToDisk(GetSavePath() + "/.registry", 0600) == MCString::MCS_SUCCESS);
193
bool CModule::SetNV(const CString & sName, const CString & sValue, bool bWriteToDisk) {
194
m_mssRegistry[sName] = sValue;
196
return SaveRegistry();
202
CString CModule::GetNV(const CString & sName) const {
203
MCString::const_iterator it = m_mssRegistry.find(sName);
205
if (it != m_mssRegistry.end()) {
212
bool CModule::DelNV(const CString & sName, bool bWriteToDisk) {
213
MCString::iterator it = m_mssRegistry.find(sName);
215
if (it != m_mssRegistry.end()) {
216
m_mssRegistry.erase(it);
222
return SaveRegistry();
228
bool CModule::ClearNV(bool bWriteToDisk) {
229
m_mssRegistry.clear();
232
return SaveRegistry();
237
bool CModule::AddTimer(CTimer* pTimer) {
238
if ((!pTimer) || (!pTimer->GetName().empty() && FindTimer(pTimer->GetName()))) {
243
if (!m_sTimers.insert(pTimer).second)
247
m_pManager->AddCron(pTimer);
251
bool CModule::AddTimer(FPTimer_t pFBCallback, const CString& sLabel, u_int uInterval, u_int uCycles, const CString& sDescription) {
252
CFPTimer *pTimer = new CFPTimer(this, uInterval, uCycles, sLabel, sDescription);
253
pTimer->SetFPCallback(pFBCallback);
255
return AddTimer(pTimer);
258
bool CModule::RemTimer(CTimer* pTimer) {
259
if (m_sTimers.erase(pTimer) == 0)
261
m_pManager->DelCronByAddr(pTimer);
265
bool CModule::RemTimer(const CString& sLabel) {
266
CTimer *pTimer = FindTimer(sLabel);
269
return RemTimer(pTimer);
272
bool CModule::UnlinkTimer(CTimer* pTimer) {
273
set<CTimer*>::iterator it;
274
for (it = m_sTimers.begin(); it != m_sTimers.end(); ++it) {
284
CTimer* CModule::FindTimer(const CString& sLabel) {
285
if (sLabel.empty()) {
289
set<CTimer*>::iterator it;
290
for (it = m_sTimers.begin(); it != m_sTimers.end(); ++it) {
291
CTimer* pTimer = *it;
292
if (pTimer->GetName().Equals(sLabel)) {
300
void CModule::ListTimers() {
301
if (m_sTimers.empty()) {
302
PutModule("You have no timers running.");
307
Table.AddColumn("Name");
308
Table.AddColumn("Secs");
309
Table.AddColumn("Cycles");
310
Table.AddColumn("Description");
312
set<CTimer*>::iterator it;
313
for (it = m_sTimers.begin(); it != m_sTimers.end(); ++it) {
314
CTimer* pTimer = *it;
315
unsigned int uCycles = pTimer->GetCyclesLeft();
316
timeval Interval = pTimer->GetInterval();
319
Table.SetCell("Name", pTimer->GetName());
320
Table.SetCell("Secs", CString(Interval.tv_sec) + "seconds" + (Interval.tv_usec ? " " + CString(Interval.tv_usec) + " microseconds" : ""));
321
Table.SetCell("Cycles", ((uCycles) ? CString(uCycles) : "INF"));
322
Table.SetCell("Description", pTimer->GetDescription());
328
bool CModule::AddSocket(CSocket* pSocket) {
333
m_sSockets.insert(pSocket);
337
bool CModule::RemSocket(CSocket* pSocket) {
338
set<CSocket*>::iterator it;
339
for (it = m_sSockets.begin(); it != m_sSockets.end(); ++it) {
340
if (*it == pSocket) {
341
m_sSockets.erase(it);
342
m_pManager->DelSockByAddr(pSocket);
350
bool CModule::RemSocket(const CString& sSockName) {
351
set<CSocket*>::iterator it;
352
for (it = m_sSockets.begin(); it != m_sSockets.end(); ++it) {
353
CSocket* pSocket = *it;
355
if (pSocket->GetSockName().Equals(sSockName)) {
356
m_sSockets.erase(it);
357
m_pManager->DelSockByAddr(pSocket);
365
bool CModule::UnlinkSocket(CSocket* pSocket) {
366
set<CSocket*>::iterator it;
367
for (it = m_sSockets.begin(); it != m_sSockets.end(); ++it) {
368
if (pSocket == *it) {
369
m_sSockets.erase(it);
377
CSocket* CModule::FindSocket(const CString& sSockName) {
378
set<CSocket*>::iterator it;
379
for (it = m_sSockets.begin(); it != m_sSockets.end(); ++it) {
380
CSocket* pSocket = *it;
381
if (pSocket->GetSockName().Equals(sSockName)) {
389
void CModule::ListSockets() {
390
if (m_sSockets.empty()) {
391
PutModule("You have no open sockets.");
396
Table.AddColumn("Name");
397
Table.AddColumn("State");
398
Table.AddColumn("LocalPort");
399
Table.AddColumn("SSL");
400
Table.AddColumn("RemoteIP");
401
Table.AddColumn("RemotePort");
403
set<CSocket*>::iterator it;
404
for (it = m_sSockets.begin(); it != m_sSockets.end(); ++it) {
405
CSocket* pSocket = *it;
408
Table.SetCell("Name", pSocket->GetSockName());
410
if (pSocket->GetType() == CSocket::LISTENER) {
411
Table.SetCell("State", "Listening");
413
Table.SetCell("State", (pSocket->IsConnected() ? "Connected" : ""));
416
Table.SetCell("LocalPort", CString(pSocket->GetLocalPort()));
417
Table.SetCell("SSL", (pSocket->GetSSL() ? "yes" : "no"));
418
Table.SetCell("RemoteIP", pSocket->GetRemoteIP());
419
Table.SetCell("RemotePort", (pSocket->GetRemotePort()) ? CString(pSocket->GetRemotePort()) : CString(""));
425
bool CModule::AddCommand(const CModCommand& Command)
427
if (Command.GetFunction() == NULL)
429
if (Command.GetCommand().find(' ') != CString::npos)
431
if (FindCommand(Command.GetCommand()) != NULL)
434
m_mCommands[Command.GetCommand()] = Command;
438
bool CModule::AddCommand(const CString& sCmd, CModCommand::ModCmdFunc func, const CString& sArgs, const CString& sDesc)
440
CModCommand cmd(sCmd, func, sArgs, sDesc);
441
return AddCommand(cmd);
444
void CModule::AddHelpCommand()
446
AddCommand("Help", &CModule::HandleHelpCommand, "search", "Generate this output");
449
bool CModule::RemCommand(const CString& sCmd)
451
return m_mCommands.erase(sCmd) > 0;
454
const CModCommand* CModule::FindCommand(const CString& sCmd) const
456
map<CString, CModCommand>::const_iterator it;
457
for (it = m_mCommands.begin(); it != m_mCommands.end(); ++it) {
458
if (!it->first.Equals(sCmd))
465
bool CModule::HandleCommand(const CString& sLine) {
466
const CString& sCmd = sLine.Token(0);
467
const CModCommand* pCmd = FindCommand(sCmd);
470
pCmd->Call(this, sLine);
474
OnUnknownModCommand(sLine);
479
void CModule::HandleHelpCommand(const CString& sLine) {
480
CString sFilter = sLine.Token(1, true);
481
CString::size_type iFilterLength = sFilter.size();
483
map<CString, CModCommand>::const_iterator it;
485
CModCommand::InitHelp(Table);
486
for (it = m_mCommands.begin(); it != m_mCommands.end(); ++it) {
487
if (sFilter.empty() || (it->second.GetCommand().Equals(sFilter, false, iFilterLength))) {
488
it->second.AddHelp(Table);
494
CString CModule::GetModNick() const { return ((m_pUser) ? m_pUser->GetStatusPrefix() : "*") + m_sModName; }
497
bool CModule::OnWebPreRequest(CWebSock& WebSock, const CString& sPageName) { return false; }
498
bool CModule::OnWebRequest(CWebSock& WebSock, const CString& sPageName, CTemplate& Tmpl) { return false; }
499
bool CModule::OnEmbeddedWebRequest(CWebSock& WebSock, const CString& sPageName, CTemplate& Tmpl) { return false; }
502
bool CModule::OnLoad(const CString& sArgs, CString& sMessage) { sMessage = ""; return true; }
503
bool CModule::OnBoot() { return true; }
504
void CModule::OnPreRehash() {}
505
void CModule::OnPostRehash() {}
506
void CModule::OnIRCDisconnected() {}
507
void CModule::OnIRCConnected() {}
508
CModule::EModRet CModule::OnIRCConnecting(CIRCSock *IRCSock) { return CONTINUE; }
509
void CModule::OnIRCConnectionError(CIRCSock *IRCSock) {}
510
CModule::EModRet CModule::OnIRCRegistration(CString& sPass, CString& sNick, CString& sIdent, CString& sRealName) { return CONTINUE; }
511
CModule::EModRet CModule::OnBroadcast(CString& sMessage) { return CONTINUE; }
513
void CModule::OnChanPermission(const CNick& OpNick, const CNick& Nick, CChan& Channel, unsigned char uMode, bool bAdded, bool bNoChange) {}
514
void CModule::OnOp(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) {}
515
void CModule::OnDeop(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) {}
516
void CModule::OnVoice(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) {}
517
void CModule::OnDevoice(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) {}
518
void CModule::OnRawMode(const CNick& OpNick, CChan& Channel, const CString& sModes, const CString& sArgs) {}
519
void CModule::OnMode(const CNick& OpNick, CChan& Channel, char uMode, const CString& sArg, bool bAdded, bool bNoChange) {}
521
CModule::EModRet CModule::OnRaw(CString& sLine) { return CONTINUE; }
523
CModule::EModRet CModule::OnStatusCommand(CString& sCommand) { return CONTINUE; }
524
void CModule::OnModNotice(const CString& sMessage) {}
525
void CModule::OnModCTCP(const CString& sMessage) {}
527
void CModule::OnModCommand(const CString& sCommand) {
528
HandleCommand(sCommand);
530
void CModule::OnUnknownModCommand(const CString& sLine) {
531
if (m_mCommands.empty())
532
// This function is only called if OnModCommand wasn't
533
// overriden, so no false warnings for modules which don't use
534
// CModCommand for command handling.
535
PutModule("This module doesn't implement any commands.");
537
PutModule("Unknown command!");
540
void CModule::OnQuit(const CNick& Nick, const CString& sMessage, const vector<CChan*>& vChans) {}
541
void CModule::OnNick(const CNick& Nick, const CString& sNewNick, const vector<CChan*>& vChans) {}
542
void CModule::OnKick(const CNick& Nick, const CString& sKickedNick, CChan& Channel, const CString& sMessage) {}
543
void CModule::OnJoin(const CNick& Nick, CChan& Channel) {}
544
void CModule::OnPart(const CNick& Nick, CChan& Channel, const CString& sMessage) {}
545
CModule::EModRet CModule::OnInvite(const CNick& Nick, const CString& sChan) { return CONTINUE; }
547
CModule::EModRet CModule::OnChanBufferStarting(CChan& Chan, CClient& Client) { return CONTINUE; }
548
CModule::EModRet CModule::OnChanBufferEnding(CChan& Chan, CClient& Client) { return CONTINUE; }
549
CModule::EModRet CModule::OnChanBufferPlayLine(CChan& Chan, CClient& Client, CString& sLine) { return CONTINUE; }
550
CModule::EModRet CModule::OnPrivBufferPlayLine(CClient& Client, CString& sLine) { return CONTINUE; }
552
void CModule::OnClientLogin() {}
553
void CModule::OnClientDisconnect() {}
554
CModule::EModRet CModule::OnUserRaw(CString& sLine) { return CONTINUE; }
555
CModule::EModRet CModule::OnUserCTCPReply(CString& sTarget, CString& sMessage) { return CONTINUE; }
556
CModule::EModRet CModule::OnUserCTCP(CString& sTarget, CString& sMessage) { return CONTINUE; }
557
CModule::EModRet CModule::OnUserAction(CString& sTarget, CString& sMessage) { return CONTINUE; }
558
CModule::EModRet CModule::OnUserMsg(CString& sTarget, CString& sMessage) { return CONTINUE; }
559
CModule::EModRet CModule::OnUserNotice(CString& sTarget, CString& sMessage) { return CONTINUE; }
560
CModule::EModRet CModule::OnUserJoin(CString& sChannel, CString& sKey) { return CONTINUE; }
561
CModule::EModRet CModule::OnUserPart(CString& sChannel, CString& sMessage) { return CONTINUE; }
562
CModule::EModRet CModule::OnUserTopic(CString& sChannel, CString& sTopic) { return CONTINUE; }
563
CModule::EModRet CModule::OnUserTopicRequest(CString& sChannel) { return CONTINUE; }
565
CModule::EModRet CModule::OnCTCPReply(CNick& Nick, CString& sMessage) { return CONTINUE; }
566
CModule::EModRet CModule::OnPrivCTCP(CNick& Nick, CString& sMessage) { return CONTINUE; }
567
CModule::EModRet CModule::OnChanCTCP(CNick& Nick, CChan& Channel, CString& sMessage) { return CONTINUE; }
568
CModule::EModRet CModule::OnPrivAction(CNick& Nick, CString& sMessage) { return CONTINUE; }
569
CModule::EModRet CModule::OnChanAction(CNick& Nick, CChan& Channel, CString& sMessage) { return CONTINUE; }
570
CModule::EModRet CModule::OnPrivMsg(CNick& Nick, CString& sMessage) { return CONTINUE; }
571
CModule::EModRet CModule::OnChanMsg(CNick& Nick, CChan& Channel, CString& sMessage) { return CONTINUE; }
572
CModule::EModRet CModule::OnPrivNotice(CNick& Nick, CString& sMessage) { return CONTINUE; }
573
CModule::EModRet CModule::OnChanNotice(CNick& Nick, CChan& Channel, CString& sMessage) { return CONTINUE; }
574
CModule::EModRet CModule::OnTopic(CNick& Nick, CChan& Channel, CString& sTopic) { return CONTINUE; }
575
CModule::EModRet CModule::OnTimerAutoJoin(CChan& Channel) { return CONTINUE; }
577
bool CModule::OnServerCapAvailable(const CString& sCap) { return false; }
578
void CModule::OnServerCapResult(const CString& sCap, bool bSuccess) {}
580
bool CModule::PutIRC(const CString& sLine) {
581
return (m_pNetwork) ? m_pNetwork->PutIRC(sLine) : false;
583
bool CModule::PutUser(const CString& sLine) {
584
return (m_pNetwork) ? m_pNetwork->PutUser(sLine, m_pClient) : false;
586
bool CModule::PutStatus(const CString& sLine) {
587
return (m_pNetwork) ? m_pNetwork->PutStatus(sLine, m_pClient) : false;
589
unsigned int CModule::PutModule(const CTable& table) {
593
unsigned int idx = 0;
595
while (table.GetLine(idx++, sLine))
599
bool CModule::PutModule(const CString& sLine) {
601
m_pClient->PutModule(GetModName(), sLine);
606
return m_pNetwork->PutModule(GetModName(), sLine);
610
return m_pUser->PutModule(GetModName(), sLine);
615
bool CModule::PutModNotice(const CString& sLine) {
620
m_pClient->PutModNotice(GetModName(), sLine);
624
return m_pUser->PutModNotice(GetModName(), sLine);
630
CModule::EModRet CModule::OnAddUser(CUser& User, CString& sErrorRet) { return CONTINUE; }
631
CModule::EModRet CModule::OnDeleteUser(CUser& User) { return CONTINUE; }
632
void CModule::OnClientConnect(CZNCSock* pClient, const CString& sHost, unsigned short uPort) {}
633
CModule::EModRet CModule::OnLoginAttempt(CSmartPtr<CAuthBase> Auth) { return CONTINUE; }
634
void CModule::OnFailedLogin(const CString& sUsername, const CString& sRemoteIP) {}
635
CModule::EModRet CModule::OnUnknownUserRaw(CClient* pClient, CString& sLine) { return CONTINUE; }
636
void CModule::OnClientCapLs(CClient* pClient, SCString& ssCaps) {}
637
bool CModule::IsClientCapSupported(CClient* pClient, const CString& sCap, bool bState) { return false; }
638
void CModule::OnClientCapRequest(CClient* pClient, const CString& sCap, bool bState) {}
639
CModule::EModRet CModule::OnModuleLoading(const CString& sModName, const CString& sArgs,
640
CModInfo::EModuleType eType, bool& bSuccess, CString& sRetMsg) { return CONTINUE; }
641
CModule::EModRet CModule::OnModuleUnloading(CModule* pModule, bool& bSuccess, CString& sRetMsg) {
644
CModule::EModRet CModule::OnGetModInfo(CModInfo& ModInfo, const CString& sModule,
645
bool& bSuccess, CString& sRetMsg) { return CONTINUE; }
646
void CModule::OnGetAvailableMods(set<CModInfo>& ssMods, CModInfo::EModuleType eType) {}
649
CModules::CModules() {
655
CModules::~CModules() {
659
void CModules::UnloadAll() {
662
CString sModName = back()->GetModName();
663
UnloadModule(sModName, sRetMsg);
667
bool CModules::OnBoot() {
668
for (unsigned int a = 0; a < size(); a++) {
670
if (!(*this)[a]->OnBoot()) {
673
} catch (CModule::EModException e) {
674
if (e == CModule::UNLOAD) {
675
UnloadModule((*this)[a]->GetModName());
683
bool CModules::OnPreRehash() { MODUNLOADCHK(OnPreRehash()); return false; }
684
bool CModules::OnPostRehash() { MODUNLOADCHK(OnPostRehash()); return false; }
685
bool CModules::OnIRCConnected() { MODUNLOADCHK(OnIRCConnected()); return false; }
686
bool CModules::OnIRCConnecting(CIRCSock *pIRCSock) { MODHALTCHK(OnIRCConnecting(pIRCSock)); }
687
bool CModules::OnIRCConnectionError(CIRCSock *pIRCSock) { MODUNLOADCHK(OnIRCConnectionError(pIRCSock)); return false; }
688
bool CModules::OnIRCRegistration(CString& sPass, CString& sNick, CString& sIdent, CString& sRealName) { MODHALTCHK(OnIRCRegistration(sPass, sNick, sIdent, sRealName)); }
689
bool CModules::OnBroadcast(CString& sMessage) { MODHALTCHK(OnBroadcast(sMessage)); }
690
bool CModules::OnIRCDisconnected() { MODUNLOADCHK(OnIRCDisconnected()); return false; }
691
bool CModules::OnChanPermission(const CNick& OpNick, const CNick& Nick, CChan& Channel, unsigned char uMode, bool bAdded, bool bNoChange) { MODUNLOADCHK(OnChanPermission(OpNick, Nick, Channel, uMode, bAdded, bNoChange)); return false; }
692
bool CModules::OnOp(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) { MODUNLOADCHK(OnOp(OpNick, Nick, Channel, bNoChange)); return false; }
693
bool CModules::OnDeop(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) { MODUNLOADCHK(OnDeop(OpNick, Nick, Channel, bNoChange)); return false; }
694
bool CModules::OnVoice(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) { MODUNLOADCHK(OnVoice(OpNick, Nick, Channel, bNoChange)); return false; }
695
bool CModules::OnDevoice(const CNick& OpNick, const CNick& Nick, CChan& Channel, bool bNoChange) { MODUNLOADCHK(OnDevoice(OpNick, Nick, Channel, bNoChange)); return false; }
696
bool CModules::OnRawMode(const CNick& OpNick, CChan& Channel, const CString& sModes, const CString& sArgs) { MODUNLOADCHK(OnRawMode(OpNick, Channel, sModes, sArgs)); return false; }
697
bool CModules::OnMode(const CNick& OpNick, CChan& Channel, char uMode, const CString& sArg, bool bAdded, bool bNoChange) { MODUNLOADCHK(OnMode(OpNick, Channel, uMode, sArg, bAdded, bNoChange)); return false; }
698
bool CModules::OnRaw(CString& sLine) { MODHALTCHK(OnRaw(sLine)); }
700
bool CModules::OnClientLogin() { MODUNLOADCHK(OnClientLogin()); return false; }
701
bool CModules::OnClientDisconnect() { MODUNLOADCHK(OnClientDisconnect()); return false; }
702
bool CModules::OnUserRaw(CString& sLine) { MODHALTCHK(OnUserRaw(sLine)); }
703
bool CModules::OnUserCTCPReply(CString& sTarget, CString& sMessage) { MODHALTCHK(OnUserCTCPReply(sTarget, sMessage)); }
704
bool CModules::OnUserCTCP(CString& sTarget, CString& sMessage) { MODHALTCHK(OnUserCTCP(sTarget, sMessage)); }
705
bool CModules::OnUserAction(CString& sTarget, CString& sMessage) { MODHALTCHK(OnUserAction(sTarget, sMessage)); }
706
bool CModules::OnUserMsg(CString& sTarget, CString& sMessage) { MODHALTCHK(OnUserMsg(sTarget, sMessage)); }
707
bool CModules::OnUserNotice(CString& sTarget, CString& sMessage) { MODHALTCHK(OnUserNotice(sTarget, sMessage)); }
708
bool CModules::OnUserJoin(CString& sChannel, CString& sKey) { MODHALTCHK(OnUserJoin(sChannel, sKey)); }
709
bool CModules::OnUserPart(CString& sChannel, CString& sMessage) { MODHALTCHK(OnUserPart(sChannel, sMessage)); }
710
bool CModules::OnUserTopic(CString& sChannel, CString& sTopic) { MODHALTCHK(OnUserTopic(sChannel, sTopic)); }
711
bool CModules::OnUserTopicRequest(CString& sChannel) { MODHALTCHK(OnUserTopicRequest(sChannel)); }
713
bool CModules::OnQuit(const CNick& Nick, const CString& sMessage, const vector<CChan*>& vChans) { MODUNLOADCHK(OnQuit(Nick, sMessage, vChans)); return false; }
714
bool CModules::OnNick(const CNick& Nick, const CString& sNewNick, const vector<CChan*>& vChans) { MODUNLOADCHK(OnNick(Nick, sNewNick, vChans)); return false; }
715
bool CModules::OnKick(const CNick& Nick, const CString& sKickedNick, CChan& Channel, const CString& sMessage) { MODUNLOADCHK(OnKick(Nick, sKickedNick, Channel, sMessage)); return false; }
716
bool CModules::OnJoin(const CNick& Nick, CChan& Channel) { MODUNLOADCHK(OnJoin(Nick, Channel)); return false; }
717
bool CModules::OnPart(const CNick& Nick, CChan& Channel, const CString& sMessage) { MODUNLOADCHK(OnPart(Nick, Channel, sMessage)); return false; }
718
bool CModules::OnInvite(const CNick& Nick, const CString& sChan) { MODHALTCHK(OnInvite(Nick, sChan)); }
719
bool CModules::OnChanBufferStarting(CChan& Chan, CClient& Client) { MODHALTCHK(OnChanBufferStarting(Chan, Client)); }
720
bool CModules::OnChanBufferEnding(CChan& Chan, CClient& Client) { MODHALTCHK(OnChanBufferEnding(Chan, Client)); }
721
bool CModules::OnChanBufferPlayLine(CChan& Chan, CClient& Client, CString& sLine) { MODHALTCHK(OnChanBufferPlayLine(Chan, Client, sLine)); }
722
bool CModules::OnPrivBufferPlayLine(CClient& Client, CString& sLine) { MODHALTCHK(OnPrivBufferPlayLine(Client, sLine)); }
723
bool CModules::OnCTCPReply(CNick& Nick, CString& sMessage) { MODHALTCHK(OnCTCPReply(Nick, sMessage)); }
724
bool CModules::OnPrivCTCP(CNick& Nick, CString& sMessage) { MODHALTCHK(OnPrivCTCP(Nick, sMessage)); }
725
bool CModules::OnChanCTCP(CNick& Nick, CChan& Channel, CString& sMessage) { MODHALTCHK(OnChanCTCP(Nick, Channel, sMessage)); }
726
bool CModules::OnPrivAction(CNick& Nick, CString& sMessage) { MODHALTCHK(OnPrivAction(Nick, sMessage)); }
727
bool CModules::OnChanAction(CNick& Nick, CChan& Channel, CString& sMessage) { MODHALTCHK(OnChanAction(Nick, Channel, sMessage)); }
728
bool CModules::OnPrivMsg(CNick& Nick, CString& sMessage) { MODHALTCHK(OnPrivMsg(Nick, sMessage)); }
729
bool CModules::OnChanMsg(CNick& Nick, CChan& Channel, CString& sMessage) { MODHALTCHK(OnChanMsg(Nick, Channel, sMessage)); }
730
bool CModules::OnPrivNotice(CNick& Nick, CString& sMessage) { MODHALTCHK(OnPrivNotice(Nick, sMessage)); }
731
bool CModules::OnChanNotice(CNick& Nick, CChan& Channel, CString& sMessage) { MODHALTCHK(OnChanNotice(Nick, Channel, sMessage)); }
732
bool CModules::OnTopic(CNick& Nick, CChan& Channel, CString& sTopic) { MODHALTCHK(OnTopic(Nick, Channel, sTopic)); }
733
bool CModules::OnTimerAutoJoin(CChan& Channel) { MODHALTCHK(OnTimerAutoJoin(Channel)); }
734
bool CModules::OnStatusCommand(CString& sCommand) { MODHALTCHK(OnStatusCommand(sCommand)); }
735
bool CModules::OnModCommand(const CString& sCommand) { MODUNLOADCHK(OnModCommand(sCommand)); return false; }
736
bool CModules::OnModNotice(const CString& sMessage) { MODUNLOADCHK(OnModNotice(sMessage)); return false; }
737
bool CModules::OnModCTCP(const CString& sMessage) { MODUNLOADCHK(OnModCTCP(sMessage)); return false; }
739
// Why MODHALTCHK works only with functions returning EModRet ? :(
740
bool CModules::OnServerCapAvailable(const CString& sCap) {
741
bool bResult = false;
742
for (unsigned int a = 0; a < size(); ++a) {
744
CModule* pMod = (*this)[a];
745
CClient* pOldClient = pMod->GetClient();
746
pMod->SetClient(m_pClient);
748
CUser* pOldUser = pMod->GetUser();
749
pMod->SetUser(m_pUser);
750
bResult |= pMod->OnServerCapAvailable(sCap);
751
pMod->SetUser(pOldUser);
753
// WTF? Is that possible?
754
bResult |= pMod->OnServerCapAvailable(sCap);
756
pMod->SetClient(pOldClient);
757
} catch (CModule::EModException e) {
758
if (CModule::UNLOAD == e) {
759
UnloadModule((*this)[a]->GetModName());
766
bool CModules::OnServerCapResult(const CString& sCap, bool bSuccess) { MODUNLOADCHK(OnServerCapResult(sCap, bSuccess)); return false; }
771
bool CModules::OnAddUser(CUser& User, CString& sErrorRet) {
772
MODHALTCHK(OnAddUser(User, sErrorRet));
775
bool CModules::OnDeleteUser(CUser& User) {
776
MODHALTCHK(OnDeleteUser(User));
779
bool CModules::OnClientConnect(CZNCSock* pClient, const CString& sHost, unsigned short uPort) {
780
MODUNLOADCHK(OnClientConnect(pClient, sHost, uPort));
784
bool CModules::OnLoginAttempt(CSmartPtr<CAuthBase> Auth) {
785
MODHALTCHK(OnLoginAttempt(Auth));
788
bool CModules::OnFailedLogin(const CString& sUsername, const CString& sRemoteIP) {
789
MODUNLOADCHK(OnFailedLogin(sUsername, sRemoteIP));
793
bool CModules::OnUnknownUserRaw(CClient* pClient, CString& sLine) {
794
MODHALTCHK(OnUnknownUserRaw(pClient, sLine));
797
bool CModules::OnClientCapLs(CClient* pClient, SCString& ssCaps) {
798
MODUNLOADCHK(OnClientCapLs(pClient, ssCaps));
802
// Maybe create new macro for this?
803
bool CModules::IsClientCapSupported(CClient* pClient, const CString& sCap, bool bState) {
804
bool bResult = false;
805
for (unsigned int a = 0; a < size(); ++a) {
807
CModule* pMod = (CModule*) (*this)[a];
808
CClient* pOldClient = pMod->GetClient();
809
pMod->SetClient(m_pClient);
811
CUser* pOldUser = pMod->GetUser();
812
pMod->SetUser(m_pUser);
813
bResult |= pMod->IsClientCapSupported(pClient, sCap, bState);
814
pMod->SetUser(pOldUser);
816
// WTF? Is that possible?
817
bResult |= pMod->IsClientCapSupported(pClient, sCap, bState);
819
pMod->SetClient(pOldClient);
820
} catch (CModule::EModException e) {
821
if (CModule::UNLOAD == e) {
822
UnloadModule((*this)[a]->GetModName());
829
bool CModules::OnClientCapRequest(CClient* pClient, const CString& sCap, bool bState) {
830
MODUNLOADCHK(OnClientCapRequest(pClient, sCap, bState));
834
bool CModules::OnModuleLoading(const CString& sModName, const CString& sArgs,
835
CModInfo::EModuleType eType, bool& bSuccess, CString& sRetMsg) {
836
MODHALTCHK(OnModuleLoading(sModName, sArgs, eType, bSuccess, sRetMsg));
839
bool CModules::OnModuleUnloading(CModule* pModule, bool& bSuccess, CString& sRetMsg) {
840
MODHALTCHK(OnModuleUnloading(pModule, bSuccess, sRetMsg));
843
bool CModules::OnGetModInfo(CModInfo& ModInfo, const CString& sModule,
844
bool& bSuccess, CString& sRetMsg) {
845
MODHALTCHK(OnGetModInfo(ModInfo, sModule, bSuccess, sRetMsg));
848
bool CModules::OnGetAvailableMods(set<CModInfo>& ssMods, CModInfo::EModuleType eType) {
849
MODUNLOADCHK(OnGetAvailableMods(ssMods, eType));
854
CModule* CModules::FindModule(const CString& sModule) const {
855
for (unsigned int a = 0; a < size(); a++) {
856
if (sModule.Equals((*this)[a]->GetModName())) {
864
bool CModules::LoadModule(const CString& sModule, const CString& sArgs, CModInfo::EModuleType eType, CUser* pUser, CIRCNetwork *pNetwork, CString& sRetMsg) {
867
if (FindModule(sModule) != NULL) {
868
sRetMsg = "Module [" + sModule + "] already loaded.";
873
bool bHandled = false;
874
_GLOBALMODULECALL(OnModuleLoading(sModule, sArgs, eType, bSuccess, sRetMsg), pUser, pNetwork, NULL, &bHandled);
875
if (bHandled) return bSuccess;
877
CString sModPath, sDataPath;
878
bool bVersionMismatch;
881
if (!FindModPath(sModule, sModPath, sDataPath)) {
882
sRetMsg = "Unable to find module [" + sModule + "]";
886
ModHandle p = OpenModule(sModule, sModPath, bVersionMismatch, Info, sRetMsg);
891
if (bVersionMismatch) {
893
sRetMsg = "Version mismatch, recompile this module.";
897
if (!Info.SupportsType(eType)) {
899
sRetMsg = "Module [" + sModule + "] does not support module type ["
900
+ CModInfo::ModuleTypeToString(eType) + "].";
904
if (!pUser && eType == CModInfo::UserModule) {
906
sRetMsg = "Module [" + sModule + "] requires a user.";
910
if (!pNetwork && eType == CModInfo::NetworkModule) {
912
sRetMsg = "Module [" + sModule + "] requires a network.";
916
CModule* pModule = Info.GetLoader()(p, pUser, pNetwork, sModule, sDataPath);
917
pModule->SetDescription(Info.GetDescription());
918
pModule->SetType(eType);
919
pModule->SetArgs(sArgs);
920
pModule->SetModPath(CDir::ChangeDir(CZNC::Get().GetCurPath(), sModPath));
925
bLoaded = pModule->OnLoad(sArgs, sRetMsg);
926
} catch (CModule::EModException) {
928
sRetMsg = "Caught an exception";
932
UnloadModule(sModule, sModPath);
933
if (!sRetMsg.empty())
934
sRetMsg = "Module [" + sModule + "] aborted: " + sRetMsg;
936
sRetMsg = "Module [" + sModule + "] aborted.";
940
if (!sRetMsg.empty()) {
941
sRetMsg += "[" + sRetMsg + "] ";
943
sRetMsg += "[" + sModPath + "]";
947
bool CModules::UnloadModule(const CString& sModule) {
949
return UnloadModule(sModule, s);
952
bool CModules::UnloadModule(const CString& sModule, CString& sRetMsg) {
953
CString sMod = sModule; // Make a copy incase the reference passed in is from CModule::GetModName()
954
CModule* pModule = FindModule(sMod);
958
sRetMsg = "Module [" + sMod + "] not loaded.";
963
bool bHandled = false;
964
_GLOBALMODULECALL(OnModuleUnloading(pModule, bSuccess, sRetMsg), pModule->GetUser(), pModule->GetNetwork(), NULL, &bHandled);
965
if (bHandled) return bSuccess;
967
ModHandle p = pModule->GetDLL();
972
for (iterator it = begin(); it != end(); ++it) {
973
if (*it == pModule) {
980
sRetMsg = "Module [" + sMod + "] unloaded";
985
sRetMsg = "Unable to unload module [" + sMod + "]";
989
bool CModules::ReloadModule(const CString& sModule, const CString& sArgs, CUser* pUser, CIRCNetwork* pNetwork, CString& sRetMsg) {
990
CString sMod = sModule; // Make a copy incase the reference passed in is from CModule::GetModName()
991
CModule *pModule = FindModule(sMod);
994
sRetMsg = "Module [" + sMod + "] not loaded";
998
CModInfo::EModuleType eType = pModule->GetType();
1002
if (!UnloadModule(sMod, sRetMsg)) {
1006
if (!LoadModule(sMod, sArgs, eType, pUser, pNetwork, sRetMsg)) {
1010
sRetMsg = "Reloaded module [" + sMod + "]";
1014
bool CModules::GetModInfo(CModInfo& ModInfo, const CString& sModule, CString& sRetMsg) {
1015
CString sModPath, sTmp;
1018
bool bHandled = false;
1019
GLOBALMODULECALL(OnGetModInfo(ModInfo, sModule, bSuccess, sRetMsg), &bHandled);
1020
if (bHandled) return bSuccess;
1022
if (!FindModPath(sModule, sModPath, sTmp)) {
1023
sRetMsg = "Unable to find module [" + sModule + "]";
1027
return GetModPathInfo(ModInfo, sModule, sModPath, sRetMsg);
1030
bool CModules::GetModPathInfo(CModInfo& ModInfo, const CString& sModule, const CString& sModPath, CString& sRetMsg) {
1031
bool bVersionMismatch;
1033
ModHandle p = OpenModule(sModule, sModPath, bVersionMismatch, ModInfo, sRetMsg);
1038
ModInfo.SetName(sModule);
1039
ModInfo.SetPath(sModPath);
1041
if (bVersionMismatch) {
1042
ModInfo.SetDescription("--- Version mismatch, recompile this module. ---");
1050
void CModules::GetAvailableMods(set<CModInfo>& ssMods, CModInfo::EModuleType eType) {
1056
ModDirList dirs = GetModDirs();
1058
while (!dirs.empty()) {
1059
Dir.FillByWildcard(dirs.front().first, "*.so");
1062
for (a = 0; a < Dir.size(); a++) {
1063
CFile& File = *Dir[a];
1064
CString sName = File.GetShortName();
1065
CString sPath = File.GetLongName();
1067
sName.RightChomp(3);
1069
CString sIgnoreRetMsg;
1070
if (GetModPathInfo(ModInfo, sName, sPath, sIgnoreRetMsg)) {
1071
if (ModInfo.SupportsType(eType)) {
1072
ssMods.insert(ModInfo);
1078
GLOBALMODULECALL(OnGetAvailableMods(ssMods, eType), NOTHING);
1081
bool CModules::FindModPath(const CString& sModule, CString& sModPath,
1082
CString& sDataPath) {
1083
CString sMod = sModule;
1084
CString sDir = sMod;
1085
if (sModule.find(".") == CString::npos)
1088
ModDirList dirs = GetModDirs();
1090
while (!dirs.empty()) {
1091
sModPath = dirs.front().first + sMod;
1092
sDataPath = dirs.front().second;
1095
if (CFile::Exists(sModPath)) {
1104
CModules::ModDirList CModules::GetModDirs() {
1108
#ifdef RUN_FROM_SOURCE
1110
sDir = CZNC::Get().GetCurPath() + "/modules/";
1111
ret.push(std::make_pair(sDir, sDir + "data/"));
1115
sDir = CZNC::Get().GetModPath() + "/";
1116
ret.push(std::make_pair(sDir, sDir));
1118
// <moduledir> and <datadir> (<prefix>/lib/znc)
1119
ret.push(std::make_pair(_MODDIR_ + CString("/"), _DATADIR_ + CString("/modules/")));
1124
ModHandle CModules::OpenModule(const CString& sModule, const CString& sModPath, bool &bVersionMismatch,
1125
CModInfo& Info, CString& sRetMsg) {
1126
// Some sane defaults in case anything errors out below
1127
bVersionMismatch = false;
1130
for (unsigned int a = 0; a < sModule.length(); a++) {
1131
if (((sModule[a] < '0') || (sModule[a] > '9')) && ((sModule[a] < 'a') || (sModule[a] > 'z')) && ((sModule[a] < 'A') || (sModule[a] > 'Z')) && (sModule[a] != '_')) {
1132
sRetMsg = "Module names can only contain letters, numbers and underscores, [" + sModule + "] is invalid.";
1137
// The second argument to dlopen() has a long history. It seems clear
1138
// that (despite what the man page says) we must include either of
1139
// RTLD_NOW and RTLD_LAZY and either of RTLD_GLOBAL and RTLD_LOCAL.
1141
// RTLD_NOW vs. RTLD_LAZY: We use RTLD_NOW to avoid ZNC dying due to
1142
// failed symbol lookups later on. Doesn't really seem to have much of a
1143
// performance impact.
1145
// RTLD_GLOBAL vs. RTLD_LOCAL: If perl is loaded with RTLD_LOCAL and later on
1146
// loads own modules (which it apparently does with RTLD_LAZY), we will die in a
1147
// name lookup since one of perl's symbols isn't found. That's worse
1148
// than any theoretical issue with RTLD_GLOBAL.
1149
ModHandle p = dlopen((sModPath).c_str(), RTLD_NOW | RTLD_GLOBAL);
1152
sRetMsg = "Unable to open module [" + sModule + "] [" + dlerror() + "]";
1156
typedef bool (*InfoFP)(double, CModInfo&);
1157
InfoFP ZNCModInfo = (InfoFP) dlsym(p, "ZNCModInfo");
1161
sRetMsg = "Could not find ZNCModInfo() in module [" + sModule + "]";
1165
if (ZNCModInfo(CModule::GetCoreVersion(), Info)) {
1167
bVersionMismatch = false;
1169
bVersionMismatch = true;
1170
sRetMsg = "Version mismatch, recompile this module.";
1176
CModCommand::CModCommand()
1177
: m_sCmd(), m_pFunc(NULL), m_sArgs(), m_sDesc()
1181
CModCommand::CModCommand(const CString& sCmd, ModCmdFunc func, const CString& sArgs, const CString& sDesc)
1182
: m_sCmd(sCmd), m_pFunc(func), m_sArgs(sArgs), m_sDesc(sDesc)
1186
CModCommand::CModCommand(const CModCommand& other)
1187
: m_sCmd(other.m_sCmd), m_pFunc(other.m_pFunc), m_sArgs(other.m_sArgs), m_sDesc(other.m_sDesc)
1191
CModCommand& CModCommand::operator=(const CModCommand& other)
1193
m_sCmd = other.m_sCmd;
1194
m_pFunc = other.m_pFunc;
1195
m_sArgs = other.m_sArgs;
1196
m_sDesc = other.m_sDesc;
1200
void CModCommand::InitHelp(CTable& Table) {
1201
Table.AddColumn("Command");
1202
Table.AddColumn("Arguments");
1203
Table.AddColumn("Description");
1206
void CModCommand::AddHelp(CTable& Table) const {
1208
Table.SetCell("Command", GetCommand());
1209
Table.SetCell("Arguments", GetArgs());
1210
Table.SetCell("Description", GetDescription());