summaryrefslogtreecommitdiffstats
path: root/src/kvirc/module/kvi_module.cpp
blob: f0e50d06ab4b6e5ed548a12397a3593f3196f25e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
//=============================================================================
//
//   File : kvi_module.cpp
//   Creation date : Sat Aug 12 2000 20:30:29 by Szymon Stefanek
//
//   This file is part of the KVirc irc client distribution
//   Copyright (C) 2000-2004 Szymon Stefanek (pragma at kvirc dot net)
//
//   This program is FREE software. You can redistribute it and/or
//   modify it under the terms of the GNU General Public License
//   as published by the Free Software Foundation; either version 2
//   of the License, or (at your opinion) any later version.
//
//   This program is distributed in the HOPE that it will be USEFUL,
//   but WITHOUT ANY WARRANTY; without even the implied warranty of
//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//   See the GNU General Public License for more details.
//
//   You should have received a copy of the GNU General Public License
//   along with this program. If not, write to the Free Software Foundation,
//   Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
//=============================================================================

#define __KVIRC__

#include "kvi_module.h"
#include "kvi_app.h"
#include "kvi_settings.h"
#include "kvi_kvs_eventmanager.h"
#include "kvi_kvs_eventhandler.h"
#include "kvi_modulemanager.h"

#include <time.h>

#if QT_VERSION < 300
	#include <qobjectdict.h>
#endif

#ifdef COMPILE_CRYPT_SUPPORT
	extern KviCryptEngineManager * g_pCryptEngineManager;
#endif

extern KVIRC_API KviModuleExtensionManager    * g_pModuleExtensionManager;

/*
	@doc: modules
	@type:
		generic
	@keyterms:
		module loading, functions exported by modules, commands exported by modules,
		module naming convention, module locking, plugins, functions exported by modules,
		dots in command names,dots in function names
	@title:
		Loadable modules
	@short:
		KVIrc modules model
	@body:
		Starting from version 2.0.0, KVIrc included support for external plugins:
		parts of code that can be loaded at runtime. The support was optional
		and the main KVIrc functionality was indipendant of that support.
		In version 3.0.0 the "modularity" has becomed one of the primary KVIrc features.
		The pieces of external code are now named "modules". The module
		support has been rewritten completely to extend the available features
		and remove some "basic" problems that were present in 2.0.0.
		This caused the old "plugins" to be binary incompatible with the new KVIrc
		executable; anyway, most old "plugins" have been rewritten as "modules"
		and included in the 3.0.0 distribution. Some of the basic KVIrc features
		are based on modules now; for example, the help browser is now in an
		external library called libkvihelp.so. This allows to keep the basic
		KVIrc executable smaller and faster (in some phases).
		Module loading is now "transparent" to the user. There are no
		"load" and "unload" commands: the modules are automatically
		loaded when the "core" requests them and unloaded after some (configurable) time
		of inactivity.[br]

		[big]Module naming convention[/big][br]
		Every KVIrc module must have an "unique" name: the name is a single token,
		made only of [b]lowercase[/b] letters , digits and underscores.
		The real object file (library) is named "libkvi<name>.so".
		This convention allows KVIrc to load modules when they are referenced
		by name in the scripting code (the reference in the code is case insensitive
		and remapped always to the lowercase version).[br]
		[big]What a module can do[/big][br]
		Basically, a module exports parts of the scripting language features.
		For example, the module "about" exports the "aboutkvirc" command, that
		shows the dialog that lists the KVIrc staff people. The dialog
		will be effectively activated only few times (maybe only once) by a single
		user: including it in a separate module allows keeping rarely used code out
		of the KVIrc executable and saving some memory.
		To activate the dialog you only need to execute the command:[br]
		[example]
		about.aboutkvirc
		[/example]
		That's all. KVIrc will load the necessary module, run the "aboutkvirc" command,
		wait until the module is not used anymore and then unload it.[br]

		[big]Transparent loading and unloading[/big][br]
		Any command that has the form <name>.<command> is assumed to be
		a module reference. KVIrc tries to locate the module named <name>, load it (if
		not already in memory) and execute the <command>.
		After the command execution KVIrc waits some user defined interval of time
		(typically 2-3 minutes) and then check the module state: if the module
		has not been referenced again, it is unloaded, otherwise it is kept in memory
		for another period of time. To prevent accidentaly unloading a module
		that has some windows or dialogs open, a module can lock itself in memory.
		For example, the 'help' module lock itself when a help browser window is open
		and unlocks itself when the last help browser window is closed.[br]
		A module can export functions as well: the function names follow
		exactly the same rule as the commands: $<name>.<function> is assumed
		to be a reference to the <function> exported by module named <name>.

		[big]Forced loading and unloading[/big]
		All the modules export a "load" and a "unload" command.
		[example]
		about.load
		[/example]
		The example above will do nothing more than loading the "about"
		module into the core memory.
		[example]
		about.unload
		[/example]
		The example above will forcibly unload the module from the core memory;
		even if it is still locked.[br]
		Please note that this can be dangerous in some situations...so
		better check the KVIrc behaviour twice before making public any script
		that uses this command.
*/







// FIXME: #warning "Move all the modules to the new locking method ?"


KviModule::KviModule(kvi_library_t handle,KviModuleInfo * info,const char * name,const char * filename)
: KviKvsModuleInterface()
{
	m_dlHandle = handle;
	m_pModuleInfo = info;
	m_szName = name;
	m_szFileName = filename;
// FIXME: this should become case insensitive and converted toUpper()
	/*
	m_pCommandDict = new KviPointerHashTable<const char *,KviModuleCommandParseProc>(17,false,true);
	m_pCommandDict->setAutoDelete(true);
	m_pFunctionDict = new KviPointerHashTable<const char *,KviModuleFunctionParseProc>(17,false,true);
	m_pFunctionDict->setAutoDelete(true);
	*/
	m_uLock = 0;
	m_lastAccessTime = (long int)time(0);
	/*
	m_pGenericCommandParseProc = 0;
	m_pGenericFunctionParseProc = 0;
	*/
}

KviModule::~KviModule()
{
#ifdef COMPILE_CRYPT_SUPPORT
	unregisterCryptEngines();
#endif
	unregisterAllExtensions();
	/*
	unregisterAllEventHandlers();
	delete m_pCommandDict;
	delete m_pFunctionDict;
	if(m_pGenericCommandParseProc)delete m_pGenericCommandParseProc;
	if(m_pGenericFunctionParseProc)delete m_pGenericFunctionParseProc;
	*/
}

KviModuleExtensionDescriptor * KviModule::registerExtension(const KviStr &szType,const KviStr &szName,const QString &szVisibleName,KviModuleExtensionAllocRoutine r)
{
	QPixmap pix; // null
	return g_pModuleExtensionManager->registerExtension(this,szType,szName,szVisibleName,r,pix);
}

KviModuleExtensionDescriptor * KviModule::registerExtension(const KviStr &szType,const KviStr &szName,const QString &szVisibleName,KviModuleExtensionAllocRoutine r,const QPixmap &icon)
{
	return g_pModuleExtensionManager->registerExtension(this,szType,szName,szVisibleName,r,icon);
}

KviModuleExtensionDescriptor * KviModule::findExtensionDescriptor(const KviStr &szType,const KviStr &szName)
{
	return g_pModuleExtensionManager->findExtensionDescriptor(szType,szName);
}

void KviModule::unregisterAllExtensions()
{
	g_pModuleExtensionManager->unregisterExtensionsByModule(this);
}
/*
void KviModule::setGenericCommandParseProc(KviModuleCommandParseProc proc)
{
	if(m_pGenericCommandParseProc)delete m_pGenericCommandParseProc;
	if(proc)
	{
		m_pGenericCommandParseProc = new KviModuleCommandParseProc(proc);
	} else {
		m_pGenericCommandParseProc = 0;
	}
}

void KviModule::setGenericFunctionParseProc(KviModuleFunctionParseProc proc)
{
	if(m_pGenericFunctionParseProc)delete m_pGenericFunctionParseProc;
	if(proc)
	{
		m_pGenericFunctionParseProc = new KviModuleFunctionParseProc(proc);
	} else {
		m_pGenericFunctionParseProc = 0;
	}
}

void KviModule::completeCommand(const QString &cmd,KviPointerList<QString> * matches)
{
	KviPointerHashTableIterator<const char *,KviModuleCommandParseProc> it(*m_pCommandDict);

	while(it.current())
	{
		if(KviQString::equalCIN(cmd,it.currentKey(),cmd.length()))
		{
			QString * s = new QString();
			KviQString::sprintf(*s,"%s.%s",name(),it.currentKey());
			matches->append(s);
		}
		++it;
	}
}

void KviModule::completeFunction(const QString &cmd,KviPointerList<QString> * matches)
{
	KviPointerHashTableIterator<const char *,KviModuleFunctionParseProc> it(*m_pFunctionDict);

	while(it.current())
	{
		if(KviQString::equalCIN(cmd,it.currentKey(),cmd.length()))
		{
			QString * s = new QString();
			KviQString::sprintf(*s,"%s.%s",name(),it.currentKey());
			matches->append(s);
		}
		++it;
	}
}


void KviModule::unregisterMetaObject(const char * metaObjName)
{
#if QT_VERSION < 300
// FIXME: 	#warning "We might need zeroing the d->slotAccess member of QMetaObject!"
	if(!objectDict)return;
	objectDict->remove(metaObjName);
#endif
}
*/
void KviModule::updateAccessTime()
{
	m_lastAccessTime = (long int)time(0);
}

unsigned int KviModule::secondsSinceLastAccess()
{
	return (unsigned int)(((long int)time(0)) - m_lastAccessTime);
}
/*
void KviModule::registerCommand(const char * cmd,KviModuleCommandParseProc proc)
{
	if(m_pCommandDict->find(cmd))m_pCommandDict->remove(cmd);
	m_pCommandDict->insert(cmd,new KviModuleCommandParseProc(proc));
}

void KviModule::unregisterCommand(const char * cmd)
{
	m_pCommandDict->remove(cmd);
}

void KviModule::unregisterAllCommands()
{
	delete m_pCommandDict;
	m_pCommandDict = new KviPointerHashTable<const char *,KviModuleCommandParseProc>(17,false,true);
	m_pCommandDict->setAutoDelete(true);
}

void KviModule::registerEventHandler(int evIdx,KviModuleEventParseProc proc)
{
	KviKvsOldModuleEventHandler * h = new KviKvsOldModuleEventHandler(proc,this);
	KviKvsEventManager::instance()->addAppHandler(evIdx,h);
}

void KviModule::unregisterEventHandler(int evIdx)
{
	KviKvsEventManager::instance()->removeModuleAppHandler(evIdx,this);
}

void KviModule::registerRawNumericEventHandler(int evIdx,KviModuleEventParseProc proc)
{
	KviKvsOldModuleEventHandler * h = new KviKvsOldModuleEventHandler(proc,this);
	KviKvsEventManager::instance()->addRawHandler(evIdx,h);
}

void KviModule::unregisterRawNumericEventHandler(int evIdx)
{
	KviKvsEventManager::instance()->removeModuleRawHandler(evIdx,this);
}


void KviModule::unregisterAllEventHandlers()
{
	KviKvsEventManager::instance()->removeAllModuleHandlers(this);
}

void KviModule::registerFunction(const char * fnc,KviModuleFunctionParseProc proc)
{
	if(m_pFunctionDict->find(fnc))m_pFunctionDict->remove(fnc);
	m_pFunctionDict->insert(fnc,new KviModuleFunctionParseProc(proc));
}

void KviModule::unregisterFunction(const char * fnc)
{
	m_pFunctionDict->remove(fnc);
}

void KviModule::unregisterAllFunctions()
{
	delete m_pFunctionDict;
	m_pFunctionDict = new KviPointerHashTable<const char *,KviModuleFunctionParseProc>(17,false,true);
	m_pFunctionDict->setAutoDelete(true);
}
*/

#ifdef COMPILE_CRYPT_SUPPORT

void KviModule::registerCryptEngine(KviCryptEngineDescription * d)
{
	d->providerHandle = (void *)this;
	g_pCryptEngineManager->registerEngine(d);
}

void KviModule::unregisterCryptEngine(const char * szName)
{
	g_pCryptEngineManager->unregisterEngine(szName);
}

void KviModule::unregisterCryptEngines()
{
	g_pCryptEngineManager->unregisterEngines((void *)this);
}

#endif

void * KviModule::getSymbol(const char * symname)
{
	return kvi_library_symbol(handle(),symname);
}

void KviModule::getDefaultConfigFileName(KviStr &buffer)
{
	KviStr szName(KviStr::Format,"libkvi%s.kvc",m_szName.ptr());
	g_pApp->getLocalKvircDirectory(buffer,KviApp::ConfigPlugins,szName.ptr());
}

void KviModule::getDefaultConfigFileName(QString &szBuffer)
{
	QString tmp = "libkvi";
	tmp += m_szName.ptr();
	tmp += ".kvc";
	g_pApp->getLocalKvircDirectory(szBuffer,KviApp::ConfigPlugins,tmp);
}

bool KviModule::ctrl(const char * operation,void * param)
{
	if(!(m_pModuleInfo->ctrl_routine))return false;
	return m_pModuleInfo->ctrl_routine(this,operation,param);
}