~ubuntu-branches/ubuntu/trusty/znc/trusty

« back to all changes in this revision

Viewing changes to src/Modules.cpp

  • Committer: Package Import Robot
  • Author(s): Patrick Matthäi
  • Date: 2013-05-06 09:18:27 UTC
  • mfrom: (21.1.5 experimental)
  • Revision ID: package-import@ubuntu.com-20130506091827-08sixjiyy3hjfx6b
Tags: 1.0-4
* Change section from znc-tcl to interpreters.
* Uploading to unstable.

Show diffs side-by-side

added added

removed removed

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