[cmdopts,fix-memleak] Start to clean things a bit
authorMyhailo Danylenko <isbear@ukrpost.net>
Tue, 12 Mar 2013 01:23:02 +0200
changeset 76 3c8b784f92c7
parent 75 17cd00b2e722
child 77 7197414053c9
[cmdopts,fix-memleak] Start to clean things a bit * added fix-nickcolor-memleak.diff * changes to cmdopts.diff
cmdopts.diff
fix-nickcolor-memleak.diff
series
--- a/cmdopts.diff	Mon Mar 11 01:33:26 2013 +0200
+++ b/cmdopts.diff	Tue Mar 12 01:23:02 2013 +0200
@@ -1,5 +1,5 @@
 # HG changeset patch
-# Parent 92fa48ef53c909928706ab4c51518953339a38e4
+# Parent b527e88002781b92309dfd32d80f4e04170bb2cf
 [work-in-progress] Unified command option parsing
 
   * wrecking chaos all over the place
@@ -33,9 +33,9 @@
     * -j(--jid), -n(--name)
   * /rawxml uses parser
 
-diff -r 92fa48ef53c9 mcabber/doc/help/cs/hlp_buffer.txt
---- a/mcabber/doc/help/cs/hlp_buffer.txt	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/doc/help/cs/hlp_buffer.txt	Mon Mar 11 01:32:27 2013 +0200
+diff -r b527e8800278 mcabber/doc/help/cs/hlp_buffer.txt
+--- a/mcabber/doc/help/cs/hlp_buffer.txt	Mon Mar 11 21:45:31 2013 +0200
++++ b/mcabber/doc/help/cs/hlp_buffer.txt	Tue Mar 12 01:21:22 2013 +0200
 @@ -25,7 +25,7 @@
   Přesune se o [n] řádků nahoru (výchozí: polovina obrazovky).
  /buffer down [n]
@@ -45,18 +45,18 @@
   Přesune se na první řádek po datu [datum] (formát: "RRRR-mm-dd").
  /buffer % n
   Přesune se na procentuální pozici n%.
-diff -r 92fa48ef53c9 mcabber/doc/help/cs/hlp_del.txt
---- a/mcabber/doc/help/cs/hlp_del.txt	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/doc/help/cs/hlp_del.txt	Mon Mar 11 01:32:27 2013 +0200
+diff -r b527e8800278 mcabber/doc/help/cs/hlp_del.txt
+--- a/mcabber/doc/help/cs/hlp_del.txt	Mon Mar 11 21:45:31 2013 +0200
++++ b/mcabber/doc/help/cs/hlp_del.txt	Tue Mar 12 01:21:22 2013 +0200
 @@ -1,4 +1,4 @@
  
 - /DEL
 + /DEL [-n|--dryrun] [jid]
  
  Smaže aktuální kontakt ze seznamu kontaktů (rosteru) a zruší povolení oznamování o stavu daného kontaktu (autorizaci) na obou stranách.
-diff -r 92fa48ef53c9 mcabber/doc/help/cs/hlp_move.txt
---- a/mcabber/doc/help/cs/hlp_move.txt	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/doc/help/cs/hlp_move.txt	Mon Mar 11 01:32:27 2013 +0200
+diff -r b527e8800278 mcabber/doc/help/cs/hlp_move.txt
+--- a/mcabber/doc/help/cs/hlp_move.txt	Mon Mar 11 21:45:31 2013 +0200
++++ b/mcabber/doc/help/cs/hlp_move.txt	Tue Mar 12 01:21:22 2013 +0200
 @@ -1,5 +1,6 @@
  
 - /MOVE [skupina]
@@ -65,9 +65,9 @@
  Přesune aktuální kontakt do požadované skupiny. Není-li skupina zadána, přesune se kontakt do výchozí skupiny. Pokud skupina neexistuje, automaticky se založí.
 +You can select other buddy that current using options --jid and --name.
  Tip: V módu rozhovoru lze použít "/roster alternate" pro skok na přesunutý kontakt.
-diff -r 92fa48ef53c9 mcabber/doc/help/cs/hlp_rename.txt
---- a/mcabber/doc/help/cs/hlp_rename.txt	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/doc/help/cs/hlp_rename.txt	Mon Mar 11 01:32:27 2013 +0200
+diff -r b527e8800278 mcabber/doc/help/cs/hlp_rename.txt
+--- a/mcabber/doc/help/cs/hlp_rename.txt	Mon Mar 11 21:45:31 2013 +0200
++++ b/mcabber/doc/help/cs/hlp_rename.txt	Tue Mar 12 01:21:22 2013 +0200
 @@ -1,4 +1,6 @@
  
 - /RENAME jméno
@@ -77,9 +77,9 @@
 +Přejmenuje aktuálního uživatele nebo skupinu na 'jméno'.
 +If --reset is specified, "newname" is ignored and name will be reset to default - jid or username.
 +Optionally you can use one of --jid, --group or --name to select object, different from current.
-diff -r 92fa48ef53c9 mcabber/doc/help/de/hlp_buffer.txt
---- a/mcabber/doc/help/de/hlp_buffer.txt	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/doc/help/de/hlp_buffer.txt	Mon Mar 11 01:32:27 2013 +0200
+diff -r b527e8800278 mcabber/doc/help/de/hlp_buffer.txt
+--- a/mcabber/doc/help/de/hlp_buffer.txt	Mon Mar 11 21:45:31 2013 +0200
++++ b/mcabber/doc/help/de/hlp_buffer.txt	Tue Mar 12 01:21:22 2013 +0200
 @@ -25,7 +25,7 @@
   Scrollt den Puffer um n Zeilen hoch. Gibt man keine Zahl an, scrollt er um einen halben Bildschirm
  /buffer down [n]
@@ -89,18 +89,18 @@
   Springe zu der ersten Zeile nach dem Datum, welches im Format "JJJJ-mm-tt" anstatt [date] angegeben werden muss
  /buffer % n
   Springe zur Position "n" im Chatpuffer
-diff -r 92fa48ef53c9 mcabber/doc/help/de/hlp_del.txt
---- a/mcabber/doc/help/de/hlp_del.txt	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/doc/help/de/hlp_del.txt	Mon Mar 11 01:32:27 2013 +0200
+diff -r b527e8800278 mcabber/doc/help/de/hlp_del.txt
+--- a/mcabber/doc/help/de/hlp_del.txt	Mon Mar 11 21:45:31 2013 +0200
++++ b/mcabber/doc/help/de/hlp_del.txt	Tue Mar 12 01:21:22 2013 +0200
 @@ -1,4 +1,4 @@
  
 - /DEL
 + /DEL [-n|--dryrun] [jid]
  
  Löscht den gerade ausgewählten Buddy vom Roster. Außerdem werden die automatischen Presence Benachrichtigungen vom/zum Buddy gestoppt.
-diff -r 92fa48ef53c9 mcabber/doc/help/de/hlp_move.txt
---- a/mcabber/doc/help/de/hlp_move.txt	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/doc/help/de/hlp_move.txt	Mon Mar 11 01:32:27 2013 +0200
+diff -r b527e8800278 mcabber/doc/help/de/hlp_move.txt
+--- a/mcabber/doc/help/de/hlp_move.txt	Mon Mar 11 21:45:31 2013 +0200
++++ b/mcabber/doc/help/de/hlp_move.txt	Tue Mar 12 01:21:22 2013 +0200
 @@ -1,6 +1,7 @@
  
 - /MOVE [groupname]
@@ -110,9 +110,9 @@
 +You can select other buddy that current using options --jid and --name.
  
  Tipp: Wenn der Chatmodus aktiviert ist, kannst du "/roster alternate" benutzen um zu dem gerade bewegten Buddy zu springen.
-diff -r 92fa48ef53c9 mcabber/doc/help/de/hlp_rename.txt
---- a/mcabber/doc/help/de/hlp_rename.txt	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/doc/help/de/hlp_rename.txt	Mon Mar 11 01:32:27 2013 +0200
+diff -r b527e8800278 mcabber/doc/help/de/hlp_rename.txt
+--- a/mcabber/doc/help/de/hlp_rename.txt	Mon Mar 11 21:45:31 2013 +0200
++++ b/mcabber/doc/help/de/hlp_rename.txt	Tue Mar 12 01:21:22 2013 +0200
 @@ -1,4 +1,6 @@
  
 - /RENAME name
@@ -122,9 +122,9 @@
 +Setzt den Namen des gerade ausgewählten Buddys bzw. der ausgewählten Gruppe auf "name".
 +If --reset is specified, "newname" is ignored and name will be reset to default - jid or username.
 +Optionally you can use one of --jid, --group or --name to select object, different from current.
-diff -r 92fa48ef53c9 mcabber/doc/help/en/hlp_buffer.txt
---- a/mcabber/doc/help/en/hlp_buffer.txt	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/doc/help/en/hlp_buffer.txt	Mon Mar 11 01:32:27 2013 +0200
+diff -r b527e8800278 mcabber/doc/help/en/hlp_buffer.txt
+--- a/mcabber/doc/help/en/hlp_buffer.txt	Mon Mar 11 21:45:31 2013 +0200
++++ b/mcabber/doc/help/en/hlp_buffer.txt	Tue Mar 12 01:21:22 2013 +0200
 @@ -25,7 +25,7 @@
   Scroll the buffer up [n] lines (default: half a screen)
  /buffer down [n]
@@ -134,9 +134,9 @@
   Jump to the first line after the specified [date] in the chat buffer (date format: "YYYY-mm-dd")
  /buffer % n
   Jump to position %n of the buddy chat buffer
-diff -r 92fa48ef53c9 mcabber/doc/help/en/hlp_del.txt
---- a/mcabber/doc/help/en/hlp_del.txt	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/doc/help/en/hlp_del.txt	Mon Mar 11 01:32:27 2013 +0200
+diff -r b527e8800278 mcabber/doc/help/en/hlp_del.txt
+--- a/mcabber/doc/help/en/hlp_del.txt	Mon Mar 11 21:45:31 2013 +0200
++++ b/mcabber/doc/help/en/hlp_del.txt	Tue Mar 12 01:21:22 2013 +0200
 @@ -1,4 +1,4 @@
  
 - /DEL
@@ -144,9 +144,9 @@
  
 -Delete the current buddy from our roster, unsubscribe from its presence notification and unsubscribe it from ours.
 +Delete the current buddy or one, specified with [jid] from our roster, unsubscribe from its presence notification and unsubscribe it from ours.
-diff -r 92fa48ef53c9 mcabber/doc/help/en/hlp_move.txt
---- a/mcabber/doc/help/en/hlp_move.txt	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/doc/help/en/hlp_move.txt	Mon Mar 11 01:32:27 2013 +0200
+diff -r b527e8800278 mcabber/doc/help/en/hlp_move.txt
+--- a/mcabber/doc/help/en/hlp_move.txt	Mon Mar 11 21:45:31 2013 +0200
++++ b/mcabber/doc/help/en/hlp_move.txt	Tue Mar 12 01:21:22 2013 +0200
 @@ -1,5 +1,6 @@
  
 - /MOVE [groupname]
@@ -155,9 +155,9 @@
  Move the current buddy to the requested group.  If no group is specified, then the buddy is moved to the default group.  If the group "groupname" doesn't exist, it is created.
 +You can select other buddy that current using options --jid and --name.
  Tip: if the chatmode is enabled, you can use "/roster alternate" to jump to the moved buddy.
-diff -r 92fa48ef53c9 mcabber/doc/help/en/hlp_rename.txt
---- a/mcabber/doc/help/en/hlp_rename.txt	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/doc/help/en/hlp_rename.txt	Mon Mar 11 01:32:27 2013 +0200
+diff -r b527e8800278 mcabber/doc/help/en/hlp_rename.txt
+--- a/mcabber/doc/help/en/hlp_rename.txt	Mon Mar 11 21:45:31 2013 +0200
++++ b/mcabber/doc/help/en/hlp_rename.txt	Tue Mar 12 01:21:22 2013 +0200
 @@ -1,4 +1,6 @@
  
 - /RENAME name
@@ -167,9 +167,9 @@
 +Rename the current buddy or group to the given "newname".
 +If --reset is specified, "newname" is ignored and name will be reset to default - jid or username.
 +Optionally you can use one of --jid, --group or --name to select object, different from current.
-diff -r 92fa48ef53c9 mcabber/doc/help/fr/hlp_buffer.txt
---- a/mcabber/doc/help/fr/hlp_buffer.txt	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/doc/help/fr/hlp_buffer.txt	Mon Mar 11 01:32:27 2013 +0200
+diff -r b527e8800278 mcabber/doc/help/fr/hlp_buffer.txt
+--- a/mcabber/doc/help/fr/hlp_buffer.txt	Mon Mar 11 21:45:31 2013 +0200
++++ b/mcabber/doc/help/fr/hlp_buffer.txt	Tue Mar 12 01:21:22 2013 +0200
 @@ -25,7 +25,7 @@
   Défile vers le haut de [n] lignes (par défaut un demi écran)
  /buffer down [n]
@@ -179,18 +179,18 @@
   Va à la première ligne après la [date] dans le tampon actuel (format: "aaaa-mm-jj")
  /buffer % n
   Va à la position n% du tampon
-diff -r 92fa48ef53c9 mcabber/doc/help/fr/hlp_del.txt
---- a/mcabber/doc/help/fr/hlp_del.txt	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/doc/help/fr/hlp_del.txt	Mon Mar 11 01:32:27 2013 +0200
+diff -r b527e8800278 mcabber/doc/help/fr/hlp_del.txt
+--- a/mcabber/doc/help/fr/hlp_del.txt	Mon Mar 11 21:45:31 2013 +0200
++++ b/mcabber/doc/help/fr/hlp_del.txt	Tue Mar 12 01:21:22 2013 +0200
 @@ -1,4 +1,4 @@
  
 - /DEL
 + /DEL [-n|--dryrun] [jid]
  
  Supprime le contact sélectionné du roster, supprime notre abonnement à ses notifications de présence et supprime son abonnement aux nôtres.
-diff -r 92fa48ef53c9 mcabber/doc/help/fr/hlp_move.txt
---- a/mcabber/doc/help/fr/hlp_move.txt	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/doc/help/fr/hlp_move.txt	Mon Mar 11 01:32:27 2013 +0200
+diff -r b527e8800278 mcabber/doc/help/fr/hlp_move.txt
+--- a/mcabber/doc/help/fr/hlp_move.txt	Mon Mar 11 21:45:31 2013 +0200
++++ b/mcabber/doc/help/fr/hlp_move.txt	Tue Mar 12 01:21:22 2013 +0200
 @@ -1,5 +1,6 @@
  
 - /MOVE [groupname]
@@ -199,9 +199,9 @@
  Déplace le contact sélectionné vers le groupe spécifié. Si aucun groupe n'est donné, le contact est déplacé vers le groupe par défaut. Si le groupe "groupname" n'existe pas, il est créé.
 +You can select other buddy that current using options --jid and --name.
  Astuce : si le mode discussion (chatmode) est activé, vous pouvez utiliser "/roster alternate" pour vous positionner sur le contact que vous venez de déplacer.
-diff -r 92fa48ef53c9 mcabber/doc/help/fr/hlp_rename.txt
---- a/mcabber/doc/help/fr/hlp_rename.txt	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/doc/help/fr/hlp_rename.txt	Mon Mar 11 01:32:27 2013 +0200
+diff -r b527e8800278 mcabber/doc/help/fr/hlp_rename.txt
+--- a/mcabber/doc/help/fr/hlp_rename.txt	Mon Mar 11 21:45:31 2013 +0200
++++ b/mcabber/doc/help/fr/hlp_rename.txt	Tue Mar 12 01:21:22 2013 +0200
 @@ -1,4 +1,6 @@
  
 - /RENAME nom
@@ -211,9 +211,9 @@
 +Renomme le contact/groupe sélectionné avec le "nom" spécifié.
 +If --reset is specified, "newname" is ignored and name will be reset to default - jid or username.
 +Optionally you can use one of --jid, --group or --name to select object, different from current.
-diff -r 92fa48ef53c9 mcabber/doc/help/it/hlp_buffer.txt
---- a/mcabber/doc/help/it/hlp_buffer.txt	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/doc/help/it/hlp_buffer.txt	Mon Mar 11 01:32:27 2013 +0200
+diff -r b527e8800278 mcabber/doc/help/it/hlp_buffer.txt
+--- a/mcabber/doc/help/it/hlp_buffer.txt	Mon Mar 11 21:45:31 2013 +0200
++++ b/mcabber/doc/help/it/hlp_buffer.txt	Tue Mar 12 01:21:22 2013 +0200
 @@ -25,7 +25,7 @@
   Fa scorrere indietro il buffer di [n] linee (default: metà schermo)
  /buffer down [n]
@@ -223,18 +223,18 @@
   Salta alla prima linea successiva alla [data] specificata nel buffer di chat (formato della data: "YYYY-mm-dd")
  /buffer % n
   Salta alla posizione %n del buffer di chat corrente
-diff -r 92fa48ef53c9 mcabber/doc/help/it/hlp_del.txt
---- a/mcabber/doc/help/it/hlp_del.txt	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/doc/help/it/hlp_del.txt	Mon Mar 11 01:32:27 2013 +0200
+diff -r b527e8800278 mcabber/doc/help/it/hlp_del.txt
+--- a/mcabber/doc/help/it/hlp_del.txt	Mon Mar 11 21:45:31 2013 +0200
++++ b/mcabber/doc/help/it/hlp_del.txt	Tue Mar 12 01:21:22 2013 +0200
 @@ -1,4 +1,4 @@
  
 - /DEL
 + /DEL [-n|--dryrun] [jid]
  
  Elimina il contatto corrente dal roster, cancellando la sottoscrizione alle reciproche notifiche della propria presenza.
-diff -r 92fa48ef53c9 mcabber/doc/help/it/hlp_move.txt
---- a/mcabber/doc/help/it/hlp_move.txt	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/doc/help/it/hlp_move.txt	Mon Mar 11 01:32:27 2013 +0200
+diff -r b527e8800278 mcabber/doc/help/it/hlp_move.txt
+--- a/mcabber/doc/help/it/hlp_move.txt	Mon Mar 11 21:45:31 2013 +0200
++++ b/mcabber/doc/help/it/hlp_move.txt	Tue Mar 12 01:21:22 2013 +0200
 @@ -1,5 +1,6 @@
  
 - /MOVE [gruppo]
@@ -243,9 +243,9 @@
  Muove il contatto corrente nel gruppo richiesto. Se non viene specificato alcun gruppo, il contatto viene spostato nel gruppo si default. Se il gruppo "gruppo" non esiste, viene creato.
 +You can select other buddy that current using options --jid and --name.
  Trucco: se la modalità chat è abilitata, puoi usare "/roster alternate" per spostarti sul contatto appena mosso.
-diff -r 92fa48ef53c9 mcabber/doc/help/it/hlp_rename.txt
---- a/mcabber/doc/help/it/hlp_rename.txt	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/doc/help/it/hlp_rename.txt	Mon Mar 11 01:32:27 2013 +0200
+diff -r b527e8800278 mcabber/doc/help/it/hlp_rename.txt
+--- a/mcabber/doc/help/it/hlp_rename.txt	Mon Mar 11 21:45:31 2013 +0200
++++ b/mcabber/doc/help/it/hlp_rename.txt	Tue Mar 12 01:21:22 2013 +0200
 @@ -1,4 +1,6 @@
  
 - /RENAME nome
@@ -255,9 +255,9 @@
 +Rinomina il contatto od il gruppo correnti usando "nome".
 +If --reset is specified, "newname" is ignored and name will be reset to default - jid or username.
 +Optionally you can use one of --jid, --group or --name to select object, different from current.
-diff -r 92fa48ef53c9 mcabber/doc/help/nl/hlp_buffer.txt
---- a/mcabber/doc/help/nl/hlp_buffer.txt	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/doc/help/nl/hlp_buffer.txt	Mon Mar 11 01:32:27 2013 +0200
+diff -r b527e8800278 mcabber/doc/help/nl/hlp_buffer.txt
+--- a/mcabber/doc/help/nl/hlp_buffer.txt	Mon Mar 11 21:45:31 2013 +0200
++++ b/mcabber/doc/help/nl/hlp_buffer.txt	Tue Mar 12 01:21:22 2013 +0200
 @@ -25,7 +25,7 @@
   Scroll de buffer [n] regels omhoog (standaard: een half scherm)
  /buffer down [n]
@@ -267,18 +267,18 @@
   Spring naar de eerste regel na de aangeduide [datum] in de chat buffer (datum formaat: "YYYY-mm-dd")
  /buffer % n
   Spring naar positie %n in de buddy chat buffer
-diff -r 92fa48ef53c9 mcabber/doc/help/nl/hlp_del.txt
---- a/mcabber/doc/help/nl/hlp_del.txt	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/doc/help/nl/hlp_del.txt	Mon Mar 11 01:32:27 2013 +0200
+diff -r b527e8800278 mcabber/doc/help/nl/hlp_del.txt
+--- a/mcabber/doc/help/nl/hlp_del.txt	Mon Mar 11 21:45:31 2013 +0200
++++ b/mcabber/doc/help/nl/hlp_del.txt	Tue Mar 12 01:21:22 2013 +0200
 @@ -1,4 +1,4 @@
  
 - /DEL
 + /DEL [-n|--dryrun] [jid]
  
  Verwijder de actieve buddy uit ons roster, en zet het wederzijds toezenden van status veranderingen stop.
-diff -r 92fa48ef53c9 mcabber/doc/help/nl/hlp_move.txt
---- a/mcabber/doc/help/nl/hlp_move.txt	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/doc/help/nl/hlp_move.txt	Mon Mar 11 01:32:27 2013 +0200
+diff -r b527e8800278 mcabber/doc/help/nl/hlp_move.txt
+--- a/mcabber/doc/help/nl/hlp_move.txt	Mon Mar 11 21:45:31 2013 +0200
++++ b/mcabber/doc/help/nl/hlp_move.txt	Tue Mar 12 01:21:22 2013 +0200
 @@ -1,5 +1,6 @@
  
 - /MOVE [groepsnaam]
@@ -287,9 +287,9 @@
  Verplaats de actieve buddy naar de aangegeven groep.  Indien geen groep werd gespecificeerd wordt buddy verplaatst naar de standaard groep.  Indien de groep "groepsnaam" niet bestaat, wordt die eerst aangemaakt.
 +You can select other buddy that current using options --jid and --name.
  Tip: indien chatmode actief is, kun je "/roster alternate" gebruiken om direct naar de verplaatste buddy te springen.
-diff -r 92fa48ef53c9 mcabber/doc/help/nl/hlp_rename.txt
---- a/mcabber/doc/help/nl/hlp_rename.txt	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/doc/help/nl/hlp_rename.txt	Mon Mar 11 01:32:27 2013 +0200
+diff -r b527e8800278 mcabber/doc/help/nl/hlp_rename.txt
+--- a/mcabber/doc/help/nl/hlp_rename.txt	Mon Mar 11 21:45:31 2013 +0200
++++ b/mcabber/doc/help/nl/hlp_rename.txt	Tue Mar 12 01:21:22 2013 +0200
 @@ -1,4 +1,6 @@
  
 - /RENAME naam
@@ -299,18 +299,18 @@
 +Hernoem de actieve buddy of groep in de aangegeven "naam".
 +If --reset is specified, "newname" is ignored and name will be reset to default - jid or username.
 +Optionally you can use one of --jid, --group or --name to select object, different from current.
-diff -r 92fa48ef53c9 mcabber/doc/help/pl/hlp_del.txt
---- a/mcabber/doc/help/pl/hlp_del.txt	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/doc/help/pl/hlp_del.txt	Mon Mar 11 01:32:27 2013 +0200
+diff -r b527e8800278 mcabber/doc/help/pl/hlp_del.txt
+--- a/mcabber/doc/help/pl/hlp_del.txt	Mon Mar 11 21:45:31 2013 +0200
++++ b/mcabber/doc/help/pl/hlp_del.txt	Tue Mar 12 01:21:22 2013 +0200
 @@ -1,4 +1,4 @@
  
 - /DEL
 + /DEL [-n|--dryrun] [jid]
  
  Usuwa aktualnie zaznaczoną osobę z rostera, usuwa subskrypcję powiadomienia dostępności u danej osoby oraz u nas.
-diff -r 92fa48ef53c9 mcabber/doc/help/pl/hlp_move.txt
---- a/mcabber/doc/help/pl/hlp_move.txt	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/doc/help/pl/hlp_move.txt	Mon Mar 11 01:32:27 2013 +0200
+diff -r b527e8800278 mcabber/doc/help/pl/hlp_move.txt
+--- a/mcabber/doc/help/pl/hlp_move.txt	Mon Mar 11 21:45:31 2013 +0200
++++ b/mcabber/doc/help/pl/hlp_move.txt	Tue Mar 12 01:21:22 2013 +0200
 @@ -1,5 +1,6 @@
  
 - /MOVE [nazwa grupy]
@@ -319,9 +319,9 @@
  Przenosi aktualną osobę do grupy "nazwa grupy".  Jeśli nie podano nazwy grupy, wtedy osoba jest przenoszona do grupy domyślnej.  Jeśli grupa "nazwa grupy" nie istnieje, zostaje utworzona.
 +You can select other buddy that current using options --jid and --name.
  Podpowiedź: jeśli jest włączony tryb czatu, możesz użyć "/roster alternate" aby skoczyć do przeniesionej osoby.
-diff -r 92fa48ef53c9 mcabber/doc/help/pl/hlp_rename.txt
---- a/mcabber/doc/help/pl/hlp_rename.txt	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/doc/help/pl/hlp_rename.txt	Mon Mar 11 01:32:27 2013 +0200
+diff -r b527e8800278 mcabber/doc/help/pl/hlp_rename.txt
+--- a/mcabber/doc/help/pl/hlp_rename.txt	Mon Mar 11 21:45:31 2013 +0200
++++ b/mcabber/doc/help/pl/hlp_rename.txt	Tue Mar 12 01:21:22 2013 +0200
 @@ -1,4 +1,6 @@
  
 - /RENAME nazwa
@@ -331,9 +331,9 @@
 +Zmienia nazwę aktualnej osoby lub grupy na "nazwa". 
 +If --reset is specified, "newname" is ignored and name will be reset to default - jid or username.
 +Optionally you can use one of --jid, --group or --name to select object, different from current.
-diff -r 92fa48ef53c9 mcabber/doc/help/ru/hlp_buffer.txt
---- a/mcabber/doc/help/ru/hlp_buffer.txt	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/doc/help/ru/hlp_buffer.txt	Mon Mar 11 01:32:27 2013 +0200
+diff -r b527e8800278 mcabber/doc/help/ru/hlp_buffer.txt
+--- a/mcabber/doc/help/ru/hlp_buffer.txt	Mon Mar 11 21:45:31 2013 +0200
++++ b/mcabber/doc/help/ru/hlp_buffer.txt	Tue Mar 12 01:21:22 2013 +0200
 @@ -25,7 +25,7 @@
   Перемещает на [n] строк вверх в буфере (истории переписки) (по умолчанию: половина экрана)
  /buffer down [n]
@@ -343,9 +343,9 @@
   Перемещает в первой строке после определенной даты [date] в буфере (истории переписки) (формат даты: "год-месяц-день", для примера "2006-01-01")
  /buffer % n
   Перемещает на позицию %n в текущем буфере (истории переписки)
-diff -r 92fa48ef53c9 mcabber/doc/help/ru/hlp_del.txt
---- a/mcabber/doc/help/ru/hlp_del.txt	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/doc/help/ru/hlp_del.txt	Mon Mar 11 01:32:27 2013 +0200
+diff -r b527e8800278 mcabber/doc/help/ru/hlp_del.txt
+--- a/mcabber/doc/help/ru/hlp_del.txt	Mon Mar 11 21:45:31 2013 +0200
++++ b/mcabber/doc/help/ru/hlp_del.txt	Tue Mar 12 01:21:22 2013 +0200
 @@ -1,4 +1,4 @@
  
 - /DEL
@@ -353,9 +353,9 @@
  
 -Удаляет текущего пользователя из списка контактов, отключает уведомления о его статусе и отключает уведомления пользователя о вашем статусе.
 +Удаляет текущего пользователя (или указанного с помощью jid) из списка контактов, отключает уведомления о его статусе и отключает уведомление пользователя о вашем статусе.
-diff -r 92fa48ef53c9 mcabber/doc/help/ru/hlp_move.txt
---- a/mcabber/doc/help/ru/hlp_move.txt	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/doc/help/ru/hlp_move.txt	Mon Mar 11 01:32:27 2013 +0200
+diff -r b527e8800278 mcabber/doc/help/ru/hlp_move.txt
+--- a/mcabber/doc/help/ru/hlp_move.txt	Mon Mar 11 21:45:31 2013 +0200
++++ b/mcabber/doc/help/ru/hlp_move.txt	Tue Mar 12 01:21:22 2013 +0200
 @@ -1,6 +1,7 @@
  
 - /MOVE [groupname]
@@ -365,9 +365,9 @@
 +С помощью параметров --jid и --name можно перемещать контакты, отличные от текущего.
  Полезно: Если включен режим чата (chatmode), Вы можете использовать "/roster alternate" для перехода к перемещенному пользователю.
  
-diff -r 92fa48ef53c9 mcabber/doc/help/ru/hlp_rename.txt
---- a/mcabber/doc/help/ru/hlp_rename.txt	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/doc/help/ru/hlp_rename.txt	Mon Mar 11 01:32:27 2013 +0200
+diff -r b527e8800278 mcabber/doc/help/ru/hlp_rename.txt
+--- a/mcabber/doc/help/ru/hlp_rename.txt	Mon Mar 11 21:45:31 2013 +0200
++++ b/mcabber/doc/help/ru/hlp_rename.txt	Tue Mar 12 01:21:22 2013 +0200
 @@ -1,4 +1,6 @@
  
 - /RENAME name
@@ -377,9 +377,9 @@
 +Переименовывает текущего пользователя или группу в заданное имя "newname".
 +Если указан параметр --reset, "newname" игнорируется, а имя сбрасывается (mcabber будет отображать JID или имя пользователя по умолчанию).
 +Для указания обьекта, отличного от текущего, можно использовать опции --jid, --group и --name.
-diff -r 92fa48ef53c9 mcabber/doc/help/uk/hlp_buffer.txt
---- a/mcabber/doc/help/uk/hlp_buffer.txt	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/doc/help/uk/hlp_buffer.txt	Mon Mar 11 01:32:27 2013 +0200
+diff -r b527e8800278 mcabber/doc/help/uk/hlp_buffer.txt
+--- a/mcabber/doc/help/uk/hlp_buffer.txt	Mon Mar 11 21:45:31 2013 +0200
++++ b/mcabber/doc/help/uk/hlp_buffer.txt	Tue Mar 12 01:21:22 2013 +0200
 @@ -25,7 +25,7 @@
   Посунути буфер вверх на n рядків (якщо не вказано - пів екрану).
  /buffer down [n]
@@ -389,9 +389,9 @@
   Перейти до першого повідомлення після дати (дата вигляду РРРР-ММ-ДД).
  /buffer % процент
   Перейти до вказаної у процентах позиції.
-diff -r 92fa48ef53c9 mcabber/doc/help/uk/hlp_del.txt
---- a/mcabber/doc/help/uk/hlp_del.txt	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/doc/help/uk/hlp_del.txt	Mon Mar 11 01:32:27 2013 +0200
+diff -r b527e8800278 mcabber/doc/help/uk/hlp_del.txt
+--- a/mcabber/doc/help/uk/hlp_del.txt	Mon Mar 11 21:45:31 2013 +0200
++++ b/mcabber/doc/help/uk/hlp_del.txt	Tue Mar 12 01:21:22 2013 +0200
 @@ -1,4 +1,4 @@
  
 - /DEL
@@ -399,9 +399,9 @@
  
 -Потерти поточний контакт зі списку. На додачу відписатися від його повідомлень про статус і відписати його від ваших.
 +Потерти поточний контакт (або контакт, що має вказаний jid) зі списку. Також відписатися від його сповіщень про статус і відписати його від ваших.
-diff -r 92fa48ef53c9 mcabber/doc/help/uk/hlp_move.txt
---- a/mcabber/doc/help/uk/hlp_move.txt	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/doc/help/uk/hlp_move.txt	Mon Mar 11 01:32:27 2013 +0200
+diff -r b527e8800278 mcabber/doc/help/uk/hlp_move.txt
+--- a/mcabber/doc/help/uk/hlp_move.txt	Mon Mar 11 21:45:31 2013 +0200
++++ b/mcabber/doc/help/uk/hlp_move.txt	Tue Mar 12 01:21:22 2013 +0200
 @@ -1,5 +1,6 @@
  
 - /MOVE [група]
@@ -411,9 +411,9 @@
 +Переносить поточний контакт до вказаної групи. Якщо групу не вказати контакт опиниться у головній групі. Якщо групи не існує, її буде створено.
 +За допомогою опцій --jid та --name можна перемістити контакт, відмінний від поточного.
  Примітка: в режимі розмови можна використати "/roster alternate", щоб перейти до нового місця контакту контакту.
-diff -r 92fa48ef53c9 mcabber/doc/help/uk/hlp_rename.txt
---- a/mcabber/doc/help/uk/hlp_rename.txt	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/doc/help/uk/hlp_rename.txt	Mon Mar 11 01:32:27 2013 +0200
+diff -r b527e8800278 mcabber/doc/help/uk/hlp_rename.txt
+--- a/mcabber/doc/help/uk/hlp_rename.txt	Mon Mar 11 21:45:31 2013 +0200
++++ b/mcabber/doc/help/uk/hlp_rename.txt	Tue Mar 12 01:21:22 2013 +0200
 @@ -1,4 +1,6 @@
  
 - /RENAME ім'я
@@ -422,9 +422,9 @@
  Змінює прізвисько поточного контакту або назву групи.
 +За допомогою параметра --reset можна повернути контакту типову назву. При цьому нове ім’я (якщо вказане) ігнорується.
 +Опції --jid, --group та --name дозволяють перейменовувати об’єкти, відмінні від поточного.
-diff -r 92fa48ef53c9 mcabber/mcabber/commands.c
---- a/mcabber/mcabber/commands.c	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/mcabber/commands.c	Mon Mar 11 01:32:27 2013 +0200
+diff -r b527e8800278 mcabber/mcabber/commands.c
+--- a/mcabber/mcabber/commands.c	Mon Mar 11 21:45:31 2013 +0200
++++ b/mcabber/mcabber/commands.c	Tue Mar 12 01:21:22 2013 +0200
 @@ -19,7 +19,7 @@
   * USA
   */
@@ -434,7 +434,7 @@
  #include <stdlib.h>
  #include <sys/types.h>
  #include <sys/stat.h>
-@@ -43,512 +43,663 @@
+@@ -43,512 +43,671 @@
  #include "xmpp.h"
  #include "main.h"
  
@@ -462,11 +462,11 @@
 +
 +//static void room_bookmark(gpointer bud, char *arg);
 +
-+#define BUILTIN_COUNT 3
++#define BUILTIN_COUNT 4
 +static cmdopts_t def_roster,
 +                 def_color,
 +                 def_status,
-+                 def_status_to,
++                 def_status_to;
 +#if 0
 +                 def_add,
 +                 def_del,
@@ -500,9 +500,9 @@
 +                 def_otrpolicy,
 +                 def_echo,
 +                 def_module,
-+                 def_exit
++                 def_exit;
  #endif
--
+ 
 -// Return value container for the following functions
 -static int retval_for_cmds;
 -
@@ -555,48 +555,45 @@
 -#include "modules.h"
 -
 -gpointer cmd_del(gpointer id)
-+                 ;
-+
-+static cmd_handler_t do_roster,
-+                     do_color,
-+                     do_status,
-+                     do_status_to,
++static gchar *do_roster    (cmdopts_t *command);
++static gchar *do_color     (cmdopts_t *command);
++static gchar *do_status    (cmdopts_t *command);
++static gchar *do_status_to (cmdopts_t *command);
 +#if 0
-+                     do_add,
-+                     do_del,
-+                     do_group,
-+                     do_say,
-+                     do_msay,
-+                     do_say_to,
-+                     do_buffer,
-+                     do_clear,
-+                     do_info,
-+                     do_rename,
-+                     do_move,
-+                     do_set,
-+                     do_alias,
-+                     do_bind,
-+                     do_connect,
-+                     do_disconnect,
-+                     do_rawxml,
-+                     do_room,
-+                     do_authorization,
-+                     do_version,
-+                     do_request,
-+                     do_event,
-+                     do_help,
-+                     do_pgp,
-+                     do_iline,
-+                     do_screen_refresh,
-+                     do_chat_disable,
-+                     do_source,
-+                     do_otr,
-+                     do_otrpolicy,
-+                     do_echo,
-+                     do_module,
-+                     do_exit
++static gchar *do_add (cmdopts_t *command);
++static gchar *do_del (cmdopts_t *command);
++static gchar *do_group (cmdopts_t *command);
++static gchar *do_say (cmdopts_t *command);
++static gchar *do_msay (cmdopts_t *command);
++static gchar *do_say_to (cmdopts_t *command);
++static gchar *do_buffer (cmdopts_t *command);
++static gchar *do_clear (cmdopts_t *command);
++static gchar *do_info (cmdopts_t *command);
++static gchar *do_rename (cmdopts_t *command);
++static gchar *do_move (cmdopts_t *command);
++static gchar *do_set (cmdopts_t *command);
++static gchar *do_alias (cmdopts_t *command);
++static gchar *do_bind (cmdopts_t *command);
++static gchar *do_connect (cmdopts_t *command);
++static gchar *do_disconnect (cmdopts_t *command);
++static gchar *do_rawxml (cmdopts_t *command);
++static gchar *do_room (cmdopts_t *command);
++static gchar *do_authorization (cmdopts_t *command);
++static gchar *do_version (cmdopts_t *command);
++static gchar *do_request (cmdopts_t *command);
++static gchar *do_event (cmdopts_t *command);
++static gchar *do_help (cmdopts_t *command);
++static gchar *do_pgp (cmdopts_t *command);
++static gchar *do_iline (cmdopts_t *command);
++static gchar *do_screen_refresh (cmdopts_t *command);
++static gchar *do_chat_disable (cmdopts_t *command);
++static gchar *do_source (cmdopts_t *command);
++static gchar *do_otr (cmdopts_t *command);
++static gchar *do_otrpolicy (cmdopts_t *command);
++static gchar *do_echo (cmdopts_t *command);
++static gchar *do_module (cmdopts_t *command);
++static gchar *do_exit (cmdopts_t *command);
 +#endif
-+                     ;
 +
 +//
 +//  Main commands mechanics
@@ -620,11 +617,12 @@
 -      compl_del_category_word(COMPL_CMD, command->name);
 -      g_slice_free(cmd, command);
 -      return userdata;
-+  cmd_list = g_new ((cmdopts_t *), BUILTIN_COUNT+1);
-+  cmd_list[0]  = def_roster;
-+  cmd_list[1]  = def_color;
-+  cmd_list[2]  = def_status;
-+  cmd_list[3]  = def_status_to;
++  cmd_list = g_new (cmdopts_t *, BUILTIN_COUNT+1);
++
++  cmd_list[0]  = &def_roster;
++  cmd_list[1]  = &def_color;
++  cmd_list[2]  = &def_status;
++  cmd_list[3]  = &def_status_to;
 +#if 0
 +  cmd_list[4]  = def_add;
 +  cmd_list[5]  = def_del;
@@ -661,6 +659,7 @@
 +  cmd_list[36] = def_exit;
 +#endif
 +  cmd_list[BUILTIN_COUNT] = NULL;
++
 +  cmd_count = BUILTIN_COUNT;
 +}
 +
@@ -672,21 +671,27 @@
 +  cmd_count = 0;
 +}
 +
++// XXX:
++//  * if command is found, maybe still put it at the start of queue?
 +void cmd_define (cmdopts_t *command)
 +{
-+  cmd_list = g_renew ((cmdopts_t *), cmd_list, cmd_count+2);
-+  g_memmove(cmd_list, cmd_list+1, sizeof(cmdopts_t *) * cmd_count+1)
-+  cmd_list[0] = command;
++  cmdopts_t **cmd;
++  for (cmd = cmd_list; *cmd != NULL; cmd ++)
++    if (*cmd == command)
++      return;
++  cmd_list = g_renew (cmdopts_t *, cmd_list, cmd_count+2);
++  cmd_list[cmd_count] = command;
 +  cmd_count ++;
++  cmd_list[cmd_count] = NULL;
 +}
 +
 +void cmd_undef (cmdopts_t *command)
 +{
-+  gsize num = 0;
++  size_t num = 0;
 +  while (num < cmd_count) {
 +    if (cmd_list[num] == command) {
 +      g_memmove (cmd_list+num, cmd_list+num+1, sizeof(cmdopts_t *) * (cmd_count-num));
-+      cmd_list = g_renew ((cmdopts_t *), cmd_list, cmd_count);
++      cmd_list = g_renew (cmdopts_t *, cmd_list, cmd_count);
 +      cmd_count --;
 +      return;
      }
@@ -706,7 +711,7 @@
 +// Updates current/end pointers. Parsed string MUST be writable.
 +// String may shrink in size (quotation/escapes), thus endpointer is also
 +// updated.
-+const char *cmdopts_parse_argument(gchar **pr, gchar *er, cmdarg_flags_t flags)
++const char *cmdopts_parse_argument(gchar **pr, gchar **er, cmdarg_flags_t flags)
  {
 -  cmd *n_cmd = g_slice_new0(cmd);
 -  strncpy(n_cmd->name, name, 32-1);
@@ -793,7 +798,7 @@
 +  gchar    *s;               // start of current object pointer
 +  gboolean opts_ended = FALSE; // don't allow options any more
 +  cmdopt_t *option   = NULL; // option, for which argument is currently parsed
-+  gsize    argno     = 0;    // number of current positional argument
++  size_t   argno     = 0;    // number of current positional argument
 +  gchar    *error    = NULL; // error message to return
 +
 +  // general environment checking
@@ -811,8 +816,12 @@
 +    if (command -> opts) {
 +      for (n = 0; command -> opts[n] != NULL; n ++) {
 +        cmdopt_t *opt = command -> opts[n];
-+        opt -> arg.val.arg = opt -> arg.defval;
-+        opt -> cnt = 0;
++        if (opt -> flags & cmdopt_switch) {
++          opt -> arg.value.swc = 0;
++        } else {
++          opt -> arg.value.roarg = opt -> arg.defval;
++        }
++        opt -> arg.flags &= ~(cmdarg_ppclear);
        }
      }
 -  if (safe)
@@ -824,7 +833,7 @@
 +      for (n = 0; command -> args[n] != NULL; n ++) {
 +        cmdarg_t *arg = command -> args[n]; 
 +        arg -> value.roarg = arg -> defval;
-+        arg -> flags &= ~(cmdarg_visited|cmdarg_checked);
++        arg -> flags  &= ~(cmdarg_ppclear);
 +      }
 +    }
 +  }
@@ -924,9 +933,8 @@
 +        p ++;
 +      }
 +    } else if (state == in_argstart) { // option/command argument initialization
-+      cmdarg_flags_t flags;
-+      const char     *err;
-+      cmdarg_t       *arg;
++      const char *err;
++      cmdarg_t   *arg;
 +
 +      if (option) { // option argument
 +        arg = &(option -> arg);
@@ -936,21 +944,21 @@
 +        arg = command -> args[argno];
 +      }
 +
-+      if ((err = cmdopt_parse_argument(&p, &e, arg -> flags))) { // get argument value
++      if ((err = cmdopts_parse_argument(&p, &e, arg -> flags))) { // get argument value
 +        if (!option) {
-+          error = g_strdup_printf ("%s: Can't parse argument %s (%u): %s", command -> name, arg -> name, argno + 1, err);
-+        else if (option -> shortopt) {
++          error = g_strdup_printf ("%s: Can't parse argument %s (%lu): %s", command -> name, arg -> name, argno + 1, err);
++        } else if (option -> shortopt) {
 +          error = g_strdup_printf ("%s: Can't parse argument for option -%c: %s", command -> name, option -> shortopt, err);
 +        } else {
-+          error = g_strdup_printt ("%s: Can't parse argument for option --%s: %s", command -> name, option -> longopt, err);
++          error = g_strdup_printf ("%s: Can't parse argument for option --%s: %s", command -> name, option -> longopt, err);
 +        }
 +      } else {
 +        arg -> value.arg = s;
-+        arg -> flags  |= cmdarg_visited;
++        arg -> flags |= cmdarg_visited;
 +        if (option) { // option argument
 +          option = NULL;
 +        } else { // normal argument
-+          if (argument -> flags & cmdarg_subcmd) { // subcommand
++          if (arg -> flags & cmdarg_subcmd) { // subcommand
 +            cmdopts_t *subcmd;
 +            gsize     n; // XXX put command list into chkdata
 +            for (n = 0; command -> cmds[n]; n ++) {
@@ -996,7 +1004,7 @@
 +                if (opt -> shortopt) {
 +                  error = g_strdup_printf ("%s: Error in argument for option -%c: %s", command -> name, opt -> shortopt, err);
 +                } else {
-+                  error = g_strdup_printt ("%s: Error in argument for option --%s: %s", command -> name, opt -> longopt, err);
++                  error = g_strdup_printf ("%s: Error in argument for option --%s: %s", command -> name, opt -> longopt, err);
 +                }
 +                g_free (err);
 +                break;
@@ -1017,7 +1025,7 @@
 +
 +  // perform positional argument checking
 +  if (error == NULL && command -> args) {
-+    gsize n;
++    size_t n;
 +    for (n = 0; command -> args[n]; n ++) {
 +      cmdarg_t *arg = command -> args[n];
 +      // needs checking and not checked already
@@ -1094,7 +1102,7 @@
 +        if (arg -> flags & cmdarg_freeme) { // can free something
 +          arg -> flags &= ~cmdarg_freeme;
 +          if (arg -> type && arg -> type -> free) { // need to free something
-+            arg -> type.free (arg);
++            arg -> type -> free (arg);
 +          }
 +        }
 +      }
@@ -1320,24 +1328,23 @@
 -  compl_add_category_word(COMPL_MODULE, "unload");
 -#endif
 +  gchar *s = commandline;
-+  gchar *p;
-+  gchar *e;
++  gchar *p, *e;
 +  gchar *freeme = NULL;
 +  const char *err;
-+  gchar *error;
-+  cmdopts_t *command = NULL;
-+  const char *alias = NULL;
-+  gsize n;
++  gchar      *error;
++  cmdopts_t  *command = NULL;
++  const char *alias   = NULL;
++  size_t n;
 +
 +  // skip command indicator and spaces at the beginning
 +  while (*s == COMMAND_CHAR || *s == ' ')
 +    s ++;
-+  gchar *p = s;
-+  gchar *e = s + strlen (s);
++  p = s;
++  e = s + strlen (s);
 +
 +  // separate first word - command name
-+  if ((err = cmdopts_parse_argument(&p, &e, cmdarg_default))) {
-+    scr_log_print(LPRINT_NORMAL, "error: Can't comprehend command name: %s.", err);
++  if ((err = cmdopts_parse_argument (&p, &e, cmdarg_default))) {
++    scr_log_print (LPRINT_NORMAL, "error: Can't comprehend command name: %s.", err);
 +    return cmd_result_syntax_error;
 +  }
 +
@@ -1347,20 +1354,20 @@
 +  }
 +
 +  // check if we're in verbatim mode
-+  if ((flags & cmdexe_check_verbatim) && scr_get_multimode() == 2) {
-+    if (strcmp(s, "msay")) { // it is not msay
++  if ((flags & cmdexe_check_verbatim) && scr_get_multimode () == 2) {
++    if (strcmp (s, "msay")) { // it is not msay
 +      return cmd_result_verbatim;
 +    }
 +  }
 +
 +  // check and expand alias
-+  if ((alias = settings_get(SETTINGS_TYPE_ALIAS, s))) {
++  if ((alias = settings_get (SETTINGS_TYPE_ALIAS, s))) {
 +    freeme = s = g_strdup_printf ("%s %s", alias, p);
 +    p = s;
 +    e = s + strlen (s);
 +
-+    if ((err = cmdopts_parse_argument(&p, &e, cmdarg_default))) {
-+      scr_log_print(LPRINT_NORMAL, "error: Can't comprehend command name: %s.", err);
++    if ((err = cmdopts_parse_argument (&p, &e, cmdarg_default))) {
++      scr_log_print (LPRINT_NORMAL, "error: Can't comprehend command name: %s.", err);
 +      g_free (freeme);
 +      return cmd_result_syntax_error;
 +    }
@@ -1372,49 +1379,49 @@
 +    }
 +  }
 +
-+  // find command with this name
-+  for (n = 0; n < cmd_count; n ++) {
-+    if (!strcmp(s, cmd_list[n] -> name)) {
++  // find command with this name (reverse - see cmd_define())
++  for (n = cmd_count - 1; n >= 0; n --) {
++    if (!strcmp (s, cmd_list[n] -> name)) {
 +      command = cmd_list[n];
 +      break;
 +    }
 +  }
 +  if (command == NULL) {
-+    scr_log_print(LPRINT_NORMAL, "error: Unable to find command \"%s\".", s);
-+    g_free(freeme);
++    scr_log_print (LPRINT_NORMAL, "error: Unable to find command \"%s\".", s);
++    g_free (freeme);
 +    return cmd_result_not_found;
 +  }
 +
 +  // check safety
 +  if ((flags & cmdexe_check_safe) && !(command -> flags & cmd_safe)) {
-+    scr_log_print(LPRINT_NORMAL, "error: Command \"%s\" is not safe to execute here.", command -> name);
-+    g_free(freeme);
++    scr_log_print (LPRINT_NORMAL, "error: Command \"%s\" is not safe to execute here.", command -> name);
++    g_free (freeme);
 +    return cmd_result_not_found;
 +  }
 +
 +  // parse command line
 +  if ((error = cmdopts_parse_internal (&p, &e, command))) {
-+    scr_log_print(LPRINT_NORMAL, "%s", error);
-+    g_free(error);
++    scr_log_print (LPRINT_NORMAL, "%s", error);
++    g_free (error);
 +    cmdopts_free (command);
-+    g_free(freeme);
++    g_free (freeme);
 +    return cmd_result_syntax_error;
 +  }
 +
 +  // execute command handler
-+  if (command -> handler) {
-+    if ((error = command -> handler(command))) {
-+      scr_log_print(LPRINT_NORMAL, "%s: %s", command -> name, error);
-+      g_free(error);
++  if (command -> handle) {
++    if ((error = command -> handle (command))) {
++      scr_log_print (LPRINT_NORMAL, "%s: %s", command -> name, error);
++      g_free (error);
 +      cmdopts_free (command);
-+      g_free(freeme);
++      g_free (freeme);
 +      return cmd_result_runtime_error;
 +    }
 +  }
 +
 +  // free resources
-+  cmdopts_free(command);
-+  g_free(freeme);
++  cmdopts_free (command);
++  g_free (freeme);
 +  return cmd_result_ok;
  }
  
@@ -1585,7 +1592,7 @@
    if (!*line) { // User only pressed enter
      if (scr_get_multimode()) {
        scr_append_multiline("");
-@@ -556,141 +707,509 @@
+@@ -556,141 +715,516 @@
      }
      if (current_buddy) {
        if (buddy_gettype(BUDDATA(current_buddy)) & ROSTER_TYPE_GROUP)
@@ -1738,7 +1745,7 @@
 +//  common methods
 +//
 +
-+static void cmdarg_free_gfree (optarg_t *arg)
++void cmdarg_free_gfree (cmdarg_t *arg)
 +{
 +  g_free (arg -> value.arg);
 +}
@@ -1751,18 +1758,18 @@
 +// Replaces value.arg.
 +// Does not need freeing.
 +// No trailing spaces in defvalue - needs RW access for that.
-+static gchar *cmdarg_check_nospace (optarg_t *arg)
++gchar *cmdarg_check_nonspace (cmdarg_t *arg)
 +{
 +  gchar *val = arg -> value.arg;
++
 +  if (val) {
-+    while (isspace(*val))
++    while (isspace (*val))
 +      val ++;
 +    if (*val) { // valid arg
 +      arg -> value.arg = val;
-+      // XXX requires RW access. default values must not contain trailing space
 +      while (*val)
 +        val ++;
-+      while (isspace(*val))
++      while (isspace (*val))
 +        val --;
 +      val ++;
 +      if (*val)
@@ -1780,17 +1787,20 @@
 -        if (!g_strcmp0((char*)p_res->data, resource))
 -          found = TRUE;
 -        g_free(p_res->data);
++
 +  // error
 +  arg -> value.arg = NULL;
-+  return g_strdup("Non-space value required.");
++  return g_strdup ("Non-space value required.");
 +}
 +
-+cmdarg_type_t cmdarg_type_nospace = {
-+  cmdarg_check_nospace,
++static const cmdarg_type_t cmdarg_typedef_nonspace = {
++  cmdarg_check_nonspace,
 +  NULL,
 +  NULL,
 +};
 +
++const cmdarg_type_t *cmdarg_type_nonspace = &cmdarg_typedef_nonspace;
++
 +//
 +//  bjid -> bud
 +//
@@ -1799,11 +1809,11 @@
 +// Returns buddy roster entry in value.bud.
 +// Recognizes as current ".", but not "" or NULL - use defvalue.
 +// Does not require freeing.
-+static gchar *cmdarg_check_roster_bjid (optarg_t *arg)
++gchar *cmdarg_check_roster_bjid (cmdarg_t *arg)
 +{
 +  gchar *error = NULL;
 +
-+  if (!(error = cmdarg_check_nospace_required(arg))) {
++  if (!(error = cmdarg_check_nonspace(arg))) {
 +    const char *bjid = arg -> value.arg;
 +    guint      types = (guint) arg -> chkdata;
 +
@@ -1830,12 +1840,14 @@
 +  return error;
 +}
 +
-+cmdarg_type_t cmdarg_type_bjid = {
++static const cmdarg_type_t cmdarg_typedef_roster_bjid = {
 +  cmdarg_check_roster_bjid,
 +  NULL,
 +  NULL,
 +};
 +
++const cmdarg_type_t *cmdarg_type_roster_bjid = &cmdarg_typedef_roster_bjid;
++
 +//
 +//  fjid -> bud + resource
 +//
@@ -1848,32 +1860,30 @@
 +// No full "jid/resource" syntax in defvalue - needs rw for that.
 +// XXX:
 +//  * make return value a custom struct { .bud, .res } instead of using userdata
-+//  * allow bjids and '.'
 +//  * merge with roster_bjid and use own flags in chkdata to signify types and resource allowed/required conditions
-+//  * it is rather check_roster_resource
-+static gchar *cmdarg_check_roster_resource(optarg_t *arg)
++gchar *cmdarg_check_roster_resource (cmdarg_t *arg)
 +{
 +  gchar    *error    = NULL;
 +  gpointer bud       = NULL;
 +  char     *resource = NULL;
 +
-+  if (!(error = cmdarg_check_nospace(arg))) {
-+    const char *fjid     = arg -> value.arg;
-+    guint      types     = (guint) arg -> chkdata;
++  if (!(error = cmdarg_check_nonspace(arg))) {
++    const char *fjid = arg -> value.arg;
++    guint      types = (guint) arg -> chkdata;
 +
 +    if (fjid[0] == '.' && fjid[1] == JID_RESOURCE_SEPARATOR) {
 +      // current buddy
 +      resource = fjid+2;
-+    } else if (!check_jid_syntax(fjid) && (resource = strchr(fjid, JID_RESOURCE_SEPARATOR))) {
++    } else if (!check_jid_syntax (fjid) && (resource = strchr (fjid, JID_RESOURCE_SEPARATOR))) {
 +      // valid jid
 +      GSList *found;
 +      *resource = '\0'; // XXX needs rw
-+      found = roster_find(fjid, jidsearch, types);
++      found = roster_find (fjid, jidsearch, types);
 +      if (found) {
 +        bud = found->data;
 +        resource ++;
 +      } else
-+        error = g_strdup_printf("Jid <%s> is not in the roster.", bjid);
++        error = g_strdup_printf ("Jid <%s> is not in the roster.", fjid);
 +    } else {
 +      // jid is invalid - let's consider it resource (XXX)
 +      resource = fjid;
@@ -1882,8 +1892,8 @@
 +    if (error == NULL && resource) {
 +      if (bud == NULL) {
 +        if (!current_buddy)
-+          error = g_strdup_printf("No buddy selected.");
-+        else if (buddy_gettype(BUDDATA(current_buddy)) & types)
++          error = g_strdup ("No buddy selected.");
++        else if (buddy_gettype (BUDDATA(current_buddy)) & types)
 +          bud = BUDDATA(current_buddy);
 +        else // TODO: improve message
 +          error = g_strdup_printf("Currently selected buddy is of wrong type.");
@@ -1895,15 +1905,15 @@
 +      if (bud) {
 +        GSList *resources, *p_res;
 +        gboolean found = FALSE;
-+        resources = buddy_getresources(bud);
++        resources = buddy_getresources (bud);
 +        for (p_res = resources; p_res; p_res = g_slist_next(p_res)) {
-+          if (!g_strcmp0((char*)p_res->data, resource))
++          if (!g_strcmp0 ((char*)p_res->data, resource))
 +            found = TRUE;
-+          g_free(p_res->data);
++          g_free (p_res->data);
 +        }
-+        g_slist_free(resources);
++        g_slist_free (resources);
 +        if (!found)
-+          error = g_strdup_printf("No such resource <%s%c%s>...", buddy_getjid(bud), JID_RESOURCE_SEPARATOR, resource);
++          error = g_strdup_printf ("No such resource <%s%c%s>...", buddy_getjid(bud), JID_RESOURCE_SEPARATOR, resource);
        }
 +    }
 +  }
@@ -1918,12 +1928,14 @@
 +  return error;
 +}
 +
-+cmdarg_type_t cmdarg_type_roster_resource = {
++static const cmdarg_type_t cmdarg_typedef_roster_resource = {
 +  cmdarg_check_roster_resource,
 +  NULL,
 +  NULL,
 +};
 +
++const cmdarg_type_t *cmdarg_type_roster_resource = &cmdarg_typedef_roster_resource;
++
 +//
 +//  fjid -> fjid
 +//
@@ -1932,12 +1944,12 @@
 +// Recognizes as current "." and "./res".
 +// Requires freeing.
 +// XXX:
-+//  * destructor is rather generic g_freer, publish?
-+static gchar *cmdarg_check_fjid(optarg_t *arg)
++//  * g_strdup jid?
++gchar *cmdarg_check_fjid (cmdarg_t *arg)
 +{
 +  gchar *error = NULL;
 +
-+  if (!(error = cmdarg_check_nospace(arg))) {
++  if (!(error = cmdarg_check_nonspace(arg))) {
 +    const char *fjid = arg -> value.arg;
 +
 +    if (fjid[0] == '.' && (fjid[1] == JID_RESOURCE_SEPARATOR || fjid[1] == '\0')) {
@@ -1947,10 +1959,10 @@
 +      else if (!(jid = buddy_getjid(BUDDATA(current_buddy)))) {
 +        error = g_strdup_printf ("Current buddy have no jid.");
 +      } else if (fjid[1] == '\0') {
-+        arg -> value.arg = jid;
++        arg -> value.roarg = jid;
 +      } else {
 +        arg -> value.arg = g_strdup_printf ("%s%c%s", jid, JID_RESOURCE_SEPARATOR, fjid + 2);
-+        arg -> flags |= cmdarg_freeme;
++        arg -> flags    |= cmdarg_freeme;
 +      }
 +    } else if (check_jid_syntax(fjid)) {
 +      error = g_strdup_printf ("Jid <%s> is invalid.", fjid);
@@ -1962,12 +1974,14 @@
 +  return error;
 +}
 +
-+cmdarg_type_t cmdarg_type_fjid = {
++static const cmdarg_type_t cmdarg_typedef_fjid = {
 +  cmdarg_check_fjid,
 +  cmdarg_free_gfree,
 +  NULL,
 +};
 +
++const cmdarg_type_t *cmdarg_type_fjid = &cmdarg_typedef_fjid;
++
 +//
 +//  string -> uint
 +//
@@ -1977,20 +1991,20 @@
 +// XXX:
 +//  * use gulong? (strtoul allows to check conversion errors, while atoi - not)
 +//  * use flags in chkdata to specify signedness - it only affects two checks
-+static gchar *cmdarg_check_uint (cmdarg_t *arg)
++gchar *cmdarg_check_uint (cmdarg_t *arg)
 +{
 +  gchar *error;
 +
-+  if (!(error = cmdarg_check_nospace(arg))) {
-+    const char *e = NULL;
-+    const char *s = arg -> value.arg;
-+    long n = strtol(s, &e, 0);
++  if (!(error = cmdarg_check_nonspace(arg))) {
++    char *s = arg -> value.arg;
++    char *e = s;
++    long n  = strtol(s, &e, 0);
 +    if (*e != '\0')
 +      error = g_strdup_printf ("Invalid number \"%s\".", s);
 +    else if (n < 0)
 +      error = g_strdup ("Value must be greater than zero.");
 +    else if (n > G_MAXUINT)
-+      error = g_strdup ("Value %d is too big.", n);
++      error = g_strdup_printf ("Value %ld is too big.", n);
 +    else
 +      arg -> value.uint = (guint) n;
 +  }
@@ -2000,12 +2014,14 @@
 +  return error;
 +}
 +
-+cmdarg_type_t cmdarg_type_uint = {
++static const cmdarg_type_t cmdarg_typedef_uint = {
 +  cmdarg_check_uint,
 +  NULL,
 +  NULL,
 +};
 +
++const cmdarg_type_t *cmdarg_type_uint = &cmdarg_typedef_uint;
++
 +//
 +//  string -> statusmask
 +//
@@ -2022,11 +2038,11 @@
 +//    * string2enum?
 +//  * common strchr callback with valid chars in chkdata?
 +//    * Then argument name should go into cmdarg struct - message would be too generic
-+static gchar *cmdarg_check_statusmask (cmdarg_t *arg)
++gchar *cmdarg_check_statusmask (cmdarg_t *arg)
 +{
 +  gchar *error;
 +
-+  if (!(error = cmdarg_check_nospace(arg)) && arg -> value.arg) {
++  if (!(error = cmdarg_check_nonspace(arg)) && arg -> value.arg) {
 +    const char *valid = "foand_?";
 +    if (!strcmp(arg -> value.arg, "*")) {
 +      arg -> value.arg = g_strdup (valid);
@@ -2036,14 +2052,14 @@
 +      gchar *p = arg -> value.arg;
 +      gchar *e = p + strlen (p);
 +      while (p < e) {
-+        if (strchr(valid, *p)) {
++        if (strchr (valid, *p)) {
 +          p ++;
 +        } else if (arg -> flags & cmdarg_required) {
 +          // this is valid use of flag in checker
 +          return g_strdup_printf ("%s can only contain characters [%s].", arg -> name, valid);
 +        } else {
 +          scr_log_print (LPRINT_NORMAL, "Warning: Wrong %s character [%c]", arg -> name, *p);
-+          memmove (p, p+1, e-p-1);
++          g_memmove (p, p+1, e-p-1);
 +          e --;
 +        }
 +      }
@@ -2057,61 +2073,58 @@
 +  return error;
 +}
 +
-+cmdarg_type_t cmdarg_type_statusmask = {
++static const cmdarg_type_t cmdarg_typedef_statusmask = {
 +  cmdarg_check_statusmask,
 +  cmdarg_free_gfree,
 +  NULL,
 +};
 +
++const cmdarg_type_t *cmdarg_type_statusmask = &cmdarg_typedef_statusmask;
++
 +//
 +//  string -> enum
 +//
 +
-+typedef struct {
-+  const char *name;
-+  guint      value;
-+} string2enum_t;
-+
 +// Uses chkdata as a pointer to continuous array of string2enum_t structs.
 +// Returns corresponding value in value.uint.
 +// Returns 0 if not recognized and not required.
 +// Does not require freeing.
 +// XXX:
 +//  * also, print list of possible values on error?
-+static gchar *cmdarg_check_string2enum (cmdarg_t *arg)
++//  * default value on error?
++gchar *cmdarg_check_string2enum (cmdarg_t *arg)
 +{
 +  gchar *error;
 +
-+  if (!(error = cmdarg_check_nospace(arg))) {
-+    string2enum_t *list = arg -> chkdata;
-+    gsize i;
-+    for (i = 0; list[i] -> name != NULL; i ++) {
-+      if (!strcmp(list[i] -> name, arg -> value.arg)) { // found
-+        arg -> value.uint = list[i] -> value;
++  if (!(error = cmdarg_check_nonspace(arg))) {
++    const string2enum_t *list;
++    for (list = arg -> chkdata; list -> name != NULL; list ++)
++      if (!strcmp(list -> name, arg -> value.arg)) { // found
++        arg -> value.uint = list -> value;
 +        return NULL;
 +      }
-+      list ++;
-+    }
 +    // not found, error
-+    error = g_strdup_printf("Value \"%s\" is invalid for %s.", arg -> value.arg, arg -> name);
++    error = g_strdup_printf ("Value \"%s\" is invalid for %s.", arg -> value.arg, arg -> name);
 +  }
 +
 +  if (error)
-+    arg -> value.uint = 0; // XXX default value?
++    arg -> value.uint = 0;
 +  return error;
 +}
 +
-+cmdarg_type_t cmdarg_type_string2enum = {
++static const cmdarg_type_t cmdarg_typedef_string2enum = {
 +  cmdarg_check_string2enum,
 +  NULL,
 +  NULL,
 +};
 +
++const cmdarg_type_t *cmdarg_type_string2enum = &cmdarg_typedef_string2enum;
++
 +//
 +//  string -> color name
 +//
 +
-+static string2enum_t s2e_color[] = {
++static const string2enum_t s2e_color[] = {
 +  { "default", -1 },
 +  { "black",   1  },
 +  { "red",     1  },
@@ -2136,9 +2149,8 @@
 +{
 +  gchar *error;
 +
-+  if (!(error = cmdarg_check_nospace(arg))) {
-+    const char *color = arg -> value.arg;
-+    gsize i;
++  if (!(error = cmdarg_check_nonspace(arg))) {
++    char *color = arg -> value.arg;
 +    // reset color
 +    if (!strcmp(color, "-")) {
 +      return NULL;
@@ -2146,15 +2158,15 @@
 +    // allow "bright" prefix
 +    if (!strncmp(color, "bright", 6))
 +      color += 6;
-+    // check names
-+    for (i = 0; s2e_color[i] -> name != NULL; i ++) {
-+      if (!strcmp (s2e_color[i] -> name, color)) {
-+        return NULL;
-+      }
++    { // check names
++      const string2enum_t *list;
++      for (list = s2e_color; list -> name != NULL; list ++)
++        if (!strcmp (list -> name, color))
++          return NULL;
 +    }
 +    { // not found, check for numerical value
-+      const char *e = NULL;
-+      long n = strtol(color, &e, 0);
++      char *e = color;
++      long n  = strtol(color, &e, 0);
 +      if (*e != '\0' || n < 0 || n > 256)
 +        error = g_strdup_printf ("Invalid color \"%s\".", arg -> value.arg);
 +    }
@@ -2165,12 +2177,14 @@
 +  return error;
 +}
 +
-+cmdarg_type_t cmdarg_type_color = {
++static const cmdarg_type_t cmdarg_typedef_color = {
 +  cmdarg_check_color,
 +  NULL,
 +  NULL,
 +};
 +
++const cmdarg_type_t *cmdarg_type_color = &cmdarg_typedef_color;
++
 +//
 +//  Command definitions
 +//
@@ -2205,7 +2219,7 @@
  static void display_and_free_note(struct annotation *note, const char *winId)
  {
    gchar tbuf[128];
-@@ -755,41 +1274,15 @@
+@@ -755,41 +1289,15 @@
    g_slist_free(notes);
  }
  
@@ -2255,7 +2269,7 @@
      struct annotation *note = xmpp_get_storage_rosternotes(bjid, FALSE);
      if (note) {
        display_and_free_note(note, bjid);
-@@ -800,194 +1293,273 @@
+@@ -800,194 +1308,282 @@
    }
  }
  
@@ -2276,10 +2290,11 @@
 +  scmd_roster_hide, scmd_roster_show, scmd_roster_toggle,
 +} scmd_roster_t;
 +
-+#define SCMD_ROSTER(NAME, ARGS) \
-+    { #NAME, NULL, NULL, NULL, ARGS, NULL, (gpointer)scmd_roster_##NAME }
++#define SCMD_ROSTER(NAME, ARGS...) \
++    { #NAME, cmd_default, NULL, NULL, NULL, ARGS, NULL, (gpointer)scmd_roster_##NAME }
 +static cmdopts_t def_roster = {
 +  "roster",
++  cmd_default, // XXX
 +  NULL,
 +  do_roster,
 +  NULL,
@@ -2503,13 +2518,13 @@
 -    scr_LogPrint(LPRINT_NORMAL, "Missing parameter.");
 -    free_arg_lst(paramlst);
 -    return;
-+  if (!g_strcmp0(arg -> value.arg, "clear"))
++  if (!g_strcmp0 (arg -> value.arg, "clear"))
 +    return NULL;
 +  else
 +    return cmdarg_check_statusmask (arg);
 +}
 +
-+static cmdarg_type_t cmdarg_type_color_statusmask = {
++static const cmdarg_type_t cmdarg_typedef_color_statusmask = {
 +  cmdarg_check_color_statusmask,
 +  NULL,
 +  NULL,
@@ -2543,12 +2558,19 @@
 +  return error;
 +}
 +
-+static cmdarg_type_t cmdarg_type_color_roomjid = {
++static const cmdarg_type_t *cmdarg_type_color_roomjid = {
 +  cmdarg_check_color_roomjid,
 +  NULL,
 +  NULL,
 +};
 +
++// TODO: completion, that says, which roster jids do match
++static const cmdarg_type_t *cmdarg_type_bjidmask = {
++  cmdarg_check_nonspace,
++  NULL,
++  NULL,
++};
++
 +// command
 +
 +typedef enum {
@@ -2557,7 +2579,7 @@
 +  scmd_color_muc,
 +} scmd_color_t;
 +
-+static string2enum_t s2e_color_muc[] = {
++static const string2enum_t s2e_color_muc[] = {
 +  { "on",     MC_ALL    },
 +  { "off",    MC_OFF    },
 +  { "preset", MC_PRESET },
@@ -2567,19 +2589,20 @@
 +
 +static cmdopts_t def_color = {
 +  "color",
++  cmd_default, // XXX
 +  NULL,
 +  do_color,
 +  NULL,
 +  {{ "subcommand", cmdarg_subcmd | cmdarg_check, NULL, NULL }, NULL},
 +  {
 +    {"roster", NULL, NULL, NULL, {
-+        { "statusmask|clear", cmdarg_chreq, NULL, cmdarg_type_color_statusmask },
-+        { "jidmask", cmdarg_default, NULL, cmdarg_type_bjidmask         },
++        { "statusmask|clear", cmdarg_chreq, NULL, &cmdarg_type_color_statusmask },
++        { "jidmask", cmdarg_default, NULL, &cmdarg_type_bjidmask         },
 +        { "color|-", cmdarg_default, NULL, cmdarg_type_color            },
 +        NULL,
 +      }, NULL, (gpointer)scmd_color_roster},
 +    {"muc", NULL, NULL, NULL, {
-+        { "roomjid", cmdarg_chreq, NULL, cmdarg_type_color_roomjid },
++        { "roomjid", cmdarg_chreq, NULL, &cmdarg_type_color_roomjid },
 +        { "on|off|preset|-", cmdarg_chreq, "on", cmdarg_type_string2enum, (gpointer)s2e_color_muc},
 +        NULL,
 +      }, NULL, (gpointer)scmd_color_muc},
@@ -2687,7 +2710,7 @@
    enum imstatus st;
  
    if (!xmpp_is_online())
-@@ -1000,15 +1572,15 @@
+@@ -1000,15 +1596,15 @@
    if (!recipient)
      scr_check_auto_away(TRUE);
  
@@ -2708,7 +2731,7 @@
    if      (!strcasecmp(status, IMSTATUS_OFFLINE))       st = offline;
    else if (!strcasecmp(status, IMSTATUS_ONLINE))        st = available;
    else if (!strcasecmp(status, IMSTATUS_AVAILABLE))     st = available;
-@@ -1020,229 +1592,347 @@
+@@ -1020,229 +1616,351 @@
    else if (!strcasecmp(status, IMSTATUS_NOTAVAILABLE))  st = notavail;
    else if (!strcasecmp(status, IMSTATUS_FREE4CHAT))     st = freeforchat;
    else if (!strcasecmp(status, "message")) {
@@ -2743,22 +2766,6 @@
 -static void do_status(char *arg)
 +// custom type
 +
-+// XXX status|message|show -> status
-+static string2enum_t s2e_status2[] = {
-+  { "away",      away        },
-+  { "offline",   offline     },
-+  { "online",    available   },
-+  { "avail",     available   },
-+  { "notavail",  notavail    },
-+  { "dnd",       dontdisturb },
-+  { "free",      freeforchat },
-+#ifdef WITH_DEPRECATED_STATUS_INVISIBLE
-+  { "invisible", invisible   },
-+#endif
-+  { "show",      imstatus_size},
-+  { NULL,        0           },
-+};
-+
 +// needs corresponding s2e in chkdata
 +static gchar *cmdarg_check_status_status (cmdarg_t *arg)
  {
@@ -2773,7 +2780,7 @@
 +  return cmdarg_check_string2enum (arg);
 +}
 +
-+static cmdarg_type_t cmdarg_type_status_status = {
++static const cmdarg_type_t cmdarg_type_status_status = {
 +  cmdarg_check_status_status,
 +  NULL,
 +  NULL,
@@ -2781,14 +2788,31 @@
 +
 +// command
 +
++static const string2enum_t s2e_status2[] = {
++  { "away",      away        },
++  { "offline",   offline     },
++  { "online",    available   },
++  { "avail",     available   },
++  { "notavail",  notavail    },
++  { "dnd",       dontdisturb },
++  { "free",      freeforchat },
++#ifdef WITH_DEPRECATED_STATUS_INVISIBLE
++  { "invisible", invisible   },
++#endif
++  // XXX ugly
++  { "show",      imstatus_size},
++  { NULL,        0           },
++};
++
 +cmdopts_t def_status = {
 +  "status",
++  cmd_default, // XXX
 +  NULL,
 +  do_status,
 +  NULL,
 +  {
-+    {"status", cmdarg_default, NULL, cmdarg_type_status_status, (gpointer)s2e_status2},
-+    {"message", cmdarg_eol, NULL, cmdarg_type_nonspace},
++    {"status",  cmdarg_chreq, "show", &cmdarg_type_status_status, (gpointer)s2e_status2},
++    {"message", cmdarg_eol,   NULL,   cmdarg_type_nonspace},
 +    NULL,
 +  },
 +  NULL,
@@ -2816,7 +2840,7 @@
 +//
 +
 +// no "show" here
-+static string2enum_t s2e_status[] = {
++static const string2enum_t s2e_status[] = {
 +  { "away",      away        },
 +  { "offline",   offline     },
 +  { "online",    available   },
@@ -2832,12 +2856,13 @@
 +
 +cmdopts_t def_status_to = {
 +  "status_to",
++  cmd_default, // XXX
 +  NULL,
 +  do_status_to,
 +  NULL,
 +  {
-+    {"jid", cmdarg_chreq, NULL, cmdarg_type_fjid},
-+    {"status", cmdarg_chreq, NULL, cmdarg_type_status_status, (string2enum_t)s2e_status},
++    {"jid",     cmdarg_chreq, NULL, cmdarg_type_fjid},
++    {"status",  cmdarg_chreq, NULL, &cmdarg_type_status_status, (string2enum_t)s2e_status},
 +    {"message", cmdarg_eol,   NULL, cmdarg_type_nonspace},
 +    NULL,
 +  },
@@ -2848,18 +2873,20 @@
 +{
 +  const char *fjid, *stname, *msg;
 +  enum imstatus st;
-+  gsize i;
 +
 +  fjid = options -> args[0] -> value.arg;
 +  st   = options -> args[1] -> value.uint;
 +  msg  = options -> args[2] -> value.arg;
 +
-+  for (i = 0; s2e_status[i] -> name != NULL; i++) {
-+    if (s2e_status[i] -> value == st) {
-+      stname = s2e_status[i] -> name;
-+      break;
-+    }
++  { // get status name
++    const string2enum_t *list;
++    for (list = s2e_status; list -> name != NULL; list ++)
++      if (list -> value == st) {
++        stname = list -> name;
++        break;
++      }
 +  }
++  // prevent default status message
 +  msg = msg ? msg : "";
 +
 +  scr_LogPrint(LPRINT_LOGNORM, 
@@ -3217,7 +3244,7 @@
      if (roster_elt)
        group = buddy_getgroup(roster_elt->data);
    } else {
-@@ -1253,31 +1943,19 @@
+@@ -1253,31 +1971,19 @@
      goto do_group_return;
    }
  
@@ -3252,7 +3279,7 @@
  {
    char *bare_jid, *rp;
    char *hmsg;
-@@ -1285,6 +1963,7 @@
+@@ -1285,6 +1991,7 @@
    gint retval = 0;
    int isroom;
    gpointer xep184 = NULL;
@@ -3260,7 +3287,7 @@
  
    if (!xmpp_is_online()) {
      scr_LogPrint(LPRINT_NORMAL, "You are not connected.");
-@@ -1299,11 +1978,15 @@
+@@ -1299,11 +2006,15 @@
      return 1;
    }
    if (check_jid_syntax((char*)fjid)) {
@@ -3278,7 +3305,7 @@
    // We must use the bare jid in hk_message_out()
    rp = strchr(fjid, JID_RESOURCE_SEPARATOR);
    if (rp)
-@@ -1354,8 +2037,7 @@
+@@ -1354,8 +2065,7 @@
  //  send_message(msg, subj, type_overwrite)
  // Write the message in the buddy's window and send the message on
  // the network.
@@ -3288,7 +3315,7 @@
  {
    const char *bjid;
    char *jid;
-@@ -1378,34 +2060,13 @@
+@@ -1378,34 +2088,13 @@
    else
      jid = g_strdup(bjid);
  
@@ -3325,7 +3352,7 @@
  
    scr_set_chatmode(TRUE);
    scr_show_buddy_window();
-@@ -1424,80 +2085,131 @@
+@@ -1424,80 +2113,131 @@
    }
  
    buddy_setflags(bud, ROSTER_FLAG_LOCK, TRUE);
@@ -3506,7 +3533,7 @@
  
    if (!scr_get_multimode()) {
      scr_LogPrint(LPRINT_NORMAL, "No message to send.  "
-@@ -1508,49 +2220,47 @@
+@@ -1508,49 +2248,47 @@
    scr_set_chatmode(TRUE);
    scr_show_buddy_window();
  
@@ -3592,7 +3619,7 @@
  }
  
  //  load_message_from_file(filename)
-@@ -1566,7 +2276,7 @@
+@@ -1566,7 +2304,7 @@
    char *next_utf8_char;
    size_t len;
  
@@ -3601,7 +3628,7 @@
  
    if (!fd || fstat(fileno(fd), &buf)) {
      scr_LogPrint(LPRINT_LOGNORM, "Cannot open message file (%s)", filename);
-@@ -1634,130 +2344,103 @@
+@@ -1634,130 +2372,103 @@
  
  static void do_say_to(char *arg)
  {
@@ -3788,7 +3815,7 @@
  }
  
  //  buffer_updown(updown, nblines)
-@@ -1775,27 +2458,10 @@
+@@ -1775,27 +2486,10 @@
      scr_buffer_scroll_up_down(updown, nblines);
  }
  
@@ -3816,7 +3843,7 @@
    t = from_iso8601(date, 0);
    if (t)
      scr_buffer_date(t);
-@@ -1804,98 +2470,156 @@
+@@ -1804,98 +2498,156 @@
                   "not correctly formatted or invalid.");
  }
  
@@ -4055,7 +4082,7 @@
  }
  
  static void do_info(char *arg)
-@@ -2033,29 +2757,20 @@
+@@ -2033,29 +2785,20 @@
    }
  }
  
@@ -4094,7 +4121,7 @@
  
    // Enter chat mode
    scr_set_chatmode(TRUE);
-@@ -2075,12 +2790,12 @@
+@@ -2075,12 +2818,12 @@
      rstatus = buddy_getstatus(bud, p_res->data);
      rst_msg = buddy_getstatusmsg(bud, p_res->data);
  
@@ -4109,7 +4136,7 @@
          enum imrole role = buddy_getrole(bud, p_res->data);
          enum imaffiliation affil = buddy_getaffil(bud, p_res->data);
          bool showaffil = (affil != affil_none);
-@@ -2096,12 +2811,12 @@
+@@ -2096,12 +2839,12 @@
        snprintf(buffer, 4095, "[%c] %s", imstatus2char[rstatus],
                 (char*)p_res->data);
        scr_WriteIncomingMessage(bjid, buffer, 0, HBB_PREFIX_INFO, 0);
@@ -4124,7 +4151,7 @@
          enum imrole role = buddy_getrole(bud, p_res->data);
          enum imaffiliation affil = buddy_getaffil(bud, p_res->data);
  
-@@ -2145,16 +2860,69 @@
+@@ -2145,16 +2888,69 @@
  
  static void do_rename(char *arg)
  {
@@ -4199,7 +4226,7 @@
    bjid   = buddy_getjid(bud);
    group  = buddy_getgroupname(bud);
    type   = buddy_gettype(bud);
-@@ -2162,11 +2930,13 @@
+@@ -2162,11 +2958,13 @@
  
    if (type & ROSTER_TYPE_SPECIAL) {
      scr_LogPrint(LPRINT_NORMAL, "You can't rename this item.");
@@ -4214,7 +4241,7 @@
      return;
    }
  
-@@ -2181,90 +2951,117 @@
+@@ -2181,90 +2979,117 @@
    //  }
    //}
  
@@ -4363,7 +4390,7 @@
      } else {
        // This is a local item, we move it without adding to roster.
        guint msgflag;
-@@ -2276,7 +3073,7 @@
+@@ -2276,7 +3101,7 @@
        msgflag = buddy_getflags(bud) & ROSTER_FLAG_MSG;
        if (msgflag)
          roster_msg_setflag(bjid, FALSE, FALSE);
@@ -4372,7 +4399,7 @@
        if (msgflag)
          roster_msg_setflag(bjid, FALSE, TRUE);
        if ((type & ROSTER_TYPE_ROOM) && xmpp_is_bookmarked(bjid) &&
-@@ -2285,8 +3082,7 @@
+@@ -2285,8 +3110,7 @@
      }
    }
  
@@ -4382,7 +4409,7 @@
    update_roster = TRUE;
  }
  
-@@ -2468,50 +3264,33 @@
+@@ -2468,50 +3292,33 @@
  
  static void do_rawxml(char *arg)
  {
@@ -4453,7 +4480,7 @@
  }
  
  //  check_room_subcommand(arg, param_needed, buddy_must_be_a_room)
-@@ -2874,7 +3653,7 @@
+@@ -2874,7 +3681,7 @@
    fjid_utf8 = g_strdup_printf("%s/%s", buddy_getjid(bud), nick_utf8);
    g_free (nick_utf8);
    msg = to_utf8(arg);
@@ -4462,7 +4489,7 @@
    g_free(fjid_utf8);
    g_free(msg);
    free_arg_lst(paramlst);
-@@ -3290,6 +4069,207 @@
+@@ -3290,6 +4097,207 @@
  
  static void do_room(char *arg)
  {
@@ -4670,7 +4697,7 @@
    char **paramlst;
    char *subcmd;
    gpointer bud;
-@@ -3347,7 +4327,7 @@
+@@ -3347,7 +4355,7 @@
        cmd_room_leave(bud, arg);
    } else if (!strcasecmp(subcmd, "names"))  {
      if ((arg = check_room_subcommand(arg, FALSE, bud)) != NULL)
@@ -4679,28 +4706,21 @@
    } else if (!strcasecmp(subcmd, "nick"))  {
      if ((arg = check_room_subcommand(arg, FALSE, bud)) != NULL)
        room_nick(bud, arg);
-@@ -4162,5 +5142,6 @@
+@@ -4162,5 +5170,6 @@
    }
    mcabber_set_terminate_ui();
  }
 +#endif
  
  /* vim: set expandtab cindent cinoptions=>2\:2(0 sw=2 ts=2:  For Vim users... */
-diff -r 92fa48ef53c9 mcabber/mcabber/commands.h
---- a/mcabber/mcabber/commands.h	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/mcabber/commands.h	Mon Mar 11 01:32:27 2013 +0200
-@@ -5,32 +5,214 @@
+diff -r b527e8800278 mcabber/mcabber/commands.h
+--- a/mcabber/mcabber/commands.h	Mon Mar 11 21:45:31 2013 +0200
++++ b/mcabber/mcabber/commands.h	Tue Mar 12 01:21:22 2013 +0200
+@@ -5,32 +5,242 @@
  
  #include <mcabber/config.h>
  
 -// Command structure
--typedef struct {
--  char name[32];
--  const char *help;
--  guint completion_flags[2];
--  void (*func)(char *);
--  gpointer userdata;
--} cmd;
 +//
 +//  TODO:
 +//
@@ -4741,17 +4761,7 @@
 +// * Subcommands with fallback to argument?
 +// * [+foo|-foo] support?
 +// * Usable subsystem for completion, based on user-supplied completors
- 
--void cmd_init(void);
--cmd *cmd_get(const char *command);
--int  process_line(const char *line);
--int  process_command(const char *line, guint iscmd);
--char *expandalias(const char *line);
--#ifdef MODULES_ENABLE
--gpointer cmd_del(gpointer id);
--gpointer cmd_add(const char *name, const char *help, guint flags1, guint flags2,
--                 void (*f)(char*), gpointer userdata);
--gboolean cmd_set_safe(const gchar *name, gboolean safe);
++
 +// * for now we'll do without multi-options.
 +// * and without clustering.
 +// * checks
@@ -4768,7 +4778,6 @@
 +typedef struct cmdopts_struct      cmdopts_t;
 +typedef struct cmdopt_struct       cmdopt_t;
 +typedef struct cmdarg_struct       cmdarg_t;
-+typedef struct cmdarg_value_struct cmdarg_value_t;
 +typedef struct cmdarg_type_struct  cmdarg_type_t;
 +
 +// note, this is called before options are parsed!
@@ -4814,6 +4823,7 @@
 +  // convenience shortcuts
 +  cmdarg_eol      = 0x0003, // catchall + plain
 +  cmdarg_chreq    = 0x0018, // check + required
++  cmdarg_ppclear  = 0x00E0, // pre-parse clear = visited + checked + freeme
 +} cmdarg_flags_t;
 +
 +struct cmdopts_struct {
@@ -4826,12 +4836,6 @@
 +  cmdopts_t     **cmds;    // [user,req] subcommands
 +  gpointer      userdata;  // [user]
 +};
-+struct cmdopt_struct {
-+  cmdopt_flags_t flags;    // [user,req] switch
-+  char           shortopt; // [user,req]
-+  const char     *longopt; // [user,req]
-+  cmdarg_t       arg;      // [user,req]
-+};
 +struct cmdarg_struct {
 +  const char     *name;    // [user,req] argument name - errors, help
 +  cmdarg_flags_t flags;    // [user,req] catchall, plain, required, subcommand
@@ -4841,6 +4845,12 @@
 +  gpointer       userdata; // [user]
 +  cmdarg_value_t value;    // [parser,chk] current value
 +};
++struct cmdopt_struct {
++  cmdopt_flags_t flags;    // [user,req] switch
++  char           shortopt; // [user,req]
++  const char     *longopt; // [user,req]
++  cmdarg_t       arg;      // [user,req]
++};
 +
 +struct cmdarg_type_struct {
 +  cmdarg_checker_t    check;    // [user,req] check string and set argument value
@@ -4856,7 +4866,7 @@
 +// Updates current/end pointers. Parsed string MUST be writable.
 +// String may shrink in size (quotation/escapes), thus endpointer is also
 +// updated.
-+const char *cmdopts_parse_argument(gchar **pr, gchar *er, cmdarg_flags_t flags);
++const char *cmdopts_parse_argument(gchar **pr, gchar **er, cmdarg_flags_t flags);
 +
 +typedef enum {
 +  cmdexe_default        = 0,    // no flags
@@ -4889,6 +4899,50 @@
 +cmd_result_t process_line(const char *line);
 +
 +//
++//  Standard types
++//
++
+ typedef struct {
+-  char name[32];
+-  const char *help;
+-  guint completion_flags[2];
+-  void (*func)(char *);
+-  gpointer userdata;
+-} cmd;
++  const char *name;
++  guint      value;
++} string2enum_t;
+ 
+-void cmd_init(void);
+-cmd *cmd_get(const char *command);
+-int  process_line(const char *line);
+-int  process_command(const char *line, guint iscmd);
+-char *expandalias(const char *line);
+-#ifdef MODULES_ENABLE
+-gpointer cmd_del(gpointer id);
+-gpointer cmd_add(const char *name, const char *help, guint flags1, guint flags2,
+-                 void (*f)(char*), gpointer userdata);
+-gboolean cmd_set_safe(const gchar *name, gboolean safe);
++void cmdarg_free_gfree (cmdarg_t *arg);
++
++gchar *cmdarg_check_nonspace        (cmdarg_t *arg);
++gchar *cmdarg_check_roster_bjid     (cmdarg_t *arg);
++gchar *cmdarg_check_roster_resource (cmdarg_t *arg);
++gchar *cmdarg_check_fjid            (cmdarg_t *arg);
++gchar *cmdarg_check_uint            (cmdarg_t *arg);
++gchar *cmdarg_check_statusmask      (cmdarg_t *arg);
++gchar *cmdarg_check_string2enum     (cmdarg_t *arg);
++
++const cmdarg_type_t *cmdarg_type_nonspace;
++const cmdarg_type_t *cmdarg_type_roster_bjid;
++const cmdarg_type_t *cmdarg_type_roster_resource;
++const cmdarg_type_t *cmdarg_type_fjid;
++const cmdarg_type_t *cmdarg_type_uint;
++const cmdarg_type_t *cmdarg_type_statusmask;
++const cmdarg_type_t *cmdarg_type_string2enum;
++const cmdarg_type_t *cmdarg_type_color;
++
++//
 +//  Private
 +//
 +
@@ -4925,9 +4979,9 @@
  
  #endif /* __MCABBER_COMMANDS_H__ */
  
-diff -r 92fa48ef53c9 mcabber/mcabber/roster.c
---- a/mcabber/mcabber/roster.c	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/mcabber/roster.c	Mon Mar 11 01:32:27 2013 +0200
+diff -r b527e8800278 mcabber/mcabber/roster.c
+--- a/mcabber/mcabber/roster.c	Mon Mar 11 21:45:31 2013 +0200
++++ b/mcabber/mcabber/roster.c	Tue Mar 12 01:21:22 2013 +0200
 @@ -1586,13 +1586,14 @@
  // Look for a buddy whose name or jid contains string.
  // Search begins at current_buddy; if no match is found in the the buddylist,
@@ -4966,10 +5020,10 @@
        if (found)
          return buddy;
      }
-diff -r 92fa48ef53c9 mcabber/mcabber/screen.c
---- a/mcabber/mcabber/screen.c	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/mcabber/screen.c	Mon Mar 11 01:32:27 2013 +0200
-@@ -3626,7 +3626,7 @@
+diff -r b527e8800278 mcabber/mcabber/screen.c
+--- a/mcabber/mcabber/screen.c	Mon Mar 11 21:45:31 2013 +0200
++++ b/mcabber/mcabber/screen.c	Tue Mar 12 01:21:22 2013 +0200
+@@ -3630,7 +3630,7 @@
  {
    scr_check_auto_away(TRUE);
    last_activity_buddy = current_buddy;
@@ -4978,9 +5032,9 @@
      return 255;
    // Add line to history
    scr_cmdhisto_addline(inputLine);
-diff -r 92fa48ef53c9 mcabber/mcabber/xmpp_iq.c
---- a/mcabber/mcabber/xmpp_iq.c	Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/mcabber/xmpp_iq.c	Mon Mar 11 01:32:27 2013 +0200
+diff -r b527e8800278 mcabber/mcabber/xmpp_iq.c
+--- a/mcabber/mcabber/xmpp_iq.c	Mon Mar 11 21:45:31 2013 +0200
++++ b/mcabber/mcabber/xmpp_iq.c	Tue Mar 12 01:21:22 2013 +0200
 @@ -289,10 +289,7 @@
        if (value) {
          for (s = adhoc_status_list; !s->name || strcmp(s->name, value); s++);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fix-nickcolor-memleak.diff	Tue Mar 12 01:23:02 2013 +0200
@@ -0,0 +1,24 @@
+# HG changeset patch
+# Parent a70b6bce62ccc3866f844b7a5e4e6bb27309c11f
+Fix memleak on replacing nickcolor rules
+
+diff -r a70b6bce62cc -r 646da4f1d2e1 mcabber/mcabber/screen.c
+--- a/mcabber/mcabber/screen.c	Fri Jan 18 11:23:51 2013 +0200
++++ b/mcabber/mcabber/screen.c	Mon Mar 11 21:45:20 2013 +0200
+@@ -338,11 +338,15 @@
+       g_free(mnick);
+     } else {
+       nickcolor *nc = g_new(nickcolor, 1);
++      nickcolor *oc;
+       ensure_string_htable(&nickcolors, NULL);
+       nc->manual = TRUE;
+       nc->color = cl;
+       // Free the struct, if any there already
+-      g_free(g_hash_table_lookup(nickcolors, mnick));
++      if ((oc = g_hash_table_lookup(nickcolors, mnick))) {
++        g_free(oc -> color);
++        g_free(oc);
++      }
+       // Save the new ones
+       g_hash_table_replace(nickcolors, mnick, nc);
+       g_hash_table_replace(nickcolors, snick, nc);
--- a/series	Mon Mar 11 01:33:26 2013 +0200
+++ b/series	Tue Mar 12 01:23:02 2013 +0200
@@ -1,6 +1,7 @@
 automake-fix-deprecated-macro.diff
 use-otr-v4.diff
 fix-date-fill.diff
+fix-nickcolor-memleak.diff
 switch-to-experimental.diff
 separate-extcmd.diff
 modularize-extcmd.diff