Fix settings_opt_set
authorMyhailo Danylenko <isbear@ukrpost.net>
Thu, 09 Aug 2012 00:17:37 +0300
changeset 45 1c28cf9dca25
parent 44 0e723147f836
child 46 13edc1a9f1e2
Fix settings_opt_set
add-offline-message.diff
templates.diff
--- 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: */