--- a/add-offline-message.diff Wed Aug 08 21:11:04 2012 +0300
+++ b/add-offline-message.diff Thu Aug 09 00:17:37 2012 +0300
@@ -4,7 +4,7 @@
diff -r 4401d3c453d3 mcabber/ChangeLog.api
--- a/mcabber/ChangeLog.api Wed Aug 08 14:31:24 2012 +0300
-+++ b/mcabber/ChangeLog.api Wed Aug 08 21:10:23 2012 +0300
++++ b/mcabber/ChangeLog.api Thu Aug 09 00:17:15 2012 +0300
@@ -1,3 +1,10 @@
+
+experimental (36)
@@ -18,7 +18,7 @@
diff -r 4401d3c453d3 mcabber/doc/help/cs/hlp.txt
--- a/mcabber/doc/help/cs/hlp.txt Wed Aug 08 14:31:24 2012 +0300
-+++ b/mcabber/doc/help/cs/hlp.txt Wed Aug 08 21:10:23 2012 +0300
++++ b/mcabber/doc/help/cs/hlp.txt Thu Aug 09 00:17:15 2012 +0300
@@ -3,4 +3,4 @@
Zobrazí nápovědu k příkazu nebo tématu.
@@ -27,7 +27,7 @@
+Dostupné příkazy jsou: add, alias, authorization, bind, buffer, chat_disable, clear, color, connect, del, disconnect, echo, event, exit, group, help, iline, info, module, move, msay, otr, otrpolicy, pgp, quit, rawxml, rename, request, room, roster, say_to, say, screen_refresh, set, source, status_to, status, version.
diff -r 4401d3c453d3 mcabber/doc/help/cs/hlp_disconnect.txt
--- a/mcabber/doc/help/cs/hlp_disconnect.txt Wed Aug 08 14:31:24 2012 +0300
-+++ b/mcabber/doc/help/cs/hlp_disconnect.txt Wed Aug 08 21:10:23 2012 +0300
++++ b/mcabber/doc/help/cs/hlp_disconnect.txt Thu Aug 09 00:17:15 2012 +0300
@@ -1,5 +1,6 @@
- /DISCONNECT
@@ -38,7 +38,7 @@
Poznámka: Seznam kontaktů (roster) je přístupný pouze v době, kdy je spojení aktivní. Po odpojení od serveru je proto prázdný.
diff -r 4401d3c453d3 mcabber/doc/help/cs/hlp_exit.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
-+++ b/mcabber/doc/help/cs/hlp_exit.txt Wed Aug 08 21:10:23 2012 +0300
++++ b/mcabber/doc/help/cs/hlp_exit.txt Thu Aug 09 00:17:15 2012 +0300
@@ -0,0 +1,5 @@
+
+ /EXIT [message]
@@ -47,7 +47,7 @@
+This command is the same as /QUIT, but you can specify status message to exit with.
diff -r 4401d3c453d3 mcabber/doc/help/de/hlp.txt
--- a/mcabber/doc/help/de/hlp.txt Wed Aug 08 14:31:24 2012 +0300
-+++ b/mcabber/doc/help/de/hlp.txt Wed Aug 08 21:10:23 2012 +0300
++++ b/mcabber/doc/help/de/hlp.txt Thu Aug 09 00:17:15 2012 +0300
@@ -3,4 +3,4 @@
Zeigt die Hilfe zu einem Befehl oder ein Thema an.
@@ -56,7 +56,7 @@
+Verfügbare Befehle: add, alias, authorization, bind, buffer, chat_disable, clear, color, connect, del, disconnect, echo, event, exit, group, help, iline, info, module, move, msay, otr, otrpolicy, pgp, quit, rawxml, rename, request, room, roster, say_to, say, screen_refresh, set, source, status_to, status, version.
diff -r 4401d3c453d3 mcabber/doc/help/de/hlp_disconnect.txt
--- a/mcabber/doc/help/de/hlp_disconnect.txt Wed Aug 08 14:31:24 2012 +0300
-+++ b/mcabber/doc/help/de/hlp_disconnect.txt Wed Aug 08 21:10:23 2012 +0300
++++ b/mcabber/doc/help/de/hlp_disconnect.txt Thu Aug 09 00:17:15 2012 +0300
@@ -1,5 +1,6 @@
- /DISCONNECT
@@ -67,7 +67,7 @@
Denke daran, dass der Roster nur verfügbar ist wenn man mit dem Jabber Server verbunden ist. Somit ist die Buddyliste auch leer, wenn man sich beim Server abmeldet.
diff -r 4401d3c453d3 mcabber/doc/help/de/hlp_exit.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
-+++ b/mcabber/doc/help/de/hlp_exit.txt Wed Aug 08 21:10:23 2012 +0300
++++ b/mcabber/doc/help/de/hlp_exit.txt Thu Aug 09 00:17:15 2012 +0300
@@ -0,0 +1,5 @@
+
+ /EXIT [message]
@@ -76,7 +76,7 @@
+This command is the same as /QUIT, but you can specify status message to exit with.
diff -r 4401d3c453d3 mcabber/doc/help/en/hlp.txt
--- a/mcabber/doc/help/en/hlp.txt Wed Aug 08 14:31:24 2012 +0300
-+++ b/mcabber/doc/help/en/hlp.txt Wed Aug 08 21:10:23 2012 +0300
++++ b/mcabber/doc/help/en/hlp.txt Thu Aug 09 00:17:15 2012 +0300
@@ -3,4 +3,4 @@
Display some help about a command or a topic.
@@ -85,7 +85,7 @@
+Available commands: add, alias, authorization, bind, buffer, chat_disable, clear, color, connect, del, disconnect, echo, event, exit, group, help, iline, info, module, move, msay, otr, otrpolicy, pgp, quit, rawxml, rename, request, room, roster, say_to, say, screen_refresh, set, source, status_to, status, version.
diff -r 4401d3c453d3 mcabber/doc/help/en/hlp_disconnect.txt
--- a/mcabber/doc/help/en/hlp_disconnect.txt Wed Aug 08 14:31:24 2012 +0300
-+++ b/mcabber/doc/help/en/hlp_disconnect.txt Wed Aug 08 21:10:23 2012 +0300
++++ b/mcabber/doc/help/en/hlp_disconnect.txt Thu Aug 09 00:17:15 2012 +0300
@@ -1,5 +1,6 @@
- /DISCONNECT
@@ -96,7 +96,7 @@
Note: the roster is only available when the connection to the server is active, so the buddylist is empty when disconnected.
diff -r 4401d3c453d3 mcabber/doc/help/en/hlp_exit.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
-+++ b/mcabber/doc/help/en/hlp_exit.txt Wed Aug 08 21:10:23 2012 +0300
++++ b/mcabber/doc/help/en/hlp_exit.txt Thu Aug 09 00:17:15 2012 +0300
@@ -0,0 +1,5 @@
+
+ /EXIT [message]
@@ -105,7 +105,7 @@
+This command is the same as /QUIT, but you can specify status message to exit with.
diff -r 4401d3c453d3 mcabber/doc/help/fr/hlp.txt
--- a/mcabber/doc/help/fr/hlp.txt Wed Aug 08 14:31:24 2012 +0300
-+++ b/mcabber/doc/help/fr/hlp.txt Wed Aug 08 21:10:23 2012 +0300
++++ b/mcabber/doc/help/fr/hlp.txt Thu Aug 09 00:17:15 2012 +0300
@@ -2,4 +2,4 @@
/HELP [commande|+sujet]
@@ -114,7 +114,7 @@
+Les commandes disponibles sont : add, alias, authorization, bind, buffer, chat_disable, clear, color, connect, del, disconnect, echo, event, exit, group, help, iline, info, module, move, msay, otr, otrpolicy, pgp, quit, rawxml, rename, request, room, roster, say_to, say, screen_refresh, set, source, status_to, status, version.
diff -r 4401d3c453d3 mcabber/doc/help/fr/hlp_disconnect.txt
--- a/mcabber/doc/help/fr/hlp_disconnect.txt Wed Aug 08 14:31:24 2012 +0300
-+++ b/mcabber/doc/help/fr/hlp_disconnect.txt Wed Aug 08 21:10:23 2012 +0300
++++ b/mcabber/doc/help/fr/hlp_disconnect.txt Thu Aug 09 00:17:15 2012 +0300
@@ -1,5 +1,6 @@
- /DISCONNECT
@@ -125,7 +125,7 @@
Remarque : le roster n'est disponible que lorsque la connexion au serveur estactive, donc la liste de contacts est vide après déconnexion.
diff -r 4401d3c453d3 mcabber/doc/help/fr/hlp_exit.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
-+++ b/mcabber/doc/help/fr/hlp_exit.txt Wed Aug 08 21:10:23 2012 +0300
++++ b/mcabber/doc/help/fr/hlp_exit.txt Thu Aug 09 00:17:15 2012 +0300
@@ -0,0 +1,5 @@
+
+ /EXIT [message]
@@ -134,7 +134,7 @@
+This command is the same as /QUIT, but you can specify status message to exit with.
diff -r 4401d3c453d3 mcabber/doc/help/it/hlp.txt
--- a/mcabber/doc/help/it/hlp.txt Wed Aug 08 14:31:24 2012 +0300
-+++ b/mcabber/doc/help/it/hlp.txt Wed Aug 08 21:10:23 2012 +0300
++++ b/mcabber/doc/help/it/hlp.txt Thu Aug 09 00:17:15 2012 +0300
@@ -3,4 +3,4 @@
Mostra l'help relativo a comando o ad argomento.
@@ -143,7 +143,7 @@
+I comandi disponibili sono: add, alias, authorization, bind, buffer, chat_disable, clear, color, connect, del, disconnect, echo, event, exit, group, help, iline, info, module, move, msay, otr, otrpolicy, pgp, quit, rawxml, rename, request, room, roster, say_to, say, screen_refresh, set, source, status_to, status, version.
diff -r 4401d3c453d3 mcabber/doc/help/it/hlp_disconnect.txt
--- a/mcabber/doc/help/it/hlp_disconnect.txt Wed Aug 08 14:31:24 2012 +0300
-+++ b/mcabber/doc/help/it/hlp_disconnect.txt Wed Aug 08 21:10:23 2012 +0300
++++ b/mcabber/doc/help/it/hlp_disconnect.txt Thu Aug 09 00:17:15 2012 +0300
@@ -1,5 +1,6 @@
- /DISCONNECT
@@ -154,7 +154,7 @@
Nota: il roster è disponibile soltanto quando la connessione è attiva, quindi la lista dei contatti è vuota quando si è disconnessi.
diff -r 4401d3c453d3 mcabber/doc/help/it/hlp_exit.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
-+++ b/mcabber/doc/help/it/hlp_exit.txt Wed Aug 08 21:10:23 2012 +0300
++++ b/mcabber/doc/help/it/hlp_exit.txt Thu Aug 09 00:17:15 2012 +0300
@@ -0,0 +1,5 @@
+
+ /EXIT [message]
@@ -163,7 +163,7 @@
+This command is the same as /QUIT, but you can specify status message to exit with.
diff -r 4401d3c453d3 mcabber/doc/help/nl/hlp.txt
--- a/mcabber/doc/help/nl/hlp.txt Wed Aug 08 14:31:24 2012 +0300
-+++ b/mcabber/doc/help/nl/hlp.txt Wed Aug 08 21:10:23 2012 +0300
++++ b/mcabber/doc/help/nl/hlp.txt Thu Aug 09 00:17:15 2012 +0300
@@ -3,4 +3,4 @@
Toon informatie over een commando of onderwerp.
@@ -172,7 +172,7 @@
+Beschikbare commando's: add, alias, authorization, bind, buffer, chat_disable, clear, color, connect, del, disconnect, echo, event, exit, group, help, iline, info, module, move, msay, otr, otrpolicy, pgp, quit, rawxml, rename, request, room, roster, say_to, say, screen_refresh, set, source, status_to, status, version.
diff -r 4401d3c453d3 mcabber/doc/help/nl/hlp_disconnect.txt
--- a/mcabber/doc/help/nl/hlp_disconnect.txt Wed Aug 08 14:31:24 2012 +0300
-+++ b/mcabber/doc/help/nl/hlp_disconnect.txt Wed Aug 08 21:10:23 2012 +0300
++++ b/mcabber/doc/help/nl/hlp_disconnect.txt Thu Aug 09 00:17:15 2012 +0300
@@ -1,5 +1,6 @@
- /DISCONNECT
@@ -183,7 +183,7 @@
NB: het Roster is alleen beschikbaar indien er een actieve verbinding met de server bestaat. De buddylijst is dus leeg indien niet verbonden.
diff -r 4401d3c453d3 mcabber/doc/help/nl/hlp_exit.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
-+++ b/mcabber/doc/help/nl/hlp_exit.txt Wed Aug 08 21:10:23 2012 +0300
++++ b/mcabber/doc/help/nl/hlp_exit.txt Thu Aug 09 00:17:15 2012 +0300
@@ -0,0 +1,5 @@
+
+ /EXIT [message]
@@ -192,7 +192,7 @@
+This command is the same as /QUIT, but you can specify status message to exit with.
diff -r 4401d3c453d3 mcabber/doc/help/pl/hlp.txt
--- a/mcabber/doc/help/pl/hlp.txt Wed Aug 08 14:31:24 2012 +0300
-+++ b/mcabber/doc/help/pl/hlp.txt Wed Aug 08 21:10:23 2012 +0300
++++ b/mcabber/doc/help/pl/hlp.txt Thu Aug 09 00:17:15 2012 +0300
@@ -3,4 +3,4 @@
Wyświetla pomoc dotyczącą danego polecenia lub tematu.
@@ -201,7 +201,7 @@
+Dostępne polecenia: add, alias, authorization, bind, buffer, chat_disable, clear, color, connect, del, disconnect, echo, event, exit, group, help, iline, info, module, move, msay, otr, otrpolicy, pgp, quit, rawxml, rename, request, room, roster, say_to, say, screen_refresh, set, source, status_to, status, version.
diff -r 4401d3c453d3 mcabber/doc/help/pl/hlp_disconnect.txt
--- a/mcabber/doc/help/pl/hlp_disconnect.txt Wed Aug 08 14:31:24 2012 +0300
-+++ b/mcabber/doc/help/pl/hlp_disconnect.txt Wed Aug 08 21:10:23 2012 +0300
++++ b/mcabber/doc/help/pl/hlp_disconnect.txt Thu Aug 09 00:17:15 2012 +0300
@@ -1,5 +1,6 @@
- /DISCONNECT
@@ -214,7 +214,7 @@
+Uwaga: roster dostępny jest tylko gdy połączenie do serwera jest aktywne, zatem jeżeli nie jesteś połączony lista kontaktów jest pusta.
diff -r 4401d3c453d3 mcabber/doc/help/pl/hlp_exit.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
-+++ b/mcabber/doc/help/pl/hlp_exit.txt Wed Aug 08 21:10:23 2012 +0300
++++ b/mcabber/doc/help/pl/hlp_exit.txt Thu Aug 09 00:17:15 2012 +0300
@@ -0,0 +1,5 @@
+
+ /EXIT [message]
@@ -223,7 +223,7 @@
+This command is the same as /QUIT, but you can specify status message to exit with.
diff -r 4401d3c453d3 mcabber/doc/help/ru/hlp.txt
--- a/mcabber/doc/help/ru/hlp.txt Wed Aug 08 14:31:24 2012 +0300
-+++ b/mcabber/doc/help/ru/hlp.txt Wed Aug 08 21:10:23 2012 +0300
++++ b/mcabber/doc/help/ru/hlp.txt Thu Aug 09 00:17:15 2012 +0300
@@ -3,4 +3,4 @@
Отображает файл помощи о запрошенной команде или топике.
@@ -232,7 +232,7 @@
+Допустимые команды: add, alias, authorization, bind, buffer, chat_disable, clear, color, connect, del, disconnect, echo, event, exit, group, help, iline, info, module, move, msay, otr, otrpolicy, pgp, quit, rawxml, rename, request, room, roster, say_to, say, screen_refresh, set, source, status_to, status, version.
diff -r 4401d3c453d3 mcabber/doc/help/ru/hlp_disconnect.txt
--- a/mcabber/doc/help/ru/hlp_disconnect.txt Wed Aug 08 14:31:24 2012 +0300
-+++ b/mcabber/doc/help/ru/hlp_disconnect.txt Wed Aug 08 21:10:23 2012 +0300
++++ b/mcabber/doc/help/ru/hlp_disconnect.txt Thu Aug 09 00:17:15 2012 +0300
@@ -1,5 +1,6 @@
- /DISCONNECT
@@ -243,7 +243,7 @@
Примечание: список контактов доступен только когда соединение с сервером активно, поэтому список контактов пуст при завершении соединения.
diff -r 4401d3c453d3 mcabber/doc/help/ru/hlp_exit.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
-+++ b/mcabber/doc/help/ru/hlp_exit.txt Wed Aug 08 21:10:23 2012 +0300
++++ b/mcabber/doc/help/ru/hlp_exit.txt Thu Aug 09 00:17:15 2012 +0300
@@ -0,0 +1,6 @@
+
+ /EXIT [сообщение]
@@ -253,7 +253,7 @@
+Отличается от /QUIT тем, что позволяет указать сообщение статуса при выходе.
diff -r 4401d3c453d3 mcabber/doc/help/uk/hlp.txt
--- a/mcabber/doc/help/uk/hlp.txt Wed Aug 08 14:31:24 2012 +0300
-+++ b/mcabber/doc/help/uk/hlp.txt Wed Aug 08 21:10:23 2012 +0300
++++ b/mcabber/doc/help/uk/hlp.txt Thu Aug 09 00:17:15 2012 +0300
@@ -3,4 +3,4 @@
Друкує допоміжну інформацію про команду або вираз.
@@ -262,7 +262,7 @@
+Наявні команди: add, alias, authorization, bind, buffer, chat_disable, clear, color, connect, del, disconnect, echo, event, exit, group, help, iline, info, module, move, msay, otr, otrpolicy, pgp, quit, rawxml, rename, request, room, roster, say_to, say, screen_refresh, set, source, status_to, status, version.
diff -r 4401d3c453d3 mcabber/doc/help/uk/hlp_disconnect.txt
--- a/mcabber/doc/help/uk/hlp_disconnect.txt Wed Aug 08 14:31:24 2012 +0300
-+++ b/mcabber/doc/help/uk/hlp_disconnect.txt Wed Aug 08 21:10:23 2012 +0300
++++ b/mcabber/doc/help/uk/hlp_disconnect.txt Thu Aug 09 00:17:15 2012 +0300
@@ -1,5 +1,6 @@
- /DISCONNECT
@@ -273,7 +273,7 @@
Майте на увазі, що список контактів зберігається на сервері, отож після від'єднання ви його більше не побачите.
diff -r 4401d3c453d3 mcabber/doc/help/uk/hlp_exit.txt
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
-+++ b/mcabber/doc/help/uk/hlp_exit.txt Wed Aug 08 21:10:23 2012 +0300
++++ b/mcabber/doc/help/uk/hlp_exit.txt Thu Aug 09 00:17:15 2012 +0300
@@ -0,0 +1,5 @@
+
+ /EXIT [повідомлення]
@@ -282,7 +282,7 @@
+Відмінність цієї команди від /QUIT у тому, що ви можете вказати повідомлення статусу відсутності.
diff -r 4401d3c453d3 mcabber/mcabber/api.h
--- a/mcabber/mcabber/api.h Wed Aug 08 14:31:24 2012 +0300
-+++ b/mcabber/mcabber/api.h Wed Aug 08 21:10:23 2012 +0300
++++ b/mcabber/mcabber/api.h Thu Aug 09 00:17:15 2012 +0300
@@ -3,8 +3,8 @@
#include <mcabber/config.h> // For MCABBER_BRANCH
@@ -296,7 +296,7 @@
diff -r 4401d3c453d3 mcabber/mcabber/commands.c
--- a/mcabber/mcabber/commands.c Wed Aug 08 14:31:24 2012 +0300
-+++ b/mcabber/mcabber/commands.c Wed Aug 08 21:10:23 2012 +0300
++++ b/mcabber/mcabber/commands.c Thu Aug 09 00:17:15 2012 +0300
@@ -94,6 +94,7 @@
static void do_otrpolicy(char *arg);
static void do_echo(char *arg);
@@ -332,7 +332,7 @@
+{
+ if (arg) {
+ char *message = to_utf8(arg);
-+ settings_opt_set("message_exit", message);
++ settings_set(SETTINGS_TYPE_OPTION, "message_exit", message);
+ g_free(message);
+ }
+ mcabber_set_terminate_ui();
@@ -341,7 +341,7 @@
/* vim: set expandtab cindent cinoptions=>2\:2(0 sw=2 ts=2: For Vim users... */
diff -r 4401d3c453d3 mcabber/mcabber/main.c
--- a/mcabber/mcabber/main.c Wed Aug 08 14:31:24 2012 +0300
-+++ b/mcabber/mcabber/main.c Wed Aug 08 21:10:23 2012 +0300
++++ b/mcabber/mcabber/main.c Thu Aug 09 00:17:15 2012 +0300
@@ -87,7 +87,7 @@
#ifndef MODULES_ENABLE
fifo_deinit();
@@ -362,7 +362,7 @@
#endif
diff -r 4401d3c453d3 mcabber/mcabber/settings.c
--- a/mcabber/mcabber/settings.c Wed Aug 08 14:31:24 2012 +0300
-+++ b/mcabber/mcabber/settings.c Wed Aug 08 21:10:23 2012 +0300
++++ b/mcabber/mcabber/settings.c Thu Aug 09 00:17:15 2012 +0300
@@ -398,6 +398,7 @@
break;
@@ -373,7 +373,7 @@
return rstatus;
diff -r 4401d3c453d3 mcabber/mcabber/xmpp.c
--- a/mcabber/mcabber/xmpp.c Wed Aug 08 14:31:24 2012 +0300
-+++ b/mcabber/mcabber/xmpp.c Wed Aug 08 21:10:23 2012 +0300
++++ b/mcabber/mcabber/xmpp.c Thu Aug 09 00:17:15 2012 +0300
@@ -885,7 +885,7 @@
static void _try_to_reconnect(void)
@@ -412,7 +412,7 @@
lm_connection_close(lconnection, NULL);
diff -r 4401d3c453d3 mcabber/mcabber/xmpp.h
--- a/mcabber/mcabber/xmpp.h Wed Aug 08 14:31:24 2012 +0300
-+++ b/mcabber/mcabber/xmpp.h Wed Aug 08 21:10:23 2012 +0300
++++ b/mcabber/mcabber/xmpp.h Thu Aug 09 00:17:15 2012 +0300
@@ -37,7 +37,7 @@
void xmpp_init(void); /* private */
@@ -424,7 +424,7 @@
void xmpp_room_join(const char *room, const char *nickname, const char *passwd);
diff -r 4401d3c453d3 mcabber/mcabberrc.example
--- a/mcabber/mcabberrc.example Wed Aug 08 14:31:24 2012 +0300
-+++ b/mcabber/mcabberrc.example Wed Aug 08 21:10:23 2012 +0300
++++ b/mcabber/mcabberrc.example Thu Aug 09 00:17:15 2012 +0300
@@ -357,11 +357,15 @@
#set message_dnd = Please do not disturb
#set message_notavail = I'm not available
--- a/templates.diff Wed Aug 08 21:11:04 2012 +0300
+++ b/templates.diff Thu Aug 09 00:17:37 2012 +0300
@@ -1,10 +1,10 @@
# HG changeset patch
-# Parent 9ad6f102a38b4e7b040f8efc311de6a2dda22805
+# Parent 5ccd3db13ba7f9636bb686af68df9f5b281d343d
[work-in-progress] Use templates for statusbars
-diff -r 9ad6f102a38b mcabber/CMakeLists.txt
---- a/mcabber/CMakeLists.txt Fri Aug 03 14:40:25 2012 +0300
-+++ b/mcabber/CMakeLists.txt Mon Aug 06 22:53:57 2012 +0300
+diff -r 5ccd3db13ba7 mcabber/CMakeLists.txt
+--- a/mcabber/CMakeLists.txt Wed Aug 08 21:10:27 2012 +0300
++++ b/mcabber/CMakeLists.txt Thu Aug 09 00:11:13 2012 +0300
@@ -154,8 +154,8 @@
## Define targets
@@ -16,9 +16,628 @@
xmpp xmpp_helper xmpp_iq xmpp_iqrequest xmpp_muc xmpp_s10n )
if ( NOT MODULES_ENABLE )
list ( APPEND mcabber_SUBSYSTEMS extcmd fifo )
-diff -r 9ad6f102a38b mcabber/mcabber/parser.c
+diff -r 5ccd3db13ba7 mcabber/mcabber/markup_parser.c
+--- /dev/null Thu Jan 01 00:00:00 1970 +0000
++++ b/mcabber/mcabber/markup_parser.c Thu Aug 09 00:11:13 2012 +0300
+@@ -0,0 +1,45 @@
++
++/* Copyright 2012 Myhailo Danylenko
++ *
++ * This file is part of mcabber
++ *
++ * mcabber 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 option) 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, see <http://www.gnu.org/licenses/>. */
++
++#include <glib.h>
++
++#include <ctype.h> // is*
++#include <stdlib.h> // strtol
++#include <string.h> // strchr
++
++#include "parser.h"
++
++#include "config.h"
++
++typedef gchar * ( * markup_chunk_callback_t ) ( gchar chunk, gpointer userdata );
++
++typedef struct markup_link_struct markup_link_t;
++struct markup_link_struct {
++ ...
++};
++
++//
++// Private types
++//
++
++
++markup_link_t * markup_expand ( const gchar *expansion, markup_chunk_callback_t get_chunk, gpointer userdata, GError ** error )
++{
++}
++
++/* vim: se ts=4 sw=4: */
+diff -r 5ccd3db13ba7 mcabber/mcabber/markup_parser.h
+--- /dev/null Thu Jan 01 00:00:00 1970 +0000
++++ b/mcabber/mcabber/markup_parser.h Thu Aug 09 00:11:13 2012 +0300
+@@ -0,0 +1,77 @@
++
++#ifndef MCABBER_PARSER_H
++#define MCABBER_PARSER_H
++
++/* Copyright 2012 Myhailo Danylenko
++ *
++ * This file is part of mcabber
++ *
++ * mcabber 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 option) 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, see <http://www.gnu.org/licenses/>. */
++
++#include <glib.h>
++
++#define TMPL_GERROR_QUARK tmpl_gerror_quark ()
++
++#define TMPL_EWRONGVAREXP ( 0x01 )
++#define TMPL_EWRONGVARNAME ( 0x03 )
++#define TMPL_EUNBALPAREN ( 0x04 )
++#define TMPL_EWRONGENDSTATE ( 0x02 )
++
++#define TMPL_EMATHWRONGARG ( 0x05 )
++#define TMPL_EMATHWRONGNUMBER ( 0x06 )
++#define TMPL_EMATHUNBALPAREN ( 0x07 )
++#define TMPL_EMATHWRONGOP ( 0x08 )
++#define TMPL_EMATHWRONGSTATE ( 0x09 )
++
++typedef const char *(*tmpl_variable_callback_t) ( const gchar *name, gsize len, gpointer udata, gsize *ret_len );
++
++GQuark tmpl_gerror_quark ( void );
++
++// match tmpl_glob ( string, pattern, right-to-left )
++// Performs matching of given pattern against given string,
++// returns substring, that matched. In pattern, there are currently
++// two tokens recognized: '*' and '?'. Two flags determine, if
++// '*' should be greedy and which end of string must match the
++// pattern (i.e. have anchor).
++const char *tmpl_glob ( const char *str, gsize strlen, const char *pat, gsize patlen, gboolean rtl, gsize *ret_len );
++
++// match tmpl_greedy_glob ( string, pattern, rigt-to-left )
++// The same, as above, but greedy.
++const char *tmpl_greedy_glob ( const char *str, gsize strlen, const char *pat, gsize patlen, gboolean rtl, gsize *ret_len );
++
++// result tmpl_math_expand ( string, callback )
++// Performs mathematical expansion of given string.
++// Note, that $var expressions are not recognized, you have to
++// supply already expanded string here.
++// Supported operators:
++// ( ) + - * / %
++gssize tmpl_math_expand ( const char *str, gsize len, tmpl_variable_callback_t get_val, gpointer udata, GError **error );
++
++// expansion tmpl_expand ( template, callback )
++// Parse template, substitute shell-like expressions:
++// * $var ${var}
++// * ${var##pat} ${var#pat} ${var%%pat} ${var%pat}
++// * ${var/pat} ${var/pat/repl} ${var//pat/repl} ${var/%pat/repl} ${var/#pat/repl}
++// * ${var:+tmpl} ${var:-tmpl}
++// * ${var:mathexp} ${var:mathexp:mathexp}
++// * ${#var} ${!var} ${!var[operation]}
++// * $(( mathexp ))
++// * \n \t \e \$ \\ \X
++// Callback will be called to obtain variable values.
++// Variable name should be: /^[[:alnum:]][[:alnum:]_-]*$/
++// For pattern rules see mms_glob ().
++gchar *tmpl_expand ( const char *template, gsize len, tmpl_variable_callback_t get_val, gpointer udata, gsize *ret_len, GError **error );
++
++# endif
++
+diff -r 5ccd3db13ba7 mcabber/mcabber/settings.c
+--- a/mcabber/mcabber/settings.c Wed Aug 08 21:10:27 2012 +0300
++++ b/mcabber/mcabber/settings.c Thu Aug 09 00:11:13 2012 +0300
+@@ -363,6 +363,32 @@
+ return 0;
+ }
+
++// settings_tmpl_set(option, value)
++// Sets option, escaping it for use in templates.
++// Could be more efficient with notifiers instead of guards.
++void settings_tmpl_set(const gchar *key, const gchar *value)
++{
++ if (value && *value) {
++ const gchar *p = strchr(value, '%');
++ if (p) {
++ GString *result = g_string_new(NULL);
++ const gchar *s = value;
++ while (p) {
++ g_string_append_len(result, s, p - s + 1);
++ g_string_append_c(result, '%');
++ s = ++ p;
++ p = strchr(s, '%');
++ }
++ if (*s)
++ g_string_append(result, s);
++ settings_set(SETTNIGS_TYPE_OPTION, key, result -> str);
++ g_string_free(result, TRUE);
++ return;
++ }
++ }
++ settings_set ( SETTNIGS_TYPE_OPTION, key, value );
++}
++
+ // settings_get_status_msg(status)
+ // Return a string with the current status message:
+ // - if there is a user-defined message ("message" option),
+diff -r 5ccd3db13ba7 mcabber/mcabber/settings.h
+--- a/mcabber/mcabber/settings.h Wed Aug 08 21:10:27 2012 +0300
++++ b/mcabber/mcabber/settings.h Thu Aug 09 00:11:13 2012 +0300
+@@ -37,6 +37,7 @@
+ void settings_opt_set_raw(const gchar *key, const gchar *value);
+ void settings_set(guint type, const gchar *key, const gchar *value);
+ void settings_del(guint type, const gchar *key);
++void settings_tmpl_set(const gchar *key, const gchar *value);
+ const gchar *settings_get(guint type, const gchar *key);
+ int settings_get_int(guint type, const gchar *key);
+ const gchar *settings_get_status_msg(enum imstatus status);
+diff -r 5ccd3db13ba7 mcabber/mcabber/templates.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
-+++ b/mcabber/mcabber/parser.c Mon Aug 06 22:53:57 2012 +0300
++++ b/mcabber/mcabber/templates.c Thu Aug 09 00:11:13 2012 +0300
+@@ -0,0 +1,390 @@
++
++/* Copyright 2012 Myhailo Danylenko
++ *
++ * This file is part of mcabber
++ *
++ * mcabber 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 option) 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, see <http://www.gnu.org/licenses/>. */
++
++#include <glib.h>
++
++#include <string.h> // strlen
++
++#include "logprint.h"
++#include "settings.h"
++#include "main.h" // main_context
++#include "templates.h"
++#include "parser.h"
++
++//
++// globals
++//
++
++typedef void (*tmpl_callback_t) ( const gchar * expansion, gpointer udata );
++typedef void (*tmpl_root_callback_t) ( const tmpl_link_struct_t * expansion, gpointer udata );
++
++typedef enum {
++ root_template, // fully processed $ and % templates
++ shortcut_template, // no-callback $-only but %-propagating templates
++ user_template, // $-only templates with callback
++} template_type_t;
++
++typedef struct {
++ gchar * name; // variable name
++ template_type_t type; // can be only one (for simplicity)
++ tmpl_callback_t callback; // for root it is %-callback, for user it is $-callback
++ gpointer userdata; // userdata for callback
++ GSList * guards; // $-guards
++ gboolean in_use; // to mark root templates for drop
++ gboolean changed; // $-changed flag
++ gboolean chunk_changed; // %-changed flag
++ gchar * expansion; // expansion of template
++ GSList * templates; // root templates, that use this chunk template // roots? :D
++ GSList * chunks; // chunk templates in use by this root template
++} template_t;
++
++typedef struct {
++ gchar * name;
++ GSList * templates;
++} tmpl_guard_t;
++
++typedef struct tmpl_link_struct tmpl_link_t;
++struct tmpl_link_struct {
++ tmpl_link_type_t type;
++ guint color;
++ gchar * string;
++ tmpl_link_t * next;
++};
++
++static GHashTable * tmpl_templates = NULL;
++static GHashTable * tmpl_guards = NULL;
++static guint tmpl_attached_id = 0;
++
++//
++// predeclarations
++//
++
++static gchar *tmpl_guard ( const gchar *key, const gchar *new_value );
++
++//
++// code
++//
++
++// [cb] drops template from guard's 'templates' list
++static void tmpl_unguard ( gpointer data, gpointer udata )
++{
++ tmpl_guard_t *guard = data;
++ template_t *template = udata;
++ guard -> templates = g_slist_remove ( guard -> templates, template );
++}
++
++// [cb] drops template from chunk's 'templates' list
++static void tmpl_unchunk ( gpointer data, gpointer udata )
++{
++ template_t * chunk = data;
++ template_t * template = udata;
++ chunk -> templates = g_slist_remove ( chunk -> templates, template );
++}
++
++// [destructor cb] releases guard hash table entry
++static void tmpl_free_guard ( gpointer data )
++{
++ tmpl_guard_t * guard = data;
++ settings_del_guard ( guard -> name );
++ g_slist_free ( guard -> templates );
++ g_free ( guard -> name );
++ g_slice_free ( tmpl_guard_t, guard );
++}
++
++// [destructor cb] releases taken guards and frees command
++static void tmpl_free_template ( gpointer data )
++{
++ template_t * template = data;
++ // not running unchunk, as it was done earlier
++ // or it is global destruction and chunk may no longer exist
++ g_slist_free ( template -> chunks );
++ g_slist_free ( template -> templates );
++ g_slist_foreach ( template -> guards, tmpl_unguard, template );
++ g_slist_free ( template -> guards );
++ g_free ( template -> name );
++ g_free ( template -> expansion );
++ g_slice_free ( template_t, template );
++}
++
++// [cb] sets changed flag on template
++static void template_set_changed ( gpointer data, gpointer udata )
++{
++ template_t * template = data;
++ template -> changed = TRUE;
++}
++
++// [cb] sets chunk_changed flag on template
++static void template_set_chunk_changed ( gpointer data, gpointer udata )
++{
++ template_t * template = data;
++ template -> chunk_changed = TRUE;
++}
++
++// install guard (name must be glib-allocated string)
++static void tmpl_install_guard ( gchar *name, template_t *template, settings_guard_t callback )
++{
++ tmpl_guard_t *guard = g_hash_table_lookup ( tmpl_guards, name );
++ if ( guard == NULL ) {
++ if ( ! settings_set_guard ( name, callback ) ) {
++ scr_log_print ( LPRINT_LOGNORM, "Error: Unable to install guard for variable '%s' for template '%s'.", name, template -> name );
++ g_free ( name );
++ } else {
++ guard = g_slice_new ( tmpl_guard_t );
++ guard -> name = name;
++ guard -> templates = NULL;
++ g_hash_table_replace ( tmpl_guards, guard -> name, guard ); // to be sure
++ }
++ } else
++ g_free ( name );
++ if ( ! g_slist_find ( template -> guards, guard ) ) {
++ template -> guards = g_slist_prepend ( template -> guards, guard );
++ guard -> templates = g_slist_prepend ( guard -> templates, template );
++ }
++}
++
++// [parser cb] provides mcabber option values & reinstalls guards
++static const char *tmpl_get_var ( const gchar *name, gsize len, gpointer udata, gsize *ret_len )
++{
++ const char *result = NULL;
++ if ( name != NULL && len > 0 ) {
++ template_t * template = udata;
++ gchar * var = g_strndup ( name, len );
++ result = settings_opt_get ( var );
++ // consumes var
++ tmpl_install_guard ( var, template, tmpl_guard );
++ }
++ if ( ret_len != NULL ) {
++ if ( result != NULL )
++ *ret_len = strlen ( result );
++ else
++ *ret_len = 0;
++ }
++ return result;
++}
++
++// [parser cb] FIXME
++static tmpl_link_t *tmpl_get_chunk ( const gchar name, gpointer udata )
++{
++ gchar * optname = g_strdup_printf ( "tmpl_%c", name );
++ template_t * root = udata;
++ template_t * chunk = g_hash_table_lookup ( templates, optname );
++ if ( chunk ) {
++ // check type
++ // link as dep
++ } else {
++ // create new
++ // consumes optname
++ //tmpl_install_guard ( optname, chunk, tmpl_guard );
++ // var_evaluate
++ }
++ // return value
++}
++
++// [cb]
++// drop dependencies for unused root templates,
++// update expansion of all $-changed templates,
++// reinstall guards,
++// mark dependencies as %-changed,
++// call $-callbacks
++static void evaluate_template1 ( gpointer key, gpointer value, gpointer udata )
++{
++ template_t * template = value;
++
++ if ( template -> changed && template -> in_use ) {
++ const gchar * expression = settings_opt_get ( template -> name );
++ gchar * expansion = NULL;
++ // release guards (but do not free them)
++ g_slist_foreach ( template -> guards, tmpl_unguard, template );
++ g_slist_free ( template -> guards );
++ template -> guards = NULL;
++ // re-install guards & get updated expansion
++ if ( expression != NULL ) {
++ GError *error = NULL;
++ expansion = tmpl_expand ( expression, strlen ( expression ), tmpl_get_var, template, NULL, &error );
++ if ( error != NULL ) {
++ scr_log_print ( LPRINT_LOGNORM, "Error: Expansion error on template '%s': %s.\nExpansion stopped at: '%s'", template -> name, error -> message, expansion );
++ g_error_free ( error );
++ g_free ( expansion );
++ expansion = NULL;
++ }
++ }
++ // re-install guard on template itself
++ tmpl_install_guard ( g_strdup ( template -> name ), template, tmpl_guard );
++ template -> changed = FALSE;
++ // check, if expansion has changed
++ if ( g_strcmp0 ( expansion, template -> expansion ) ) {
++ g_free ( template -> expansion );
++ template -> expansion = expansion;
++ if ( template -> type == user_template )
++ // pass result to callback
++ template -> callback ( expansion, template -> userdata );
++ else if ( template -> type == chunk_template )
++ // mark %-dependencies as %-changed
++ g_slist_foreach ( template -> templates, tmpl_set_chunk_changed, NULL );
++ else if ( template -> type == root_template )
++ // mark self as %-changed
++ template -> chunk_changed = TRUE;
++ else
++ g_assert_not_reached ();
++ } else
++ g_free ( expansion );
++ }
++}
++
++// [cb]
++// evaluate %-changed templates,
++// rebuild dependencies, call %-callbacks
++static void evaluate_template2 ( gpointer key, gpointer value, gpointer udata )
++{
++ template_t * template = value;
++
++ if ( template -> type == root_template ) {
++ if ( ! template -> in_use ) {
++ // release chunks
++ g_slist_foreach ( template -> chunks, tmpl_unchunk, template );
++ g_slist_free ( template -> chunks );
++ template -> chunks = NULL;
++ } else if ( template -> chunk_changed ) {
++ // release chunks
++ g_slist_foreach ( template -> chunks, tmpl_unchunk, template );
++ g_slist_free ( template -> chunks );
++ template -> chunks = NULL;
++ // evaluate template
++ GError * error = NULL;
++ template_link_t * expansion = tmpl_chunk_expand ( template -> expansion, tmpl_get_chunk, template, NULL, &error );
++ if ( error != NULL ) {
++ scr_log_print ( LPRINT_LOGNORM, "Error: Markup error on template '%s': %s.", template -> name, error -> message );
++ g_error_free ( error );
++ // XXX free result?
++ }
++ template -> callback ( result, template -> userdata );
++ }
++ }
++}
++
++// [cb] mark deleted templates for removal
++static gboolean tmpl_drop_unused_templates ( gpointer key, gpointer value, gpointer udata )
++{
++ template_t * template = value;
++ if ( template -> type == chunk_template )
++ // drop chunk templates with no dependent root templates
++ return template -> templates == NULL;
++ else
++ // drop user templates, marked as unused
++ return ! template -> in_use;
++}
++
++// [cb] mark unused guards for removal
++static gboolean tmpl_drop_unused_guards ( gpointer key, gpointer value, gpointer udata )
++{
++ tmpl_guard_t * guard = value;
++ if ( guard -> templates == NULL )
++ return TRUE;
++ return FALSE;
++}
++
++// [idle cb] update commands/guards & call cbs when necessary
++static gboolean reevaluate_templates ( gpointer data )
++{
++ // allow reschedule in a process of reevaluation
++ tmpl_attached_id = 0;
++ // release chunks of unused root templates, update expansion of $-changed templates, call $-callbacks
++ g_hash_table_foreach ( tmpl_templates, evaluate_template1, NULL );
++ // reevaluate %-changed templates, call %-callbacks
++ g_hash_table_foreach ( tmpl_templates, evaluate_template2, NULL );
++ // drop removed chunk-templates
++ g_hash_table_foreach_remove ( tmpl_templates, tmpl_drop_unused_templates, NULL );
++ // free unused guards TODO do only when needed
++ g_hash_table_foreach_remove ( tmpl_guards, tmpl_drop_unused_guards, NULL );
++ // always return false, this is oneshot idle call
++ return FALSE;
++}
++
++// schedule templates reevaluation
++static void tmpl_schedule_rerun ( void )
++{
++ if ( tmpl_attached_id == 0 ) {
++ GSource * source = g_idle_source_new ();
++ g_source_set_callback ( source, reevaluate_templates, NULL, NULL );
++ tmpl_attached_id = g_source_attach ( source, main_context );
++ g_source_unref ( source );
++ }
++}
++
++// [guard] generic guard for variable
++static gchar *tmpl_guard ( const gchar *key, const gchar *new_value )
++{
++ if ( g_strcmp0 ( new_value, settings_opt_get ( key ) ) ) {
++ // mark dependent commands as modified
++ tmpl_guard_t *guard = g_hash_table_lookup ( tmpl_guards, key );
++ g_slist_foreach ( guard -> templates, template_set_changed, NULL );
++ // schedule execution of modified commands
++ tmpl_schedule_rerun ();
++ }
++ return g_strdup ( new_value );
++}
++
++// public
++gboolean template_add ( const gchar * name, tmpl_callback_t callback, gpointer udata )
++{
++ g_assert ( name != NULL && callback != NULL );
++ // check for existing template
++ template_t * template = g_hash_table_lookup ( tmpl_templates, name );
++ if ( template != NULL )
++ return FALSE;
++ // create new
++ template = g_slice_new ( template_t );
++ template -> name = g_strdup ( name );
++ template -> callback = callback;
++ template -> userdata = udata;
++ template -> in_use = TRUE;
++ template -> guards = NULL;
++ template -> changed = TRUE;
++ template -> prev_expansion = NULL;
++ // schedule reevaluation
++ tmpl_schedule_rerun ();
++ return TRUE;
++}
++
++// public
++void template_set_in_use ( const gchar * name, gboolean in_use )
++{
++ g_assert ( name != NULL );
++ template_t * template = g_hash_table_lookup ( tmpl_templates, name );
++ g_assert ( template != NULL );
++ template -> in_use = in_use;
++}
++
++// private
++void templates_init ( void )
++{
++ // the key will be freed by destruction cb
++ tmpl_guards = g_hash_table_new_full ( g_str_hash, g_str_equal, NULL, tmpl_free_guard );
++ tmpl_templates = g_hash_table_new_full ( g_str_hash, g_str_equal, NULL, tmpl_free_template );
++}
++
++// private
++void templates_uninit ( void )
++{
++ if ( tmpl_attached_id != 0 )
++ g_source_remove ( tmpl_attached_id );
++ g_hash_table_destroy ( tmpl_templates );
++ g_hash_table_destroy ( tmpl_guards );
++}
++
++/* vim: se ts=4 sw=4: */
+diff -r 5ccd3db13ba7 mcabber/mcabber/templates.h
+--- /dev/null Thu Jan 01 00:00:00 1970 +0000
++++ b/mcabber/mcabber/templates.h Thu Aug 09 00:11:13 2012 +0300
+@@ -0,0 +1,44 @@
++
++/* Copyright 2012 Myhailo Danylenko
++ *
++ * This file is part of mcabber
++ *
++ * mcabber 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 option) 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, see <http://www.gnu.org/licenses/>. */
++
++#include <glib.h>
++
++// Type for template callback
++typedef void (*tmpl_callback_t) ( const gchar * expansion, gpointer udata );
++
++// success template_add ( option name, cb, cb udata )
++// Adds given mcabber option to list of watched templates.
++// If any option, used in that template (or template itself) will change,
++// callback will be called with new expansion of template.
++gboolean template_add ( const gchar * name, tmpl_callback_t callback, gpointer udata );
++
++// template_set_in_use ( option name, used flag )
++// Marks template as (un)used.
++// Note: Template will be actually removed only on next evaluation run,
++// though call to this function schedules such run. This way, you can
++// mark a bunch of templates as unused and then mark some of them as used.
++void template_set_in_use ( const gchar * name, gboolean in_use );
++
++// XXX do we need this?
++// void tmpl_schedule_rerun ( void );
++
++// private
++void templates_init ( void );
++void templates_uninit ( void );
++
++/* vim: se ts=4 sw=4: */
+diff -r 5ccd3db13ba7 mcabber/mcabber/var_parser.c
+--- /dev/null Thu Jan 01 00:00:00 1970 +0000
++++ b/mcabber/mcabber/var_parser.c Thu Aug 09 00:11:13 2012 +0300
@@ -0,0 +1,853 @@
+
+/* Copyright 2012 Myhailo Danylenko
@@ -44,7 +663,7 @@
+#include <stdlib.h> // strtol
+#include <string.h> // strchr
+
-+#include "parser.h"
++#include "var_parser.h"
+
+#include "config.h"
+
@@ -873,9 +1492,9 @@
+}
+
+/* vim: se ts=4 sw=4: */
-diff -r 9ad6f102a38b mcabber/mcabber/parser.h
+diff -r 5ccd3db13ba7 mcabber/mcabber/var_parser.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
-+++ b/mcabber/mcabber/parser.h Mon Aug 06 22:53:57 2012 +0300
++++ b/mcabber/mcabber/var_parser.h Thu Aug 09 00:11:13 2012 +0300
@@ -0,0 +1,77 @@
+
+#ifndef MCABBER_PARSER_H
@@ -954,470 +1573,3 @@
+
+# endif
+
-diff -r 9ad6f102a38b mcabber/mcabber/settings.c
---- a/mcabber/mcabber/settings.c Fri Aug 03 14:40:25 2012 +0300
-+++ b/mcabber/mcabber/settings.c Mon Aug 06 22:53:57 2012 +0300
-@@ -363,6 +363,32 @@
- return 0;
- }
-
-+// settings_tmpl_set(option, value)
-+// Sets option, escaping it for use in templates.
-+// Could be more efficient with notifiers instead of guards.
-+void settings_tmpl_set(const gchar *key, const gchar *value)
-+{
-+ if (value && *value) {
-+ const gchar *p = strchr(value, '%');
-+ if (p) {
-+ GString *result = g_string_new(NULL);
-+ const gchar *s = value;
-+ while (p) {
-+ g_string_append_len(result, s, p - s + 1);
-+ g_string_append_c(result, '%');
-+ s = ++ p;
-+ p = strchr(s, '%');
-+ }
-+ if (*s)
-+ g_string_append(result, s);
-+ settings_set(SETTNIGS_TYPE_OPTION, key, result -> str);
-+ g_string_free(result, TRUE);
-+ return;
-+ }
-+ }
-+ settings_set ( SETTNIGS_TYPE_OPTION, key, value );
-+}
-+
- // settings_get_status_msg(status)
- // Return a string with the current status message:
- // - if there is a user-defined message ("message" option),
-diff -r 9ad6f102a38b mcabber/mcabber/settings.h
---- a/mcabber/mcabber/settings.h Fri Aug 03 14:40:25 2012 +0300
-+++ b/mcabber/mcabber/settings.h Mon Aug 06 22:53:57 2012 +0300
-@@ -37,6 +37,7 @@
- void settings_opt_set_raw(const gchar *key, const gchar *value);
- void settings_set(guint type, const gchar *key, const gchar *value);
- void settings_del(guint type, const gchar *key);
-+void settings_tmpl_set(const gchar *key, const gchar *value);
- const gchar *settings_get(guint type, const gchar *key);
- int settings_get_int(guint type, const gchar *key);
- const gchar *settings_get_status_msg(enum imstatus status);
-diff -r 9ad6f102a38b mcabber/mcabber/templates.c
---- /dev/null Thu Jan 01 00:00:00 1970 +0000
-+++ b/mcabber/mcabber/templates.c Mon Aug 06 22:53:57 2012 +0300
-@@ -0,0 +1,368 @@
-+
-+/* Copyright 2012 Myhailo Danylenko
-+ *
-+ * This file is part of mcabber
-+ *
-+ * mcabber 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 option) 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, see <http://www.gnu.org/licenses/>. */
-+
-+#include <glib.h>
-+
-+#include <string.h> // strlen
-+
-+#include "logprint.h"
-+#include "settings.h"
-+#include "main.h" // main_context
-+#include "templates.h"
-+#include "parser.h"
-+
-+//
-+// globals
-+//
-+
-+typedef void (*tmpl_callback_t) ( const gchar * expansion, gpointer udata );
-+typedef void (*tmpl_root_callback_t) ( const tmpl_link_struct_t * expansion, gpointer udata );
-+
-+typedef enum {
-+ root_template, // fully processed $ and % templates
-+ shortcut_template, // no-callback $-only but %-propagating templates
-+ user_template, // $-only templates with callback
-+} template_type_t;
-+
-+typedef struct {
-+ gchar * name; // variable name
-+ template_type_t type; // can be only one (for simplicity)
-+ tmpl_callback_t callback; // for root it is %-callback, for user it is $-callback
-+ gpointer userdata; // userdata for callback
-+ GSList * guards; // $-guards
-+ gboolean in_use; // to mark root templates for drop
-+ gboolean changed; // $-changed flag
-+ gboolean chunk_changed; // %-changed flag
-+ gchar * expansion; // expansion of template
-+ GSList * templates; // root templates, that use this chunk template // roots? :D
-+ GSList * chunks; // chunk templates in use by this root template
-+} template_t;
-+
-+typedef struct {
-+ gchar * name;
-+ GSList * templates;
-+} tmpl_guard_t;
-+
-+typedef struct tmpl_link_struct tmpl_link_t;
-+struct tmpl_link_struct {
-+ tmpl_link_type_t type;
-+ guint color;
-+ gchar * string;
-+ tmpl_link_t * next;
-+};
-+
-+static GHashTable * tmpl_templates = NULL;
-+static GHashTable * tmpl_guards = NULL;
-+static guint tmpl_attached_id = 0;
-+
-+//
-+// predeclarations
-+//
-+
-+static gchar *tmpl_guard ( const gchar *key, const gchar *new_value );
-+
-+//
-+// code
-+//
-+
-+// [cb] drops template from guard's 'templates' list
-+static void tmpl_unguard ( gpointer data, gpointer udata )
-+{
-+ tmpl_guard_t *guard = data;
-+ template_t *template = udata;
-+ guard -> templates = g_slist_remove ( guard -> templates, template );
-+}
-+
-+// [cb] drops template from chunk's 'templates' list
-+static void tmpl_unchunk ( gpointer data, gpointer udata )
-+{
-+ template_t * chunk = data;
-+ template_t * template = udata;
-+ chunk -> templates = g_slist_remove ( chunk -> templates, template );
-+}
-+
-+// [destructor cb] releases guard hash table entry
-+static void tmpl_free_guard ( gpointer data )
-+{
-+ tmpl_guard_t * guard = data;
-+ settings_del_guard ( guard -> name );
-+ g_slist_free ( guard -> templates );
-+ g_free ( guard -> name );
-+ g_slice_free ( tmpl_guard_t, guard );
-+}
-+
-+// [destructor cb] releases taken guards and frees command
-+static void tmpl_free_template ( gpointer data )
-+{
-+ template_t * template = data;
-+ // not running unchunk, as it was done earlier
-+ // or it is global destruction and chunk may no longer exist
-+ g_slist_free ( template -> chunks );
-+ g_slist_free ( template -> templates );
-+ g_slist_foreach ( template -> guards, tmpl_unguard, template );
-+ g_slist_free ( template -> guards );
-+ g_free ( template -> name );
-+ g_free ( template -> expansion );
-+ g_slice_free ( template_t, template );
-+}
-+
-+// [cb] sets changed flag on template
-+static void template_set_changed ( gpointer data, gpointer udata )
-+{
-+ template_t * template = data;
-+ template -> changed = TRUE;
-+}
-+
-+// [cb] sets chunk_changed flag on template
-+static void template_set_chunk_changed ( gpointer data, gpointer udata )
-+{
-+ template_t * template = data;
-+ template -> chunk_changed = TRUE;
-+}
-+
-+// install guard (name must be glib-allocated string)
-+static void tmpl_install_guard ( gchar *name, template_t *template, settings_guard_t callback )
-+{
-+ tmpl_guard_t *guard = g_hash_table_lookup ( tmpl_guards, name );
-+ if ( guard == NULL ) {
-+ if ( ! settings_set_guard ( name, callback ) ) {
-+ scr_log_print ( LPRINT_LOGNORM, "Error: Unable to install guard for variable '%s' for template '%s'.", name, template -> name );
-+ g_free ( name );
-+ } else {
-+ guard = g_slice_new ( tmpl_guard_t );
-+ guard -> name = name;
-+ guard -> templates = NULL;
-+ g_hash_table_replace ( tmpl_guards, guard -> name, guard ); // to be sure
-+ }
-+ } else
-+ g_free ( name );
-+ if ( ! g_slist_find ( template -> guards, guard ) ) {
-+ template -> guards = g_slist_prepend ( template -> guards, guard );
-+ guard -> templates = g_slist_prepend ( guard -> templates, template );
-+ }
-+}
-+
-+// [parser cb] provides mcabber option values & reinstalls guards
-+static const char *tmpl_get_var ( const gchar *name, gsize len, gpointer udata, gsize *ret_len )
-+{
-+ const char *result = NULL;
-+ if ( name != NULL && len > 0 ) {
-+ template_t * template = udata;
-+ gchar * var = g_strndup ( name, len );
-+ result = settings_opt_get ( var );
-+ // consumes var
-+ tmpl_install_guard ( var, template, tmpl_guard );
-+ }
-+ if ( ret_len != NULL ) {
-+ if ( result != NULL )
-+ *ret_len = strlen ( result );
-+ else
-+ *ret_len = 0;
-+ }
-+ return result;
-+}
-+
-+// [cb]
-+// drop dependencies for unused root templates,
-+// update expansion of all $-changed templates,
-+// reinstall guards,
-+// mark dependencies as %-changed,
-+// call $-callbacks
-+static void evaluate_template1 ( gpointer key, gpointer value, gpointer udata )
-+{
-+ template_t * template = value;
-+
-+ if ( template -> changed && template -> in_use ) {
-+ const gchar * expression = settings_opt_get ( template -> name );
-+ gchar * expansion = NULL;
-+ // release guards (but do not free them)
-+ g_slist_foreach ( template -> guards, tmpl_unguard, template );
-+ g_slist_free ( template -> guards );
-+ template -> guards = NULL;
-+ // re-install guards & get updated expansion
-+ if ( expression != NULL ) {
-+ GError *error = NULL;
-+ expansion = tmpl_expand ( expression, strlen ( expression ), tmpl_get_var, template, NULL, &error );
-+ if ( error != NULL ) {
-+ scr_log_print ( LPRINT_LOGNORM, "Error: Expansion error on template '%s': %s.\nExpansion stopped at: '%s'", template -> name, error -> message, expansion );
-+ g_error_free ( error );
-+ g_free ( expansion );
-+ expansion = NULL;
-+ }
-+ }
-+ // re-install guard on template itself
-+ tmpl_install_guard ( g_strdup ( template -> name ), template, tmpl_guard );
-+ template -> changed = FALSE;
-+ // check, if expansion has changed
-+ if ( g_strcmp0 ( expansion, template -> expansion ) ) {
-+ g_free ( template -> expansion );
-+ template -> expansion = expansion;
-+ if ( template -> type == user_template )
-+ // pass result to callback
-+ template -> callback ( expansion, template -> userdata );
-+ else if ( template -> type == chunk_template )
-+ // mark %-dependencies as %-changed
-+ g_slist_foreach ( template -> templates, tmpl_set_chunk_changed, NULL );
-+ else if ( template -> type == root_template )
-+ // mark self as %-changed
-+ template -> chunk_changed = TRUE;
-+ else
-+ g_assert_not_reached ();
-+ } else
-+ g_free ( expansion );
-+ }
-+}
-+
-+// [cb]
-+// evaluate %-changed templates,
-+// rebuild dependencies, call %-callbacks
-+static void evaluate_template2 ( gpointer key, gpointer value, gpointer udata )
-+{
-+ template_t * template = value;
-+
-+ if ( template -> type == root_template ) {
-+ if ( ! template -> in_use ) {
-+ // release chunks
-+ g_slist_foreach ( template -> chunks, tmpl_unchunk, template );
-+ g_slist_free ( template -> chunks );
-+ template -> chunks = NULL;
-+ } else if ( template -> chun_changed ) {
-+ const char *expansion = template -> expansion;
-+ // release chunks
-+ g_slist_foreach ( template -> chunks, tmpl_unchunk, template );
-+ g_slist_free ( template -> chunks );
-+ template -> chunks = NULL;
-+ // evaluate template
-+ GError * error = NULL;
-+ template_link_t * result = tmpl_chunk_expand ( expansion, tmpl_get_chunk, template, NULL, &error );
-+ // FIXME
-+ }
-+ }
-+}
-+
-+// [cb] mark deleted templates for removal
-+static gboolean tmpl_drop_unused_templates ( gpointer key, gpointer value, gpointer udata )
-+{
-+ template_t * template = value;
-+ if ( template -> type == chunk_template )
-+ // drop chunk templates with no dependent root templates
-+ return template -> templates == NULL;
-+ else
-+ // drop user templates, marked as unused
-+ return ! template -> in_use;
-+}
-+
-+// [cb] mark unused guards for removal
-+static gboolean tmpl_drop_unused_guards ( gpointer key, gpointer value, gpointer udata )
-+{
-+ tmpl_guard_t * guard = value;
-+ if ( guard -> templates == NULL )
-+ return TRUE;
-+ return FALSE;
-+}
-+
-+// [idle cb] update commands/guards & call cbs when necessary
-+static gboolean reevaluate_templates ( gpointer data )
-+{
-+ // allow reschedule in a process of reevaluation
-+ tmpl_attached_id = 0;
-+ // release chunks of unused root templates, update expansion of $-changed templates, call $-callbacks
-+ g_hash_table_foreach ( tmpl_templates, evaluate_template1, NULL );
-+ // reevaluate %-changed templates, call %-callbacks
-+ g_hash_table_foreach ( tmpl_templates, evaluate_template2, NULL );
-+ // drop removed chunk-templates
-+ g_hash_table_foreach_remove ( tmpl_templates, tmpl_drop_unused_templates, NULL );
-+ // free unused guards TODO do only when needed
-+ g_hash_table_foreach_remove ( tmpl_guards, tmpl_drop_unused_guards, NULL );
-+ // always return false, this is oneshot idle call
-+ return FALSE;
-+}
-+
-+// schedule templates reevaluation
-+static void tmpl_schedule_rerun ( void )
-+{
-+ if ( tmpl_attached_id == 0 ) {
-+ GSource * source = g_idle_source_new ();
-+ g_source_set_callback ( source, reevaluate_templates, NULL, NULL );
-+ tmpl_attached_id = g_source_attach ( source, main_context );
-+ g_source_unref ( source );
-+ }
-+}
-+
-+// [guard] generic guard for variable
-+static gchar *tmpl_guard ( const gchar *key, const gchar *new_value )
-+{
-+ if ( g_strcmp0 ( new_value, settings_opt_get ( key ) ) ) {
-+ // mark dependent commands as modified
-+ tmpl_guard_t *guard = g_hash_table_lookup ( tmpl_guards, key );
-+ g_slist_foreach ( guard -> templates, template_set_changed, NULL );
-+ // schedule execution of modified commands
-+ tmpl_schedule_rerun ();
-+ }
-+ return g_strdup ( new_value );
-+}
-+
-+// public
-+gboolean template_add ( const gchar * name, tmpl_callback_t callback, gpointer udata )
-+{
-+ g_assert ( name != NULL && callback != NULL );
-+ // check for existing template
-+ template_t * template = g_hash_table_lookup ( tmpl_templates, name );
-+ if ( template != NULL )
-+ return FALSE;
-+ // create new
-+ template = g_slice_new ( template_t );
-+ template -> name = g_strdup ( name );
-+ template -> callback = callback;
-+ template -> userdata = udata;
-+ template -> in_use = TRUE;
-+ template -> guards = NULL;
-+ template -> changed = TRUE;
-+ template -> prev_expansion = NULL;
-+ // schedule reevaluation
-+ tmpl_schedule_rerun ();
-+ return TRUE;
-+}
-+
-+// public
-+void template_set_in_use ( const gchar * name, gboolean in_use )
-+{
-+ g_assert ( name != NULL );
-+ template_t * template = g_hash_table_lookup ( tmpl_templates, name );
-+ g_assert ( template != NULL );
-+ template -> in_use = in_use;
-+}
-+
-+// private
-+void templates_init ( void )
-+{
-+ // the key will be freed by destruction cb
-+ tmpl_guards = g_hash_table_new_full ( g_str_hash, g_str_equal, NULL, tmpl_free_guard );
-+ tmpl_templates = g_hash_table_new_full ( g_str_hash, g_str_equal, NULL, tmpl_free_template );
-+}
-+
-+// private
-+void templates_uninit ( void )
-+{
-+ if ( tmpl_attached_id != 0 )
-+ g_source_remove ( tmpl_attached_id );
-+ g_hash_table_destroy ( tmpl_templates );
-+ g_hash_table_destroy ( tmpl_guards );
-+}
-+
-+/* vim: se ts=4 sw=4: */
-diff -r 9ad6f102a38b mcabber/mcabber/templates.h
---- /dev/null Thu Jan 01 00:00:00 1970 +0000
-+++ b/mcabber/mcabber/templates.h Mon Aug 06 22:53:57 2012 +0300
-@@ -0,0 +1,44 @@
-+
-+/* Copyright 2012 Myhailo Danylenko
-+ *
-+ * This file is part of mcabber
-+ *
-+ * mcabber 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 option) 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, see <http://www.gnu.org/licenses/>. */
-+
-+#include <glib.h>
-+
-+// Type for template callback
-+typedef void (*tmpl_callback_t) ( const gchar * expansion, gpointer udata );
-+
-+// success template_add ( option name, cb, cb udata )
-+// Adds given mcabber option to list of watched templates.
-+// If any option, used in that template (or template itself) will change,
-+// callback will be called with new expansion of template.
-+gboolean template_add ( const gchar * name, tmpl_callback_t callback, gpointer udata );
-+
-+// template_set_in_use ( option name, used flag )
-+// Marks template as (un)used.
-+// Note: Template will be actually removed only on next evaluation run,
-+// though call to this function schedules such run. This way, you can
-+// mark a bunch of templates as unused and then mark some of them as used.
-+void template_set_in_use ( const gchar * name, gboolean in_use );
-+
-+// XXX do we need this?
-+// void tmpl_schedule_rerun ( void );
-+
-+// private
-+void templates_init ( void );
-+void templates_uninit ( void );
-+
-+/* vim: se ts=4 sw=4: */