[cmdopts,fix-xa] Gradual conversion & error elimination
authorMyhailo Danylenko <isbear@ukrpost.net>
Wed, 13 Mar 2013 17:54:09 +0200
changeset 78 ee30584c654b
parent 77 7197414053c9
child 79 07e696e91b6f
[cmdopts,fix-xa] Gradual conversion & error elimination * add fix-set-status-rc-xa.diff * converted commands up to /group with no compiler errors
cmdopts.diff
fix-set-status-rc-xa.diff
series
--- a/cmdopts.diff	Wed Mar 13 03:23:11 2013 +0200
+++ b/cmdopts.diff	Wed Mar 13 17:54:09 2013 +0200
@@ -1,5 +1,5 @@
 # HG changeset patch
-# Parent b527e88002781b92309dfd32d80f4e04170bb2cf
+# Parent 1b0b563a81e6425da07c1da7ea4f947c4f3326cb
 [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 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	Wed Mar 13 03:21:24 2013 +0200
+diff -r 1b0b563a81e6 mcabber/doc/help/cs/hlp_buffer.txt
+--- a/mcabber/doc/help/cs/hlp_buffer.txt	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/doc/help/cs/hlp_buffer.txt	Wed Mar 13 17:51:29 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 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	Wed Mar 13 03:21:24 2013 +0200
+diff -r 1b0b563a81e6 mcabber/doc/help/cs/hlp_del.txt
+--- a/mcabber/doc/help/cs/hlp_del.txt	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/doc/help/cs/hlp_del.txt	Wed Mar 13 17:51:29 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 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	Wed Mar 13 03:21:24 2013 +0200
+diff -r 1b0b563a81e6 mcabber/doc/help/cs/hlp_move.txt
+--- a/mcabber/doc/help/cs/hlp_move.txt	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/doc/help/cs/hlp_move.txt	Wed Mar 13 17:51:29 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 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	Wed Mar 13 03:21:24 2013 +0200
+diff -r 1b0b563a81e6 mcabber/doc/help/cs/hlp_rename.txt
+--- a/mcabber/doc/help/cs/hlp_rename.txt	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/doc/help/cs/hlp_rename.txt	Wed Mar 13 17:51:29 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 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	Wed Mar 13 03:21:24 2013 +0200
+diff -r 1b0b563a81e6 mcabber/doc/help/de/hlp_buffer.txt
+--- a/mcabber/doc/help/de/hlp_buffer.txt	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/doc/help/de/hlp_buffer.txt	Wed Mar 13 17:51:29 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 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	Wed Mar 13 03:21:24 2013 +0200
+diff -r 1b0b563a81e6 mcabber/doc/help/de/hlp_del.txt
+--- a/mcabber/doc/help/de/hlp_del.txt	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/doc/help/de/hlp_del.txt	Wed Mar 13 17:51:29 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 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	Wed Mar 13 03:21:24 2013 +0200
+diff -r 1b0b563a81e6 mcabber/doc/help/de/hlp_move.txt
+--- a/mcabber/doc/help/de/hlp_move.txt	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/doc/help/de/hlp_move.txt	Wed Mar 13 17:51:29 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 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	Wed Mar 13 03:21:24 2013 +0200
+diff -r 1b0b563a81e6 mcabber/doc/help/de/hlp_rename.txt
+--- a/mcabber/doc/help/de/hlp_rename.txt	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/doc/help/de/hlp_rename.txt	Wed Mar 13 17:51:29 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 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	Wed Mar 13 03:21:24 2013 +0200
+diff -r 1b0b563a81e6 mcabber/doc/help/en/hlp_buffer.txt
+--- a/mcabber/doc/help/en/hlp_buffer.txt	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/doc/help/en/hlp_buffer.txt	Wed Mar 13 17:51:29 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 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	Wed Mar 13 03:21:24 2013 +0200
+diff -r 1b0b563a81e6 mcabber/doc/help/en/hlp_del.txt
+--- a/mcabber/doc/help/en/hlp_del.txt	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/doc/help/en/hlp_del.txt	Wed Mar 13 17:51:29 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 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	Wed Mar 13 03:21:24 2013 +0200
+diff -r 1b0b563a81e6 mcabber/doc/help/en/hlp_move.txt
+--- a/mcabber/doc/help/en/hlp_move.txt	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/doc/help/en/hlp_move.txt	Wed Mar 13 17:51:29 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 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	Wed Mar 13 03:21:24 2013 +0200
+diff -r 1b0b563a81e6 mcabber/doc/help/en/hlp_rename.txt
+--- a/mcabber/doc/help/en/hlp_rename.txt	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/doc/help/en/hlp_rename.txt	Wed Mar 13 17:51:29 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 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	Wed Mar 13 03:21:24 2013 +0200
+diff -r 1b0b563a81e6 mcabber/doc/help/fr/hlp_buffer.txt
+--- a/mcabber/doc/help/fr/hlp_buffer.txt	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/doc/help/fr/hlp_buffer.txt	Wed Mar 13 17:51:29 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 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	Wed Mar 13 03:21:24 2013 +0200
+diff -r 1b0b563a81e6 mcabber/doc/help/fr/hlp_del.txt
+--- a/mcabber/doc/help/fr/hlp_del.txt	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/doc/help/fr/hlp_del.txt	Wed Mar 13 17:51:29 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 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	Wed Mar 13 03:21:24 2013 +0200
+diff -r 1b0b563a81e6 mcabber/doc/help/fr/hlp_move.txt
+--- a/mcabber/doc/help/fr/hlp_move.txt	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/doc/help/fr/hlp_move.txt	Wed Mar 13 17:51:29 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 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	Wed Mar 13 03:21:24 2013 +0200
+diff -r 1b0b563a81e6 mcabber/doc/help/fr/hlp_rename.txt
+--- a/mcabber/doc/help/fr/hlp_rename.txt	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/doc/help/fr/hlp_rename.txt	Wed Mar 13 17:51:29 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 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	Wed Mar 13 03:21:24 2013 +0200
+diff -r 1b0b563a81e6 mcabber/doc/help/it/hlp_buffer.txt
+--- a/mcabber/doc/help/it/hlp_buffer.txt	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/doc/help/it/hlp_buffer.txt	Wed Mar 13 17:51:29 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 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	Wed Mar 13 03:21:24 2013 +0200
+diff -r 1b0b563a81e6 mcabber/doc/help/it/hlp_del.txt
+--- a/mcabber/doc/help/it/hlp_del.txt	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/doc/help/it/hlp_del.txt	Wed Mar 13 17:51:29 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 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	Wed Mar 13 03:21:24 2013 +0200
+diff -r 1b0b563a81e6 mcabber/doc/help/it/hlp_move.txt
+--- a/mcabber/doc/help/it/hlp_move.txt	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/doc/help/it/hlp_move.txt	Wed Mar 13 17:51:29 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 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	Wed Mar 13 03:21:24 2013 +0200
+diff -r 1b0b563a81e6 mcabber/doc/help/it/hlp_rename.txt
+--- a/mcabber/doc/help/it/hlp_rename.txt	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/doc/help/it/hlp_rename.txt	Wed Mar 13 17:51:29 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 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	Wed Mar 13 03:21:24 2013 +0200
+diff -r 1b0b563a81e6 mcabber/doc/help/nl/hlp_buffer.txt
+--- a/mcabber/doc/help/nl/hlp_buffer.txt	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/doc/help/nl/hlp_buffer.txt	Wed Mar 13 17:51:29 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 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	Wed Mar 13 03:21:24 2013 +0200
+diff -r 1b0b563a81e6 mcabber/doc/help/nl/hlp_del.txt
+--- a/mcabber/doc/help/nl/hlp_del.txt	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/doc/help/nl/hlp_del.txt	Wed Mar 13 17:51:29 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 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	Wed Mar 13 03:21:24 2013 +0200
+diff -r 1b0b563a81e6 mcabber/doc/help/nl/hlp_move.txt
+--- a/mcabber/doc/help/nl/hlp_move.txt	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/doc/help/nl/hlp_move.txt	Wed Mar 13 17:51:29 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 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	Wed Mar 13 03:21:24 2013 +0200
+diff -r 1b0b563a81e6 mcabber/doc/help/nl/hlp_rename.txt
+--- a/mcabber/doc/help/nl/hlp_rename.txt	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/doc/help/nl/hlp_rename.txt	Wed Mar 13 17:51:29 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 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	Wed Mar 13 03:21:24 2013 +0200
+diff -r 1b0b563a81e6 mcabber/doc/help/pl/hlp_del.txt
+--- a/mcabber/doc/help/pl/hlp_del.txt	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/doc/help/pl/hlp_del.txt	Wed Mar 13 17:51:29 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 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	Wed Mar 13 03:21:24 2013 +0200
+diff -r 1b0b563a81e6 mcabber/doc/help/pl/hlp_move.txt
+--- a/mcabber/doc/help/pl/hlp_move.txt	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/doc/help/pl/hlp_move.txt	Wed Mar 13 17:51:29 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 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	Wed Mar 13 03:21:24 2013 +0200
+diff -r 1b0b563a81e6 mcabber/doc/help/pl/hlp_rename.txt
+--- a/mcabber/doc/help/pl/hlp_rename.txt	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/doc/help/pl/hlp_rename.txt	Wed Mar 13 17:51:29 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 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	Wed Mar 13 03:21:24 2013 +0200
+diff -r 1b0b563a81e6 mcabber/doc/help/ru/hlp_buffer.txt
+--- a/mcabber/doc/help/ru/hlp_buffer.txt	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/doc/help/ru/hlp_buffer.txt	Wed Mar 13 17:51:29 2013 +0200
 @@ -25,7 +25,7 @@
   Перемещает на [n] строк вверх в буфере (истории переписки) (по умолчанию: половина экрана)
  /buffer down [n]
@@ -343,9 +343,9 @@
   Перемещает в первой строке после определенной даты [date] в буфере (истории переписки) (формат даты: "год-месяц-день", для примера "2006-01-01")
  /buffer % n
   Перемещает на позицию %n в текущем буфере (истории переписки)
-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	Wed Mar 13 03:21:24 2013 +0200
+diff -r 1b0b563a81e6 mcabber/doc/help/ru/hlp_del.txt
+--- a/mcabber/doc/help/ru/hlp_del.txt	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/doc/help/ru/hlp_del.txt	Wed Mar 13 17:51:29 2013 +0200
 @@ -1,4 +1,4 @@
  
 - /DEL
@@ -353,9 +353,9 @@
  
 -Удаляет текущего пользователя из списка контактов, отключает уведомления о его статусе и отключает уведомления пользователя о вашем статусе.
 +Удаляет текущего пользователя (или указанного с помощью jid) из списка контактов, отключает уведомления о его статусе и отключает уведомление пользователя о вашем статусе.
-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	Wed Mar 13 03:21:24 2013 +0200
+diff -r 1b0b563a81e6 mcabber/doc/help/ru/hlp_move.txt
+--- a/mcabber/doc/help/ru/hlp_move.txt	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/doc/help/ru/hlp_move.txt	Wed Mar 13 17:51:29 2013 +0200
 @@ -1,6 +1,7 @@
  
 - /MOVE [groupname]
@@ -365,9 +365,9 @@
 +С помощью параметров --jid и --name можно перемещать контакты, отличные от текущего.
  Полезно: Если включен режим чата (chatmode), Вы можете использовать "/roster alternate" для перехода к перемещенному пользователю.
  
-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	Wed Mar 13 03:21:24 2013 +0200
+diff -r 1b0b563a81e6 mcabber/doc/help/ru/hlp_rename.txt
+--- a/mcabber/doc/help/ru/hlp_rename.txt	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/doc/help/ru/hlp_rename.txt	Wed Mar 13 17:51:29 2013 +0200
 @@ -1,4 +1,6 @@
  
 - /RENAME name
@@ -377,9 +377,9 @@
 +Переименовывает текущего пользователя или группу в заданное имя "newname".
 +Если указан параметр --reset, "newname" игнорируется, а имя сбрасывается (mcabber будет отображать JID или имя пользователя по умолчанию).
 +Для указания обьекта, отличного от текущего, можно использовать опции --jid, --group и --name.
-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	Wed Mar 13 03:21:24 2013 +0200
+diff -r 1b0b563a81e6 mcabber/doc/help/uk/hlp_buffer.txt
+--- a/mcabber/doc/help/uk/hlp_buffer.txt	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/doc/help/uk/hlp_buffer.txt	Wed Mar 13 17:51:29 2013 +0200
 @@ -25,7 +25,7 @@
   Посунути буфер вверх на n рядків (якщо не вказано - пів екрану).
  /buffer down [n]
@@ -389,9 +389,9 @@
   Перейти до першого повідомлення після дати (дата вигляду РРРР-ММ-ДД).
  /buffer % процент
   Перейти до вказаної у процентах позиції.
-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	Wed Mar 13 03:21:24 2013 +0200
+diff -r 1b0b563a81e6 mcabber/doc/help/uk/hlp_del.txt
+--- a/mcabber/doc/help/uk/hlp_del.txt	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/doc/help/uk/hlp_del.txt	Wed Mar 13 17:51:29 2013 +0200
 @@ -1,4 +1,4 @@
  
 - /DEL
@@ -399,9 +399,9 @@
  
 -Потерти поточний контакт зі списку. На додачу відписатися від його повідомлень про статус і відписати його від ваших.
 +Потерти поточний контакт (або контакт, що має вказаний jid) зі списку. Також відписатися від його сповіщень про статус і відписати його від ваших.
-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	Wed Mar 13 03:21:24 2013 +0200
+diff -r 1b0b563a81e6 mcabber/doc/help/uk/hlp_move.txt
+--- a/mcabber/doc/help/uk/hlp_move.txt	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/doc/help/uk/hlp_move.txt	Wed Mar 13 17:51:29 2013 +0200
 @@ -1,5 +1,6 @@
  
 - /MOVE [група]
@@ -411,9 +411,9 @@
 +Переносить поточний контакт до вказаної групи. Якщо групу не вказати контакт опиниться у головній групі. Якщо групи не існує, її буде створено.
 +За допомогою опцій --jid та --name можна перемістити контакт, відмінний від поточного.
  Примітка: в режимі розмови можна використати "/roster alternate", щоб перейти до нового місця контакту контакту.
-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	Wed Mar 13 03:21:24 2013 +0200
+diff -r 1b0b563a81e6 mcabber/doc/help/uk/hlp_rename.txt
+--- a/mcabber/doc/help/uk/hlp_rename.txt	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/doc/help/uk/hlp_rename.txt	Wed Mar 13 17:51:29 2013 +0200
 @@ -1,4 +1,6 @@
  
 - /RENAME ім'я
@@ -422,9 +422,9 @@
  Змінює прізвисько поточного контакту або назву групи.
 +За допомогою параметра --reset можна повернути контакту типову назву. При цьому нове ім’я (якщо вказане) ігнорується.
 +Опції --jid, --group та --name дозволяють перейменовувати об’єкти, відмінні від поточного.
-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	Wed Mar 13 03:21:24 2013 +0200
+diff -r 1b0b563a81e6 mcabber/mcabber/commands.c
+--- a/mcabber/mcabber/commands.c	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/mcabber/commands.c	Wed Mar 13 17:51:29 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,671 @@
+@@ -43,512 +43,631 @@
  #include "xmpp.h"
  #include "main.h"
  
@@ -456,9 +456,9 @@
 +  scmd_group_unfold = 0,
 +  scmd_group_fold   = 1,
 +  scmd_group_toggle = -1,
-+} group_scmd_t;
-+
-+static void group_cmd (gpointer group, group_scmd_t action);
++} scmd_group_t;
++
++static void group_cmd (gpointer group, scmd_group_t action);
 +
 +//static void room_bookmark(gpointer bud, char *arg);
 +
@@ -466,11 +466,11 @@
 +static cmdopts_t def_roster,
 +                 def_color,
 +                 def_status,
-+                 def_status_to;
-+#if 0
++                 def_status_to,
 +                 def_add,
 +                 def_del,
-+                 def_group,
++                 def_group;
++#if 0
 +                 def_say,
 +                 def_msay,
 +                 def_say_to,
@@ -555,46 +555,6 @@
 -#include "modules.h"
 -
 -gpointer cmd_del(gpointer id)
-+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
-+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
 +//
@@ -623,40 +583,40 @@
 +  cmd_list[1]  = &def_color;
 +  cmd_list[2]  = &def_status;
 +  cmd_list[3]  = &def_status_to;
++  cmd_list[4]  = &def_add;
++  cmd_list[5]  = &def_del;
++  cmd_list[6]  = &def_group;
 +#if 0
-+  cmd_list[4]  = def_add;
-+  cmd_list[5]  = def_del;
-+  cmd_list[6]  = def_group;
-+  cmd_list[7]  = def_say;
-+  cmd_list[8]  = def_msay;
-+  cmd_list[9]  = def_say_to;
-+  cmd_list[10] = def_buffer;
-+  cmd_list[11] = def_clear;
-+  cmd_list[12] = def_info;
-+  cmd_list[13] = def_rename;
-+  cmd_list[14] = def_move;
-+  cmd_list[15] = def_set;
-+  cmd_list[16] = def_alias;
-+  cmd_list[17] = def_bind;
-+  cmd_list[18] = def_connect;
-+  cmd_list[19] = def_disconnect;
-+  cmd_list[20] = def_rawxml;
-+  cmd_list[21] = def_room;
-+  cmd_list[22] = def_authorization;
-+  cmd_list[23] = def_version;
-+  cmd_list[24] = def_request;
-+  cmd_list[25] = def_event;
-+  cmd_list[26] = def_help;
-+  cmd_list[27] = def_pgp;
-+  cmd_list[28] = def_iline;
-+  cmd_list[29] = def_screen_refresh;
-+  cmd_list[30] = def_chat_disable;
-+  cmd_list[31] = def_source;
-+  cmd_list[32] = def_otr;
-+  cmd_list[33] = def_otrpolicy;
-+  cmd_list[34] = def_echo;
-+  cmd_list[35] = def_module;
-+  cmd_list[36] = def_exit;
++  cmd_list[7]  = &def_say;
++  cmd_list[8]  = &def_msay;
++  cmd_list[9]  = &def_say_to;
++  cmd_list[10] = &def_buffer;
++  cmd_list[11] = &def_clear;
++  cmd_list[12] = &def_info;
++  cmd_list[13] = &def_rename;
++  cmd_list[14] = &def_move;
++  cmd_list[15] = &def_set;
++  cmd_list[16] = &def_alias;
++  cmd_list[17] = &def_bind;
++  cmd_list[18] = &def_connect;
++  cmd_list[19] = &def_disconnect;
++  cmd_list[20] = &def_rawxml;
++  cmd_list[21] = &def_room;
++  cmd_list[22] = &def_authorization;
++  cmd_list[23] = &def_version;
++  cmd_list[24] = &def_request;
++  cmd_list[25] = &def_event;
++  cmd_list[26] = &def_help;
++  cmd_list[27] = &def_pgp;
++  cmd_list[28] = &def_iline;
++  cmd_list[29] = &def_screen_refresh;
++  cmd_list[30] = &def_chat_disable;
++  cmd_list[31] = &def_source;
++  cmd_list[32] = &def_otr;
++  cmd_list[33] = &def_otrpolicy;
++  cmd_list[34] = &def_echo;
++  cmd_list[35] = &def_module;
++  cmd_list[36] = &def_exit;
 +#endif
 +  cmd_list[BUILTIN_COUNT] = NULL;
 +
@@ -1117,7 +1077,7 @@
 -// ones in init_bindings()!
 -//
 -void cmd_init(void)
-+cmd_result_t cmd_execute_internal (gchar *commandline, cmdexe_flags_t flags)
++cmd_result_t cmd_execute (gchar *commandline, cmdexe_flags_t flags)
  {
 -  cmd_add("add", "Add a jabber user", COMPL_JID, 0, &do_add, NULL);
 -  cmd_add("alias", "Add an alias", 0, 0, &do_alias, NULL);
@@ -1592,7 +1552,7 @@
    if (!*line) { // User only pressed enter
      if (scr_get_multimode()) {
        scr_append_multiline("");
-@@ -556,141 +715,500 @@
+@@ -556,141 +675,584 @@
      }
      if (current_buddy) {
        if (buddy_gettype(BUDDATA(current_buddy)) & ROSTER_TYPE_GROUP)
@@ -1668,7 +1628,7 @@
 +      say_cmd(utf8, msgtype_not_set);
 +    retval = 0;
 +  } else { // command or verbatim multiline message
-+    retval = cmd_execute_internal (utf8, cmdexe_check_verbatim);
++    retval = cmd_execute (utf8, cmdexe_check_verbatim);
 +    if (retval == cmd_result_verbatim) {
 +      g_free(utf8); // buffer has been corrupted by parser
 +      utf8 = to_utf8(line);
@@ -1688,37 +1648,6 @@
 -  if (!jidres) {
 -    if (lock) return;
 -    jidres = ".";
--  }
--
--  if (jidres[0] == '.' &&
--      (jidres[1] == '\0' || jidres[1] == JID_RESOURCE_SEPARATOR)) {
--    //Special jid: . or ./resource
--    switch (jidres[1]) {
--      case JID_RESOURCE_SEPARATOR:
--        resource = jidres+2;
--      case '\0':
--        if (current_buddy)
--          bud = BUDDATA(current_buddy);
--    }
--  } else {
--    char *tmp;
--    if (!check_jid_syntax(jidres) &&
--        (tmp = strchr(jidres, JID_RESOURCE_SEPARATOR))) {
--      //Any other valid full jid
--      *tmp = '\0'; // for roster search by bare jid;
--      resource = tmp+1;
--      GSList *roster_elt;
--      roster_elt = roster_find(jidres, jidsearch,
--          ROSTER_TYPE_USER|ROSTER_TYPE_AGENT);
--      if (roster_elt)
--        bud = roster_elt->data;
--      *tmp = JID_RESOURCE_SEPARATOR;
--    }
--    if (!bud) {
--      //Resource for current buddy
--      if (current_buddy)
--        bud = BUDDATA(current_buddy);
--      resource = jidres;
 +//
 +//  Standard types
 +//
@@ -1726,12 +1655,13 @@
 +// mcabber commands.
 +//
 +
-+// TODO: (and variations with 'required')
++// TODO: move to separate file? (and variations with 'required')
 +// + cmdarg_type_roster_bjid     - in roster, with specified types -> bud
 +// + cmdarg_type_roster_resource - in roster, with specified types, have resource -> bud + resource
 +// * cmdarg_type_roster_fjid     - in roster, with specified types, might have non-existing resource -> bud + resource
 +// * cmdarg_type_roster_jid      - in roster, with specified types, might have or not have resource -> bud + (resource)
-+// * cmdarg_type_bjid         - any bjid -> bjid
++// * cmdarg_type_roster_group    - in roster, on '.' select group of current buddy -> bud
++// + cmdarg_type_bjid         - any bjid -> bjid
 +// + cmdarg_type_fjid         - any fjid -> fjid
 +// + cmdarg_type_statusmask   - string -> string
 +// + cmdarg_type_uint         - string -> uint
@@ -1742,7 +1672,7 @@
 +// * cmdarg_type_nick        - provide completions first from current room, then from all other, nonspace, do not restrict
 +
 +//
-+//  common methods
++//  generic destructors
 +//
 +
 +void cmdarg_free_gfree (cmdarg_t *arg)
@@ -1751,6 +1681,17 @@
 +}
 +
 +//
++//  command environment checkers
++//
++
++gchar *cmd_check_online (cmdopts_t *command)
++{
++  if (!xmpp_is_online())
++    return g_strdup ("You are not connected!");
++  return NULL;
++}
++
++//
 +//  string -> stripspace string
 +//
 +
@@ -1775,19 +1716,17 @@
 +      if (*val)
 +        *val = '\0';
 +      return NULL;
-     }
++    }
    }
--  
--  if (bud && buddy_gettype(bud) & (ROSTER_TYPE_USER|ROSTER_TYPE_AGENT)) {
--    if (lock) {
--      GSList *resources, *p_res;
--      gboolean found = FALSE;
--      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))
--          found = TRUE;
--        g_free(p_res->data);
-+
+ 
+-  if (jidres[0] == '.' &&
+-      (jidres[1] == '\0' || jidres[1] == JID_RESOURCE_SEPARATOR)) {
+-    //Special jid: . or ./resource
+-    switch (jidres[1]) {
+-      case JID_RESOURCE_SEPARATOR:
+-        resource = jidres+2;
+-      case '\0':
+-        if (current_buddy)
 +  // error
 +  arg -> value.arg = NULL;
 +  return g_strdup ("Non-space value required.");
@@ -1890,14 +1829,10 @@
 +        if (!current_buddy)
 +          error = g_strdup ("No buddy selected.");
 +        else if (buddy_gettype (BUDDATA(current_buddy)) & types)
-+          bud = BUDDATA(current_buddy);
+           bud = BUDDATA(current_buddy);
 +        else // TODO: improve message
 +          error = g_strdup_printf("Currently selected buddy is of wrong type.");
-       }
--      g_slist_free(resources);
--      if (!found) {
--        scr_LogPrint(LPRINT_NORMAL, "No such resource <%s>...", jidres);
--        return;
++      }
 +      if (bud) {
 +        GSList *resources, *p_res;
 +        gboolean found = FALSE;
@@ -1910,14 +1845,23 @@
 +        g_slist_free (resources);
 +        if (!found)
 +          error = g_strdup_printf ("No such resource <%s%c%s>...", buddy_getjid(bud), JID_RESOURCE_SEPARATOR, resource);
-       }
-+    }
++      }
+     }
 +  }
 +
 +  if (error) {
 +    arg -> userdata  = NULL;
 +    arg -> value.arg = NULL;
-+  } else {
+   } else {
+-    char *tmp;
+-    if (!check_jid_syntax(jidres) &&
+-        (tmp = strchr(jidres, JID_RESOURCE_SEPARATOR))) {
+-      //Any other valid full jid
+-      *tmp = '\0'; // for roster search by bare jid;
+-      resource = tmp+1;
+-      GSList *roster_elt;
+-      roster_elt = roster_find(jidres, jidsearch,
+-          ROSTER_TYPE_USER|ROSTER_TYPE_AGENT);
 +    arg -> userdata  = bud;
 +    arg -> value.arg = resource;
 +  }
@@ -1931,6 +1875,64 @@
 +};
 +
 +//
++//  name -> group bud
++//
++
++// Returns buddy roster entry in value.bud.
++// Recognizes as current ".".
++// Does not require freeing.
++// XXX:
++//  * group, named "."?
++gchar *cmdarg_check_roster_group (cmdarg_t *arg)
++{
++  gchar    *error;
++  gpointer group  = NULL;
++
++  if (!(error = cmdarg_check_nonspace(arg))) {
++    const char *name = arg -> value.arg;
++    if (!strcmp (name, ".")) {
++      if (current_buddy)
++        group = buddy_getgroup(BUDDATA(current_buddy));
++      else
++        error = g_strdup("Unable to determine current group: "
++                         "no buddy selected.");
++    } else {
++      GSList *roster_elt = roster_find (name, namesearch, ROSTER_TYPE_GROUP);
+       if (roster_elt)
+-        bud = roster_elt->data;
+-      *tmp = JID_RESOURCE_SEPARATOR;
+-    }
+-    if (!bud) {
+-      //Resource for current buddy
+-      if (current_buddy)
+-        bud = BUDDATA(current_buddy);
+-      resource = jidres;
++        group = buddy_getgroup(roster_elt->data);
++      else
++        error = g_strdup_printf("Group \"%s\" not found.", name);
+     }
+   }
+   
+-  if (bud && buddy_gettype(bud) & (ROSTER_TYPE_USER|ROSTER_TYPE_AGENT)) {
+-    if (lock) {
+-      GSList *resources, *p_res;
+-      gboolean found = FALSE;
+-      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))
+-          found = TRUE;
+-        g_free(p_res->data);
++  arg -> value.bud = group;
++  return error;
++}
++
++const cmdarg_type_t cmdarg_type_roster_group = {
++  cmdarg_check_roster_group,
++  NULL,
++  NULL,
++};
++
++//
 +//  fjid -> fjid
 +//
 +
@@ -1957,7 +1959,11 @@
 +      } else {
 +        arg -> value.arg = g_strdup_printf ("%s%c%s", jid, JID_RESOURCE_SEPARATOR, fjid + 2);
 +        arg -> flags    |= cmdarg_freeme;
-+      }
+       }
+-      g_slist_free(resources);
+-      if (!found) {
+-        scr_LogPrint(LPRINT_NORMAL, "No such resource <%s>...", jidres);
+-        return;
 +    } else if (check_jid_syntax(fjid)) {
 +      error = g_strdup_printf ("Jid <%s> is invalid.", fjid);
 +    }
@@ -1974,6 +1980,37 @@
 +  NULL,
 +};
 +
++
++//
++//  fjid -> bjid
++//
++
++// Returns corrected bjid in value.arg.
++// Recognizes as current "." and "./res" (but still removes resource).
++// Needs RW access to trim the resource - no resources in default values!
++// Requires freeing (as fjid).
++gchar *cmdarg_check_bjid (cmdarg_t *arg)
++{
++  gchar *error = NULL;
++
++  if (!(error = cmdarg_check_fjid(arg))) {
++    gchar *res = strchr (arg -> value.arg, JID_RESOURCE_SEPARATOR);
++    if (res != NULL)
++      *res = '\0';
++  }
++
++  if (error)
++    arg -> value.arg = NULL;
++  return error;
++}
++
++const cmdarg_type_t cmdarg_type_bjid = {
++  cmdarg_check_bjid,
++  cmdarg_free_gfree,
++  NULL,
++};
++
++
 +//
 +//  string -> uint
 +//
@@ -2037,8 +2074,7 @@
 +    if (!strcmp(arg -> value.arg, "*")) {
 +      arg -> value.arg = g_strdup (valid);
 +      arg -> flags    |= cmdarg_freeme;
-     } else {
--      resource = NULL;
++    } else {
 +      gchar *p = arg -> value.arg;
 +      gchar *e = p + strlen (p);
 +      while (p < e) {
@@ -2052,7 +2088,9 @@
 +          g_memmove (p, p+1, e-p-1);
 +          e --;
 +        }
-+      }
+       }
+-    } else {
+-      resource = NULL;
 +      if (arg -> value.arg == e) // arg is not required and we deleted all string
 +        arg -> value.arg = NULL;
      }
@@ -2203,7 +2241,7 @@
  static void display_and_free_note(struct annotation *note, const char *winId)
  {
    gchar tbuf[128];
-@@ -755,41 +1273,15 @@
+@@ -755,41 +1317,15 @@
    g_slist_free(notes);
  }
  
@@ -2253,13 +2291,15 @@
      struct annotation *note = xmpp_get_storage_rosternotes(bjid, FALSE);
      if (note) {
        display_and_free_note(note, bjid);
-@@ -800,194 +1292,293 @@
+@@ -800,484 +1336,568 @@
    }
  }
  
 -//  roster_updown(updown, nitems)
 -// updown: -1=up, +1=down
 -inline static void roster_updown(int updown, char *nitems)
++static gchar *do_roster (cmdopts_t *command);
++
 +typedef enum {
 +  scmd_roster_bottom, scmd_roster_top, scmd_roster_up, scmd_roster_down,
 +  scmd_roster_group_prev, scmd_roster_group_next,
@@ -2287,10 +2327,6 @@
 +    SCMD_ROSTER(bottom, NULL),
 +    SCMD_ROSTER(top,    NULL),
 +    SCMD_ROSTER(up,   (cmdarg_t[2]){{"n", cmdarg_chreq, "1", &cmdarg_type_uint},{NULL}}),
-+//    { "up", NULL, NULL, NULL,
-+//      (cmdarg_t[2]){{"n", cmdarg_chreq, "1", cmdarg_type_uint},{NULL}},
-+//      NULL, (gpointer)scmd_roster_up
-+//    }
 +    SCMD_ROSTER(down, (cmdarg_t[2]){{"n", cmdarg_chreq, "1", &cmdarg_type_uint},{NULL}}),
 +    SCMD_ROSTER(group_prev, NULL),
 +    SCMD_ROSTER(group_next, NULL),
@@ -2568,6 +2604,8 @@
 +
 +// command
 +
++static gchar *do_color (cmdopts_t *command);
++
 +typedef enum {
 +  scmd_color_roster,
 +  scmd_color_mucnick,
@@ -2610,7 +2648,7 @@
 +  },
 +};
 +
-+static gchar *do_color(cmdopts_t *options)
++static gchar *do_color (cmdopts_t *options)
 +{
 +  scmd_color_t subcmd = (scmd_color_t) options -> args[0].value.cmd -> userdata;
 +
@@ -2686,90 +2724,50 @@
  }
  
 -//  cmd_setstatus(recipient, arg)
-+//
-+//  /status
-+//
-+
-+// FIXME: this should go to xmpp_iq, that uses it
-+//  cmd_setstatus(recipient, status, message)
- // Set your Jabber status.
+-// Set your Jabber status.
 -// - if recipient is not NULL, the status is sent to this contact only
 -// - arg must be "status message" (message is optional)
 -void cmd_setstatus(const char *recipient, const char *arg)
-+// If recipient is not NULL, the status is sent to this contact only.
-+void cmd_setstatus(const char *recipient, const char *status, const char *msg)
- {
--  char **paramlst;
--  char *status;
--  char *msg;
-   enum imstatus st;
- 
-   if (!xmpp_is_online())
-@@ -1000,15 +1591,15 @@
-   if (!recipient)
-     scr_check_auto_away(TRUE);
- 
--  paramlst = split_arg(arg, 2, 1); // status, message
--  status = *paramlst;
--  msg = *(paramlst+1);
--
-   if (!status) {
--    free_arg_lst(paramlst);
-     return;
-   }
- 
-+  // Use provided message
-+  if (msg && !*msg) {
-+    msg = NULL;
-+  }
-+
-   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 +1611,349 @@
-   else if (!strcasecmp(status, IMSTATUS_NOTAVAILABLE))  st = notavail;
-   else if (!strcasecmp(status, IMSTATUS_FREE4CHAT))     st = freeforchat;
-   else if (!strcasecmp(status, "message")) {
--    if (!msg || !*msg) {
-+    if (!msg) {
-       // We want a message.  If there's none, we give up.
-       scr_LogPrint(LPRINT_NORMAL, "Missing parameter.");
--      free_arg_lst(paramlst);
-       return;
-     }
-     st = xmpp_getstatus();  // Preserve current status
-   } else {
-     scr_LogPrint(LPRINT_NORMAL, "Unrecognized status!");
--    free_arg_lst(paramlst);
-     return;
-   }
- 
--  // Use provided message
--  if (msg && !*msg) {
--    msg = NULL;
--  }
--
-   // If a recipient is specified, let's don't use default status messages
-   if (recipient && !msg)
-     msg = "";
- 
-   xmpp_setstatus(st, recipient, msg, FALSE);
--
--  free_arg_lst(paramlst);
- }
- 
--static void do_status(char *arg)
++//
++//  /status
++//
++
 +// custom type
 +
 +// needs corresponding s2e in chkdata
 +static gchar *cmdarg_check_status_status (cmdarg_t *arg)
  {
--  if (!*arg) {
+-  char **paramlst;
+-  char *status;
+-  char *msg;
+-  enum imstatus st;
+-
+-  if (!xmpp_is_online())
+-    scr_LogPrint(LPRINT_NORMAL, "You are currently not connected...");
+-  // We do not return now, so that the status is memorized and used later...
+-
+-  // It makes sense to reset autoaway before changing the status
+-  // (esp. for FIFO or remote commands) or the behaviour could be
+-  // unexpected...
+-  if (!recipient)
+-    scr_check_auto_away(TRUE);
+-
+-  paramlst = split_arg(arg, 2, 1); // status, message
+-  status = *paramlst;
+-  msg = *(paramlst+1);
+-
+-  if (!status) {
+-    free_arg_lst(paramlst);
+-    return;
 +  if (!g_strcmp0(arg -> value.arg, "message")) {
 +    arg -> value.uint = xmpp_getstatus(); // Preserve current status
 +    return NULL;
-+  }
-+
+   }
+ 
+-  if      (!strcasecmp(status, IMSTATUS_OFFLINE))       st = offline;
+-  else if (!strcasecmp(status, IMSTATUS_ONLINE))        st = available;
+-  else if (!strcasecmp(status, IMSTATUS_AVAILABLE))     st = available;
+-  else if (!strcasecmp(status, IMSTATUS_AWAY))          st = away;
 +  return cmdarg_check_string2enum (arg);
 +}
 +
@@ -2781,6 +2779,8 @@
 +
 +// command
 +
++static gchar *do_status (cmdopts_t *command);
++
 +static const string2enum_t s2e_status2[] = {
 +  { "away",      away        },
 +  { "offline",   offline     },
@@ -2789,9 +2789,42 @@
 +  { "notavail",  notavail    },
 +  { "dnd",       dontdisturb },
 +  { "free",      freeforchat },
-+#ifdef WITH_DEPRECATED_STATUS_INVISIBLE
+ #ifdef WITH_DEPRECATED_STATUS_INVISIBLE
+-  else if (!strcasecmp(status, IMSTATUS_INVISIBLE))     st = invisible;
 +  { "invisible", invisible   },
-+#endif
+ #endif
+-  else if (!strcasecmp(status, IMSTATUS_DONOTDISTURB))  st = dontdisturb;
+-  else if (!strcasecmp(status, IMSTATUS_NOTAVAILABLE))  st = notavail;
+-  else if (!strcasecmp(status, IMSTATUS_FREE4CHAT))     st = freeforchat;
+-  else if (!strcasecmp(status, "message")) {
+-    if (!msg || !*msg) {
+-      // We want a message.  If there's none, we give up.
+-      scr_LogPrint(LPRINT_NORMAL, "Missing parameter.");
+-      free_arg_lst(paramlst);
+-      return;
+-    }
+-    st = xmpp_getstatus();  // Preserve current status
+-  } else {
+-    scr_LogPrint(LPRINT_NORMAL, "Unrecognized status!");
+-    free_arg_lst(paramlst);
+-    return;
+-  }
+-
+-  // Use provided message
+-  if (msg && !*msg) {
+-    msg = NULL;
+-  }
+-
+-  // If a recipient is specified, let's don't use default status messages
+-  if (recipient && !msg)
+-    msg = "";
+-
+-  xmpp_setstatus(st, recipient, msg, FALSE);
+-
+-  free_arg_lst(paramlst);
+-}
+-
+-static void do_status(char *arg)
 +  // XXX ugly
 +  { "show",      imstatus_size},
 +  { NULL,        0           },
@@ -2811,27 +2844,35 @@
 +  NULL,
 +};
 +
-+static gchar *do_status(cmdopts_t *options)
-+{
++static gchar *do_status (cmdopts_t *options)
+ {
+-  if (!*arg) {
 +  if (options -> args[0].value.uint == imstatus_size) {
      const char *sm = xmpp_getstatusmsg();
      scr_LogPrint(LPRINT_NORMAL, "Your status is: [%c] %s",
                   imstatus2char[xmpp_getstatus()],
                   (sm ? sm : ""));
+-    return;
 +  } else {
 +    if (!xmpp_is_online())
 +      scr_LogPrint(LPRINT_NORMAL, "You are currently not connected...");
 +    scr_check_auto_away(TRUE);
 +    xmpp_setstatus(options -> args[0].value.uint, NULL,
 +                   options -> args[1].value.arg, FALSE);
-+  }
+   }
+-  arg = to_utf8(arg);
+-  cmd_setstatus(NULL, arg);
+-  g_free(arg);
 +  return NULL;
-+}
-+
+ }
+ 
+-static void do_status_to(char *arg)
 +//
 +//  /status_to
 +//
 +
++static gchar *do_status_to (cmdopts_t *command);
++
 +// no "show" here
 +static const string2enum_t s2e_status[] = {
 +  { "away",      away        },
@@ -2862,8 +2903,22 @@
 +  NULL,
 +};
 +
-+static gchar *do_status_to(cmdopts_t *options)
-+{
++static gchar *do_status_to (cmdopts_t *options)
+ {
+-  char **paramlst;
+-  char *fjid, *st, *msg;
+-  char *jid_utf8 = NULL;
+-
+-  paramlst = split_arg(arg, 3, 1); // jid, status, [message]
+-  fjid = *paramlst;
+-  st = *(paramlst+1);
+-  msg = *(paramlst+2);
+-
+-  if (!fjid || !st) {
+-    scr_LogPrint(LPRINT_NORMAL,
+-                 "Please specify both a Jabber ID and a status.");
+-    free_arg_lst(paramlst);
+-    return;
 +  const char *fjid, *stname, *msg;
 +  enum imstatus st;
 +
@@ -2878,7 +2933,31 @@
 +        stname = list -> name;
 +        break;
 +      }
-+  }
+   }
+-
+-  // Allow things like /status_to "" away
+-  if (!*fjid || !strcmp(fjid, "."))
+-    fjid = NULL;
+-
+-  if (fjid) {
+-    // The JID has been specified.  Quick check...
+-    if (check_jid_syntax(fjid)) {
+-      scr_LogPrint(LPRINT_NORMAL|LPRINT_NOTUTF8,
+-                   "<%s> is not a valid Jabber ID.", fjid);
+-      fjid = NULL;
+-    } else {
+-      // Convert jid to lowercase
+-      char *p = fjid;
+-      for ( ; *p && *p != JID_RESOURCE_SEPARATOR; p++)
+-        *p = tolower(*p);
+-      fjid = jid_utf8 = to_utf8(fjid);
+-    }
+-  } else {
+-    // Add the current buddy
+-    if (current_buddy)
+-      fjid = (char*)buddy_getjid(BUDDATA(current_buddy));
+-    if (!fjid)
+-      scr_LogPrint(LPRINT_NORMAL, "Please specify a Jabber ID.");
 +  // prevent default status message
 +  msg = msg ? msg : "";
 +
@@ -2890,89 +2969,81 @@
 +
 +  return NULL;
 +}
-+  
-+#if 0
-+static void do_add(char *arg)
++
++//
++//  /add
++//
++
++static gchar *do_add (cmdopts_t *command);
++
++static cmdopts_t def_add = {
++  "add",
++  cmd_default,
++  cmd_check_online,
++  do_add,
++  NULL,
++  (cmdarg_t[3]){
++    {"jid",  cmdarg_chreq,   ".",  &cmdarg_type_bjid},
++    {"name", cmdarg_default, NULL, &cmdarg_type_nonspace},
++    {NULL}
++  },
++  NULL,
++};
++
++static gchar *do_add (cmdopts_t *options)
 +{
-+  cmdopts_t options = {
-+    "add",
-+    NULL,
-+    (cmdarg_t[2]){
-+      // jid
-+      { 0,                                            { .arg = "."  } },
-+      // rostername
-+      { CMDOPT_CATCHALL | CMDOPT_PLAIN | CMDOPT_LAST, { .arg = NULL } },
-+    },
-+    NULL,
-+  };
-+  gchar *jid, *nick;
-+
-+  if (!xmpp_is_online()) {
-+    scr_LogPrint(LPRINT_NORMAL, "You are not connected.");
-     return;
-   }
--  arg = to_utf8(arg);
--  cmd_setstatus(NULL, arg);
--  g_free(arg);
--}
--
--static void do_status_to(char *arg)
--{
--  char **paramlst;
--  char *fjid, *st, *msg;
--  char *jid_utf8 = NULL;
--
--  paramlst = split_arg(arg, 3, 1); // jid, status, [message]
--  fjid = *paramlst;
--  st = *(paramlst+1);
--  msg = *(paramlst+2);
--
--  if (!fjid || !st) {
--    scr_LogPrint(LPRINT_NORMAL,
--                 "Please specify both a Jabber ID and a status.");
--    free_arg_lst(paramlst);
-+
-+  if (cmdopts_parse(arg, &options))
-     return;
--  }
--
--  // Allow things like /status_to "" away
--  if (!*fjid || !strcmp(fjid, "."))
--    fjid = NULL;
--
--  if (fjid) {
-+
-+  jid  = options.args[0].value.arg;
-+  nick = options.args[1].value.arg;
-+
-+  if (jid && (!*jid || !strcmp(jid, ".")))
-+    jid = NULL;
-+
-+  if (jid) {
-     // The JID has been specified.  Quick check...
--    if (check_jid_syntax(fjid)) {
--      scr_LogPrint(LPRINT_NORMAL|LPRINT_NOTUTF8,
--                   "<%s> is not a valid Jabber ID.", fjid);
--      fjid = NULL;
-+    if (check_jid_syntax(jid)) {
-+      scr_LogPrint(LPRINT_NORMAL, "<%s> is not a valid Jabber ID.", jid);
-+      jid = NULL;
-     } else {
--      // Convert jid to lowercase
--      char *p = fjid;
--      for ( ; *p && *p != JID_RESOURCE_SEPARATOR; p++)
--        *p = tolower(*p);
--      fjid = jid_utf8 = to_utf8(fjid);
-+      mc_strtolower(jid);
-     }
-   } else {
-     // Add the current buddy
-     if (current_buddy)
--      fjid = (char*)buddy_getjid(BUDDATA(current_buddy));
--    if (!fjid)
-+      jid = (char*)buddy_getjid(BUDDATA(current_buddy));
-+    if (!jid)
-       scr_LogPrint(LPRINT_NORMAL, "Please specify a Jabber ID.");
++  gchar *jid = options -> args[0].value.arg;
++
++  // XXX
++  //mc_strtolower(jid);
++
++  xmpp_addbuddy(jid, options -> args[1].value.arg, NULL);
++  scr_LogPrint(LPRINT_LOGNORM, "Sent presence notification request to <%s>.",
++               jid);
++
++  return NULL;
++}
++
++//
++//  /del
++//
++
++static gchar *do_del (cmdopts_t *command);
++
++static cmdopts_t def_del = {
++  "del",
++  cmd_default,
++  cmd_check_online,
++  do_del,
++  (cmdopt_t[2]){
++    {'n', "dryrun", cmdopt_switch, {"dryrun", cmdarg_default, NULL, NULL}},
++    {0}
++  },
++  (cmdarg_t[2]){
++    {"jid", cmdarg_chreq, ".", &cmdarg_type_roster_bjid, (gpointer)(ROSTER_TYPE_USER|ROSTER_TYPE_AGENT|ROSTER_TYPE_GROUP)},
++    {NULL}
++  },
++  NULL,
++};
++
++static gchar *do_del (cmdopts_t *options)
++{
++  gpointer   buddy = options -> args[0].value.bud;
++  const char *jid  = buddy_getjid (buddy);
++
++  if (buddy_gettype(buddy) & ROSTER_TYPE_ROOM)
++    // This is a chatroom
++    if (buddy_getinsideroom(buddy))
++      return g_strdup ("You haven't left this room!");
++
++  scr_LogPrint(LPRINT_LOGNORM, "Removing <%s>...", jid);
++
++  if (!(options -> opts[0].arg.value.swc)) {
++    // Close the buffer
++    scr_buffer_purge(1, jid);
++
++    xmpp_delbuddy(jid);
++    scr_update_buddy_window();
    }
  
 -  if (fjid) {
@@ -2986,41 +3057,27 @@
 -    g_free(msg);
 -    g_free(cmdline);
 -    g_free(jid_utf8);
-+  if (jid) {
-+    // 2nd parameter = optional nickname
-+    xmpp_addbuddy(jid, nick, NULL);
-+    scr_LogPrint(LPRINT_LOGNORM, "Sent presence notification request to <%s>.",
-+                 jid);
-   }
+-  }
 -  free_arg_lst(paramlst);
-+
-+  cmdopts_free(&options);
++  return NULL;
  }
  
 -static void do_add(char *arg)
-+static void do_del(char *arg)
++//
++//  /group
++//
++
++static void group_cmd (gpointer group, scmd_group_t action) 
  {
 -  char **paramlst;
 -  char *id, *nick;
 -  char *jid_utf8 = NULL;
-+  cmdopts_t options = {
-+    "del",
-+    (cmdopt_t[1]){
-+      { CMDOPT_SWITCH | CMDOPT_LAST, 'n', "dryrun", { .swc = 0 } },
-+    },
-+    (cmdarg_t[1]){
-+      { CMDOPT_LAST, { .arg = "."  } }, // jid
-+    },
-+    NULL,
-+  };
-+  gchar *jid;
-+  gpointer buddy;
- 
-   if (!xmpp_is_online()) {
-     scr_LogPrint(LPRINT_NORMAL, "You are not connected.");
-     return;
-   }
- 
+-
+-  if (!xmpp_is_online()) {
+-    scr_LogPrint(LPRINT_NORMAL, "You are not connected.");
+-    return;
+-  }
+-
 -  paramlst = split_arg(arg, 2, 0); // jid, [nickname]
 -  id = *paramlst;
 -  nick = *(paramlst+1);
@@ -3031,50 +3088,23 @@
 -    id = NULL;
 -
 -  if (id) {
-+  if (cmdopts_parse(arg, &options))
-+    return;
-+
-+  jid = options.args[0].value.arg;
-+
-+  if (jid && (!*jid || !strcmp(jid, ".")))
-+    jid = NULL;
-+
-+  if (jid) {
-     // The JID has been specified.  Quick check...
+-    // The JID has been specified.  Quick check...
 -    if (check_jid_syntax(id)) {
 -      scr_LogPrint(LPRINT_NORMAL|LPRINT_NOTUTF8,
 -                   "<%s> is not a valid Jabber ID.", id);
 -      id = NULL;
-+    if (check_jid_syntax(jid)) {
-+      scr_LogPrint(LPRINT_NORMAL, "<%s> is not a valid Jabber ID.", jid);
-+      jid = NULL;
-     } else {
+-    } else {
 -      mc_strtolower(id);
 -      id = jid_utf8 = to_utf8(id);
-+      GSList *found;
-+      mc_strtolower(jid);
-+      found = roster_find(jid, jidsearch, ROSTER_TYPE_USER |
-+                          ROSTER_TYPE_AGENT | ROSTER_TYPE_GROUP);
-+      if (!found) {
-+        scr_log_print(LPRINT_NORMAL, "Jabber ID <%s> is not in roster.", jid);
-+        jid = NULL;
-+      } else {
-+        buddy = found -> data;
-+      }
-     }
-   } else {
+-    }
+-  } else {
 -    // Add the current buddy
-+    // Use current buddy
-     if (current_buddy)
+-    if (current_buddy)
 -      id = (char*)buddy_getjid(BUDDATA(current_buddy));
 -    if (!id)
-+      jid = (char*)buddy_getjid(BUDDATA(current_buddy));
-+    if (!jid)
-       scr_LogPrint(LPRINT_NORMAL, "Please specify a Jabber ID.");
-+    else
-+      buddy = BUDDATA(current_buddy);
-   }
- 
+-      scr_LogPrint(LPRINT_NORMAL, "Please specify a Jabber ID.");
+-  }
+-
 -  if (nick)
 -    nick = to_utf8(nick);
 -
@@ -3083,38 +3113,15 @@
 -    xmpp_addbuddy(id, nick, NULL);
 -    scr_LogPrint(LPRINT_LOGNORM, "Sent presence notification request to <%s>.",
 -                 id);
-+  if (jid) {
-+    if (buddy_gettype(buddy) & ROSTER_TYPE_ROOM) {
-+      // This is a chatroom
-+      if (buddy_getinsideroom(buddy)) {
-+        scr_LogPrint(LPRINT_NORMAL, "You haven't left this room!");
-+        cmdopts_free(&options);
-+        return;
-+      }
-+    }
-+
-+    scr_LogPrint(LPRINT_LOGNORM, "Removing <%s>...", jid);
-+
-+    if (!options.opts[0].value.swc) {
-+      // Close the buffer
-+      scr_buffer_purge(1, jid);
-+
-+      xmpp_delbuddy(jid);
-+      scr_update_buddy_window();
-+    }
-   }
- 
+-  }
+-
 -  g_free(jid_utf8);
 -  g_free(nick);
 -  free_arg_lst(paramlst);
-+  cmdopts_free(&options);
- }
- 
+-}
+-
 -static void do_del(char *arg)
-+#endif
-+
-+static void group_cmd (gpointer group, group_scmd_t action) 
- {
+-{
 -  const char *bjid;
 -
 -  if (*arg) {
@@ -3122,56 +3129,12 @@
 -                 "the currently-selected buddy will be deleted.");
 -    return;
 -  }
-+  // We'll have to redraw the chat window if we're not currently on the group
-+  // entry itself, because it means we'll have to leave the current buddy
-+  // chat window.
-+  if (action != scmd_group_unfold &&
-+      ((!current_buddy) ||
-+       (group != BUDDATA(current_buddy) &&
-+        group == buddy_getgroup(BUDDATA(current_buddy)))))
-+    scr_roster_prev_group();
-+
-+  buddy_hide_group(group, action);
-+
-+  buddylist_build();
-+  update_roster = TRUE;
-+}
-+
-+#if 0
-+
-+static void do_group(char *arg)
-+{
-+  scmd_group_t subcmd;
-+  cmdopts_t options = {
-+    "group",
-+    NULL,
-+    (cmdarg_t[1]){
-+      { CMDOPT_REQUIRED | CMDOPT_SUBCOMMAND | CMDOPT_LAST, { .cmd = NULL } },
-+    },
-+    // all of them have one argument - group name
-+#define GROUP_SUBCMD(NAME, REALNAME, FLAGS) \
-+      { #NAME, NULL, (cmdarg_t[1]){ \
-+          { CMDOPT_CATCHALL | CMDOPT_PLAIN | CMDOPT_LAST, { .arg = NULL } }, \
-+        }, NULL, (gpointer)group_scmd_##REALNAME, FLAGS }
-+    (cmdopts_t[5]){
-+      GROUP_SUBCMD(expand, unfold, 0),
-+      GROUP_SUBCMD(unfold, unfold, 0),
-+      GROUP_SUBCMD(shrink, fold,   0),
-+      GROUP_SUBCMD(fold,   fold,   0),
-+      GROUP_SUBCMD(toggle, toggle, CMDOPT_LAST),
-+    },
-+  };
-+  gchar *name;
-+  gpointer group = NULL;
-+  guint leave_buddywindow;
- 
-   if (!current_buddy)
-     return;
+-
+-  if (!current_buddy)
+-    return;
 -  bjid = buddy_getjid(BUDDATA(current_buddy));
 -  if (!bjid)
-+
-+  if (cmdopts_parse(arg, &options))
-     return;
+-    return;
 -
 -  if (buddy_gettype(BUDDATA(current_buddy)) & ROSTER_TYPE_ROOM) {
 -    // This is a chatroom
@@ -3224,55 +3187,99 @@
 -  }
 -
 -  if (arg && *arg) {
-+  
-+  subcmd = (enum group_scmd_t) options.args[0].value.cmd -> userdata;
-+  name   = options.args[0].value.cmd -> args[0].value.arg;
-+
-+  if (name && *name) {
-     GSList *roster_elt;
+-    GSList *roster_elt;
 -    char *group_utf8 = to_utf8(arg);
 -    roster_elt = roster_find(group_utf8, namesearch, ROSTER_TYPE_GROUP);
 -    g_free(group_utf8);
-+    roster_elt = roster_find(name, namesearch, ROSTER_TYPE_GROUP);
-     if (roster_elt)
-       group = buddy_getgroup(roster_elt->data);
-   } else {
-@@ -1253,31 +1964,19 @@
-     goto do_group_return;
-   }
- 
--  // We'll have to redraw the chat window if we're not currently on the group
--  // entry itself, because it means we'll have to leave the current buddy
--  // chat window.
+-    if (roster_elt)
+-      group = buddy_getgroup(roster_elt->data);
+-  } else {
+-    group = buddy_getgroup(BUDDATA(current_buddy));
+-  }
+-  if (!group) {
+-    scr_LogPrint(LPRINT_NORMAL, "Group not found.");
+-    goto do_group_return;
+-  }
+-
+   // We'll have to redraw the chat window if we're not currently on the group
+   // entry itself, because it means we'll have to leave the current buddy
+   // chat window.
 -  leave_buddywindow = (group != BUDDATA(current_buddy) &&
 -                       group == buddy_getgroup(BUDDATA(current_buddy)));
 -
-   if (!(buddy_gettype(group) & ROSTER_TYPE_GROUP)) {
-     scr_LogPrint(LPRINT_NORMAL, "You need to select a group.");
-     goto do_group_return;
-   }
+-  if (!(buddy_gettype(group) & ROSTER_TYPE_GROUP)) {
+-    scr_LogPrint(LPRINT_NORMAL, "You need to select a group.");
+-    goto do_group_return;
+-  }
+-
+-  if (group_state != group_unfold && leave_buddywindow)
++  if (action != scmd_group_unfold &&
++      ((!current_buddy) ||
++       (group != BUDDATA(current_buddy) &&
++        group == buddy_getgroup(BUDDATA(current_buddy)))))
+     scr_roster_prev_group();
  
--  if (group_state != group_unfold && leave_buddywindow)
--    scr_roster_prev_group();
--
 -  buddy_hide_group(group, group_state);
++  buddy_hide_group(group, action);
+ 
+   buddylist_build();
+   update_roster = TRUE;
 -
--  buddylist_build();
--  update_roster = TRUE;
-+  group_cmd (group, subcmd);
- 
- do_group_return:
+-do_group_return:
 -  free_arg_lst(paramlst);
-+  cmdopts_free(&options);
  }
  
++static gchar *do_group (cmdopts_t *command);
++
++static const string2enum_t s2e_group_scmd[] = {
++  {"expand", scmd_group_unfold},
++  {"unfold", scmd_group_unfold},
++  {"shrink", scmd_group_fold  },
++  {"fold",   scmd_group_fold  },
++  {"toggle", scmd_group_toggle},
++  {NULL,     0                },
++};
++
++#define SCMD_GROUP(NAME, REALNAME) \
++    { #NAME, cmd_default, NULL, NULL, NULL, NULL, NULL, \
++      (gpointer)scmd_group_##REALNAME}
++static cmdopts_t def_group = {
++  "group",
++  cmd_default,
++  NULL,
++  do_group,
++  NULL,
++  (cmdarg_t[3]){
++    {"subcommand", cmdarg_chreq,            NULL, &cmdarg_type_string2enum,
++                                                  (gpointer)s2e_group_scmd},
++    {"group",      cmdarg_chreq|cmdarg_eol, ".",  &cmdarg_type_roster_group},
++    {NULL}
++  },
++  NULL,
++};
++
++static gchar *do_group(cmdopts_t *options)
++{
++  //if (!current_buddy) // XXX do we need this still?
++  //  return g_strdup("Command needs selected buddy.");
++
++  group_cmd (options -> args[0].value.bud,
++             options -> args[1].value.uint);
++
++  return NULL;
++}
++
++//
++//  /say
++//
++
  static int send_message_to(const char *fjid, const char *msg, const char *subj,
 -                           LmMessageSubType type_overwrite, bool quiet)
 +                           msgtype_t msg_type, bool quiet)
  {
    char *bare_jid, *rp;
    char *hmsg;
-@@ -1285,6 +1984,7 @@
+@@ -1285,6 +1905,7 @@
    gint retval = 0;
    int isroom;
    gpointer xep184 = NULL;
@@ -3280,7 +3287,7 @@
  
    if (!xmpp_is_online()) {
      scr_LogPrint(LPRINT_NORMAL, "You are not connected.");
-@@ -1299,11 +1999,15 @@
+@@ -1299,11 +1920,15 @@
      return 1;
    }
    if (check_jid_syntax((char*)fjid)) {
@@ -3298,7 +3305,7 @@
    // We must use the bare jid in hk_message_out()
    rp = strchr(fjid, JID_RESOURCE_SEPARATOR);
    if (rp)
-@@ -1354,8 +2058,7 @@
+@@ -1354,8 +1979,7 @@
  //  send_message(msg, subj, type_overwrite)
  // Write the message in the buddy's window and send the message on
  // the network.
@@ -3308,7 +3315,7 @@
  {
    const char *bjid;
    char *jid;
-@@ -1378,34 +2081,13 @@
+@@ -1378,34 +2002,13 @@
    else
      jid = g_strdup(bjid);
  
@@ -3345,7 +3352,7 @@
  
    scr_set_chatmode(TRUE);
    scr_show_buddy_window();
-@@ -1424,80 +2106,131 @@
+@@ -1424,80 +2027,133 @@
    }
  
    buddy_setflags(bud, ROSTER_FLAG_LOCK, TRUE);
@@ -3356,6 +3363,8 @@
 -  g_free(arg);
  }
  
++#if 0
++
  static void do_say(char *arg) {
 -  say_cmd(arg, 1);
 +  cmdopts_t options = {
@@ -3526,7 +3535,7 @@
  
    if (!scr_get_multimode()) {
      scr_LogPrint(LPRINT_NORMAL, "No message to send.  "
-@@ -1508,49 +2241,47 @@
+@@ -1508,49 +2164,47 @@
    scr_set_chatmode(TRUE);
    scr_show_buddy_window();
  
@@ -3612,7 +3621,7 @@
  }
  
  //  load_message_from_file(filename)
-@@ -1566,7 +2297,7 @@
+@@ -1566,7 +2220,7 @@
    char *next_utf8_char;
    size_t len;
  
@@ -3621,7 +3630,7 @@
  
    if (!fd || fstat(fileno(fd), &buf)) {
      scr_LogPrint(LPRINT_LOGNORM, "Cannot open message file (%s)", filename);
-@@ -1634,130 +2365,103 @@
+@@ -1634,130 +2288,103 @@
  
  static void do_say_to(char *arg)
  {
@@ -3808,7 +3817,7 @@
  }
  
  //  buffer_updown(updown, nblines)
-@@ -1775,27 +2479,10 @@
+@@ -1775,27 +2402,10 @@
      scr_buffer_scroll_up_down(updown, nblines);
  }
  
@@ -3836,7 +3845,7 @@
    t = from_iso8601(date, 0);
    if (t)
      scr_buffer_date(t);
-@@ -1804,98 +2491,156 @@
+@@ -1804,98 +2414,156 @@
                   "not correctly formatted or invalid.");
  }
  
@@ -4075,7 +4084,7 @@
  }
  
  static void do_info(char *arg)
-@@ -2033,29 +2778,20 @@
+@@ -2033,29 +2701,20 @@
    }
  }
  
@@ -4114,7 +4123,7 @@
  
    // Enter chat mode
    scr_set_chatmode(TRUE);
-@@ -2075,12 +2811,12 @@
+@@ -2075,12 +2734,12 @@
      rstatus = buddy_getstatus(bud, p_res->data);
      rst_msg = buddy_getstatusmsg(bud, p_res->data);
  
@@ -4129,7 +4138,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 +2832,12 @@
+@@ -2096,12 +2755,12 @@
        snprintf(buffer, 4095, "[%c] %s", imstatus2char[rstatus],
                 (char*)p_res->data);
        scr_WriteIncomingMessage(bjid, buffer, 0, HBB_PREFIX_INFO, 0);
@@ -4144,7 +4153,7 @@
          enum imrole role = buddy_getrole(bud, p_res->data);
          enum imaffiliation affil = buddy_getaffil(bud, p_res->data);
  
-@@ -2145,16 +2881,69 @@
+@@ -2145,16 +2804,69 @@
  
  static void do_rename(char *arg)
  {
@@ -4219,7 +4228,7 @@
    bjid   = buddy_getjid(bud);
    group  = buddy_getgroupname(bud);
    type   = buddy_gettype(bud);
-@@ -2162,11 +2951,13 @@
+@@ -2162,11 +2874,13 @@
  
    if (type & ROSTER_TYPE_SPECIAL) {
      scr_LogPrint(LPRINT_NORMAL, "You can't rename this item.");
@@ -4234,7 +4243,7 @@
      return;
    }
  
-@@ -2181,90 +2972,117 @@
+@@ -2181,90 +2895,117 @@
    //  }
    //}
  
@@ -4383,7 +4392,7 @@
      } else {
        // This is a local item, we move it without adding to roster.
        guint msgflag;
-@@ -2276,7 +3094,7 @@
+@@ -2276,7 +3017,7 @@
        msgflag = buddy_getflags(bud) & ROSTER_FLAG_MSG;
        if (msgflag)
          roster_msg_setflag(bjid, FALSE, FALSE);
@@ -4392,7 +4401,7 @@
        if (msgflag)
          roster_msg_setflag(bjid, FALSE, TRUE);
        if ((type & ROSTER_TYPE_ROOM) && xmpp_is_bookmarked(bjid) &&
-@@ -2285,8 +3103,7 @@
+@@ -2285,8 +3026,7 @@
      }
    }
  
@@ -4402,7 +4411,7 @@
    update_roster = TRUE;
  }
  
-@@ -2468,50 +3285,33 @@
+@@ -2468,50 +3208,33 @@
  
  static void do_rawxml(char *arg)
  {
@@ -4473,7 +4482,25 @@
  }
  
  //  check_room_subcommand(arg, param_needed, buddy_must_be_a_room)
-@@ -2874,7 +3674,7 @@
+@@ -2815,6 +3538,8 @@
+   free_arg_lst(paramlst);
+ }
+ 
++#endif
++
+ void cmd_room_leave(gpointer bud, char *arg)
+ {
+   gchar *roomid, *desc;
+@@ -2833,6 +3558,8 @@
+   g_free(roomid);
+ }
+ 
++#if 0
++
+ static void room_nick(gpointer bud, char *arg)
+ {
+   if (!buddy_getinsideroom(bud)) {
+@@ -2874,7 +3601,7 @@
    fjid_utf8 = g_strdup_printf("%s/%s", buddy_getjid(bud), nick_utf8);
    g_free (nick_utf8);
    msg = to_utf8(arg);
@@ -4482,7 +4509,25 @@
    g_free(fjid_utf8);
    g_free(msg);
    free_arg_lst(paramlst);
-@@ -3290,6 +4090,207 @@
+@@ -3052,6 +3779,8 @@
+   free_arg_lst(paramlst);
+ }
+ 
++#endif
++
+ //  cmd_room_whois(..)
+ // If interactive is TRUE, chatmode can be enabled.
+ // Please note that usernick is expected in UTF-8 locale iff interactive is
+@@ -3146,6 +3875,8 @@
+     free_arg_lst(paramlst);
+ }
+ 
++#if 0
++
+ static void room_bookmark(gpointer bud, char *arg)
+ {
+   const char *roomid;
+@@ -3290,6 +4021,207 @@
  
  static void do_room(char *arg)
  {
@@ -4690,7 +4735,7 @@
    char **paramlst;
    char *subcmd;
    gpointer bud;
-@@ -3347,7 +4348,7 @@
+@@ -3347,7 +4279,7 @@
        cmd_room_leave(bud, arg);
    } else if (!strcasecmp(subcmd, "names"))  {
      if ((arg = check_room_subcommand(arg, FALSE, bud)) != NULL)
@@ -4699,17 +4744,17 @@
    } else if (!strcasecmp(subcmd, "nick"))  {
      if ((arg = check_room_subcommand(arg, FALSE, bud)) != NULL)
        room_nick(bud, arg);
-@@ -4162,5 +5163,6 @@
+@@ -4162,5 +5094,6 @@
    }
    mcabber_set_terminate_ui();
  }
 +#endif
  
  /* vim: set expandtab cindent cinoptions=>2\:2(0 sw=2 ts=2:  For Vim users... */
-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	Wed Mar 13 03:21:24 2013 +0200
-@@ -5,32 +5,242 @@
+diff -r 1b0b563a81e6 mcabber/mcabber/commands.h
+--- a/mcabber/mcabber/commands.h	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/mcabber/commands.h	Wed Mar 13 17:51:29 2013 +0200
+@@ -5,32 +5,246 @@
  
  #include <mcabber/config.h>
  
@@ -4921,7 +4966,9 @@
 +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_roster_group    (cmdarg_t *arg);
 +gchar *cmdarg_check_fjid            (cmdarg_t *arg);
++gchar *cmdarg_check_bjid            (cmdarg_t *arg);
 +gchar *cmdarg_check_uint            (cmdarg_t *arg);
 +gchar *cmdarg_check_statusmask      (cmdarg_t *arg);
 +gchar *cmdarg_check_string2enum     (cmdarg_t *arg);
@@ -4929,7 +4976,9 @@
 +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_roster_group;
 +const cmdarg_type_t cmdarg_type_fjid;
++const cmdarg_type_t cmdarg_type_bjid;
 +const cmdarg_type_t cmdarg_type_uint;
 +const cmdarg_type_t cmdarg_type_statusmask;
 +const cmdarg_type_t cmdarg_type_string2enum;
@@ -4972,9 +5021,38 @@
  
  #endif /* __MCABBER_COMMANDS_H__ */
  
-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	Wed Mar 13 03:21:24 2013 +0200
+diff -r 1b0b563a81e6 mcabber/mcabber/hooks.c
+--- a/mcabber/mcabber/hooks.c	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/mcabber/hooks.c	Wed Mar 13 17:51:29 2013 +0200
+@@ -638,10 +638,9 @@
+ 
+   scr_LogPrint(LPRINT_LOGNORM, "Running hook-post-connect...");
+ 
+-  cmdline = from_utf8(hook_command);
+-  if (process_command(cmdline, TRUE) == 255)
++  cmdline = g_strdup(hook_command);
++  if (cmd_execute(cmdline, cmd_default) == cmd_result_quit)
+     mcabber_set_terminate_ui();
+-
+   g_free(cmdline);
+ }
+ 
+@@ -665,10 +664,9 @@
+ 
+   scr_LogPrint(LPRINT_LOGNORM, "Running hook-pre-disconnect...");
+ 
+-  cmdline = from_utf8(hook_command);
+-  if (process_command(cmdline, TRUE) == 255)
++  cmdline = g_strdup(hook_command);
++  if (cmd_execute(cmdline, cmd_default) == cmd_result_quit)
+     mcabber_set_terminate_ui();
+-
+   g_free(cmdline);
+ }
+ 
+diff -r 1b0b563a81e6 mcabber/mcabber/roster.c
+--- a/mcabber/mcabber/roster.c	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/mcabber/roster.c	Wed Mar 13 17:51:29 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,
@@ -5013,9 +5091,9 @@
        if (found)
          return buddy;
      }
-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	Wed Mar 13 03:21:24 2013 +0200
+diff -r 1b0b563a81e6 mcabber/mcabber/screen.c
+--- a/mcabber/mcabber/screen.c	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/mcabber/screen.c	Wed Mar 13 17:51:29 2013 +0200
 @@ -3630,7 +3630,7 @@
  {
    scr_check_auto_away(TRUE);
@@ -5025,10 +5103,135 @@
      return 255;
    // Add line to history
    scr_cmdhisto_addline(inputLine);
-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	Wed Mar 13 03:21:24 2013 +0200
-@@ -289,10 +289,7 @@
+@@ -3802,8 +3802,12 @@
+ void readline_send_multiline(void)
+ {
+   // Validate current multi-line
+-  if (multimode)
+-    process_command(mkcmdstr("msay send"), TRUE);
++  if (multimode) {
++    // FIXME - do it without parsing
++    gchar *cmdline = g_strdup("msay send");
++    cmd_execute(cmdline, cmdexe_default);
++    g_free(cmdline);
++  }
+ }
+ 
+ void readline_insert(const char *toinsert)
+@@ -3883,6 +3887,8 @@
+ // Initiate or continue a completion...
+ static void scr_handle_tab(void)
+ {
++// FIXME completion
++#if 0
+   int nrow;
+   const char *row;
+   const char *cchar;
+@@ -3978,6 +3984,7 @@
+     if (cchar)
+       scr_insert_text(cchar);
+   }
++#endif
+ }
+ 
+ static void scr_cancel_current_completion(void)
+@@ -4098,7 +4105,9 @@
+ {
+   if (!Curses) return;
+   // Leave multi-line mode
+-  process_command(mkcmdstr("msay abort"), TRUE);
++  gchar *cmdline = g_strdup("msay abort");
++  cmd_execute(cmdline, cmdexe_default);
++  g_free(cmdline);
+   // Same as Ctrl-g, now
+   scr_cancel_current_completion();
+   scr_end_current_completion();
+@@ -4302,10 +4311,12 @@
+   boundcmd = settings_get(SETTINGS_TYPE_BINDING, asciikey);
+ 
+   if (boundcmd) {
+-    gchar *cmdline = from_utf8(boundcmd);
++    gchar *cmdline = g_strdup(boundcmd);
+     scr_check_auto_away(TRUE);
+-    if (process_command(cmdline, TRUE))
++    if (cmd_execute(cmdline, cmdexe_default) == cmd_result_quit) {
++      g_free(cmdline);
+       return 255; // Quit
++    }
+     g_free(cmdline);
+     return 0;
+   }
+diff -r 1b0b563a81e6 mcabber/mcabber/settings.c
+--- a/mcabber/mcabber/settings.c	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/mcabber/settings.c	Wed Mar 13 17:51:29 2013 +0200
+@@ -183,28 +183,12 @@
+     if ((*line == '\n') || (*line == '\0') || (*line == '#'))
+       continue;
+ 
+-    // If we aren't in runtime (i.e. startup) we'll only accept "safe" commands
+-    if (!runtime) {
+-      const gchar *cmdend = strchr(line, ' ');
+-      gchar *cmdname = NULL;
+-      gboolean safe;
+-      if (cmdend)
+-        cmdname = g_strndup(line, cmdend - line);
+-      safe = cmd_is_safe(cmdname ? cmdname : line);
+-      g_free(cmdname);
+-      if (!safe) {
+-        scr_log_print(LPRINT_LOGNORM, "Error in configuration file (l. %d): "
+-                      "this command can't be used here", ln);
+-        err++;
+-        continue;
+-      }
+-    }
+-
+-    // Set the leading COMMAND_CHAR to build a command line
+-    // and process the command
+-    *(--line) = COMMAND_CHAR;
+-    if (process_command(line, TRUE) == 255)
++    // FIXME: in-buffer conversion? some glib iochannel stuff?
++    gchar *utf8 = to_utf8(line);
++    if (cmd_execute(utf8, runtime ? cmdexe_default : cmdexe_check_safe)
++        == cmd_result_quit)
+       mcabber_set_terminate_ui();
++    g_free(utf8);
+   }
+   g_free(buf);
+   fclose(fp);
+diff -r 1b0b563a81e6 mcabber/mcabber/xmpp_iq.c
+--- a/mcabber/mcabber/xmpp_iq.c	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/mcabber/xmpp_iq.c	Wed Mar 13 17:51:29 2013 +0200
+@@ -71,20 +71,20 @@
+ struct adhoc_status {
+   char *name;   // the name used by adhoc
+   char *description;
+-  char *status; // the string, used by setstus
++  enum imstatus status; // corresponding imstatus value
+ };
+ // It has to match imstatus of roster.h!
+ const struct adhoc_status adhoc_status_list[] = {
+-  {"offline", "Offline", "offline"},
+-  {"online", "Online", "avail"},
+-  {"chat", "Chat", "free"},
+-  {"dnd", "Do not disturb", "dnd"},
+-  {"xa", "Extended away", "notavail"},
+-  {"away", "Away", "away"},
++  {"offline", "Offline", offline},
++  {"online", "Online", available},
++  {"chat", "Chat", freeforchat},
++  {"dnd", "Do not disturb", dontdisturb},
++  {"xa", "Extended away", notavail},
++  {"away", "Away", away},
+ #ifdef WITH_DEPRECATED_STATUS_INVISIBLE
+-  {"invisible", "Invisible", "invisible"},
++  {"invisible", "Invisible", invisible},
+ #endif
+-  {NULL, NULL, NULL},
++  {NULL, NULL, imstatus_size},
+ };
+ 
+ static char *generate_session_id(char *prefix)
+@@ -289,10 +289,11 @@
        if (value) {
          for (s = adhoc_status_list; !s->name || strcmp(s->name, value); s++);
          if (s->name) {
@@ -5036,7 +5239,116 @@
 -                                         message ? message : "");
 -          cmd_setstatus(NULL, status);
 -          g_free(status);
-+          cmd_setstatus(NULL, s->status, message ? message : "");
++          // It makes sense to reset autoaway before changing the status
++          // (esp. for FIFO or remote commands) or the behaviour could be
++          // unexpected...
++          scr_check_auto_away(TRUE);
++          xmpp_setstatus(s->status, NULL, message ? message : "", FALSE);
            lm_message_node_set_attribute(command, "status", "completed");
            lm_message_node_add_dataform_result(command,
                                                "Status has been changed");
+diff -r 1b0b563a81e6 mcabber/modules/beep/beep.c
+--- a/mcabber/modules/beep/beep.c	Wed Mar 13 16:11:16 2013 +0200
++++ b/mcabber/modules/beep/beep.c	Wed Mar 13 17:51:29 2013 +0200
+@@ -31,6 +31,7 @@
+ 
+ static void beep_init   (void);
+ static void beep_uninit (void);
++static gchar *do_beep (cmdopts_t *command);
+ 
+ /* Module description */
+ module_info_t info_beep = {
+@@ -46,9 +47,7 @@
+         .next            = NULL,
+ };
+ 
+-static guint    beep_cid  = 0;  /* Command completion category id */
+-static gpointer beep_cmid = 0;  /* Command id */
+-static guint    beep_hid  = 0;  /* Hook handler id */
++static guint beep_hid  = 0;  /* Hook handler id */
+ 
+ /* Event handler */
+ static guint beep_hh(const gchar *hookname, hk_arg_t *args, gpointer userdata)
+@@ -61,20 +60,38 @@
+   return HOOK_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
+ }
+ 
++static const string2enum_t s2e_onoff[] = {
++  { "on",      1  },
++  { "off",     0  },
++  { "enable",  1  },
++  { "disable", 0  },
++  { "1",       1  },
++  { "0",       0  },
++  { "show",    2  },
++  { NULL,      0  },
++};
++
++static cmdopts_t def_beep = {
++  "beep",
++  cmd_default,
++  NULL,
++  do_beep,
++  NULL,
++  (cmdarg_t[2]){
++    {"on|off", cmdarg_chreq, "show", &cmdarg_type_string2enum, (gpointer)s2e_onoff},
++    {NULL}
++  },
++  NULL
++};
++
+ /* beep command handler */
+-static void do_beep(char *args)
++static gchar *do_beep(cmdopts_t *command)
+ {
+   /* Check arguments, and if recognized,
+    * set mcabber option accordingly */
+-  if (!strcmp(args, "enable") ||
+-      !strcmp(args, "on") ||
+-      !strcmp(args, "yes") ||
+-      !strcmp(args, "1"))
++  if (command -> args[0].value.uint == 1)
+     settings_set(SETTINGS_TYPE_OPTION, "beep_enable", "1");
+-  else if (!strcmp(args, "disable") ||
+-           !strcmp(args, "off") ||
+-           !strcmp(args, "no") ||
+-           !strcmp(args, "0"))
++  else if (command -> args[0].value.uint == 0)
+     settings_set(SETTINGS_TYPE_OPTION, "beep_enable", "0");
+ 
+   /* Output current state, either if state is
+@@ -83,19 +100,14 @@
+     scr_log_print(LPRINT_NORMAL, "Beep on messages is enabled");
+   else
+     scr_log_print(LPRINT_NORMAL, "Beep on messages is disabled");
++  return NULL;
+ }
+ 
+ /* Initialization */
+ static void beep_init(void)
+ {
+-  /* Create completions */
+-  beep_cid = compl_new_category(COMPL_FLAGS_SORT);
+-  if (beep_cid) {
+-    compl_add_category_word(beep_cid, "enable");
+-    compl_add_category_word(beep_cid, "disable");
+-  }
+   /* Add command */
+-  beep_cmid = cmd_add("beep", "", beep_cid, 0, do_beep, NULL);
++  cmd_define(&def_beep);
+   /* Add handler
+    * We are only interested in incoming message events
+    */
+@@ -109,11 +121,7 @@
+   /* Unregister event handler */
+   hk_del_handler(HOOK_POST_MESSAGE_IN, beep_hid);
+   /* Unregister command */
+-  cmd_del(beep_cmid);
+-  /* Give back completion handle */
+-  if (beep_cid)
+-    compl_del_category(beep_cid);
++  cmd_undef(&def_beep);
+ }
+ 
+-/* The End */
+ /* vim: set et cindent cinoptions=>2\:2(0 ts=2 sw=2:  For Vim users... */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fix-set-status-rc-xa.diff	Wed Mar 13 17:54:09 2013 +0200
@@ -0,0 +1,17 @@
+# HG changeset patch
+# Parent 646da4f1d2e1bcb69efbcc68bc45ae95afa7249e
+Fix typo in form field value for set-status remote command
+s/xd/xa/
+
+diff -r 646da4f1d2e1 -r 9b4e36de294e mcabber/mcabber/xmpp_iq.c
+--- a/mcabber/mcabber/xmpp_iq.c	Mon Mar 11 21:45:20 2013 +0200
++++ b/mcabber/mcabber/xmpp_iq.c	Wed Mar 13 16:10:13 2013 +0200
+@@ -79,7 +79,7 @@
+   {"online", "Online", "avail"},
+   {"chat", "Chat", "free"},
+   {"dnd", "Do not disturb", "dnd"},
+-  {"xd", "Extended away", "notavail"},
++  {"xa", "Extended away", "notavail"},
+   {"away", "Away", "away"},
+ #ifdef WITH_DEPRECATED_STATUS_INVISIBLE
+   {"invisible", "Invisible", "invisible"},
--- a/series	Wed Mar 13 03:23:11 2013 +0200
+++ b/series	Wed Mar 13 17:54:09 2013 +0200
@@ -2,6 +2,7 @@
 use-otr-v4.diff
 fix-date-fill.diff
 fix-nickcolor-memleak.diff
+fix-set-status-rc-xa.diff
 switch-to-experimental.diff
 separate-extcmd.diff
 modularize-extcmd.diff