]>
jfr.im git - irc/rizon/znc.git/blob - Modules.cpp
2 * Copyright (C) 2004-2011 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.
10 #include "FileUtils.h"
13 #include "WebModules.h"
19 # warning "your crap box doesnt define RTLD_LOCAL !?"
22 #define _MODUNLOADCHK(func, type) \
23 for (unsigned int a = 0; a < size(); a++) { \
25 type* pMod = (type *) (*this)[a]; \
26 CClient* pOldClient = pMod->GetClient(); \
27 pMod->SetClient(m_pClient); \
29 CUser* pOldUser = pMod->GetUser(); \
30 pMod->SetUser(m_pUser); \
32 pMod->SetUser(pOldUser); \
36 pMod->SetClient(pOldClient); \
37 } catch (CModule::EModException e) { \
38 if (e == CModule::UNLOAD) { \
39 UnloadModule((*this)[a]->GetModName()); \
44 #define MODUNLOADCHK(func) _MODUNLOADCHK(func, CModule)
45 #define GLOBALMODCALL(func) _MODUNLOADCHK(func, CGlobalModule)
47 #define _MODHALTCHK(func, type) \
48 bool bHaltCore = false; \
49 for (unsigned int a = 0; a < size(); a++) { \
51 type* pMod = (type*) (*this)[a]; \
52 CModule::EModRet e = CModule::CONTINUE; \
53 CClient* pOldClient = pMod->GetClient(); \
54 pMod->SetClient(m_pClient); \
56 CUser* pOldUser = pMod->GetUser(); \
57 pMod->SetUser(m_pUser); \
59 pMod->SetUser(pOldUser); \
63 pMod->SetClient(pOldClient); \
64 if (e == CModule::HALTMODS) { \
66 } else if (e == CModule::HALTCORE) { \
68 } else if (e == CModule::HALT) { \
72 } catch (CModule::EModException e) { \
73 if (e == CModule::UNLOAD) { \
74 UnloadModule((*this)[a]->GetModName()); \
80 #define MODHALTCHK(func) _MODHALTCHK(func, CModule)
81 #define GLOBALMODHALTCHK(func) _MODHALTCHK(func, CGlobalModule)
83 /////////////////// Timer ///////////////////
84 CTimer::CTimer(CModule
* pModule
, unsigned int uInterval
, unsigned int uCycles
, const CString
& sLabel
, const CString
& sDescription
) : CCron() {
86 m_sDescription
= sDescription
;
90 StartMaxCycles(uInterval
, uCycles
);
97 m_pModule
->UnlinkTimer(this);
100 void CTimer::SetModule(CModule
* p
) { m_pModule
= p
; }
101 void CTimer::SetDescription(const CString
& s
) { m_sDescription
= s
; }
102 CModule
* CTimer::GetModule() const { return m_pModule
; }
103 const CString
& CTimer::GetDescription() const { return m_sDescription
; }
104 /////////////////// !Timer ///////////////////
107 CModule::CModule(ModHandle pDLL
, CUser
* pUser
, const CString
& sModName
, const CString
& sDataDir
) {
110 m_pManager
= &(CZNC::Get().GetManager());;
113 m_sModName
= sModName
;
114 m_sDataDir
= sDataDir
;
117 m_sSavePath
= m_pUser
->GetUserPath() + "/moddata/" + m_sModName
;
122 CModule::CModule(ModHandle pDLL
, const CString
& sModName
, const CString
& sDataDir
) {
124 m_pManager
= &(CZNC::Get().GetManager());
127 m_sModName
= sModName
;
128 m_sDataDir
= sDataDir
;
130 m_sSavePath
= CZNC::Get().GetZNCPath() + "/moddata/" + m_sModName
;
134 CModule::~CModule() {
135 while (!m_sTimers
.empty()) {
136 RemTimer(*m_sTimers
.begin());
139 while (!m_sSockets
.empty()) {
140 RemSocket(*m_sSockets
.begin());
146 void CModule::SetUser(CUser
* pUser
) { m_pUser
= pUser
; }
147 void CModule::SetClient(CClient
* pClient
) { m_pClient
= pClient
; }
149 const CString
& CModule::GetSavePath() const {
150 if (!CFile::Exists(m_sSavePath
)) {
151 CDir::MakeDir(m_sSavePath
);
156 bool CModule::LoadRegistry() {
157 //CString sPrefix = (m_pUser) ? m_pUser->GetUserName() : ".global";
158 return (m_mssRegistry
.ReadFromDisk(GetSavePath() + "/.registry") == MCString::MCS_SUCCESS
);
161 bool CModule::SaveRegistry() const {
162 //CString sPrefix = (m_pUser) ? m_pUser->GetUserName() : ".global";
163 return (m_mssRegistry
.WriteToDisk(GetSavePath() + "/.registry", 0600) == MCString::MCS_SUCCESS
);
166 bool CModule::SetNV(const CString
& sName
, const CString
& sValue
, bool bWriteToDisk
) {
167 m_mssRegistry
[sName
] = sValue
;
169 return SaveRegistry();
175 CString
CModule::GetNV(const CString
& sName
) const {
176 MCString::const_iterator it
= m_mssRegistry
.find(sName
);
178 if (it
!= m_mssRegistry
.end()) {
185 bool CModule::DelNV(const CString
& sName
, bool bWriteToDisk
) {
186 MCString::iterator it
= m_mssRegistry
.find(sName
);
188 if (it
!= m_mssRegistry
.end()) {
189 m_mssRegistry
.erase(it
);
195 return SaveRegistry();
201 bool CModule::ClearNV(bool bWriteToDisk
) {
202 m_mssRegistry
.clear();
205 return SaveRegistry();
210 bool CModule::AddTimer(CTimer
* pTimer
) {
211 if ((!pTimer
) || (FindTimer(pTimer
->GetName()))) {
216 if (!m_sTimers
.insert(pTimer
).second
)
220 m_pManager
->AddCron(pTimer
);
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
);
228 return AddTimer(pTimer
);
231 bool CModule::RemTimer(CTimer
* pTimer
) {
232 if (m_sTimers
.erase(pTimer
) == 0)
234 m_pManager
->DelCronByAddr(pTimer
);
238 bool CModule::RemTimer(const CString
& sLabel
) {
239 CTimer
*pTimer
= FindTimer(sLabel
);
242 return RemTimer(pTimer
);
245 bool CModule::UnlinkTimer(CTimer
* pTimer
) {
246 set
<CTimer
*>::iterator it
;
247 for (it
= m_sTimers
.begin(); it
!= m_sTimers
.end(); ++it
) {
257 CTimer
* CModule::FindTimer(const CString
& sLabel
) {
258 set
<CTimer
*>::iterator it
;
259 for (it
= m_sTimers
.begin(); it
!= m_sTimers
.end(); ++it
) {
260 CTimer
* pTimer
= *it
;
261 if (pTimer
->GetName().Equals(sLabel
)) {
269 void CModule::ListTimers() {
270 if (m_sTimers
.empty()) {
271 PutModule("You have no timers running.");
276 Table
.AddColumn("Name");
277 Table
.AddColumn("Secs");
278 Table
.AddColumn("Cycles");
279 Table
.AddColumn("Description");
281 set
<CTimer
*>::iterator it
;
282 for (it
= m_sTimers
.begin(); it
!= m_sTimers
.end(); ++it
) {
283 CTimer
* pTimer
= *it
;
284 unsigned int uCycles
= pTimer
->GetCyclesLeft();
287 Table
.SetCell("Name", pTimer
->GetName());
288 Table
.SetCell("Secs", CString(pTimer
->GetInterval()));
289 Table
.SetCell("Cycles", ((uCycles
) ? CString(uCycles
) : "INF"));
290 Table
.SetCell("Description", pTimer
->GetDescription());
296 bool CModule::AddSocket(CSocket
* pSocket
) {
301 m_sSockets
.insert(pSocket
);
305 bool CModule::RemSocket(CSocket
* pSocket
) {
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
);
310 m_pManager
->DelSockByAddr(pSocket
);
318 bool CModule::RemSocket(const CString
& sSockName
) {
319 set
<CSocket
*>::iterator it
;
320 for (it
= m_sSockets
.begin(); it
!= m_sSockets
.end(); ++it
) {
321 CSocket
* pSocket
= *it
;
323 if (pSocket
->GetSockName().Equals(sSockName
)) {
324 m_sSockets
.erase(it
);
325 m_pManager
->DelSockByAddr(pSocket
);
333 bool CModule::UnlinkSocket(CSocket
* pSocket
) {
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
);
345 CSocket
* CModule::FindSocket(const CString
& sSockName
) {
346 set
<CSocket
*>::iterator it
;
347 for (it
= m_sSockets
.begin(); it
!= m_sSockets
.end(); ++it
) {
348 CSocket
* pSocket
= *it
;
349 if (pSocket
->GetSockName().Equals(sSockName
)) {
357 void CModule::ListSockets() {
358 if (m_sSockets
.empty()) {
359 PutModule("You have no open sockets.");
364 Table
.AddColumn("Name");
365 Table
.AddColumn("State");
366 Table
.AddColumn("LocalPort");
367 Table
.AddColumn("SSL");
368 Table
.AddColumn("RemoteIP");
369 Table
.AddColumn("RemotePort");
371 set
<CSocket
*>::iterator it
;
372 for (it
= m_sSockets
.begin(); it
!= m_sSockets
.end(); ++it
) {
373 CSocket
* pSocket
= *it
;
376 Table
.SetCell("Name", pSocket
->GetSockName());
378 if (pSocket
->GetType() == CSocket::LISTENER
) {
379 Table
.SetCell("State", "Listening");
381 Table
.SetCell("State", (pSocket
->IsConnected() ? "Connected" : ""));
384 Table
.SetCell("LocalPort", CString(pSocket
->GetLocalPort()));
385 Table
.SetCell("SSL", (pSocket
->GetSSL() ? "yes" : "no"));
386 Table
.SetCell("RemoteIP", pSocket
->GetRemoteIP());
387 Table
.SetCell("RemotePort", (pSocket
->GetRemotePort()) ? CString(pSocket
->GetRemotePort()) : CString(""));
393 bool CModule::AddCommand(const CModCommand
& Command
)
395 if (Command
.GetFunction() == NULL
)
397 if (Command
.GetCommand().find(' ') != CString::npos
)
399 if (FindCommand(Command
.GetCommand()) != NULL
)
402 m_mCommands
[Command
.GetCommand()] = Command
;
406 bool CModule::AddCommand(const CString
& sCmd
, CModCommand::ModCmdFunc func
, const CString
& sArgs
, const CString
& sDesc
)
408 CModCommand
cmd(sCmd
, func
, sArgs
, sDesc
);
409 return AddCommand(cmd
);
412 void CModule::AddHelpCommand()
414 AddCommand("Help", &CModule::HandleHelpCommand
, "search", "Generate this output");
417 bool CModule::RemCommand(const CString
& sCmd
)
419 return m_mCommands
.erase(sCmd
) > 0;
422 const CModCommand
* CModule::FindCommand(const CString
& sCmd
) const
424 map
<CString
, CModCommand
>::const_iterator it
;
425 for (it
= m_mCommands
.begin(); it
!= m_mCommands
.end(); ++it
) {
426 if (!it
->first
.Equals(sCmd
))
433 bool CModule::HandleCommand(const CString
& sLine
) {
434 const CString
& sCmd
= sLine
.Token(0);
435 const CModCommand
* pCmd
= FindCommand(sCmd
);
438 pCmd
->Call(this, sLine
);
442 OnUnknownModCommand(sLine
);
447 void CModule::HandleHelpCommand(const CString
& sLine
) {
448 CString sFilter
= sLine
.Token(1, true);
449 unsigned int iFilterLength
= sFilter
.size();
451 map
<CString
, CModCommand
>::const_iterator it
;
453 CModCommand::InitHelp(Table
);
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
);
462 CString
CModule::GetModNick() const { return ((m_pUser
) ? m_pUser
->GetStatusPrefix() : "*") + m_sModName
; }
465 bool CModule::OnWebPreRequest(CWebSock
& WebSock
, const CString
& sPageName
) { return false; }
466 bool CModule::OnWebRequest(CWebSock
& WebSock
, const CString
& sPageName
, CTemplate
& Tmpl
) { return false; }
467 bool CModule::OnEmbeddedWebRequest(CWebSock
& WebSock
, const CString
& sPageName
, CTemplate
& Tmpl
) { return false; }
470 bool CModule::OnLoad(const CString
& sArgs
, CString
& sMessage
) { sMessage
= ""; return true; }
471 bool CModule::OnBoot() { return true; }
472 void CModule::OnPreRehash() {}
473 void CModule::OnPostRehash() {}
474 void CModule::OnIRCDisconnected() {}
475 void CModule::OnIRCConnected() {}
476 CModule::EModRet
CModule::OnIRCConnecting(CIRCSock
*IRCSock
) { return CONTINUE
; }
477 void CModule::OnIRCConnectionError(CIRCSock
*IRCSock
) {}
478 CModule::EModRet
CModule::OnIRCRegistration(CString
& sPass
, CString
& sNick
, CString
& sIdent
, CString
& sRealName
) { return CONTINUE
; }
479 CModule::EModRet
CModule::OnBroadcast(CString
& sMessage
) { return CONTINUE
; }
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
) {}
487 void CModule::OnMode(const CNick
& OpNick
, CChan
& Channel
, char uMode
, const CString
& sArg
, bool bAdded
, bool bNoChange
) {}
489 CModule::EModRet
CModule::OnRaw(CString
& sLine
) { return CONTINUE
; }
491 CModule::EModRet
CModule::OnStatusCommand(CString
& sCommand
) { return CONTINUE
; }
492 void CModule::OnModNotice(const CString
& sMessage
) {}
493 void CModule::OnModCTCP(const CString
& sMessage
) {}
495 void CModule::OnModCommand(const CString
& sCommand
) {
496 HandleCommand(sCommand
);
498 void CModule::OnUnknownModCommand(const CString
& sLine
) {
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.");
505 PutModule("Unknown command!");
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
) {}
510 void CModule::OnKick(const CNick
& Nick
, const CString
& sKickedNick
, CChan
& Channel
, const CString
& sMessage
) {}
511 void CModule::OnJoin(const CNick
& Nick
, CChan
& Channel
) {}
512 void CModule::OnPart(const CNick
& Nick
, CChan
& Channel
, const CString
& sMessage
) {}
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
; }
519 void CModule::OnClientLogin() {}
520 void CModule::OnClientDisconnect() {}
521 CModule::EModRet
CModule::OnUserRaw(CString
& sLine
) { return CONTINUE
; }
522 CModule::EModRet
CModule::OnUserCTCPReply(CString
& sTarget
, CString
& sMessage
) { return CONTINUE
; }
523 CModule::EModRet
CModule::OnUserCTCP(CString
& sTarget
, CString
& sMessage
) { return CONTINUE
; }
524 CModule::EModRet
CModule::OnUserAction(CString
& sTarget
, CString
& sMessage
) { return CONTINUE
; }
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
; }
529 CModule::EModRet
CModule::OnUserTopic(CString
& sChannel
, CString
& sTopic
) { return CONTINUE
; }
530 CModule::EModRet
CModule::OnUserTopicRequest(CString
& sChannel
) { return CONTINUE
; }
532 CModule::EModRet
CModule::OnCTCPReply(CNick
& Nick
, CString
& sMessage
) { return CONTINUE
; }
533 CModule::EModRet
CModule::OnPrivCTCP(CNick
& Nick
, CString
& sMessage
) { return CONTINUE
; }
534 CModule::EModRet
CModule::OnChanCTCP(CNick
& Nick
, CChan
& Channel
, CString
& sMessage
) { return CONTINUE
; }
535 CModule::EModRet
CModule::OnPrivAction(CNick
& Nick
, CString
& sMessage
) { return CONTINUE
; }
536 CModule::EModRet
CModule::OnChanAction(CNick
& Nick
, CChan
& Channel
, CString
& sMessage
) { return CONTINUE
; }
537 CModule::EModRet
CModule::OnPrivMsg(CNick
& Nick
, CString
& sMessage
) { return CONTINUE
; }
538 CModule::EModRet
CModule::OnChanMsg(CNick
& Nick
, CChan
& Channel
, CString
& sMessage
) { return CONTINUE
; }
539 CModule::EModRet
CModule::OnPrivNotice(CNick
& Nick
, CString
& sMessage
) { return CONTINUE
; }
540 CModule::EModRet
CModule::OnChanNotice(CNick
& Nick
, CChan
& Channel
, CString
& sMessage
) { return CONTINUE
; }
541 CModule::EModRet
CModule::OnTopic(CNick
& Nick
, CChan
& Channel
, CString
& sTopic
) { return CONTINUE
; }
542 CModule::EModRet
CModule::OnTimerAutoJoin(CChan
& Channel
) { return CONTINUE
; }
544 bool CModule::OnServerCapAvailable(const CString
& sCap
) { return false; }
545 void CModule::OnServerCapResult(const CString
& sCap
, bool bSuccess
) {}
547 bool CModule::PutIRC(const CString
& sLine
) {
548 return (m_pUser
) ? m_pUser
->PutIRC(sLine
) : false;
550 bool CModule::PutUser(const CString
& sLine
) {
551 return (m_pUser
) ? m_pUser
->PutUser(sLine
, m_pClient
) : false;
553 bool CModule::PutStatus(const CString
& sLine
) {
554 return (m_pUser
) ? m_pUser
->PutStatus(sLine
, m_pClient
) : false;
556 unsigned int CModule::PutModule(const CTable
& table
) {
560 unsigned int idx
= 0;
562 while (table
.GetLine(idx
++, sLine
))
566 bool CModule::PutModule(const CString
& sLine
) {
569 return m_pUser
->PutModule(GetModName(), sLine
, m_pClient
);
571 bool CModule::PutModNotice(const CString
& sLine
) {
574 return m_pUser
->PutModNotice(GetModName(), sLine
, m_pClient
);
580 CModule::EModRet
CGlobalModule::OnAddUser(CUser
& User
, CString
& sErrorRet
) { return CONTINUE
; }
581 CModule::EModRet
CGlobalModule::OnDeleteUser(CUser
& User
) { return CONTINUE
; }
582 void CGlobalModule::OnClientConnect(CZNCSock
* pClient
, const CString
& sHost
, unsigned short uPort
) {}
583 CModule::EModRet
CGlobalModule::OnLoginAttempt(CSmartPtr
<CAuthBase
> Auth
) { return CONTINUE
; }
584 void CGlobalModule::OnFailedLogin(const CString
& sUsername
, const CString
& sRemoteIP
) {}
585 CModule::EModRet
CGlobalModule::OnUnknownUserRaw(CString
& sLine
) { return CONTINUE
; }
586 void CGlobalModule::OnClientCapLs(SCString
& ssCaps
) {}
587 bool CGlobalModule::IsClientCapSupported(const CString
& sCap
, bool bState
) { return false; }
588 void CGlobalModule::OnClientCapRequest(const CString
& sCap
, bool bState
) {}
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
) {
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
) {}
599 CModules::CModules() {
604 CModules::~CModules() {
608 void CModules::UnloadAll() {
611 CString sModName
= back()->GetModName();
612 UnloadModule(sModName
, sRetMsg
);
616 bool CModules::OnBoot() {
617 for (unsigned int a
= 0; a
< size(); a
++) {
619 if (!(*this)[a
]->OnBoot()) {
622 } catch (CModule::EModException e
) {
623 if (e
== CModule::UNLOAD
) {
624 UnloadModule((*this)[a
]->GetModName());
632 bool CModules::OnPreRehash() { MODUNLOADCHK(OnPreRehash()); return false; }
633 bool CModules::OnPostRehash() { MODUNLOADCHK(OnPostRehash()); return false; }
634 bool CModules::OnIRCConnected() { MODUNLOADCHK(OnIRCConnected()); return false; }
635 bool CModules::OnIRCConnecting(CIRCSock
*pIRCSock
) { MODHALTCHK(OnIRCConnecting(pIRCSock
)); }
636 bool CModules::OnIRCConnectionError(CIRCSock
*pIRCSock
) { MODUNLOADCHK(OnIRCConnectionError(pIRCSock
)); return false; }
637 bool CModules::OnIRCRegistration(CString
& sPass
, CString
& sNick
, CString
& sIdent
, CString
& sRealName
) { MODHALTCHK(OnIRCRegistration(sPass
, sNick
, sIdent
, sRealName
)); }
638 bool CModules::OnBroadcast(CString
& sMessage
) { MODHALTCHK(OnBroadcast(sMessage
)); }
639 bool CModules::OnIRCDisconnected() { MODUNLOADCHK(OnIRCDisconnected()); return false; }
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; }
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; }
647 bool CModules::OnRaw(CString
& sLine
) { MODHALTCHK(OnRaw(sLine
)); }
649 bool CModules::OnClientLogin() { MODUNLOADCHK(OnClientLogin()); return false; }
650 bool CModules::OnClientDisconnect() { MODUNLOADCHK(OnClientDisconnect()); return false; }
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
)); }
654 bool CModules::OnUserAction(CString
& sTarget
, CString
& sMessage
) { MODHALTCHK(OnUserAction(sTarget
, sMessage
)); }
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
)); }
659 bool CModules::OnUserTopic(CString
& sChannel
, CString
& sTopic
) { MODHALTCHK(OnUserTopic(sChannel
, sTopic
)); }
660 bool CModules::OnUserTopicRequest(CString
& sChannel
) { MODHALTCHK(OnUserTopicRequest(sChannel
)); }
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; }
666 bool CModules::OnPart(const CNick
& Nick
, CChan
& Channel
, const CString
& sMessage
) { MODUNLOADCHK(OnPart(Nick
, Channel
, sMessage
)); return false; }
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
)); }
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
)); }
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
)); }
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
)); }
680 bool CModules::OnTopic(CNick
& Nick
, CChan
& Channel
, CString
& sTopic
) { MODHALTCHK(OnTopic(Nick
, Channel
, sTopic
)); }
681 bool CModules::OnTimerAutoJoin(CChan
& Channel
) { MODHALTCHK(OnTimerAutoJoin(Channel
)); }
682 bool CModules::OnStatusCommand(CString
& sCommand
) { MODHALTCHK(OnStatusCommand(sCommand
)); }
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; }
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
) {
692 CModule
* pMod
= (*this)[a
];
693 CClient
* pOldClient
= pMod
->GetClient();
694 pMod
->SetClient(m_pClient
);
696 CUser
* pOldUser
= pMod
->GetUser();
697 pMod
->SetUser(m_pUser
);
698 bResult
|= pMod
->OnServerCapAvailable(sCap
);
699 pMod
->SetUser(pOldUser
);
701 // WTF? Is that possible?
702 bResult
|= pMod
->OnServerCapAvailable(sCap
);
704 pMod
->SetClient(pOldClient
);
705 } catch (CModule::EModException e
) {
706 if (CModule::UNLOAD
== e
) {
707 UnloadModule((*this)[a
]->GetModName());
714 bool CModules::OnServerCapResult(const CString
& sCap
, bool bSuccess
) { MODUNLOADCHK(OnServerCapResult(sCap
, bSuccess
)); return false; }
719 bool CGlobalModules::OnAddUser(CUser
& User
, CString
& sErrorRet
) {
720 GLOBALMODHALTCHK(OnAddUser(User
, sErrorRet
));
723 bool CGlobalModules::OnDeleteUser(CUser
& User
) {
724 GLOBALMODHALTCHK(OnDeleteUser(User
));
727 bool CGlobalModules::OnClientConnect(CZNCSock
* pClient
, const CString
& sHost
, unsigned short uPort
) {
728 GLOBALMODCALL(OnClientConnect(pClient
, sHost
, uPort
));
732 bool CGlobalModules::OnLoginAttempt(CSmartPtr
<CAuthBase
> Auth
) {
733 GLOBALMODHALTCHK(OnLoginAttempt(Auth
));
736 bool CGlobalModules::OnFailedLogin(const CString
& sUsername
, const CString
& sRemoteIP
) {
737 GLOBALMODCALL(OnFailedLogin(sUsername
, sRemoteIP
));
741 bool CGlobalModules::OnUnknownUserRaw(CString
& sLine
) {
742 GLOBALMODHALTCHK(OnUnknownUserRaw(sLine
));
745 bool CGlobalModules::OnClientCapLs(SCString
& ssCaps
) {
746 GLOBALMODCALL(OnClientCapLs(ssCaps
));
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
) {
755 CGlobalModule
* pMod
= (CGlobalModule
*) (*this)[a
];
756 CClient
* pOldClient
= pMod
->GetClient();
757 pMod
->SetClient(m_pClient
);
759 CUser
* pOldUser
= pMod
->GetUser();
760 pMod
->SetUser(m_pUser
);
761 bResult
|= pMod
->IsClientCapSupported(sCap
, bState
);
762 pMod
->SetUser(pOldUser
);
764 // WTF? Is that possible?
765 bResult
|= pMod
->IsClientCapSupported(sCap
, bState
);
767 pMod
->SetClient(pOldClient
);
768 } catch (CModule::EModException e
) {
769 if (CModule::UNLOAD
== e
) {
770 UnloadModule((*this)[a
]->GetModName());
777 bool CGlobalModules::OnClientCapRequest(const CString
& sCap
, bool bState
) {
778 GLOBALMODCALL(OnClientCapRequest(sCap
, bState
));
782 bool CGlobalModules::OnModuleLoading(const CString
& sModName
, const CString
& sArgs
,
783 bool& bSuccess
, CString
& sRetMsg
) {
784 GLOBALMODHALTCHK(OnModuleLoading(sModName
, sArgs
, bSuccess
, sRetMsg
));
787 bool CGlobalModules::OnModuleUnloading(CModule
* pModule
, bool& bSuccess
, CString
& sRetMsg
) {
788 GLOBALMODHALTCHK(OnModuleUnloading(pModule
, bSuccess
, sRetMsg
));
791 bool CGlobalModules::OnGetModInfo(CModInfo
& ModInfo
, const CString
& sModule
,
792 bool& bSuccess
, CString
& sRetMsg
) {
793 GLOBALMODHALTCHK(OnGetModInfo(ModInfo
, sModule
, bSuccess
, sRetMsg
));
796 bool CGlobalModules::OnGetAvailableMods(set
<CModInfo
>& ssMods
, bool bGlobal
) {
797 GLOBALMODCALL(OnGetAvailableMods(ssMods
, bGlobal
));
802 CModule
* CModules::FindModule(const CString
& sModule
) const {
803 for (unsigned int a
= 0; a
< size(); a
++) {
804 if (sModule
.Equals((*this)[a
]->GetModName())) {
812 bool CModules::LoadModule(const CString
& sModule
, const CString
& sArgs
, CUser
* pUser
, CString
& sRetMsg
) {
815 if (FindModule(sModule
) != NULL
) {
816 sRetMsg
= "Module [" + sModule
+ "] already loaded.";
821 GLOBALMODULECALL(OnModuleLoading(sModule
, sArgs
, bSuccess
, sRetMsg
), pUser
, NULL
, return bSuccess
);
823 CString sModPath
, sDataPath
;
824 bool bVersionMismatch
;
827 if (!FindModPath(sModule
, sModPath
, sDataPath
)) {
828 sRetMsg
= "Unable to find module [" + sModule
+ "]";
832 ModHandle p
= OpenModule(sModule
, sModPath
, bVersionMismatch
, Info
, sRetMsg
);
837 if (bVersionMismatch
) {
839 sRetMsg
= "Version mismatch, recompile this module.";
843 if ((pUser
== NULL
) != Info
.IsGlobal()) {
845 sRetMsg
= "Module [" + sModule
+ "] is ";
846 sRetMsg
+= Info
.IsGlobal() ? "" : "not ";
847 sRetMsg
+= "a global module.";
851 CModule
* pModule
= NULL
;
854 pModule
= Info
.GetLoader()(p
, pUser
, sModule
, sDataPath
);
856 pModule
= Info
.GetGlobalLoader()(p
, sModule
, sDataPath
);
859 pModule
->SetDescription(Info
.GetDescription());
860 pModule
->SetGlobal(Info
.IsGlobal());
861 pModule
->SetArgs(sArgs
);
862 pModule
->SetModPath(CDir::ChangeDir(CZNC::Get().GetCurPath(), sModPath
));
867 bLoaded
= pModule
->OnLoad(sArgs
, sRetMsg
);
868 } catch (CModule::EModException
) {
870 sRetMsg
= "Caught an exception";
874 UnloadModule(sModule
, sModPath
);
875 if (!sRetMsg
.empty())
876 sRetMsg
= "Module [" + sModule
+ "] aborted: " + sRetMsg
;
878 sRetMsg
= "Module [" + sModule
+ "] aborted.";
882 if (!sRetMsg
.empty()) {
883 sRetMsg
+= "[" + sRetMsg
+ "] ";
885 sRetMsg
+= "[" + sModPath
+ "]";
889 bool CModules::UnloadModule(const CString
& sModule
) {
891 return UnloadModule(sModule
, s
);
894 bool CModules::UnloadModule(const CString
& sModule
, CString
& sRetMsg
) {
895 CString sMod
= sModule
; // Make a copy incase the reference passed in is from CModule::GetModName()
896 CModule
* pModule
= FindModule(sMod
);
900 sRetMsg
= "Module [" + sMod
+ "] not loaded.";
905 GLOBALMODULECALL(OnModuleUnloading(pModule
, bSuccess
, sRetMsg
), pModule
->GetUser(), NULL
, return bSuccess
);
907 ModHandle p
= pModule
->GetDLL();
912 for (iterator it
= begin(); it
!= end(); ++it
) {
913 if (*it
== pModule
) {
920 sRetMsg
= "Module [" + sMod
+ "] unloaded";
925 sRetMsg
= "Unable to unload module [" + sMod
+ "]";
929 bool CModules::ReloadModule(const CString
& sModule
, const CString
& sArgs
, CUser
* pUser
, CString
& sRetMsg
) {
930 CString sMod
= sModule
; // Make a copy incase the reference passed in is from CModule::GetModName()
932 if (!UnloadModule(sMod
, sRetMsg
)) {
936 if (!LoadModule(sMod
, sArgs
, pUser
, sRetMsg
)) {
940 sRetMsg
= "Reloaded module [" + sMod
+ "]";
944 bool CModules::GetModInfo(CModInfo
& ModInfo
, const CString
& sModule
, CString
& sRetMsg
) {
945 CString sModPath
, sTmp
;
948 GLOBALMODULECALL(OnGetModInfo(ModInfo
, sModule
, bSuccess
, sRetMsg
), NULL
, NULL
, return bSuccess
);
950 if (!FindModPath(sModule
, sModPath
, sTmp
)) {
951 sRetMsg
= "Unable to find module [" + sModule
+ "]";
955 return GetModPathInfo(ModInfo
, sModule
, sModPath
, sRetMsg
);
958 bool CModules::GetModPathInfo(CModInfo
& ModInfo
, const CString
& sModule
, const CString
& sModPath
, CString
& sRetMsg
) {
959 bool bVersionMismatch
;
961 ModHandle p
= OpenModule(sModule
, sModPath
, bVersionMismatch
, ModInfo
, sRetMsg
);
966 ModInfo
.SetName(sModule
);
967 ModInfo
.SetPath(sModPath
);
969 if (bVersionMismatch
) {
970 ModInfo
.SetDescription("--- Version mismatch, recompile this module. ---");
978 void CModules::GetAvailableMods(set
<CModInfo
>& ssMods
, bool bGlobal
) {
984 ModDirList dirs
= GetModDirs();
986 while (!dirs
.empty()) {
987 Dir
.FillByWildcard(dirs
.front().first
, "*.so");
990 for (a
= 0; a
< Dir
.size(); a
++) {
991 CFile
& File
= *Dir
[a
];
992 CString sName
= File
.GetShortName();
993 CString sPath
= File
.GetLongName();
997 CString sIgnoreRetMsg
;
998 if (GetModPathInfo(ModInfo
, sName
, sPath
, sIgnoreRetMsg
)) {
999 if (ModInfo
.IsGlobal() == bGlobal
) {
1000 ssMods
.insert(ModInfo
);
1006 GLOBALMODULECALL(OnGetAvailableMods(ssMods
, bGlobal
), NULL
, NULL
, NOTHING
);
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
)
1016 ModDirList dirs
= GetModDirs();
1018 while (!dirs
.empty()) {
1019 sModPath
= dirs
.front().first
+ sMod
;
1020 sDataPath
= dirs
.front().second
;
1023 if (CFile::Exists(sModPath
)) {
1032 CModules::ModDirList
CModules::GetModDirs() {
1036 #ifdef RUN_FROM_SOURCE
1038 sDir
= CZNC::Get().GetCurPath() + "/modules/";
1039 ret
.push(std::make_pair(sDir
, sDir
+ "data/"));
1042 sDir
= CZNC::Get().GetCurPath() + "/modules/extra/";
1043 ret
.push(std::make_pair(sDir
, sDir
+ "data/"));
1047 sDir
= CZNC::Get().GetModPath() + "/";
1048 ret
.push(std::make_pair(sDir
, sDir
));
1050 // <moduledir> and <datadir> (<prefix>/lib/znc)
1051 ret
.push(std::make_pair(_MODDIR_
+ CString("/"), _DATADIR_
+ CString("/modules/")));
1056 ModHandle
CModules::OpenModule(const CString
& sModule
, const CString
& sModPath
, bool &bVersionMismatch
,
1057 CModInfo
& Info
, CString
& sRetMsg
) {
1058 // Some sane defaults in case anything errors out below
1059 bVersionMismatch
= false;
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.";
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.
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.
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
1080 // than any theoretical issue with RTLD_GLOBAL.
1081 ModHandle p
= dlopen((sModPath
).c_str(), RTLD_NOW
| RTLD_GLOBAL
);
1084 sRetMsg
= "Unable to open module [" + sModule
+ "] [" + dlerror() + "]";
1088 typedef bool (*InfoFP
)(double, CModInfo
&);
1089 InfoFP ZNCModInfo
= (InfoFP
) dlsym(p
, "ZNCModInfo");
1093 sRetMsg
= "Could not find ZNCModInfo() in module [" + sModule
+ "]";
1097 if (ZNCModInfo(CModule::GetCoreVersion(), Info
)) {
1099 bVersionMismatch
= false;
1101 bVersionMismatch
= true;
1102 sRetMsg
= "Version mismatch, recompile this module.";
1108 CModCommand::CModCommand()
1109 : m_sCmd(), m_pFunc(NULL
), m_sArgs(), m_sDesc()
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
)
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
)
1123 CModCommand
& CModCommand::operator=(const CModCommand
& other
)
1125 m_sCmd
= other
.m_sCmd
;
1126 m_pFunc
= other
.m_pFunc
;
1127 m_sArgs
= other
.m_sArgs
;
1128 m_sDesc
= other
.m_sDesc
;
1132 void CModCommand::InitHelp(CTable
& Table
) {
1133 Table
.AddColumn("Command");
1134 Table
.AddColumn("Arguments");
1135 Table
.AddColumn("Description");
1138 void CModCommand::AddHelp(CTable
& Table
) const {
1140 Table
.SetCell("Command", GetCommand());
1141 Table
.SetCell("Arguments", GetArgs());
1142 Table
.SetCell("Description", GetDescription());