1 //=============================================================================
2 //
3 //   File : KviKvsCoreFunctions_sz.cpp
4 //   Creation date : Fri 31 Oct 2003 01:52:04 by Szymon Stefanek
5 //
6 //   This file is part of the KVIrc IRC client distribution
7 //   Copyright (C) 2003-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 "kvi_sourcesdate.h"
26 #include "kvi_socket.h"
27 #include "kvi_out.h"
28 #include "KviKvsCoreFunctions.h"
29 #include "KviKvsKernel.h"
30 #include "KviKvsArrayCast.h"
31 #include "KviKvsObjectController.h"
32 #include "KviWindow.h"
33 #include "KviLocale.h"
34 #include "KviApplication.h"
35 #include "KviOptions.h"
36 #include "KviChannelWindow.h"
37 #include "KviConsoleWindow.h"
38 #include "KviTimeUtils.h"
39 #include "KviIrcUserDataBase.h"
40 #include "KviModuleManager.h"
41 #include "KviControlCodes.h"
42 #include "KviBuildInfo.h"
43 
44 /*
45 	Data types:
46 
47 	<variant>
48 		<nothing>
49 		<scalar>
50 			<boolean>
51 			<string>
52 			<numeric>
53 				<integer>
54 				<real>
55 		<array>
56 		<hash>
57 		<object>
58 
59 	$isEmpty(<nothing>) == $true
60 
61 	<nothing> == <empty string>
62 	<null> == <null object>
63 
64 
65 */
66 
67 namespace KviKvsCoreFunctions
68 {
69 
70 	/*
71 		@doc: scriptContextName
72 		@type:
73 			function
74 		@title:
75 			$scriptContextName
76 		@short:
77 			Returns the actual script context's name..
78 		@syntax:
79 			<string> $scriptContextName()
80 		@description:
81 			Returns the actual script context's name. Useful only for custom debug.
82 		@seealso:
83 			[cmd]debug[/cmd]
84 	*/
85 
KVSCF(scriptContextName)86 	KVSCF(scriptContextName)
87 	{
88 		KVSCF_pRetBuffer->setString(KVSCF_pContext->script()->name());
89 		return true;
90 	}
91 
92 	/*
93 		@doc: selected
94 		@type:
95 			function
96 		@title:
97 			$selected
98 		@short:
99 			Returns the list of selected nicknames in the channel
100 		@syntax:
101 			<array> $selected
102 			<array> $selected(<window id:string>)
103 		@description:
104 			This is an internal alias for [fnc]$userlist.selected[/fnc].[br]
105 			This function is deprecated and its use is discouraged.
106 		@seealso:
107 			[fnc]$userlist.selected[/fnc]
108 	*/
109 
KVSCF(selected)110 	KVSCF(selected)
111 	{
112 		KviKvsScript::evaluate("$userlist.selected", KVSCF_pContext->window(), KVSCF_pParams, KVSCF_pRetBuffer);
113 		return true;
114 	}
115 
116 	/*
117 		@doc: sentBytes
118 		@type:
119 			function
120 		@title:
121 			$sentBytes
122 		@short:
123 			Returns total sent bytes
124 		@syntax:
125 			<uint> $sentBytes()
126 		@description:
127 			Returns total sent bytes
128 		@seealso:
129 			[fnc]$receivedBytes[/fnc]
130 	*/
131 
KVSCF(sentBytes)132 	KVSCF(sentBytes)
133 	{
134 		KVSCF_pRetBuffer->setInteger(g_uOutgoingTraffic);
135 		return true;
136 	}
137 
138 	/*
139 		@doc: serialize
140 		@type:
141 			function
142 		@title:
143 			$serialize
144 		@short:
145 			Encodes variable to JSON string
146 		@syntax:
147 			<string> $serialize(<data:mixed>)
148 		@description:
149 			Decodes JSON-encoded string
150 			$serialize() returns a string containing a byte-stream representation of value that can be stored anywhere.
151 		@seealso:
152 			[fnc]$unserialize[/fnc]
153 	*/
154 
KVSCF(serialize)155 	KVSCF(serialize)
156 	{
157 		KviKvsVariant * pVar = nullptr;
158 		QString szBuffer;
159 
160 		KVSCF_PARAMETERS_BEGIN
161 		KVSCF_PARAMETER("data", KVS_PT_VARIANT, 0, pVar)
162 		KVSCF_PARAMETERS_END
163 
164 		if(!pVar)
165 			return false;
166 		pVar->serialize(szBuffer);
167 		KVSCF_pRetBuffer->setString(szBuffer);
168 		return true;
169 	}
170 
171 	/*
172 		@doc: server
173 		@type:
174 			function
175 		@title:
176 			$server
177 		@short:
178 			Returns the current server name (if any)
179 		@syntax:
180 			<string> $server[(irc_context_id:uint)]
181 		@description:
182 			Returns the current server name of the specified IRC context.[br]
183 			If no <irc_context_id> is specified, the current IRC context is used.[br]
184 			If you are not connected to a server, this function will return an empty string.[br]
185 			If the current window does not belong to any IRC context and no irc_context_id
186 			is specified, this function prints a warning and also returns an empty string.[br]
187 	*/
188 
KVSCF(server)189 	KVSCF(server)
190 	{
191 		kvs_uint_t uCntx;
192 
193 		KVSCF_PARAMETERS_BEGIN
194 		KVSCF_PARAMETER("irc_context_id", KVS_PT_UINT, KVS_PF_OPTIONAL, uCntx)
195 		KVSCF_PARAMETERS_END
196 
197 		KviConsoleWindow * cns;
198 
199 		if(KVSCF_pParams->count() > 0)
200 		{
201 			cns = g_pApp->findConsole(uCntx);
202 			if(cns && (cns->context()->isConnected() || cns->context()->isLoggingIn()))
203 				KVSCF_pRetBuffer->setString(cns->connection()->currentServerName());
204 			else
205 				KVSCF_pRetBuffer->setNothing();
206 		}
207 		else
208 		{
209 			cns = KVSCF_pContext->window()->console();
210 			if(cns)
211 			{
212 				if(cns->context()->isConnected() || cns->context()->isLoggingIn())
213 					KVSCF_pRetBuffer->setString(cns->connection()->currentServerName());
214 				else
215 					KVSCF_pRetBuffer->setNothing();
216 			}
217 			else
218 			{
219 				KVSCF_pContext->warning(__tr2qs_ctx("This window has no associated IRC context", "kvs"));
220 				KVSCF_pRetBuffer->setNothing();
221 			}
222 		}
223 		return true;
224 	}
225 
226 	/*
227 		@doc: sort
228 		@type:
229 			function
230 		@title:
231 			$sort
232 		@short:
233 			Sorts an array
234 		@syntax:
235 			<array> $sort(<data:array>)
236 		@description:
237 			Sorts an array in ascending order.
238 		@seealso:
239 			[fnc]$rsort[/fnc]
240 	*/
241 
KVSCF(sort)242 	KVSCF(sort)
243 	{
244 		KviKvsArrayCast a;
245 
246 		KVSCF_PARAMETERS_BEGIN
247 		KVSCF_PARAMETER("data", KVS_PT_ARRAYCAST, 0, a)
248 		KVSCF_PARAMETERS_END
249 
250 		if(a.array())
251 		{
252 			KviKvsArray * arry = new KviKvsArray(*(a.array()));
253 			arry->sort();
254 			KVSCF_pRetBuffer->setArray(arry);
255 		}
256 		else
257 		{
258 			KVSCF_pRetBuffer->setArray(new KviKvsArray());
259 		}
260 		return true;
261 	}
262 
263 	/*
264 		@doc: string
265 		@type:
266 			function
267 		@title:
268 			$string
269 		@short:
270 			Casts a variable to a string
271 		@syntax:
272 			<integer> $string(<data:variant>)
273 		@description:
274 			Forces <data> to be a string data type with the following semantics:
275 			[ul]
276 				[li]If <data> is a string then <data> itself is returned.[/li]
277 				[li]If <data> is an integer then its decimal representation is returned.[/li]
278 				[li]If <data> is a real then its decimal floating-point representation is returned.[/li]
279 				[li]If <data> is a boolean then the string [b]1[/b] is returned for a true value and the string [b]0[/b] for a false value.[/li]
280 				[li]If <data> is nothing (unset) then an empty string is returned[/li]
281 				[li]If <data> is an array then a string with all the items converted to strings and separated by commas is returned[/li]
282 				[li]If <data> is a hash then a string with all the values converted to strings and separated by commas is returned[/li]
283 				[li]If <data> is a hobject then the string "object" is returned[/li]
284 			[/ul]
285 			Note that since KVIrc does most of the casting work automatically
286 			you shouldn't need to use this function.
287 		@seealso:
288 			[fnc]$real[/fnc]
289 			[fnc]$integer[/fnc]
290 	*/
291 
KVSCF(string)292 	KVSCF(string)
293 	{
294 		KviKvsVariant * v;
295 		KVSCF_PARAMETERS_BEGIN
296 		KVSCF_PARAMETER("data", KVS_PT_VARIANT, 0, v)
297 		KVSCF_PARAMETERS_END
298 
299 		QString szVal;
300 		v->asString(szVal);
301 		KVSCF_pRetBuffer->setString(szVal);
302 		return true;
303 	}
304 
305 	/*
306 		@doc: sw
307 		@type:
308 			function
309 		@title:
310 			$sw
311 		@short:
312 			Returns the value of a switch for an alias
313 		@syntax:
314 			<variant> $sw(<switch_name:string>[,<long_switch_name:string>])
315 		@description:
316 			This function is valid and useful only in aliases.
317 			It allows an alias to handle switches just like any other
318 			KVIrc command. If a switch in the form -<letter> was
319 			passed to the current alias then $sw(<letter>)
320 			returns 1 (true). If a switch in the form -<letter>=<value>
321 			was passed to the current alias then <value> is returned.
322 			If the switch was not present at all then this function
323 			returns an empty string (that evaluates to false in an expression).
324 			A warning is printed if this function is used non-alias code.
325 		@seealso:
326 			[fnc]$insideAlias[/fnc]
327 		@examples:
328 			[example]
329 				[cmd]alias[/cmd](test){
330 					if($sw(a,append)) [cmd]echo[/cmd] "Switch -a was passed"
331 					%x = $sw(x);
332 					if(%x) [cmd]echo[/cmd] "Switch -x=%x was passed"
333 				}
334 				test -a
335 				test -x
336 				test --append -x
337 				test -a -x
338 				test -a -x=test
339 				test -a=10 -x=test
340 			[/example]
341 	*/
342 
KVSCF(sw)343 	KVSCF(sw)
344 	{
345 		QString szSwitch;
346 		QString szLongSwitch;
347 
348 		KVSCF_PARAMETERS_BEGIN
349 		KVSCF_PARAMETER("switch_name", KVS_PT_STRING, 0, szSwitch)
350 		KVSCF_PARAMETER("long_name", KVS_PT_STRING, KVS_PF_OPTIONAL, szLongSwitch)
351 		KVSCF_PARAMETERS_END
352 
353 		KviKvsSwitchList * sl = KVSCF_pContext->aliasSwitchList();
354 		if(!sl)
355 		{
356 			KVSCF_pContext->warning(__tr2qs_ctx("The $sw() function can be used only in aliases", "kvs"));
357 			return true;
358 		}
359 
360 		KviKvsVariant * v;
361 
362 		if(szSwitch.length() > 1)
363 		{
364 			if(szLongSwitch.isEmpty())
365 				v = sl->find(szSwitch);
366 			else
367 				v = sl->find(szSwitch[0].unicode(), szLongSwitch);
368 		}
369 		else
370 		{
371 			if(szLongSwitch.isEmpty())
372 				v = sl->find(szSwitch[0]);
373 			else
374 				v = sl->find(szSwitch[0].unicode(), szLongSwitch);
375 		}
376 
377 		if(v)
378 			KVSCF_pRetBuffer->copyFrom(*v);
379 		else
380 			KVSCF_pRetBuffer->setNothing();
381 		return true;
382 	}
383 
384 	/*
385 		@doc: target
386 		@type:
387 			function
388 		@title:
389 			$target
390 		@short:
391 			Returns the target of the current window
392 		@syntax:
393 			<string> $target
394 			<string> $target(<window id>)
395 		@description:
396 			The form with the <window id> parameter returns the target
397 			of the channel,query or DCC that has the specified ID.
398 			The form without parameters returns the target of the current window,
399 			thus it is equivalent to calling $target([fnc]$window[/fnc]).
400 			For channel windows the target is the channel name,
401 			for query windows it is the list of the "queried" users, for the
402 			DCC windows it is the remote end of the connection.
403 			The other windows have an empty target.
404 		@examples:
405 			[example]
406 				[cmd]echo[/cmd] $target
407 			[/example]
408 		@seealso:
409 			[fnc]$window[/fnc],
410 			[fnc]$console[/fnc],
411 			[fnc]$channel[/fnc],
412 			[fnc]$query[/fnc],
413 			[doc:window_naming_conventions]Window naming conventions[/doc]
414 	*/
415 
KVSCF(target)416 	KVSCF(target)
417 	{
418 		QString winId;
419 		KVSCF_PARAMETERS_BEGIN
420 		KVSCF_PARAMETER("winId", KVS_PT_NONEMPTYSTRING, KVS_PF_OPTIONAL, winId)
421 		KVSCF_PARAMETERS_END
422 
423 		KviWindow * wnd = nullptr;
424 		if(KVSCF_pParams->count() > 0)
425 		{
426 			wnd = g_pApp->findWindow(winId.toUtf8().data());
427 			if(!wnd)
428 			{
429 				KVSCF_pContext->warning(__tr2qs_ctx("Window with ID '%s' not found, returning empty string", "kvs"), winId.toUtf8().data());
430 				KVSCF_pRetBuffer->setNothing();
431 				return true;
432 			}
433 		}
434 		else
435 		{
436 			wnd = KVSCF_pContext->window();
437 		}
438 
439 		//qDebug("CALLING $target on window %s",wnd->name());
440 		QString szTa = wnd->target();
441 
442 		KVSCF_pRetBuffer->setString(wnd->target());
443 		return true;
444 	}
445 
446 	/*
447 		@doc: this
448 		@type:
449 			function
450 		@title:
451 			$this
452 		@short:
453 			Retrieves the ID of the current object
454 		@syntax:
455 			$this
456 		@description:
457 			Returns the ID of the current object or [b]0[/b] if there is
458 			none. This function has a [i]quick[/i] version with syntax:
459 			[b]$$[/b][br]
460 	*/
461 
462 	/*
463 		@doc: $
464 		@type:
465 			function
466 		@title:
467 			$$
468 		@short:
469 			Retrieves the ID of the current object
470 		@syntax:
471 			$$
472 		@description:
473 			Returns the ID of the current object or [b]0[/b] if there is
474 			none. This function is equivalent to [fnc]$this[/fnc]
475 	*/
476 
KVSCF(thisCKEYWORDWORKAROUND)477 	KVSCF(thisCKEYWORDWORKAROUND)
478 	{
479 		// prologue: parameter handling
480 		KviKvsObject * o = KVSCF_pContext->thisObject();
481 		KVSCF_pRetBuffer->setHObject(o ? o->handle() : ((kvs_hobject_t) nullptr));
482 		return true;
483 	}
484 
485 	/*
486 		@doc: script_localization
487 		@type:
488 			generic
489 		@title:
490 			Localization of scripts
491 		@short:
492 			Explains how to add translation capabilities to your scripts
493 		@body:
494 			[big]Introduction[/big]
495 			Adding the translated versions of the strings adds a great
496 			value to your scripts. The process of translating a part of
497 			software is called localization. KVIrc offers some commands
498 			and functions for this purpose and this document explains
499 			briefly how to use them.
500 			[big]The big picture[/big]
501 			[br]
502 			All of the strings in your script are written in a [i]primary language[/i].
503 			The most common [i]primary language[/i] is English, but theoretically
504 			it can be any language of your choice.
505 			[br]
506 			By the means of the gettext package programs you extract
507 			the strings from your script and produce a translation file.
508 			[br]
509 			The translation file is then effectively translated in another
510 			language and later compiled in a binary form.
511 			[br]
512 			The binary form translations are then loaded in the KVIrc
513 			executable at runtime and a function is used to look up the
514 			translations.
515 			[big]How to translate scripts[/big]
516 			[br]
517 			Your strings should be surrounded by the [fnc]$tr[/fnc]() function in the following way:
518 			[example]
519 				[fnc]$tr[/fnc]("your default language text")
520 			[/example]
521 			[br]
522 			Then you should run the xgettext command on your script files.
523 			This is done by a shell commandline similar to the following:
524 			[example]
525 				xgettext -o myscript.pot -ktr mykvsfile1.kvs mykvsfile2.kvs ...
526 			[/example]
527 			[br]
528 			Copy the translation file obtained in the following way:
529 			[example]
530 				cp myscript.pot myscript_XX.po
531 			[/example]
532 			Where the XX is your country/language code. For example, for Italian
533 			it would be:
534 			[example]
535 				cp myscript.pot myscript_it.po
536 			[/example]
537 			[br]
538 			Translate mytranslation_it.po. The format of the po file is straightforward.
539 			There are msgid lines with the original English text and immediately
540 			following msgstr lines that must be filled with the corresponding translation.
541 			For example in Italian you would translate:[br]
542 			msgid "your default language text"
543 			msgstr "il tuo testo in linguaggio predefinito"
544 			[br]
545 			Compile your translation to binary form with the following command:
546 			[example]
547 				msgfmt -o myscript_it.mo myscript_it.po
548 			[/example]
549 			Copy the generated *.mo file to the [i]locale[/i] subdirectory
550 			in the KVIrc's local directory (usually $HOME/.kvirc/locale/).
551 			[br]
552 			Set the system language to the XX above with the following command:
553 			[example]
554 				export LANG="XX"
555 			[/example]
556 			For Italian it would be:
557 			[example]export LANG="it"[/example]
558 			[br]
559 			Start KVIrc and type in the commandline:
560 			[example]
561 				[cmd]echo[/cmd] [fnc]$tr[/fnc]("your default language text","myscript")
562 			[/example]
563 			If you did everything well, you should see the translated
564 			text echoed in the window :)[br]
565 			[br]
566 			Obviously if you don't set LANG="XX", the same command will
567 			output the original string unchanged.
568 			[br]
569 			You can manage translations in several languages by producing
570 			several *.mo files all with the proper language/country code appended.
571 			The right *.mo file will be magically loaded by KVIrc that
572 			will look up the user's LANG variable. (If you don't want
573 			to use LANG, you can use KVIRC_LANG instead, it will still work).
574 			[big]Caveats[/big]
575 			[br]
576 			You should [b]never[/b] use variables or identifiers inside the $tr() function.
577 			This because the translation files are generated offline,
578 			when the string is not evaluated yet (i.e variables ad identifiers
579 			are not substituted by their actual return values).
580 			The translation process, instead, happens at runtime, when
581 			the variables and identifiers have been substituted by their
582 			actual values. This would lead to a mismatch between the
583 			string you look up in the translation catalog and the
584 			effectively translated one. If you need to include variables
585 			in your strings you should compose the string with smaller pieces
586 			[example]
587 				[cmd]echo[/cmd] [fnc]$tr[/fnc]("On this channel") %number [fnc]$tr[/fnc]("users are operators")
588 			[/example]
589 			The translation process can be realized only if your
590 			scripts are written in external files. This makes sense since
591 			if you're translating the script then you will probably want to
592 			distribute it and the only way to distribute it is on files.
593 			But well.. this is a caveat.
594 	*/
595 
596 	/*
597 		@doc: tr
598 		@type:
599 			function
600 		@title:
601 			$tr
602 		@short:
603 			Translates an English string to the current language
604 		@syntax:
605 			<string> $tr(<default_language_string:string>[,<catalogue:string>])
606 		@description:
607 			This function searches for the translation of <default_language_string>
608 			in the specified translation <catalogue> or in the main
609 			KVIrc translation file if <catalogue> is omitted.[br]
610 			If no translation is found then <english_string> is returned.[br]
611 			<default_language_string> is a string in your script default
612 			language (which should probably be English since it is the
613 			most common language spoken by the translators).[br]
614 			If the <catalogue> is not loaded yet, KVIrc will attempt to load it,
615 			but only the first time that the catalogue is accessed (i.e. a load
616 			failure will cause the catalogue to be ignored completely until [cmd]trunload[/cmd]
617 			is explicitly used.[br]
618 			KVIrc will search the catalogue only in [fnc]$file.localdir[/fnc]/locale/
619 			and in [fnc]$file.globaldir[/fnc]/locale/. If your catalogues are
620 			in some other place then you must load them explicitly by the
621 			means of [cmd]trload[/cmd].
622 			For more information see the documentation about [doc:script_localization]script localization[/doc].
623 		@examples:
624 			[example]
625 				[cmd]echo[/cmd] $tr("Hello World!")
626 			[/example]
627 		@seealso:
628 			[cmd]trload[/cmd], [cmd]trunload[/cmd]
629 	*/
630 
KVSCF(tr)631 	KVSCF(tr)
632 	{
633 		// prologue: parameter handling
634 		QString szString;
635 		QString szCatalogue;
636 
637 		KVSCF_PARAMETERS_BEGIN
638 		KVSCF_PARAMETER("default_language_string", KVS_PT_STRING, 0, szString)
639 		KVSCF_PARAMETER("catalogue", KVS_PT_STRING, KVS_PF_OPTIONAL, szCatalogue)
640 		KVSCF_PARAMETERS_END
641 		if(szString.isEmpty())
642 			return true;
643 		// body: the real job
644 		QString translation;
645 
646 		if(!szCatalogue.isEmpty())
647 		{
648 			KviMessageCatalogue * pCat = KviLocale::instance()->getLoadedCatalogue(szCatalogue);
649 			if(pCat)
650 			{
651 				translation = pCat->translateToQString(szString.toUtf8().data());
652 			}
653 			else
654 			{
655 				// attempt to load it automatically
656 				QString szDir;
657 				g_pApp->getLocalKvircDirectory(szDir, KviApplication::Locale);
658 				if(!KviLocale::instance()->loadCatalogue(szCatalogue, szDir))
659 				{
660 					g_pApp->getGlobalKvircDirectory(szDir, KviApplication::Locale);
661 					KviLocale::instance()->loadCatalogue(szCatalogue, szDir);
662 				}
663 				// If the code above fails to load the catalogue
664 				// then __tr2qs_ctx_no_xgettext will place
665 				// a dummy catalogue in its place
666 				// This means that the next call to getLoadedCatalogue will
667 				// not fail unless /trunload is explicitly used
668 				// This will avoid trashing the user's disk too much
669 				// when a catalogue for a given language is not available
670 				translation = __tr2qs_ctx_no_xgettext(szString.toUtf8().data(), szCatalogue.toUtf8().data());
671 			}
672 		}
673 		else
674 		{
675 			translation = __tr2qs_no_xgettext(szString.toUtf8().data());
676 		}
677 
678 		// epilogue: set the return value
679 		KVSCF_pRetBuffer->setString(translation);
680 		return true;
681 	}
682 
683 	/*
684 		@doc: true
685 		@type:
686 			function
687 		@title:
688 			$true
689 		@short:
690 			The boolean true constant
691 		@syntax:
692 			<boolean> $true
693 		@description:
694 			Evaluates to the true boolean constant. True
695 			is equivalent to the integer 1 too. This function/constant
696 			is useful to keep your code readable: when you
697 			have a variable that can assume boolean values it's
698 			nicer to use $true and [fnc]$false[/fnc] instead of
699 			the integer constants 1 and 0. The reader will
700 			understand immediately that the variable simply can't
701 			assume any other value.
702 		@examples:
703 			[example]
704 				%a = $true
705 				[cmd]echo[/cmd] $typeof(%a)
706 				[cmd]echo[/cmd] $(%a + 1)
707 			[/example]
708 		@seealso:
709 			[fnc]$false[/fnc]
710 	*/
711 
KVSCF(trueCKEYWORDWORKAROUND)712 	KVSCF(trueCKEYWORDWORKAROUND)
713 	{
714 		KVSCF_pRetBuffer->setBoolean(true);
715 		return true;
716 	}
717 
718 	/*
719 		@doc: typeof
720 		@type:
721 			function
722 		@title:
723 			$typeof
724 		@short:
725 			Returns the internal data type of a variable
726 		@syntax:
727 			<string> $typeof(<data:variant>)
728 		@description:
729 			Returns the internal data type of the <data>.
730 		@examples:
731 			[example]
732 				[cmd]echo[/cmd] $typeof("test")
733 				%a = "test"
734 				[cmd]echo[/cmd] $typeof(%a)
735 				%a = 1
736 				[cmd]echo[/cmd] $typeof(%a)
737 				%a = $(1 + 2)
738 				[cmd]echo[/cmd] $typeof(%a)
739 				[cmd]echo[/cmd] $typeof($typeof(%a))
740 			[/example]
741 	*/
742 
KVSCF(typeofCKEYWORDWORKAROUND)743 	KVSCF(typeofCKEYWORDWORKAROUND)
744 	{
745 		KviKvsVariant * v;
746 
747 		KVSCF_PARAMETERS_BEGIN
748 		KVSCF_PARAMETER("data", KVS_PT_VARIANT, 0, v)
749 		KVSCF_PARAMETERS_END
750 
751 		QString szType;
752 		v->getTypeName(szType);
753 		KVSCF_pRetBuffer->setString(szType);
754 		return true;
755 	}
756 
757 	/*
758 		@doc: u
759 		@type:
760 			function
761 		@title:
762 			$u
763 		@short:
764 			Returns the UNDERLINE mIRC control character
765 		@syntax:
766 			<string> $u
767 		@description:
768 			Returns the UNDERLINE mIRC control character (Ctrl+U).[br]
769 		@seealso:
770 			[fnc]$k[/fnc], [fnc]$b[/fnc], [fnc]$i[/fnc], [fnc]$r[/fnc], [fnc]$o[/fnc]
771 	*/
772 
KVSCF(u)773 	KVSCF(u)
774 	{
775 		KVSCF_pRetBuffer->setString(QString(QChar(KviControlCodes::Underline)));
776 		return true;
777 	}
778 
779 	/*
780 		@doc: uflags
781 		@type:
782 			function
783 		@title:
784 			$uflags
785 		@short:
786 			Retrieves the user flags of a user
787 		@syntax:
788 			$uflags[(<nickname>[,<irc context id>])]
789 		@description:
790 			Returns the user flags of the user with <nickname>.[br]
791 			If the <nickname> is not given it is assumed to be the current nickname.[br]
792 			If this information is not known yet or the user with <nickname> is not found
793 			in the current IRC context user database, an empty string is returned.[br]
794 		@examples:
795 		@seealso:
796 	*/
797 
KVSCF(uflags)798 	KVSCF(uflags)
799 	{
800 		QString szNick;
801 		kvs_uint_t uContextId;
802 
803 		KVSCF_PARAMETERS_BEGIN
804 		KVSCF_PARAMETER("nickname", KVS_PT_STRING, KVS_PF_OPTIONAL, szNick)
805 		KVSCF_PARAMETER("context_id", KVS_PT_UINT, KVS_PF_OPTIONAL, uContextId)
806 		KVSCF_PARAMETERS_END
807 
808 		KviConsoleWindow * cons = nullptr;
809 		if(KVSCF_pParams->count() > 1)
810 		{
811 			cons = g_pApp->findConsole(uContextId);
812 			if(!cons)
813 				KVSCF_pContext->warning(__tr2qs_ctx("No such IRC context (%u)", "kvs"), uContextId);
814 		}
815 		else
816 		{
817 			cons = KVSCF_pContext->window()->console();
818 			if(!cons)
819 				KVSCF_pContext->warning(__tr2qs_ctx("This window is not associated to an IRC context", "kvs"));
820 		}
821 
822 		if(cons && cons->isConnected())
823 		{
824 			KviIrcUserEntry * e = cons->connection()->userDataBase()->find(szNick.isEmpty() ? cons->connection()->currentNickName() : szNick);
825 			if(e)
826 			{
827 				KVSCF_pRetBuffer->setString(e->userFlags());
828 				return true;
829 			}
830 		}
831 
832 		KVSCF_pRetBuffer->setNothing();
833 		return true;
834 	}
835 
836 	/*
837 		@doc: unicode
838 		@type:
839 			function
840 		@title:
841 			$unicode
842 		@short:
843 			Returns the Unicode code of a set of characters
844 		@syntax:
845 			<variant> $unicode(<char:string>)
846 		@description:
847 			If <char> is composed only of a single character
848 			then returns its Unicode code point as an integer.
849 			If <char> is composed of more than one character
850 			then an array of Unicode code points is returned.
851 		@seealso:
852 			[fnc]$cr[/fnc], [fnc]$lf[/fnc], [fnc]$char[/fnc]
853 	*/
854 
KVSCF(unicode)855 	KVSCF(unicode)
856 	{
857 		QString sz;
858 		KVSCF_PARAMETERS_BEGIN
859 		KVSCF_PARAMETER("char", KVS_PT_NONEMPTYSTRING, 0, sz)
860 		KVSCF_PARAMETERS_END
861 
862 		if(sz.length() > 1)
863 		{
864 			KviKvsArray * a = new KviKvsArray();
865 			for(auto&& c : sz)
866 				a->append(new KviKvsVariant((kvs_int_t)(c.unicode())));
867 			KVSCF_pRetBuffer->setArray(a);
868 		}
869 		else
870 		{
871 			KVSCF_pRetBuffer->setInteger((kvs_int_t)(sz[0].unicode()));
872 		}
873 		return true;
874 	}
875 
876 	/*
877 		@doc: unixtime
878 		@type:
879 			function
880 		@title:
881 			$unixTime
882 		@short:
883 			Returns the current UNIX time
884 		@syntax:
885 			<integer> $unixtime
886 		@description:
887 			Returns the time since the Epoch (00:00:00 UTC, January 1, 1970),
888 			measured in seconds.
889 		@seealso:
890 			[fnc]$date[/fnc], [fnc]$hpTimeStamp[/fnc]
891 	*/
892 
KVSCF(unixtime)893 	KVSCF(unixtime)
894 	{
895 		KVSCF_pRetBuffer->setInteger((kvs_int_t)(time(nullptr)));
896 		return true;
897 	}
898 
899 	/*
900 		@doc: unserialize
901 		@type:
902 			function
903 		@title:
904 			$unserialize
905 		@short:
906 			Decodes JSON-encoded string
907 		@syntax:
908 			<mixed> $unserialize(<data:string>)
909 		@description:
910 			Decodes JSON-encoded string
911 		@seealso:
912 			[fnc]$serialize[/fnc]
913 	*/
914 
KVSCF(unserialize)915 	KVSCF(unserialize)
916 	{
917 		QString szData;
918 
919 		KVSCF_PARAMETERS_BEGIN
920 		KVSCF_PARAMETER("data", KVS_PT_NONEMPTYSTRING, 0, szData)
921 		KVSCF_PARAMETERS_END
922 
923 		KviKvsVariant * pVar = KviKvsVariant::unserialize(szData);
924 		if(pVar)
925 		{
926 			KVSCF_pRetBuffer->copyFrom(pVar);
927 			delete pVar;
928 		}
929 		return true;
930 	}
931 
932 	/*
933 		@doc: username
934 		@type:
935 			function
936 		@title:
937 			$username
938 		@short:
939 			Returns the username of the specified user
940 		@syntax:
941 			<string> $username(<nickname:string>)
942 		@description:
943 			Returns the username of the specified IRC user IF it is known.[br]
944 			The username is known if [fnc]$isWellKnown[/fnc] returns 1.[br]
945 			The username is generally known if the user is on a channel with you
946 			or has an open query with you.[br]
947 			Detailed explanation:[br]
948 			KVIrc has an internal database of users that are currently
949 			visible by [i][b]this client[/b][/i]: this includes users on open channels
950 			and queries.[br] The other IRC users are [b]not[/b] in the database:
951 			this means that KVIrc knows NOTHING about them and can't return
952 			any information immediately. In this case this function will return
953 			an EMPTY string.[br]
954 			If a user is in the database, at least his nickname is known.[br]
955 			The username and hostname are known only if the server provides that information
956 			spontaneously or after a KVIrc request.[br]
957 			KVIrc requests user information for all the users in open queries
958 			and channels. This information takes some time to be retrieved,
959 			in this interval of time KVIrc knows only the user's nickname.
960 			This function will return the string "*" in this case.[br]
961 		@seealso:
962 			[fnc]$isWellKnown[/fnc], [fnc]$hostname[/fnc], [fnc]$realname[/fnc], [cmd]awhois[/cmd]
963 	*/
964 
KVSCF(username)965 	KVSCF(username)
966 	{
967 		QString szNick;
968 
969 		KVSCF_PARAMETERS_BEGIN
970 		KVSCF_PARAMETER("nick", KVS_PT_NONEMPTYSTRING, 0, szNick)
971 		KVSCF_PARAMETERS_END
972 
973 		KviConsoleWindow * c = KVSCF_pContext->window()->console();
974 		if(c && c->isConnected())
975 		{
976 			KviIrcUserEntry * e = KVSCF_pContext->window()->connection()->userDataBase()->find(szNick);
977 			if(e)
978 			{
979 				KVSCF_pRetBuffer->setString(e->user());
980 				return true;
981 			}
982 		}
983 
984 		KVSCF_pRetBuffer->setNothing();
985 		return true;
986 	}
987 
988 	/*
989 		@doc: version
990 		@type:
991 			function
992 		@title:
993 			$version
994 		@short:
995 			Returns information about the version of KVIrc.
996 		@syntax:
997 			<string> $version()
998 			<string> $version(<type:string>)
999 		@description:
1000 			Returns information about the version of the currently running KVIrc.[br]
1001 			Type can be one of:
1002 			[ul]
1003 			[li]a: return the application name[/li]
1004 			[li]b: return the build date in human readable form[/li]
1005 			[li]n: return the release name[/li]
1006 			[li]r: return the revision number[/li]
1007 			[li]s: return the current sources date[/li]
1008 			[li]v: return the current numeric version[/li]
1009 			[/ul]
1010 
1011 			If <type> is omitted a full string is returned.[br]
1012 		@examples:
1013 			[example]
1014 				[cmd]echo[/cmd] $version $version(r)
1015 			[/example]
1016 		@seealso:
1017 			[fnc]$features[/fnc]
1018 	*/
1019 
full_version_helper()1020 	static QString full_version_helper()
1021 	{
1022 		QString szVersion;
1023 
1024 		szVersion = "KVIrc";
1025 		szVersion += " " KVI_RELEASE_NAME " " KVI_VERSION;
1026 		szVersion += ", revision: ";
1027 		szVersion += KviBuildInfo::buildRevision();
1028 		szVersion += ", build type: ";
1029 		szVersion += KviBuildInfo::buildType();
1030 		szVersion += ", sources date: ";
1031 		szVersion += KviBuildInfo::buildSourcesDate();
1032 		szVersion += ", built on: ";
1033 		szVersion += KviBuildInfo::buildDate();
1034 
1035 		return szVersion;
1036 	}
1037 
KVSCF(version)1038 	KVSCF(version)
1039 	{
1040 		QString szType;
1041 
1042 		KVSCF_PARAMETERS_BEGIN
1043 		KVSCF_PARAMETER("type", KVS_PT_STRING, KVS_PF_OPTIONAL, szType)
1044 		KVSCF_PARAMETERS_END
1045 
1046 		if(szType.isEmpty())
1047 			KVSCF_pRetBuffer->setString(full_version_helper());
1048 		else
1049 		{
1050 			QString szRetValue;
1051 			if(szType.contains('b'))
1052 				szRetValue = KviBuildInfo::buildDate();
1053 			else if(szType.contains('a'))
1054 				szRetValue = "KVIrc";
1055 			else if(szType.contains('n'))
1056 				szRetValue = KVI_RELEASE_NAME;
1057 			else if(szType.contains('r'))
1058 				szRetValue = KviBuildInfo::buildRevision();
1059 			else if(szType.contains('s'))
1060 				szRetValue = KviBuildInfo::buildSourcesDate();
1061 			else if(szType.contains('t'))
1062 				szRetValue = KviBuildInfo::buildType();
1063 			else if(szType.contains('v'))
1064 				szRetValue = KVI_VERSION;
1065 			else
1066 				szRetValue = full_version_helper();
1067 
1068 			KVSCF_pRetBuffer->setString(szRetValue);
1069 		}
1070 		return true;
1071 	}
1072 
1073 	/*
1074 		@doc: window
1075 		@type:
1076 			function
1077 		@title:
1078 			$window
1079 		@short:
1080 			Retrieve the ID of a specified window.
1081 		@syntax:
1082 			<string> $window
1083 			<string> $window([<caption_text:hash>[,<context_id:uint>]])
1084 		@description:
1085 			Returns the [b]window ID[/b] of the first window that
1086 			has the specified <caption text>.[br]
1087 			If no window matches the specified <caption text>, an invalid
1088 			window ID is returned (0).[br]
1089 			If no <caption text> is specified, this function returns the ID
1090 			of the current window.[br]
1091 			<context_id> restricts search in only one IRC context.
1092 		@examples:
1093 			[example]
1094 				[cmd]echo[/cmd] This is the window with ID $window
1095 			[/example]
1096 		@seealso:
1097 			[fnc]$channel[/fnc],
1098 			[fnc]$query[/fnc],
1099 			[fnc]$console[/fnc],
1100 			[doc:window_naming_conventions]Window naming conventions[/doc]
1101 	*/
1102 
KVSCF(window)1103 	KVSCF(window)
1104 	{
1105 		//#warning "FIXME: the window identifiers could be numbers!"
1106 		QString szCaption;
1107 		kvs_int_t iContextId; // kvs_int_t is 64bit while int is 32 (and thus KVSCF_PARAMETER() crashes)
1108 
1109 		KVSCF_PARAMETERS_BEGIN
1110 		KVSCF_PARAMETER("caption_text", KVS_PT_STRING, KVS_PF_OPTIONAL, szCaption)
1111 		KVSCF_PARAMETER("context_id", KVS_PT_INTEGER, KVS_PF_OPTIONAL, iContextId)
1112 		KVSCF_PARAMETERS_END
1113 
1114 		KviWindow * pWnd = nullptr;
1115 		if(szCaption.isEmpty())
1116 		{
1117 			pWnd = KVSCF_pContext->window();
1118 		}
1119 		else
1120 		{
1121 			if(KVSCF_pParams->count() < 2)
1122 				iContextId = -1;
1123 
1124 			pWnd = g_pApp->findWindowByCaption(szCaption, iContextId);
1125 		}
1126 		KVSCF_pRetBuffer->setInteger(pWnd ? pWnd->numericId() : 0);
1127 		return true;
1128 	}
1129 };
1130