1 //=============================================================================
2 //
3 //   File : KviKvsEventManager.cpp
4 //   Creation date : Thu Aug 17 2000 13:59:12 by Szymon Stefanek
5 //
6 //   This file is part of the KVIrc IRC client distribution
7 //   Copyright (C) 2000-2010 Szymon Stefanek <pragma at kvirc dot net>
8 //
9 //   This program is FREE software. You can redistribute it and/or
10 //   modify it under the terms of the GNU General Public License
11 //   as published by the Free Software Foundation; either version 2
12 //   of the License, or (at your option) any later version.
13 //
14 //   This program is distributed in the HOPE that it will be USEFUL,
15 //   but WITHOUT ANY WARRANTY; without even the implied warranty of
16 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 //   See the GNU General Public License for more details.
18 //
19 //   You should have received a copy of the GNU General Public License
20 //   along with this program. If not, write to the Free Software Foundation,
21 //   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 //
23 //=============================================================================
24 
25 #include "KviKvsEventManager.h"
26 #include "KviConfigurationFile.h"
27 #include "KviKvsScript.h"
28 #include "KviKvsVariant.h"
29 #include "KviOptions.h"
30 #include "KviLocale.h"
31 #include "kvi_out.h"
32 #include "KviModule.h"
33 #include "KviWindow.h"
34 #include "KviKvsVariantList.h"
35 
36 #include <QRegExp>
37 
38 /*
39 	@doc: events
40 	@type:
41 		language
42 	@keyterms:
43 		events,event handlers,event
44 	@title:
45 		Events
46 	@short:
47 		Events: user reactions
48 	@body:
49 		KVIrc triggers an event when a particular situation occurs.[br]
50 		You can define a set of event handlers for each event type.[br]
51 		An event handler is a snippet of user-defined code that gets executed when the event is triggered.[br]
52 		Event handlers can be created or destroyed by using the scriptcenter (graphic interface)
53 		or even from the commandline (or script) by using the [cmd]event[/cmd] command.[br]
54 		For example, the [event:onirc]OnIRC[/event] is triggered when the login operations have
55 		been terminated and you can consider yourself [i]completely[/i] on IRC. For example, you might
56 		want to [i]auto-join[/i] some channels. Nothing easier! The following snippet of code
57 		adds a handler to the OnIRC event that joins three channels:
58 		[example]
59 		[cmd]event[/cmd](OnIRC,autojoin)
60 		{
61 			[cmd]echo[/cmd] Auto-joining my preferred channels...
62 			[cmd]join[/cmd] #kvirc,#siena,#linux
63 		}
64 		[/example]
65 		Now try to connect to a server and you'll see that it joins automatically the three channels!.[br]
66 		You might also want to do some other actions just after the connection has been established,
67 		for example you might want to look immediately for a friend of yours by issuing a [cmd]whois[/cmd]
68 		to the server (you could use the notify list for that).[br]
69 		You can add the [cmd]whois[/cmd] request to the handler above or just create a new one:
70 		[example]
71 		[cmd]event[/cmd](OnIRC,lookforfred)
72 		{
73 			[cmd]echo[/cmd] Looking for fred...
74 			[cmd]whois[/cmd] fred
75 		}
76 		[/example]
77 		(An even nicer idea would be to use the [cmd]awhois[/cmd] command, but that's left to the reader as an exercise.[br]
78 		To remove an event handler you still use the [cmd]event[/cmd] command, but with an empty code block:
79 		[example]
80 		[cmd]event[/cmd](OnIRC,lookforfred){}[br]
81 		[/example]
82 		[br]
83 		Certain events will pass you some data in the positional parameters.[br]
84 		For example, when you are being banned from a channel, KVIrc triggers the [event:onmeban]OnMeBan[/event]
85 		event: you might be interested in WHO has banned you. KVIrc will pass the [i]ban source[/i] information
86 		in the positional parameters $0,$1 and $2.[br]
87 		(Please note that the parameters started from $1 in KVIrc versions older than 3.0.0!).[br]
88 		You may take a look at the list of available [doc:event_index_all]events[/doc].[br]
89 */
90 
91 KviKvsEventManager * KviKvsEventManager::m_pInstance = nullptr;
92 
KviKvsEventManager()93 KviKvsEventManager::KviKvsEventManager()
94 {
95 	m_pInstance = this;
96 	for(auto & i : m_rawEventTable)
97 		i = nullptr;
98 }
99 
~KviKvsEventManager()100 KviKvsEventManager::~KviKvsEventManager()
101 {
102 	clear();
103 }
104 
init()105 void KviKvsEventManager::init()
106 {
107 	if(KviKvsEventManager::instance())
108 	{
109 		qDebug("WARNING: trying to create KviKvsEventManager twice!");
110 		return;
111 	}
112 	(void)new KviKvsEventManager();
113 }
114 
done()115 void KviKvsEventManager::done()
116 {
117 	if(!KviKvsEventManager::instance())
118 	{
119 		qDebug("WARNING: trying to destroy the KviKvsEventManager twice!");
120 		return;
121 	}
122 	delete KviKvsEventManager::instance();
123 }
124 
findAppEventIndexByName(const QString & szName)125 unsigned int KviKvsEventManager::findAppEventIndexByName(const QString & szName)
126 {
127 	for(unsigned int u = 0; u < KVI_KVS_NUM_APP_EVENTS; u++)
128 	{
129 		if(KviQString::equalCI(szName, m_appEventTable[u].name()))
130 			return u;
131 		//Backwards compatibility >_<
132 		if((u == 4) && KviQString::equalCI(szName, "OnIrcConnectionEstablished"))
133 			return u;
134 	}
135 	return KVI_KVS_NUM_APP_EVENTS; // <-- invalid event number
136 }
137 
findAppEventByName(const QString & szName)138 KviKvsEvent * KviKvsEventManager::findAppEventByName(const QString & szName)
139 {
140 	for(unsigned int u = 0; u < KVI_KVS_NUM_APP_EVENTS; u++)
141 	{
142 		if(KviQString::equalCI(szName, m_appEventTable[u].name()))
143 			return &(m_appEventTable[u]);
144 		//Backwards compatibility >_<
145 		if((u == 4) && KviQString::equalCI(szName, "OnIrcConnectionEstablished"))
146 			return &(m_appEventTable[u]);
147 	}
148 	return nullptr;
149 }
150 
addAppHandler(unsigned int uEvIdx,KviKvsEventHandler * h)151 bool KviKvsEventManager::addAppHandler(unsigned int uEvIdx, KviKvsEventHandler * h)
152 {
153 	if(uEvIdx >= KVI_KVS_NUM_APP_EVENTS)
154 		return false;
155 	m_appEventTable[uEvIdx].addHandler(h);
156 	return true;
157 }
158 
addRawHandler(unsigned int uRawIdx,KviKvsEventHandler * h)159 bool KviKvsEventManager::addRawHandler(unsigned int uRawIdx, KviKvsEventHandler * h)
160 {
161 	if(uRawIdx >= KVI_KVS_NUM_RAW_EVENTS)
162 		return false;
163 	if(!m_rawEventTable[uRawIdx])
164 	{
165 		m_rawEventTable[uRawIdx] = new KviPointerList<KviKvsEventHandler>();
166 		m_rawEventTable[uRawIdx]->setAutoDelete(true);
167 	}
168 	m_rawEventTable[uRawIdx]->append(h);
169 	return true;
170 }
171 
addRawHandler(unsigned int uRawIdx,const KviKvsEventHandler & h)172 bool KviKvsEventManager::addRawHandler(unsigned int uRawIdx, const KviKvsEventHandler & h)
173 {
174 	if(uRawIdx >= KVI_KVS_NUM_RAW_EVENTS)
175 		return false;
176 	KviKvsEventHandler * copy = new KviKvsEventHandler(h);
177 	return addRawHandler(uRawIdx, copy);
178 }
179 
removeScriptAppHandler(unsigned int uEvIdx,const QString & szName)180 bool KviKvsEventManager::removeScriptAppHandler(unsigned int uEvIdx, const QString & szName)
181 {
182 	if(uEvIdx >= KVI_KVS_NUM_APP_EVENTS)
183 		return false;
184 	KviKvsEventHandler * h;
185 	if(!(m_appEventTable[uEvIdx].handlers()))
186 		return false;
187 	for(h = m_appEventTable[uEvIdx].handlers()->first(); h; h = m_appEventTable[uEvIdx].handlers()->next())
188 	{
189 		if(h->type() == KviKvsEventHandler::Script)
190 		{
191 			if(KviQString::equalCI(((KviKvsScriptEventHandler *)h)->name(), szName))
192 			{
193 				m_appEventTable[uEvIdx].removeHandler(h);
194 				return true;
195 			}
196 		}
197 	}
198 	return false;
199 }
200 
findScriptRawHandler(unsigned int uEvIdx,const QString & szName)201 KviKvsScriptEventHandler * KviKvsEventManager::findScriptRawHandler(unsigned int uEvIdx, const QString & szName)
202 {
203 	if(uEvIdx >= KVI_KVS_NUM_RAW_EVENTS)
204 		return nullptr;
205 	if(!m_rawEventTable[uEvIdx])
206 		return nullptr;
207 	KviKvsEventHandler * h;
208 	for(h = m_rawEventTable[uEvIdx]->first(); h; h = m_rawEventTable[uEvIdx]->next())
209 	{
210 		if(h->type() == KviKvsEventHandler::Script)
211 		{
212 			if(KviQString::equalCI(((KviKvsScriptEventHandler *)h)->name(), szName))
213 			{
214 				return (KviKvsScriptEventHandler *)h;
215 			}
216 		}
217 	}
218 	return nullptr;
219 }
220 
findScriptAppHandler(unsigned int uEvIdx,const QString & szName)221 KviKvsScriptEventHandler * KviKvsEventManager::findScriptAppHandler(unsigned int uEvIdx, const QString & szName)
222 {
223 	if(uEvIdx >= KVI_KVS_NUM_APP_EVENTS)
224 		return nullptr;
225 	KviKvsEventHandler * h;
226 	if(!(m_appEventTable[uEvIdx].handlers()))
227 		return nullptr;
228 	for(h = m_appEventTable[uEvIdx].handlers()->first(); h; h = m_appEventTable[uEvIdx].handlers()->next())
229 	{
230 		if(h->type() == KviKvsEventHandler::Script)
231 		{
232 			if(KviQString::equalCI(((KviKvsScriptEventHandler *)h)->name(), szName))
233 			{
234 				return (KviKvsScriptEventHandler *)h;
235 			}
236 		}
237 	}
238 	return nullptr;
239 }
240 
enableScriptAppHandler(unsigned int uEvIdx,const QString & szName,bool bEnable)241 bool KviKvsEventManager::enableScriptAppHandler(unsigned int uEvIdx, const QString & szName, bool bEnable)
242 {
243 	KviKvsScriptEventHandler * h = findScriptAppHandler(uEvIdx, szName);
244 	if(!h)
245 		return false;
246 	h->setEnabled(bEnable);
247 	return true;
248 }
249 
removeModuleAppHandler(unsigned int uEvIdx,KviKvsModuleInterface * i)250 bool KviKvsEventManager::removeModuleAppHandler(unsigned int uEvIdx, KviKvsModuleInterface * i)
251 {
252 	if(uEvIdx >= KVI_KVS_NUM_APP_EVENTS)
253 		return false;
254 	KviKvsEventHandler * h;
255 	if(!(m_appEventTable[uEvIdx].handlers()))
256 		return false;
257 	for(h = m_appEventTable[uEvIdx].handlers()->first(); h; h = m_appEventTable[uEvIdx].handlers()->next())
258 	{
259 		if(h->type() == KviKvsEventHandler::Module)
260 		{
261 			if(((KviKvsModuleEventHandler *)h)->moduleInterface() == i)
262 			{
263 				m_appEventTable[uEvIdx].removeHandler(h);
264 				return true;
265 			}
266 		}
267 	}
268 	return false;
269 }
270 
removeAllModuleAppHandlers(KviKvsModuleInterface * pIface)271 void KviKvsEventManager::removeAllModuleAppHandlers(KviKvsModuleInterface * pIface)
272 {
273 	KviKvsEventHandler * h;
274 	for(auto & i : m_appEventTable)
275 	{
276 		if(!i.handlers())
277 			continue;
278 
279 		KviPointerList<KviKvsEventHandler> l;
280 		l.setAutoDelete(false);
281 		for(h = i.handlers()->first(); h; h = i.handlers()->next())
282 		{
283 			if(h->type() == KviKvsEventHandler::Module)
284 			{
285 				if(((KviKvsModuleEventHandler *)h)->moduleInterface() == pIface)
286 				{
287 					l.append(h);
288 				}
289 			}
290 		}
291 		for(h = l.first(); h; h = l.next())
292 			i.removeHandler(h);
293 	}
294 }
295 
removeAllModuleRawHandlers(KviKvsModuleInterface * pIface)296 void KviKvsEventManager::removeAllModuleRawHandlers(KviKvsModuleInterface * pIface)
297 {
298 	KviKvsEventHandler * h;
299 	for(auto & i : m_rawEventTable)
300 	{
301 		if(!i)
302 			continue;
303 
304 		KviPointerList<KviKvsEventHandler> l;
305 		l.setAutoDelete(false);
306 		for(h = i->first(); h; h = i->next())
307 		{
308 			if(h->type() == KviKvsEventHandler::Module)
309 			{
310 				if(((KviKvsModuleEventHandler *)h)->moduleInterface() == pIface)
311 				{
312 					l.append(h);
313 				}
314 			}
315 		}
316 		for(h = l.first(); h; h = l.next())
317 			i->removeRef(h);
318 		if(i->isEmpty())
319 		{
320 			delete i;
321 			i = nullptr;
322 		}
323 	}
324 }
325 
removeScriptRawHandler(unsigned int uEvIdx,const QString & szName)326 bool KviKvsEventManager::removeScriptRawHandler(unsigned int uEvIdx, const QString & szName)
327 {
328 	if(uEvIdx >= KVI_KVS_NUM_RAW_EVENTS)
329 		return false;
330 	if(!m_rawEventTable[uEvIdx])
331 		return false;
332 	KviKvsEventHandler * h;
333 	for(h = m_rawEventTable[uEvIdx]->first(); h; h = m_rawEventTable[uEvIdx]->next())
334 	{
335 		if(h->type() == KviKvsEventHandler::Script)
336 		{
337 			if(KviQString::equalCI(((KviKvsScriptEventHandler *)h)->name(), szName))
338 			{
339 				m_rawEventTable[uEvIdx]->removeRef(h);
340 				if(m_rawEventTable[uEvIdx]->isEmpty())
341 				{
342 					delete m_rawEventTable[uEvIdx];
343 					m_rawEventTable[uEvIdx] = nullptr;
344 				}
345 				return true;
346 			}
347 		}
348 	}
349 	return false;
350 }
351 
enableScriptRawHandler(unsigned int uEvIdx,const QString & szName,bool bEnable)352 bool KviKvsEventManager::enableScriptRawHandler(unsigned int uEvIdx, const QString & szName, bool bEnable)
353 {
354 	KviKvsScriptEventHandler * h = findScriptRawHandler(uEvIdx, szName);
355 	if(!h)
356 		return false;
357 	h->setEnabled(bEnable);
358 	return true;
359 }
360 
removeModuleRawHandler(unsigned int uRawIdx,KviKvsModuleInterface * i)361 bool KviKvsEventManager::removeModuleRawHandler(unsigned int uRawIdx, KviKvsModuleInterface * i)
362 {
363 	if(uRawIdx >= KVI_KVS_NUM_RAW_EVENTS)
364 		return false;
365 	if(!m_rawEventTable[uRawIdx])
366 		return false;
367 	KviKvsEventHandler * h;
368 	for(h = m_rawEventTable[uRawIdx]->first(); h; h = m_rawEventTable[uRawIdx]->next())
369 	{
370 		if(h->type() == KviKvsEventHandler::Module)
371 		{
372 			if(((KviKvsModuleEventHandler *)h)->moduleInterface() == i)
373 			{
374 				m_rawEventTable[uRawIdx]->removeRef(h);
375 				if(m_rawEventTable[uRawIdx]->isEmpty())
376 				{
377 					delete m_rawEventTable[uRawIdx];
378 					m_rawEventTable[uRawIdx] = nullptr;
379 				}
380 				return true;
381 			}
382 		}
383 	}
384 	return false;
385 }
386 
removeAllModuleHandlers(KviKvsModuleInterface * pIface)387 void KviKvsEventManager::removeAllModuleHandlers(KviKvsModuleInterface * pIface)
388 {
389 	removeAllModuleAppHandlers(pIface);
390 	removeAllModuleRawHandlers(pIface);
391 }
392 
removeAllScriptAppHandlers()393 void KviKvsEventManager::removeAllScriptAppHandlers()
394 {
395 	for(auto & i : m_appEventTable)
396 	{
397 		i.clearScriptHandlers();
398 	}
399 }
400 
removeAllScriptRawHandlers()401 void KviKvsEventManager::removeAllScriptRawHandlers()
402 {
403 	for(auto & i : m_rawEventTable)
404 	{
405 		if(i)
406 		{
407 			KviPointerList<KviKvsEventHandler> dl;
408 			dl.setAutoDelete(false);
409 			KviKvsEventHandler * e;
410 			for(e = i->first(); e; e = i->next())
411 			{
412 				if(e->type() == KviKvsEventHandler::Script)
413 					dl.append(e);
414 			}
415 
416 			for(e = dl.first(); e; e = dl.next())
417 			{
418 				i->removeRef(e);
419 			}
420 
421 			if(i->isEmpty())
422 			{
423 				delete i;
424 				i = nullptr;
425 			}
426 		}
427 	}
428 }
429 
clearRawEvents()430 void KviKvsEventManager::clearRawEvents()
431 {
432 	for(auto & i : m_rawEventTable)
433 	{
434 		if(i)
435 			delete i;
436 		i = nullptr;
437 	}
438 }
439 
clearAppEvents()440 void KviKvsEventManager::clearAppEvents()
441 {
442 	for(auto & i : m_appEventTable)
443 	{
444 		i.clear();
445 	}
446 }
447 
clear()448 void KviKvsEventManager::clear()
449 {
450 	clearRawEvents();
451 	clearAppEvents();
452 }
453 
triggerHandlers(KviPointerList<KviKvsEventHandler> * pHandlers,KviWindow * pWnd,KviKvsVariantList * pParams)454 bool KviKvsEventManager::triggerHandlers(KviPointerList<KviKvsEventHandler> * pHandlers, KviWindow * pWnd, KviKvsVariantList * pParams)
455 {
456 	if(!pHandlers)
457 		return false;
458 
459 	bool bGotHalt = false;
460 	for(KviKvsEventHandler * h = pHandlers->first(); h; h = pHandlers->next())
461 	{
462 		switch(h->type())
463 		{
464 			case KviKvsEventHandler::Script:
465 			{
466 				if(((KviKvsScriptEventHandler *)h)->isEnabled())
467 				{
468 					KviKvsScript * s = ((KviKvsScriptEventHandler *)h)->script();
469 					KviKvsScript copy(*s);
470 					KviKvsVariant retVal;
471 					int iRet = copy.run(pWnd, pParams, &retVal, KviKvsScript::PreserveParams);
472 					if(!iRet)
473 					{
474 						// error! disable the handler if it's broken
475 						if(KVI_OPTION_BOOL(KviOption_boolDisableBrokenEventHandlers))
476 						{
477 							((KviKvsScriptEventHandler *)h)->setEnabled(false);
478 							pWnd->output(KVI_OUT_PARSERERROR, __tr2qs_ctx("Event handler %Q is broken: disabling", "kvs"), &(s->name()));
479 							emit eventHandlerDisabled(s->name());
480 						}
481 					}
482 					if(!bGotHalt)
483 						bGotHalt = (iRet & KviKvsScript::HaltEncountered);
484 				}
485 			}
486 			break;
487 			case KviKvsEventHandler::Module:
488 			{
489 				KviModule * m = (KviModule *)((KviKvsModuleEventHandler *)h)->moduleInterface();
490 				KviKvsModuleEventHandlerRoutine * proc = ((KviKvsModuleEventHandler *)h)->handlerRoutine();
491 				KviKvsVariant retVal;
492 				KviKvsRunTimeContext ctx(nullptr, pWnd, pParams, &retVal);
493 				KviKvsModuleEventCall call(m, &ctx, pParams);
494 				if(!(*proc)(&call))
495 					bGotHalt = true;
496 			}
497 			break;
498 		}
499 	}
500 	return bGotHalt;
501 }
502 
loadRawEvents(const QString & szFileName)503 void KviKvsEventManager::loadRawEvents(const QString & szFileName)
504 {
505 	KviConfigurationFile cfg(szFileName, KviConfigurationFile::Read);
506 	removeAllScriptRawHandlers();
507 
508 	for(size_t i = 0; i < KVI_KVS_NUM_RAW_EVENTS; i++)
509 	{
510 		QString szTmp = QString("RAW%1").arg(i);
511 		if(cfg.hasGroup(szTmp))
512 		{
513 			cfg.setGroup(szTmp);
514 			unsigned int uHandlers = cfg.readUIntEntry("NHandlers", 0);
515 			if(uHandlers)
516 			{
517 				m_rawEventTable[i] = new KviPointerList<KviKvsEventHandler>();
518 				m_rawEventTable[i]->setAutoDelete(true);
519 				for(unsigned int uIdx = 0; uIdx < uHandlers; uIdx++)
520 				{
521 					szTmp = QString("Name%1").arg(uIdx);
522 					QString szName = cfg.readEntry(szTmp, "unnamed");
523 					szTmp = QString("Buffer%1").arg(uIdx);
524 					QString szCode = cfg.readEntry(szTmp, "");
525 					szTmp = QString("RawEvent%1::%2").arg(uIdx).arg(szName);
526 					KviKvsScriptEventHandler * pScript = new KviKvsScriptEventHandler(szName, szTmp, szCode);
527 					szTmp = QString("Enabled%1").arg(uIdx);
528 					pScript->setEnabled(cfg.readBoolEntry(szTmp, false));
529 					m_rawEventTable[i]->append(pScript);
530 				}
531 			}
532 		}
533 	}
534 }
535 
saveRawEvents(const QString & szFileName)536 void KviKvsEventManager::saveRawEvents(const QString & szFileName)
537 {
538 	KviConfigurationFile cfg(szFileName, KviConfigurationFile::Write);
539 	cfg.clear();
540 
541 	for(size_t i = 0; i < KVI_KVS_NUM_RAW_EVENTS; i++)
542 	{
543 		if(m_rawEventTable[i])
544 		{
545 			QString szTmp = QString("RAW%1").arg(i);
546 			cfg.setGroup(szTmp);
547 
548 			int iIdx = 0;
549 			for(KviKvsEventHandler * pEvent = m_rawEventTable[i]->first(); pEvent; pEvent = m_rawEventTable[i]->next())
550 			{
551 				if(pEvent->type() == KviKvsEventHandler::Script)
552 				{
553 					szTmp = QString("Name%1").arg(iIdx);
554 					cfg.writeEntry(szTmp, ((KviKvsScriptEventHandler *)pEvent)->name());
555 					szTmp = QString("Buffer%1").arg(iIdx);
556 					cfg.writeEntry(szTmp, ((KviKvsScriptEventHandler *)pEvent)->code());
557 					szTmp = QString("Enabled%1").arg(iIdx);
558 					cfg.writeEntry(szTmp, ((KviKvsScriptEventHandler *)pEvent)->isEnabled());
559 					iIdx++;
560 				}
561 			}
562 			cfg.writeEntry("NHandlers", iIdx);
563 		}
564 	}
565 }
566 
loadAppEvents(const QString & szFileName)567 void KviKvsEventManager::loadAppEvents(const QString & szFileName)
568 {
569 	KviConfigurationFile cfg(szFileName, KviConfigurationFile::Read);
570 	removeAllScriptAppHandlers();
571 
572 	for(size_t i = 0; i < KVI_KVS_NUM_APP_EVENTS; i++)
573 	{
574 		QString szEventName(m_appEventTable[i].name());
575 		// Backwards compatibility >_<
576 		if((i == 4) && !cfg.hasGroup(szEventName))
577 			szEventName = "OnIrcConnectionEstablished";
578 		if(cfg.hasGroup(szEventName))
579 		{
580 			cfg.setGroup(szEventName);
581 			unsigned int uHandlers = cfg.readUIntEntry("NHandlers", 0);
582 			if(uHandlers)
583 			{
584 				for(unsigned int uIdx = 0; uIdx < uHandlers; uIdx++)
585 				{
586 					QString szTmp = QString("Name%1").arg(uIdx);
587 					QString szName = cfg.readEntry(szTmp, "unnamed");
588 					szTmp = QString("Buffer%1").arg(uIdx);
589 					QString szCode = cfg.readEntry(szTmp, "");
590 					szTmp = QString("Enabled%1").arg(uIdx);
591 					bool bEnabled = cfg.readBoolEntry(szTmp, false);
592 					QString szCntx = QString("%1::%2").arg(m_appEventTable[i].name(), szName);
593 					KviKvsScriptEventHandler * pEvent = new KviKvsScriptEventHandler(szName, szCntx, szCode, bEnabled);
594 					m_appEventTable[i].addHandler(pEvent);
595 				}
596 			}
597 		}
598 	}
599 }
600 
saveAppEvents(const QString & szFileName)601 void KviKvsEventManager::saveAppEvents(const QString & szFileName)
602 {
603 	KviConfigurationFile cfg(szFileName, KviConfigurationFile::Write);
604 	cfg.clear();
605 	bool bCompat = false;
606 
607 	for(size_t i = 0; i < KVI_KVS_NUM_APP_EVENTS; i++)
608 	{
609 		if(m_appEventTable[i].hasHandlers())
610 		{
611 			QString szEventName(m_appEventTable[i].name());
612 			// Backwards compatibility >_<
613 			if((i == 4) && cfg.hasGroup(szEventName))
614 			{
615 				szEventName = "OnIRCConnectionEstablished";
616 				bCompat = true;
617 			}
618 			cfg.setGroup(szEventName);
619 			int iIdx = 0;
620 			for(KviKvsEventHandler * pEvent = m_appEventTable[i].handlers()->first(); pEvent; pEvent = m_appEventTable[i].handlers()->next())
621 			{
622 				if(pEvent->type() == KviKvsEventHandler::Script)
623 				{
624 					QString szTmp = QString("Name%1").arg(iIdx);
625 					cfg.writeEntry(szTmp, ((KviKvsScriptEventHandler *)pEvent)->name());
626 					szTmp = QString("Buffer%1").arg(iIdx);
627 					cfg.writeEntry(szTmp, ((KviKvsScriptEventHandler *)pEvent)->code());
628 					szTmp = QString("Enabled%1").arg(iIdx);
629 					cfg.writeEntry(szTmp, ((KviKvsScriptEventHandler *)pEvent)->isEnabled());
630 					iIdx++;
631 				}
632 			}
633 			cfg.writeEntry("NHandlers", iIdx);
634 
635 			// Backwards compatibility >_<
636 			if((i == 4) && !bCompat)
637 				i--;
638 		}
639 	}
640 }
641 
cleanHandlerName(QString & szHandlerName)642 void KviKvsEventManager::cleanHandlerName(QString & szHandlerName)
643 {
644 	static QRegExp re(KVI_KVS_EVENT_HANDLER_NAME_INVALID_CHARS_REG_EXP);
645 	szHandlerName.replace(re, "");
646 	if (szHandlerName.isEmpty())
647 		szHandlerName = "unnamed";
648 }
649