--- a/cmdopts.diff Tue Mar 05 01:11:24 2013 +0200
+++ b/cmdopts.diff Mon Mar 11 01:33:26 2013 +0200
@@ -35,7 +35,7 @@
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 Tue Mar 05 01:08:31 2013 +0200
++++ b/mcabber/doc/help/cs/hlp_buffer.txt Mon Mar 11 01:32:27 2013 +0200
@@ -25,7 +25,7 @@
Přesune se o [n] řádků nahoru (výchozí: polovina obrazovky).
/buffer down [n]
@@ -47,7 +47,7 @@
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 Tue Mar 05 01:08:31 2013 +0200
++++ b/mcabber/doc/help/cs/hlp_del.txt Mon Mar 11 01:32:27 2013 +0200
@@ -1,4 +1,4 @@
- /DEL
@@ -56,7 +56,7 @@
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 Tue Mar 05 01:08:31 2013 +0200
++++ b/mcabber/doc/help/cs/hlp_move.txt Mon Mar 11 01:32:27 2013 +0200
@@ -1,5 +1,6 @@
- /MOVE [skupina]
@@ -67,7 +67,7 @@
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 Tue Mar 05 01:08:31 2013 +0200
++++ b/mcabber/doc/help/cs/hlp_rename.txt Mon Mar 11 01:32:27 2013 +0200
@@ -1,4 +1,6 @@
- /RENAME jméno
@@ -79,7 +79,7 @@
+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 Tue Mar 05 01:08:31 2013 +0200
++++ b/mcabber/doc/help/de/hlp_buffer.txt Mon Mar 11 01:32:27 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]
@@ -91,7 +91,7 @@
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 Tue Mar 05 01:08:31 2013 +0200
++++ b/mcabber/doc/help/de/hlp_del.txt Mon Mar 11 01:32:27 2013 +0200
@@ -1,4 +1,4 @@
- /DEL
@@ -100,7 +100,7 @@
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 Tue Mar 05 01:08:31 2013 +0200
++++ b/mcabber/doc/help/de/hlp_move.txt Mon Mar 11 01:32:27 2013 +0200
@@ -1,6 +1,7 @@
- /MOVE [groupname]
@@ -112,7 +112,7 @@
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 Tue Mar 05 01:08:31 2013 +0200
++++ b/mcabber/doc/help/de/hlp_rename.txt Mon Mar 11 01:32:27 2013 +0200
@@ -1,4 +1,6 @@
- /RENAME name
@@ -124,7 +124,7 @@
+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 Tue Mar 05 01:08:31 2013 +0200
++++ b/mcabber/doc/help/en/hlp_buffer.txt Mon Mar 11 01:32:27 2013 +0200
@@ -25,7 +25,7 @@
Scroll the buffer up [n] lines (default: half a screen)
/buffer down [n]
@@ -136,7 +136,7 @@
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 Tue Mar 05 01:08:31 2013 +0200
++++ b/mcabber/doc/help/en/hlp_del.txt Mon Mar 11 01:32:27 2013 +0200
@@ -1,4 +1,4 @@
- /DEL
@@ -146,7 +146,7 @@
+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 Tue Mar 05 01:08:31 2013 +0200
++++ b/mcabber/doc/help/en/hlp_move.txt Mon Mar 11 01:32:27 2013 +0200
@@ -1,5 +1,6 @@
- /MOVE [groupname]
@@ -157,7 +157,7 @@
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 Tue Mar 05 01:08:31 2013 +0200
++++ b/mcabber/doc/help/en/hlp_rename.txt Mon Mar 11 01:32:27 2013 +0200
@@ -1,4 +1,6 @@
- /RENAME name
@@ -169,7 +169,7 @@
+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 Tue Mar 05 01:08:31 2013 +0200
++++ b/mcabber/doc/help/fr/hlp_buffer.txt Mon Mar 11 01:32:27 2013 +0200
@@ -25,7 +25,7 @@
Défile vers le haut de [n] lignes (par défaut un demi écran)
/buffer down [n]
@@ -181,7 +181,7 @@
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 Tue Mar 05 01:08:31 2013 +0200
++++ b/mcabber/doc/help/fr/hlp_del.txt Mon Mar 11 01:32:27 2013 +0200
@@ -1,4 +1,4 @@
- /DEL
@@ -190,7 +190,7 @@
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 Tue Mar 05 01:08:31 2013 +0200
++++ b/mcabber/doc/help/fr/hlp_move.txt Mon Mar 11 01:32:27 2013 +0200
@@ -1,5 +1,6 @@
- /MOVE [groupname]
@@ -201,7 +201,7 @@
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 Tue Mar 05 01:08:31 2013 +0200
++++ b/mcabber/doc/help/fr/hlp_rename.txt Mon Mar 11 01:32:27 2013 +0200
@@ -1,4 +1,6 @@
- /RENAME nom
@@ -213,7 +213,7 @@
+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 Tue Mar 05 01:08:31 2013 +0200
++++ b/mcabber/doc/help/it/hlp_buffer.txt Mon Mar 11 01:32:27 2013 +0200
@@ -25,7 +25,7 @@
Fa scorrere indietro il buffer di [n] linee (default: metà schermo)
/buffer down [n]
@@ -225,7 +225,7 @@
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 Tue Mar 05 01:08:31 2013 +0200
++++ b/mcabber/doc/help/it/hlp_del.txt Mon Mar 11 01:32:27 2013 +0200
@@ -1,4 +1,4 @@
- /DEL
@@ -234,7 +234,7 @@
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 Tue Mar 05 01:08:31 2013 +0200
++++ b/mcabber/doc/help/it/hlp_move.txt Mon Mar 11 01:32:27 2013 +0200
@@ -1,5 +1,6 @@
- /MOVE [gruppo]
@@ -245,7 +245,7 @@
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 Tue Mar 05 01:08:31 2013 +0200
++++ b/mcabber/doc/help/it/hlp_rename.txt Mon Mar 11 01:32:27 2013 +0200
@@ -1,4 +1,6 @@
- /RENAME nome
@@ -257,7 +257,7 @@
+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 Tue Mar 05 01:08:31 2013 +0200
++++ b/mcabber/doc/help/nl/hlp_buffer.txt Mon Mar 11 01:32:27 2013 +0200
@@ -25,7 +25,7 @@
Scroll de buffer [n] regels omhoog (standaard: een half scherm)
/buffer down [n]
@@ -269,7 +269,7 @@
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 Tue Mar 05 01:08:31 2013 +0200
++++ b/mcabber/doc/help/nl/hlp_del.txt Mon Mar 11 01:32:27 2013 +0200
@@ -1,4 +1,4 @@
- /DEL
@@ -278,7 +278,7 @@
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 Tue Mar 05 01:08:31 2013 +0200
++++ b/mcabber/doc/help/nl/hlp_move.txt Mon Mar 11 01:32:27 2013 +0200
@@ -1,5 +1,6 @@
- /MOVE [groepsnaam]
@@ -289,7 +289,7 @@
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 Tue Mar 05 01:08:31 2013 +0200
++++ b/mcabber/doc/help/nl/hlp_rename.txt Mon Mar 11 01:32:27 2013 +0200
@@ -1,4 +1,6 @@
- /RENAME naam
@@ -301,7 +301,7 @@
+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 Tue Mar 05 01:08:31 2013 +0200
++++ b/mcabber/doc/help/pl/hlp_del.txt Mon Mar 11 01:32:27 2013 +0200
@@ -1,4 +1,4 @@
- /DEL
@@ -310,7 +310,7 @@
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 Tue Mar 05 01:08:31 2013 +0200
++++ b/mcabber/doc/help/pl/hlp_move.txt Mon Mar 11 01:32:27 2013 +0200
@@ -1,5 +1,6 @@
- /MOVE [nazwa grupy]
@@ -321,7 +321,7 @@
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 Tue Mar 05 01:08:31 2013 +0200
++++ b/mcabber/doc/help/pl/hlp_rename.txt Mon Mar 11 01:32:27 2013 +0200
@@ -1,4 +1,6 @@
- /RENAME nazwa
@@ -333,7 +333,7 @@
+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 Tue Mar 05 01:08:31 2013 +0200
++++ b/mcabber/doc/help/ru/hlp_buffer.txt Mon Mar 11 01:32:27 2013 +0200
@@ -25,7 +25,7 @@
Перемещает на [n] строк вверх в буфере (истории переписки) (по умолчанию: половина экрана)
/buffer down [n]
@@ -345,7 +345,7 @@
Перемещает на позицию %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 Tue Mar 05 01:08:31 2013 +0200
++++ b/mcabber/doc/help/ru/hlp_del.txt Mon Mar 11 01:32:27 2013 +0200
@@ -1,4 +1,4 @@
- /DEL
@@ -355,7 +355,7 @@
+Удаляет текущего пользователя (или указанного с помощью 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 Tue Mar 05 01:08:31 2013 +0200
++++ b/mcabber/doc/help/ru/hlp_move.txt Mon Mar 11 01:32:27 2013 +0200
@@ -1,6 +1,7 @@
- /MOVE [groupname]
@@ -367,7 +367,7 @@
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 Tue Mar 05 01:08:31 2013 +0200
++++ b/mcabber/doc/help/ru/hlp_rename.txt Mon Mar 11 01:32:27 2013 +0200
@@ -1,4 +1,6 @@
- /RENAME name
@@ -379,7 +379,7 @@
+Для указания обьекта, отличного от текущего, можно использовать опции --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 Tue Mar 05 01:08:31 2013 +0200
++++ b/mcabber/doc/help/uk/hlp_buffer.txt Mon Mar 11 01:32:27 2013 +0200
@@ -25,7 +25,7 @@
Посунути буфер вверх на n рядків (якщо не вказано - пів екрану).
/buffer down [n]
@@ -391,7 +391,7 @@
Перейти до вказаної у процентах позиції.
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 Tue Mar 05 01:08:31 2013 +0200
++++ b/mcabber/doc/help/uk/hlp_del.txt Mon Mar 11 01:32:27 2013 +0200
@@ -1,4 +1,4 @@
- /DEL
@@ -401,7 +401,7 @@
+Потерти поточний контакт (або контакт, що має вказаний 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 Tue Mar 05 01:08:31 2013 +0200
++++ b/mcabber/doc/help/uk/hlp_move.txt Mon Mar 11 01:32:27 2013 +0200
@@ -1,5 +1,6 @@
- /MOVE [група]
@@ -413,7 +413,7 @@
Примітка: в режимі розмови можна використати "/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 Tue Mar 05 01:08:31 2013 +0200
++++ b/mcabber/doc/help/uk/hlp_rename.txt Mon Mar 11 01:32:27 2013 +0200
@@ -1,4 +1,6 @@
- /RENAME ім'я
@@ -424,7 +424,7 @@
+Опції --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 Tue Mar 05 01:08:31 2013 +0200
++++ b/mcabber/mcabber/commands.c Mon Mar 11 01:32:27 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,645 @@
+@@ -43,512 +43,663 @@
#include "xmpp.h"
#include "main.h"
@@ -464,6 +464,7 @@
+
+#define BUILTIN_COUNT 3
+static cmdopts_t def_roster,
++ def_color,
+ def_status,
+ def_status_to,
+#if 0
@@ -495,7 +496,6 @@
+ def_screen_refresh,
+ def_chat_disable,
+ def_source,
-+ def_color,
+ def_otr,
+ def_otrpolicy,
+ def_echo,
@@ -558,6 +558,7 @@
+ ;
+
+static cmd_handler_t do_roster,
++ do_color,
+ do_status,
+ do_status_to,
+#if 0
@@ -589,7 +590,6 @@
+ do_screen_refresh,
+ do_chat_disable,
+ do_source,
-+ do_color,
+ do_otr,
+ do_otrpolicy,
+ do_echo,
@@ -622,38 +622,38 @@
- return userdata;
+ cmd_list = g_new ((cmdopts_t *), BUILTIN_COUNT+1);
+ cmd_list[0] = def_roster;
-+ cmd_list[1] = def_status;
-+ cmd_list[2] = def_status_to;
++ cmd_list[1] = def_color;
++ cmd_list[2] = def_status;
++ cmd_list[3] = def_status_to;
+#if 0
-+ cmd_list[3] = def_add;
-+ cmd_list[4] = def_del;
-+ cmd_list[5] = def_group;
-+ cmd_list[6] = def_say;
-+ cmd_list[7] = def_msay;
-+ cmd_list[8] = def_say_to;
-+ cmd_list[9] = def_buffer;
-+ cmd_list[10] = def_clear;
-+ cmd_list[11] = def_info;
-+ cmd_list[12] = def_rename;
-+ cmd_list[13] = def_move;
-+ cmd_list[14] = def_set;
-+ cmd_list[15] = def_alias;
-+ cmd_list[16] = def_bind;
-+ cmd_list[17] = def_connect;
-+ cmd_list[18] = def_disconnect;
-+ cmd_list[19] = def_rawxml;
-+ cmd_list[20] = def_room;
-+ cmd_list[21] = def_authorization;
-+ cmd_list[22] = def_version;
-+ cmd_list[23] = def_request;
-+ cmd_list[24] = def_event;
-+ cmd_list[25] = def_help;
-+ cmd_list[26] = def_pgp;
-+ cmd_list[27] = def_iline;
-+ cmd_list[28] = def_screen_refresh;
-+ cmd_list[29] = def_chat_disable;
-+ cmd_list[30] = def_source;
-+ cmd_list[31] = def_color;
++ 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;
@@ -824,7 +824,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|cmdarg_freed);
++ arg -> flags &= ~(cmdarg_visited|cmdarg_checked);
+ }
+ }
+ }
@@ -938,7 +938,7 @@
+
+ if ((err = cmdopt_parse_argument(&p, &e, arg -> flags))) { // get argument value
+ if (!option) {
-+ error = g_strdup_printf ("%s: Can't parse argument #%u: %s", command -> name, argno + 1, err);
++ 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 for option -%c: %s", command -> name, option -> shortopt, err);
+ } else {
@@ -989,16 +989,25 @@
+ // needs checking and not checked already
+ if ((opt -> arg.flags & (cmdarg_check | cmdarg_visited)) && !(opt -> arg.flags & cmdarg_checked)) {
+ if (opt -> arg.type && opt -> arg.type -> check) { // checker is present
++ gchar *err;
+ opt -> arg.flags |= cmdarg_checked;
-+ if ((error = opt -> arg.type -> check (&(opt -> arg)))) {
-+ gchar *err = error;
-+ if (option -> shortopt) {
-+ error = g_strdup_printf ("%s: Error in argument for option -%c: %s", command -> name, option -> shortopt, err);
++ if ((err = opt -> arg.type -> check (&(opt -> arg)))) {
++ if (opt -> arg.flags & cmdarg_required) {
++ 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);
++ }
++ g_free (err);
++ break;
+ } else {
-+ error = g_strdup_printt ("%s: Error in argument for option --%s: %s", command -> name, option -> longopt, err);
++ if (opt -> shortopt) {
++ scr_log_print (LPRINT_NORMAL, "Warning: %s: Error in argument for option -%c: %s", command -> name, opt -> shortopt, err);
++ } else {
++ scr_log_print (LPRINT_NORMAL, "Warning: %s: Error in argument for option --%s: %s", command -> name, opt -> longopt, err);
++ }
++ g_free (err);
+ }
-+ g_free (err);
-+ break;
+ }
+ }
+ }
@@ -1015,17 +1024,26 @@
+ if ((arg -> flags & (cmdarg_check | cmdarg_visited)) && !(arg -> flags & cmdarg_checked)) {
+ if (arg -> flags & cmdarg_subcmd) { // subcommand
+ if (!arg -> value.cmd) {
-+ error = g_strdup_printf ("%s: No subcommand specified.", command -> name);
-+ break;
++ if (arg -> flags & cmdarg_required) {
++ error = g_strdup_printf ("%s: No %s specified.", command -> name, arg -> name);
++ break;
++ } else { // XXX more prefixes
++ scr_log_print (LPRINT_NORMAL, "Warning: %s: No %s specified.", command -> name, arg -> name);
++ }
+ }
+ } else { // normal argument
+ if (arg -> type && arg -> type -> check) {
++ gchar *err;
+ arg -> flags |= cmdarg_checked;
-+ if ((error = arg -> type -> check (arg))) {
-+ gchar *err = error;
-+ error = g_strdup_printf ("%s: Error in argument #%u: %s", command -> name, n, err);
-+ g_free (err);
-+ break;
++ if ((err = arg -> type -> check (arg))) {
++ if (arg -> flags & cmdarg_required) {
++ error = g_strdup_printf ("%s: Error in argument %s (%u): %s", command -> name, arg -> name, n, err);
++ g_free (err);
++ break;
++ } else { // XXX more prefixes
++ scr_log_print (LPRINT_NORMAL, "Warning: %s: Error in argument %s (%u): %s", command -> name, arg -> name, n, err);
++ g_free (err);
++ }
+ }
+ }
+ }
@@ -1055,8 +1073,8 @@
+ for (n = 0; command -> opts[n]; n ++) {
+ cmdopt_t *opt = command -> opts[n];
+ if (!(opt -> flags & cmdopt_switch)) { // not switch
-+ if (opt -> arg.flags & cmdarg_checked) { // can free something
-+ opt -> arg.flags &= ~cmdarg_checked;
++ if (opt -> arg.flags & cmdarg_freeme) { // can free something
++ opt -> arg.flags &= ~cmdarg_freeme;
+ if (opt -> arg.type && opt -> arg.type -> free) { // need to free something
+ opt -> arg.type -> free (&(opt -> arg));
+ }
@@ -1073,8 +1091,8 @@
+ arg -> value.cmd = NULL;
+ }
+ } else { // normal argument
-+ if (arg -> flags & cmdarg_checked) { // can free something
-+ arg -> flags &= ~cmdarg_checked;
++ 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);
+ }
@@ -1567,7 +1585,7 @@
if (!*line) { // User only pressed enter
if (scr_get_multimode()) {
scr_append_multiline("");
-@@ -556,75 +689,114 @@
+@@ -556,141 +707,509 @@
}
if (current_buddy) {
if (buddy_gettype(BUDDATA(current_buddy)) & ROSTER_TYPE_GROUP)
@@ -1657,6 +1675,43 @@
}
-static void roster_resourcelock(char *jidres, gboolean lock) {
+- gpointer bud = NULL;
+- char *resource = NULL;
+-
+- 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
+//
@@ -1665,80 +1720,54 @@
+//
+
+// TODO: (and variations with 'required')
-+// * cmdarg_type_roster_bjid - in roster, with specified types -> bud
-+// * cmdarg_type_roster_fjid - in roster, with specified types -> bud + resource
++// + 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_fjid - any fjid -> fjid
-+// * cmdarg_type_statusmask
-+// * cmdarg_type_uint
-+// * cmdarg_type_nonspace - space only -> null
++// + cmdarg_type_fjid - any fjid -> fjid
++// + cmdarg_type_statusmask - string -> string
++// + cmdarg_type_uint - string -> uint
++// + cmdarg_type_nonspace - strip, space only -> null
+// * cmdarg_type_bjidmask
-+// * cmdarg_type_color
-+// * cmdarg_type_string2enum
++// + cmdarg_type_color
++// + cmdarg_type_string2enum
+// * cmdarg_type_nick - provide completions first from current room, then from all other, nonspace, do not restrict
+
-+// Uses chkdata as guint with allowed ROSTER_TYPE_*.
-+// Returns buddy roster entry in value.bud.
-+// Recognizes as current ".", but not "" or NULL - use defvalue.
-+// Does not require freeing.
-+gchar *cmdarg_check_roster_bjid_required(optarg_t *arg)
-+{
-+ const char *bjid;
-+ guint types;
-+ gchar *error;
-+
-+ if ((error = cmdarg_check_nospace_required(arg)))
-+ return error;
-+
-+ bjid = arg -> value.arg;
-+ types = (guint) arg -> chkdata;
++//
++// common methods
++//
+
-+ if (strcmp(bjid, ".")) { // jid specified
-+ GSList *found;
-+ if (check_jid_syntax(bjid))
-+ return g_strdup_printf("<%s> is not a valid Jabber ID.", bjid);
-+ // find the buddy
-+ found = roster_find(bjid, jidsearch, types);
-+ if (found)
-+ arg -> value.bud = found->data;
-+ else
-+ return g_strdup_printf("Jid <%s> is not in the roster.", bjid);
-+ } else { // current buddy
-+ if (!current_buddy)
-+ return g_strdup_printf("No jid specified, and no buddy selected.");
-+ else if (buddy_gettype(BUDDATA(current_buddy)) & types)
-+ arg -> value.bud = BUDDATA(current_buddy);
-+ else // TODO: improve message
-+ return g_strdup_printf("Currently selected buddy is of wrong type.");
-+ }
-+
-+ return NULL;
++static void cmdarg_free_gfree (optarg_t *arg)
++{
++ g_free (arg -> value.arg);
+}
+
-+// The same as bjid_required, but in the case of error just sets value.bud
-+// to NULL.
-+gchar *cmdarg_check_roster_bjid(optarg_t *arg)
-+{
-+ gchar *error = cmdarg_check_roster_bjid_required(arg);
-+
-+ if (error) {
-+ g_free (error);
-+ arg -> value.bud = NULL;
-+ }
++//
++// string -> stripspace string
++//
+
-+ return NULL;
-+}
-+
-+// FIXME check fjid
-+// XXX can't specify resource in bud - fjid or bud+resource?
-+// resource must be present in roster - cmdarg_check_fjid_in_roster?
-+gchac *cmdarg_check_fjid(optarg_t *arg)
++// Strips leading and trailing spaces, checks if anything left.
++// 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)
+{
- gpointer bud = NULL;
- char *resource = NULL;
-
-@@ -664,33 +836,61 @@
- resource = jidres;
++ gchar *val = arg -> value.arg;
++ if (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))
++ val --;
++ val ++;
++ if (*val)
++ *val = '\0';
++ return NULL;
}
}
-
@@ -1751,32 +1780,396 @@
- 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.");
++}
++
++cmdarg_type_t cmdarg_type_nospace = {
++ cmdarg_check_nospace,
++ NULL,
++ NULL,
++};
++
++//
++// bjid -> bud
++//
++
++// Uses chkdata as guint with allowed ROSTER_TYPE_*.
++// 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 *error = NULL;
++
++ if (!(error = cmdarg_check_nospace_required(arg))) {
++ const char *bjid = arg -> value.arg;
++ guint types = (guint) arg -> chkdata;
++
++ if (!strcmp(bjid, ".")) { // current buddy
++ if (!current_buddy)
++ error = g_strdup_printf("No buddy selected.");
++ else if (buddy_gettype(BUDDATA(current_buddy)) & types)
++ arg -> value.bud = BUDDATA(current_buddy);
++ else // TODO: improve message
++ error = g_strdup_printf("Currently selected buddy is of wrong type.");
++ } else if (!check_jid_syntax(bjid)) { // valid jid specified
++ GSList *found = roster_find(bjid, jidsearch, types);
++ if (found)
++ arg -> value.bud = found->data;
++ else
++ error = g_strdup_printf("Jid <%s> is not in the roster.", bjid);
++ } else { // jid is invalid
++ error = g_strdup_printf("<%s> is not a valid Jabber ID.", bjid);
++ }
++ }
++
++ if (error)
++ arg -> value.bud = NULL;
++ return error;
++}
++
++cmdarg_type_t cmdarg_type_bjid = {
++ cmdarg_check_roster_bjid,
++ NULL,
++ NULL,
++};
++
++//
++// fjid -> bud + resource
++//
++
++// Uses chkdata as guint with allowed ROSTER_TYPE_*.
++// Returns buddy roster entry in userdata.
++// Returns resource string in value.arg.
++// Recognizes as current "./res" and "res".
++// Does not require freeing.
++// 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 *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 (fjid[0] == '.' && fjid[1] == JID_RESOURCE_SEPARATOR) {
++ // current buddy
++ resource = fjid+2;
++ } 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);
++ if (found) {
++ bud = found->data;
++ resource ++;
++ } else
++ error = g_strdup_printf("Jid <%s> is not in the roster.", bjid);
++ } else {
++ // jid is invalid - let's consider it resource (XXX)
++ resource = fjid;
++ }
++ // resource for current buddy
++ 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)
++ 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;
-- }
-- } else {
++ if (bud) {
++ 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);
++ }
++ 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 {
++ arg -> userdata = bud;
++ arg -> value.arg = resource;
++ }
++ return error;
++}
++
++cmdarg_type_t cmdarg_type_roster_resource = {
++ cmdarg_check_roster_resource,
++ NULL,
++ NULL,
++};
++
++//
++// fjid -> fjid
++//
++
++// Returns corrected fjid in value.arg.
++// Recognizes as current "." and "./res".
++// Requires freeing.
++// XXX:
++// * destructor is rather generic g_freer, publish?
++static gchar *cmdarg_check_fjid(optarg_t *arg)
++{
++ gchar *error = NULL;
++
++ if (!(error = cmdarg_check_nospace(arg))) {
++ const char *fjid = arg -> value.arg;
++
++ if (fjid[0] == '.' && (fjid[1] == JID_RESOURCE_SEPARATOR || fjid[1] == '\0')) {
++ const char *jid;
++ if (!current_buddy)
++ error = g_strdup_printf ("No buddy selected.");
++ 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;
++ } else {
++ arg -> value.arg = g_strdup_printf ("%s%c%s", jid, JID_RESOURCE_SEPARATOR, fjid + 2);
++ arg -> flags |= cmdarg_freeme;
++ }
++ } else if (check_jid_syntax(fjid)) {
++ error = g_strdup_printf ("Jid <%s> is invalid.", fjid);
++ }
++ }
++
++ if (error)
++ arg -> value.arg = NULL;
++ return error;
++}
++
++cmdarg_type_t cmdarg_type_fjid = {
++ cmdarg_check_fjid,
++ cmdarg_free_gfree,
++ NULL,
++};
++
++//
++// string -> uint
++//
++
++// Returns unsigned integer in value.uint.
++// Does not require freeing.
++// 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 *error;
++
++ if (!(error = cmdarg_check_nospace(arg))) {
++ const char *e = NULL;
++ const char *s = arg -> value.arg;
++ 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);
++ else
++ arg -> value.uint = (guint) n;
++ }
++
++ if (error)
++ arg -> value.uint = 0;
++ return error;
++}
++
++cmdarg_type_t cmdarg_type_uint = {
++ cmdarg_check_uint,
++ NULL,
++ NULL,
++};
++
++//
++// string -> statusmask
++//
++
++// Strips/checks for any non-valid status chars in mask.
++// Returns mask in value.arg.
++// Recognizes "*" as glob.
++// Does not require freeing.
++// No errors in default vaules - needs RW for that.
++// XXX:
++// * check duplicates?
++// * string2flags?
++// * canonicize?
++// * 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 *error;
++
++ if (!(error = cmdarg_check_nospace(arg)) && arg -> value.arg) {
++ const char *valid = "foand_?";
++ if (!strcmp(arg -> value.arg, "*")) {
++ arg -> value.arg = g_strdup (valid);
++ arg -> flags |= cmdarg_freeme;
+ } else {
- resource = NULL;
-- }
++ gchar *p = arg -> value.arg;
++ gchar *e = p + strlen (p);
++ while (p < e) {
++ 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);
++ e --;
++ }
++ }
++ if (arg -> value.arg == e) // arg is not required and we deleted all string
++ arg -> value.arg = NULL;
+ }
- buddy_setactiveresource(bud, resource);
- scr_update_chat_status(TRUE);
++ }
+
-+ 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);
++ return error;
++}
++
++cmdarg_type_t cmdarg_type_statusmask = {
++ cmdarg_check_statusmask,
++ cmdarg_free_gfree,
++ NULL,
++};
++
++//
++// 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)
++{
++ 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;
++ return NULL;
++ }
++ list ++;
++ }
++ // not found, error
++ error = g_strdup_printf("Value \"%s\" is invalid for %s.", arg -> value.arg, arg -> name);
+ }
-+ g_slist_free(resources);
-+ if (!found) {
-+ scr_LogPrint(LPRINT_NORMAL, "No such resource <%s>...", jidres);
-+ return;
- }
- }
++
++ if (error)
++ arg -> value.uint = 0; // XXX default value?
++ return error;
++}
++
++cmdarg_type_t cmdarg_type_string2enum = {
++ cmdarg_check_string2enum,
++ NULL,
++ NULL,
++};
++
++//
++// string -> color name
++//
++
++static string2enum_t s2e_color[] = {
++ { "default", -1 },
++ { "black", 1 },
++ { "red", 1 },
++ { "green", 1 },
++ { "yellow", 1 },
++ { "blue", 1 },
++ { "magenta", 1 },
++ { "white", 1 },
++ { NULL, 0 },
++};
++
++// Recognizes "-" for reset, prefix "bright", standard names and numerical values.
++// Returns color name in value.arg.
++// Does not require freeing.
++// XXX
++// * in fact, we can straight away do color parsing & allocate ccolor,
++// but to not break too much things, for now we'll wait with that.
++// * that needs access to ncurses internals, so, probably, this will
++// be better done, when moving related command definitions to
++// corresponding subsystems.
++static gchar *cmdarg_check_color (cmdarg_t *arg)
++{
++ gchar *error;
++
++ if (!(error = cmdarg_check_nospace(arg))) {
++ const char *color = arg -> value.arg;
++ gsize i;
++ // reset color
++ if (!strcmp(color, "-")) {
++ return NULL;
++ }
++ // 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;
++ }
++ }
++ { // not found, check for numerical value
++ const char *e = NULL;
++ long n = strtol(color, &e, 0);
++ if (*e != '\0' || n < 0 || n > 256)
++ error = g_strdup_printf ("Invalid color \"%s\".", arg -> value.arg);
++ }
++ }
++
++ if (error)
++ arg -> value.arg = NULL;
++ return error;
++}
++
++cmdarg_type_t cmdarg_type_color = {
++ cmdarg_check_color,
++ NULL,
++ NULL,
++};
+
+//
+// Command definitions
@@ -1801,17 +2194,8 @@
+ if ((!current_buddy) || bud == BUDDATA(current_buddy)) {
+ buddylist_build();
+ update_roster = TRUE;
-+ }
-+}
-+
-+static void roster_resourcelock(gpointer bud, const char *resource, gboolean lock)
-+{
-+ if (lock)
-+ buddy_setactiveresource(bud, resource);
-+ else
-+ buddy_setactiveresource(buf, NULL);
-+ scr_update_chat_status(TRUE);
-+}
+ }
+ }
+
// display_and_free_note(note, winId)
// Display the note information in the winId buffer, and free note
@@ -1821,7 +2205,7 @@
static void display_and_free_note(struct annotation *note, const char *winId)
{
gchar tbuf[128];
-@@ -755,41 +955,15 @@
+@@ -755,41 +1274,15 @@
g_slist_free(notes);
}
@@ -1871,7 +2255,7 @@
struct annotation *note = xmpp_get_storage_rosternotes(bjid, FALSE);
if (note) {
display_and_free_note(note, bjid);
-@@ -800,194 +974,244 @@
+@@ -800,194 +1293,273 @@
}
}
@@ -1899,40 +2283,40 @@
+ NULL,
+ do_roster,
+ NULL,
-+ {{cmdarg_subcmd | cmdarg_check, NULL, NULL}, NULL},
++ {{"subcommand", cmdarg_subcmd | cmdarg_check, NULL, NULL}, NULL},
+ {
+ SCMD_ROSTER(bottom, NULL),
+ SCMD_ROSTER(top, NULL),
-+ SCMD_ROSTER(up, {{cmdarg_check, "1", cmdarg_type_uint}, NULL}),
-+ SCMD_ROSTER(down, {{cmdarg_check, "1", cmdarg_type_uint}, NULL}),
++ SCMD_ROSTER(up, {{"n", cmdarg_chreq, "1", cmdarg_type_uint}, NULL}),
++ SCMD_ROSTER(down, {{"n", cmdarg_chreq, "1", cmdarg_type_uint}, NULL}),
+ SCMD_ROSTER(group_prev, NULL),
+ SCMD_ROSTER(group_next, NULL),
+ SCMD_ROSTER(alternate, NULL),
+ SCMD_ROSTER(unread_first, NULL),
+ SCMD_ROSTER(unread_next, NULL),
-+ SCMD_ROSTER(search, {{cmdarg_catchall|cmdarg_plain|cmdarg_check, NULL, cmdarg_type_nonspace}, NULL}),
-+ SCMD_ROSTER(display, {{cmdarg_check, NULL, cmdarg_type_statusmask}, NULL}),
++ SCMD_ROSTER(search, {{"name", cmdarg_eol|cmdarg_required, NULL, cmdarg_type_nonspace}, NULL}),
++ SCMD_ROSTER(display, {{"statusmask", cmdarg_check, NULL, cmdarg_type_statusmask}, NULL}),
+ SCMD_ROSTER(hide_offline, NULL),
+ SCMD_ROSTER(show_offline, NULL),
+ SCMD_ROSTER(toggle_offline, NULL),
-+ SCMD_ROSTER(item_lock, {{cmdarg_check, ".", cmdarg_type_bjid, (gpointer)(ROSTER_TYPE_USER|ROSTER_TYPE_ROOM)}, NULL}),
-+ SCMD_ROSTER(item_unlock, {{cmdarg_check, ".", cmdarg_type_bjid, (gpointer)(ROSTER_TYPE_USER|ROSTER_TYPE_ROOM)}, NULL}),
-+ SCMD_ROSTER(item_toggle_lock, {{cmdarg_check, ".", cmdarg_type_bjid, (gpointer)(ROSTER_TYPE_USER|ROSTER_TYPE_ROOM)}, NULL}),
++ SCMD_ROSTER(item_lock, {{"jid", cmdarg_chreq, ".", cmdarg_type_roster_bjid, (gpointer)(ROSTER_TYPE_USER|ROSTER_TYPE_ROOM)}, NULL}),
++ SCMD_ROSTER(item_unlock, {{"jid", cmdarg_chreq, ".", cmdarg_type_roster_bjid, (gpointer)(ROSTER_TYPE_USER|ROSTER_TYPE_ROOM)}, NULL}),
++ SCMD_ROSTER(item_toggle_lock, {{"jid", cmdarg_chreq, ".", cmdarg_type_roster_bjid, (gpointer)(ROSTER_TYPE_USER|ROSTER_TYPE_ROOM)}, NULL}),
+ { "note", NULL, NULL,
+ {
-+ {cmdopt_switch, 'r', "reset", {cmdarg_default, NULL, NULL, NULL}},
-+ {cmdopt_default, 'j', "jid", {cmdarg_check, ".", cmdarg_type_bjid, (gpointer)(ROSTER_TYPE_USER|ROSTER_TYPE_ROOM|ROSTER_TYPE_AGENT)}},
++ {cmdopt_switch, 'r', "reset", {"reset", cmdarg_default, NULL, NULL, NULL}},
++ {cmdopt_default, 'j', "jid", {"jid", cmdarg_chreq, ".", cmdarg_type_roster_bjid, (gpointer)(ROSTER_TYPE_USER|ROSTER_TYPE_ROOM|ROSTER_TYPE_AGENT)}},
+ NULL,
+ },
+ {
-+ {cmdarg_catchall|cmdarg_plain, NULL, cmdarg_type_nonspace},
++ {cmdarg_eol, NULL, cmdarg_type_nonspace},
+ NULL,
+ },
+ NULL, (gpointer)scmd_roster_note
+ },
+ SCMD_ROSTER(notes, NULL),
-+ SCMD_ROSTER(resource_lock, {{cmdarg_check, NULL, cmdarg_type_fjid, (gpointer)(ROSTER_TYPE_USER|ROSTER_TYPE_AGENT}, NULL}),
-+ SCMD_ROSTER(resource_unlock, {{cmdarg_check, NULL, cmdarg_type_fjid, (gpointer)(ROSTER_TYPE_USER|ROSTER_TYPE_AGENT}, NULL}),
++ SCMD_ROSTER(resource_lock, {{"resource|fjid", cmdarg_chreq, NULL, cmdarg_type_roster_resource, (gpointer)(ROSTER_TYPE_USER|ROSTER_TYPE_AGENT)}, NULL}),
++ SCMD_ROSTER(resource_unlock, {{"jid", cmdarg_chreq, ".", cmdarg_type_roster_bjid, (gpointer)(ROSTER_TYPE_USER|ROSTER_TYPE_AGENT)}, NULL}),
+ SCMD_ROSTER(hide, NULL),
+ SCMD_ROSTER(show, NULL),
+ SCMD_ROSTER(toggle, NULL),
@@ -2081,10 +2465,12 @@
+ arg -> value.arg);
+ } else if (subcmd == scmd_roster_notes) {
+ display_all_annotations();
-+ } else if (subcmd == scmd_roster_resource_lock) { // FIXME implement fjid checker and decide where to get resource
-+ roster_resourcelock(arg -> value.bud, resource, TRUE);
++ } else if (subcmd == scmd_roster_resource_lock) {
++ buddy_setactiveresource(arg -> userdata, arg -> value.arg);
++ scr_update_chat_status(TRUE);
+ } else if (subcmd == scmd_roster_resource_unlock) {
-+ roster_resourcelock(arg -> value.bud, NULL, FALSE);
++ buddy_setactiveresource(arg -> value.bud, NULL);
++ scr_update_chat_status(TRUE);
+ } else if (subcmd == scmd_roster_hide) {
+ scr_roster_visibility(0);
+ } else if (subcmd == scmd_roster_show) {
@@ -2101,9 +2487,69 @@
+// /color
+//
+
-+// TODO:
-+// * cmdarg_type_color_statusmask - also accept "clear"
-+// * cmdarg_type_color_roomjid - also accept "*"
++// custom argument types
++
++// statusmask + "clear"
++static gchar *cmdarg_check_color_statusmask (cmdarg_t *arg)
+ {
+- char **paramlst;
+- char *subcmd;
+-
+- paramlst = split_arg(arg, 2, 1); // subcmd, arg
+- subcmd = *paramlst;
+- arg = *(paramlst+1);
+-
+- if (!subcmd || !*subcmd) {
+- scr_LogPrint(LPRINT_NORMAL, "Missing parameter.");
+- free_arg_lst(paramlst);
+- return;
++ if (!g_strcmp0(arg -> value.arg, "clear"))
++ return NULL;
++ else
++ return cmdarg_check_statusmask (arg);
++}
++
++static cmdarg_type_t cmdarg_type_color_statusmask = {
++ cmdarg_check_color_statusmask,
++ NULL,
++ NULL,
++};
++
++// bjid + "*"
++// Returns string, not buddy.
++static gchar *cmdarg_check_color_roomjid (cmdarg_t *arg)
++{
++ gchar *error;
++
++ if (!g_strcmp0(arg -> value.arg, "*"))
++ return NULL;
++
++ arg -> chkdata = (gpointer) ROSTER_TYPE_ROOM;
++ if (!(error = cmdarg_check_roster_bjid (arg))) {
++ arg -> value.roarg = buddy_getjid (arg -> value.bud); // XXX strdup?
+ }
+
+- if (!strcasecmp(subcmd, "roster")) {
+- char *status, *wildcard, *color;
+- char **arglist = split_arg(arg, 3, 0);
+-
+- status = *arglist;
+- wildcard = to_utf8(arglist[1]);
+- color = arglist[2];
+-
+- if (status && !strcmp(status, "clear")) { // Not a color command, clear all
++ if (error)
++ arg -> value.arg = NULL;
++ return error;
++}
++
++static cmdarg_type_t cmdarg_type_color_roomjid = {
++ cmdarg_check_color_roomjid,
++ NULL,
++ NULL,
++};
++
++// command
+
+typedef enum {
+ scmd_color_roster,
@@ -2119,27 +2565,27 @@
+ { NULL, 0 },
+};
+
-+cmdopts_t def_color = {
++static cmdopts_t def_color = {
+ "color",
+ NULL,
+ do_color,
+ NULL,
-+ {{ cmdarg_subcmd | cmdarg_check, NULL, NULL }, NULL},
++ {{ "subcommand", cmdarg_subcmd | cmdarg_check, NULL, NULL }, NULL},
+ {
+ {"roster", NULL, NULL, NULL, {
-+ { cmdarg_check, NULL, cmdarg_type_color_statusmask },
-+ { cmdarg_default, NULL, cmdarg_type_bjidmask },
-+ { cmdarg_default, NULL, cmdarg_type_color },
++ { "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, {
-+ { cmdarg_check, NULL, cmdarg_type_color_roomjid },
-+ { cmdarg_check, "on", cmdarg_type_string2enum, (gpointer)s2e_color_muc},
++ { "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},
+ {"mucnick", NULL, NULL, NULL {
-+ { cmdarg_check, NULL, cmdarg_type_nick },
-+ { cmdarg_check, NULL, cmdarg_type_color },
++ { "nick", cmdarg_chreq, NULL, cmdarg_type_nick },
++ { "color|-", cmdarg_chreq, NULL, cmdarg_type_color },
+ NULL,
+ }, NULL, (gpointer)scmd_color_mucnick},
+ NULL,
@@ -2147,29 +2593,7 @@
+};
+
+static gchar *do_color(cmdopts_t *options)
- {
-- char **paramlst;
-- char *subcmd;
--
-- paramlst = split_arg(arg, 2, 1); // subcmd, arg
-- subcmd = *paramlst;
-- arg = *(paramlst+1);
--
-- if (!subcmd || !*subcmd) {
-- scr_LogPrint(LPRINT_NORMAL, "Missing parameter.");
-- free_arg_lst(paramlst);
-- return;
-- }
--
-- if (!strcasecmp(subcmd, "roster")) {
-- char *status, *wildcard, *color;
-- char **arglist = split_arg(arg, 3, 0);
--
-- status = *arglist;
-- wildcard = to_utf8(arglist[1]);
-- color = arglist[2];
--
-- if (status && !strcmp(status, "clear")) { // Not a color command, clear all
++{
+ scmd_color_t subcmd = (scmd_color_t) options -> args[0] -> value.cmd -> userdata;
+
+ if (subcmd == scmd_color_roster) {
@@ -2248,20 +2672,7 @@
+// /status
+//
+
-+static string2enum_t s2e_status[] = {
-+ { "away", away },
-+ { "offline", offline },
-+ { "online", available },
-+ { "avail", available },
-+ { "notavail", notavail },
-+ { "dnd", dontdisturb },
-+ { "free", freeforchat },
-+#ifdef WITH_DEPRECATED_STATUS_INVISIBLE
-+ { "invisible", invisible },
-+#endif
-+ { NULL, 0 },
-+};
-+
++// FIXME: this should go to xmpp_iq, that uses it
+// cmd_setstatus(recipient, status, message)
// Set your Jabber status.
-// - if recipient is not NULL, the status is sent to this contact only
@@ -2276,7 +2687,7 @@
enum imstatus st;
if (!xmpp_is_online())
-@@ -1000,15 +1224,15 @@
+@@ -1000,15 +1572,15 @@
if (!recipient)
scr_check_auto_away(TRUE);
@@ -2297,7 +2708,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,64 +1244,88 @@
+@@ -1020,229 +1592,347 @@
else if (!strcasecmp(status, IMSTATUS_NOTAVAILABLE)) st = notavail;
else if (!strcasecmp(status, IMSTATUS_FREE4CHAT)) st = freeforchat;
else if (!strcasecmp(status, "message")) {
@@ -2330,6 +2741,45 @@
}
-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)
+ {
+- if (!*arg) {
++ gchar *error;
++
++ if (!g_strcmp0(arg, "message")) {
++ arg -> value.uint = xmpp_getstatus(); // Preserve current status
++ return NULL;
++ }
++
++ return cmdarg_check_string2enum (arg);
++}
++
++static cmdarg_type_t cmdarg_type_status_status = {
++ cmdarg_check_status_status,
++ NULL,
++ NULL,
++};
++
++// command
+
+cmdopts_t def_status = {
+ "status",
@@ -2337,36 +2787,58 @@
+ do_status,
+ NULL,
+ {
-+ {cmdarg_default, NULL, cmdarg_type_status_status, (string2enum_t)s2e_status2},
-+ {cmdarg_catchall|cmdarg_plain, NULL, cmdarg_type_nonspace},
++ {"status", cmdarg_default, NULL, cmdarg_type_status_status, (gpointer)s2e_status2},
++ {"message", cmdarg_eol, NULL, cmdarg_type_nonspace},
+ NULL,
+ },
+ NULL,
+};
+
+static gchar *do_status(cmdopts_t *options)
- {
-- if (!*arg) {
-+ if (options.args[0].value.arg == NULL) {
++{
++ 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 : ""));
+ } else {
-+ cmd_setstatus(NULL, options.args[0].value.arg, options.args[1].value.arg);
++ 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);
+ }
+ return NULL;
+}
+
++//
++// /status_to
++//
++
++// no "show" here
++static string2enum_t s2e_status[] = {
++ { "away", away },
++ { "offline", offline },
++ { "online", available },
++ { "avail", available },
++ { "notavail", notavail },
++ { "dnd", dontdisturb },
++ { "free", freeforchat },
++#ifdef WITH_DEPRECATED_STATUS_INVISIBLE
++ { "invisible", invisible },
++#endif
++ { NULL, 0 },
++};
++
+cmdopts_t def_status_to = {
+ "status_to",
+ NULL,
+ do_status_to,
+ NULL,
-+ { // FIXME NOT in roster, just any fjid, and as a string
-+ {cmdarg_check, NULL, cmdarg_type_fjid},
-+ {cmdarg_check, NULL, cmdarg_type_status_status, (string2enum_t)s2e_status2},
-+ {cmdarg_catchall|cmdarg_plain, NULL, cmdarg_type_nonspace},
++ {
++ {"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,
+ },
+ NULL,
@@ -2374,24 +2846,51 @@
+
+static gchar *do_status_to(cmdopts_t *options)
+{
++ 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;
++ }
++ }
++ msg = msg ? msg : "";
++
++ scr_LogPrint(LPRINT_LOGNORM,
++ "Sending to <%s> /status %s %s", fjid, stname, msg);
++ if (!xmpp_is_online())
++ scr_LogPrint(LPRINT_NORMAL, "You are currently not connected...");
++ xmpp_setstatus(st, fjid, msg, FALSE);
++
++ return NULL
++}
++
++#if 0
++static void do_add(char *arg)
++{
+ cmdopts_t options = {
-+ "status_to",
++ "add",
+ NULL,
-+ (cmdarg_t[3]){
++ (cmdarg_t[2]){
+ // jid
-+ { CMDOPT_REQUIRED, { .arg = NULL } },
-+ // status
-+ { CMDOPT_REQUIRED, { .arg = NULL } },
-+ // message
-+ { CMDOPT_CATCHALL | CMDOPT_PLAIN | CMDOPT_LAST, { .arg = "" } },
++ { 0, { .arg = "." } },
++ // rostername
++ { CMDOPT_CATCHALL | CMDOPT_PLAIN | CMDOPT_LAST, { .arg = NULL } },
+ },
+ NULL,
+ };
-+ char *fjid, *st, *msg;
++ gchar *jid, *nick;
+
-+ if (cmdopts_parse(arg, &options))
++ if (!xmpp_is_online()) {
++ scr_LogPrint(LPRINT_NORMAL, "You are not connected.");
return;
-- }
+ }
- arg = to_utf8(arg);
- cmd_setstatus(NULL, arg);
- g_free(arg);
@@ -2412,36 +2911,51 @@
- scr_LogPrint(LPRINT_NORMAL,
- "Please specify both a Jabber ID and a status.");
- free_arg_lst(paramlst);
-- return;
-- }
+
-+ fjid = options.args[0].value.arg;
-+ st = options.args[1].value.arg;
-+ msg = options.args[2].value.arg;
-
- // Allow things like /status_to "" away
- if (!*fjid || !strcmp(fjid, "."))
-@@ -1086,15 +1334,13 @@
- if (fjid) {
++ 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)) {
+- if (check_jid_syntax(fjid)) {
- scr_LogPrint(LPRINT_NORMAL|LPRINT_NOTUTF8,
- "<%s> is not a valid Jabber ID.", fjid);
-+ scr_LogPrint(LPRINT_NORMAL, "<%s> is not a valid Jabber ID.", fjid);
- fjid = NULL;
+- 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);
+- // 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
-@@ -1105,144 +1351,208 @@
+ 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.");
}
- if (fjid) {
+- if (fjid) {
- char *cmdline;
- if (!msg)
- msg = "";
@@ -2452,33 +2966,35 @@
- g_free(msg);
- g_free(cmdline);
- g_free(jid_utf8);
-+ scr_LogPrint(LPRINT_LOGNORM,
-+ "Sending to <%s> /status %s %s", fjid, st, msg);
-+ cmd_setstatus(fjid, st, msg);
++ 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);
}
-+#if 0
- static void do_add(char *arg)
+-static void do_add(char *arg)
++static void do_del(char *arg)
{
- char **paramlst;
- char *id, *nick;
- char *jid_utf8 = NULL;
+ cmdopts_t options = {
-+ "add",
-+ NULL,
-+ (cmdarg_t[2]){
-+ // jid
-+ { 0, { .arg = "." } },
-+ // rostername
-+ { CMDOPT_CATCHALL | CMDOPT_PLAIN | CMDOPT_LAST, { .arg = NULL } },
++ "del",
++ (cmdopt_t[1]){
++ { CMDOPT_SWITCH | CMDOPT_LAST, 'n', "dryrun", { .swc = 0 } },
++ },
++ (cmdarg_t[1]){
++ { CMDOPT_LAST, { .arg = "." } }, // jid
+ },
+ NULL,
+ };
-+ gchar *jid, *nick;
++ gchar *jid;
++ gpointer buddy;
if (!xmpp_is_online()) {
scr_LogPrint(LPRINT_NORMAL, "You are not connected.");
@@ -2498,8 +3014,7 @@
+ if (cmdopts_parse(arg, &options))
+ return;
+
-+ jid = options.args[0].value.arg;
-+ nick = options.args[1].value.arg;
++ jid = options.args[0].value.arg;
+
+ if (jid && (!*jid || !strcmp(jid, ".")))
+ jid = NULL;
@@ -2516,76 +3031,6 @@
} else {
- mc_strtolower(id);
- id = jid_utf8 = to_utf8(id);
-+ mc_strtolower(jid);
- }
- } else {
- // Add the 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.");
- }
-
-- if (nick)
-- nick = to_utf8(nick);
--
-- if (id) {
-+ if (jid) {
- // 2nd parameter = optional nickname
-- xmpp_addbuddy(id, nick, NULL);
-+ xmpp_addbuddy(jid, nick, NULL);
- scr_LogPrint(LPRINT_LOGNORM, "Sent presence notification request to <%s>.",
-- id);
-+ jid);
- }
-
-- g_free(jid_utf8);
-- g_free(nick);
-- free_arg_lst(paramlst);
-+ cmdopts_free(&options);
- }
-
- static void do_del(char *arg)
- {
-- const char *bjid;
--
-- if (*arg) {
-- scr_LogPrint(LPRINT_NORMAL, "This action does not require a parameter; "
-- "the currently-selected buddy will be deleted.");
-+ 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 (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...
-+ if (check_jid_syntax(jid)) {
-+ scr_LogPrint(LPRINT_NORMAL, "<%s> is not a valid Jabber ID.", jid);
-+ jid = NULL;
-+ } else {
+ GSList *found;
+ mc_strtolower(jid);
+ found = roster_find(jid, jidsearch, ROSTER_TYPE_USER |
@@ -2596,17 +3041,28 @@
+ } 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.");
+ scr_LogPrint(LPRINT_NORMAL, "Please specify a Jabber ID.");
+ else
+ buddy = BUDDATA(current_buddy);
-+ }
-+
+ }
+
+- if (nick)
+- nick = to_utf8(nick);
+-
+- if (id) {
+- // 2nd parameter = optional nickname
+- 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
@@ -2626,15 +3082,26 @@
+ 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) {
+- scr_LogPrint(LPRINT_NORMAL, "This action does not require a parameter; "
+- "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.
@@ -2677,7 +3144,7 @@
+ gchar *name;
+ gpointer group = NULL;
+ guint leave_buddywindow;
-+
+
if (!current_buddy)
return;
- bjid = buddy_getjid(BUDDATA(current_buddy));
@@ -2750,7 +3217,7 @@
if (roster_elt)
group = buddy_getgroup(roster_elt->data);
} else {
-@@ -1253,31 +1563,19 @@
+@@ -1253,31 +1943,19 @@
goto do_group_return;
}
@@ -2785,7 +3252,7 @@
{
char *bare_jid, *rp;
char *hmsg;
-@@ -1285,6 +1583,7 @@
+@@ -1285,6 +1963,7 @@
gint retval = 0;
int isroom;
gpointer xep184 = NULL;
@@ -2793,7 +3260,7 @@
if (!xmpp_is_online()) {
scr_LogPrint(LPRINT_NORMAL, "You are not connected.");
-@@ -1299,11 +1598,15 @@
+@@ -1299,11 +1978,15 @@
return 1;
}
if (check_jid_syntax((char*)fjid)) {
@@ -2811,7 +3278,7 @@
// We must use the bare jid in hk_message_out()
rp = strchr(fjid, JID_RESOURCE_SEPARATOR);
if (rp)
-@@ -1354,8 +1657,7 @@
+@@ -1354,8 +2037,7 @@
// send_message(msg, subj, type_overwrite)
// Write the message in the buddy's window and send the message on
// the network.
@@ -2821,7 +3288,7 @@
{
const char *bjid;
char *jid;
-@@ -1378,34 +1680,13 @@
+@@ -1378,34 +2060,13 @@
else
jid = g_strdup(bjid);
@@ -2858,7 +3325,7 @@
scr_set_chatmode(TRUE);
scr_show_buddy_window();
-@@ -1424,80 +1705,131 @@
+@@ -1424,80 +2085,131 @@
}
buddy_setflags(bud, ROSTER_FLAG_LOCK, TRUE);
@@ -3039,7 +3506,7 @@
if (!scr_get_multimode()) {
scr_LogPrint(LPRINT_NORMAL, "No message to send. "
-@@ -1508,49 +1840,47 @@
+@@ -1508,49 +2220,47 @@
scr_set_chatmode(TRUE);
scr_show_buddy_window();
@@ -3125,7 +3592,7 @@
}
// load_message_from_file(filename)
-@@ -1566,7 +1896,7 @@
+@@ -1566,7 +2276,7 @@
char *next_utf8_char;
size_t len;
@@ -3134,7 +3601,7 @@
if (!fd || fstat(fileno(fd), &buf)) {
scr_LogPrint(LPRINT_LOGNORM, "Cannot open message file (%s)", filename);
-@@ -1634,130 +1964,103 @@
+@@ -1634,130 +2344,103 @@
static void do_say_to(char *arg)
{
@@ -3321,7 +3788,7 @@
}
// buffer_updown(updown, nblines)
-@@ -1775,27 +2078,10 @@
+@@ -1775,27 +2458,10 @@
scr_buffer_scroll_up_down(updown, nblines);
}
@@ -3349,7 +3816,7 @@
t = from_iso8601(date, 0);
if (t)
scr_buffer_date(t);
-@@ -1804,98 +2090,156 @@
+@@ -1804,98 +2470,156 @@
"not correctly formatted or invalid.");
}
@@ -3588,7 +4055,7 @@
}
static void do_info(char *arg)
-@@ -2033,29 +2377,20 @@
+@@ -2033,29 +2757,20 @@
}
}
@@ -3627,7 +4094,7 @@
// Enter chat mode
scr_set_chatmode(TRUE);
-@@ -2075,12 +2410,12 @@
+@@ -2075,12 +2790,12 @@
rstatus = buddy_getstatus(bud, p_res->data);
rst_msg = buddy_getstatusmsg(bud, p_res->data);
@@ -3642,7 +4109,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 +2431,12 @@
+@@ -2096,12 +2811,12 @@
snprintf(buffer, 4095, "[%c] %s", imstatus2char[rstatus],
(char*)p_res->data);
scr_WriteIncomingMessage(bjid, buffer, 0, HBB_PREFIX_INFO, 0);
@@ -3657,7 +4124,7 @@
enum imrole role = buddy_getrole(bud, p_res->data);
enum imaffiliation affil = buddy_getaffil(bud, p_res->data);
-@@ -2145,16 +2480,69 @@
+@@ -2145,16 +2860,69 @@
static void do_rename(char *arg)
{
@@ -3732,7 +4199,7 @@
bjid = buddy_getjid(bud);
group = buddy_getgroupname(bud);
type = buddy_gettype(bud);
-@@ -2162,11 +2550,13 @@
+@@ -2162,11 +2930,13 @@
if (type & ROSTER_TYPE_SPECIAL) {
scr_LogPrint(LPRINT_NORMAL, "You can't rename this item.");
@@ -3747,7 +4214,7 @@
return;
}
-@@ -2181,90 +2571,117 @@
+@@ -2181,90 +2951,117 @@
// }
//}
@@ -3896,7 +4363,7 @@
} else {
// This is a local item, we move it without adding to roster.
guint msgflag;
-@@ -2276,7 +2693,7 @@
+@@ -2276,7 +3073,7 @@
msgflag = buddy_getflags(bud) & ROSTER_FLAG_MSG;
if (msgflag)
roster_msg_setflag(bjid, FALSE, FALSE);
@@ -3905,7 +4372,7 @@
if (msgflag)
roster_msg_setflag(bjid, FALSE, TRUE);
if ((type & ROSTER_TYPE_ROOM) && xmpp_is_bookmarked(bjid) &&
-@@ -2285,8 +2702,7 @@
+@@ -2285,8 +3082,7 @@
}
}
@@ -3915,7 +4382,7 @@
update_roster = TRUE;
}
-@@ -2468,50 +2884,33 @@
+@@ -2468,50 +3264,33 @@
static void do_rawxml(char *arg)
{
@@ -3986,7 +4453,7 @@
}
// check_room_subcommand(arg, param_needed, buddy_must_be_a_room)
-@@ -2874,7 +3273,7 @@
+@@ -2874,7 +3653,7 @@
fjid_utf8 = g_strdup_printf("%s/%s", buddy_getjid(bud), nick_utf8);
g_free (nick_utf8);
msg = to_utf8(arg);
@@ -3995,7 +4462,7 @@
g_free(fjid_utf8);
g_free(msg);
free_arg_lst(paramlst);
-@@ -3290,6 +3689,207 @@
+@@ -3290,6 +4069,207 @@
static void do_room(char *arg)
{
@@ -4203,7 +4670,7 @@
char **paramlst;
char *subcmd;
gpointer bud;
-@@ -3347,7 +3947,7 @@
+@@ -3347,7 +4327,7 @@
cmd_room_leave(bud, arg);
} else if (!strcasecmp(subcmd, "names")) {
if ((arg = check_room_subcommand(arg, FALSE, bud)) != NULL)
@@ -4212,7 +4679,7 @@
} else if (!strcasecmp(subcmd, "nick")) {
if ((arg = check_room_subcommand(arg, FALSE, bud)) != NULL)
room_nick(bud, arg);
-@@ -4162,5 +4762,6 @@
+@@ -4162,5 +5142,6 @@
}
mcabber_set_terminate_ui();
}
@@ -4221,8 +4688,8 @@
/* 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 Tue Mar 05 01:08:31 2013 +0200
-@@ -5,32 +5,209 @@
++++ b/mcabber/mcabber/commands.h Mon Mar 11 01:32:27 2013 +0200
+@@ -5,32 +5,214 @@
#include <mcabber/config.h>
@@ -4335,13 +4802,18 @@
+ cmdopt_switch = 1<<0, // option have no argument
+} cmdopt_flags_t;
+typedef enum {
-+ cmdarg_default = 0, // no flags
-+ cmdarg_catchall = 1<<0, // argument consumes the end of command line
-+ cmdarg_plain = 1<<1, // quotes and escapes are not processed
-+ cmdarg_subcmd = 1<<2, // argument is subcommand
-+ cmdarg_check = 1<<3, // force checker call on argument
-+ cmdarg_visited = 1<<4, // private, marks initialized arguments
-+ cmdarg_checked = 1<<5, // private, marks checked argument
++ cmdarg_default = 0x0000, // no flags ['u' - user, 'p' - parser, 'c' - checker]
++ cmdarg_catchall = 0x0001, // u2p, argument consumes the end of command line
++ cmdarg_plain = 0x0002, // u2p, quotes and escapes are not processed
++ cmdarg_subcmd = 0x0004, // u2p, argument is subcommand
++ cmdarg_check = 0x0008, // u2p, force checker call on argument
++ cmdarg_required = 0x0010, // u2p[c], treat checker errors as errors or warnings (may be used by checker too)
++ cmdarg_visited = 0x0020, // p2p, marks initialized arguments
++ cmdarg_checked = 0x0040, // p2p, marks checked argument
++ cmdarg_freeme = 0x0080, // c2p, marks argument, that needs freeing
++ // convenience shortcuts
++ cmdarg_eol = 0x0003, // catchall + plain
++ cmdarg_chreq = 0x0018, // check + required
+} cmdarg_flags_t;
+
+struct cmdopts_struct {
@@ -4361,6 +4833,7 @@
+ 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
+ const char *defval; // [user,req] default value
+ cmdarg_type_t *type; // [user,req] type cbs - checker and completor
@@ -4370,7 +4843,6 @@
+};
+
+struct cmdarg_type_struct {
-+ const char *name; // [user,req] type name (help)
+ cmdarg_checker_t check; // [user,req] check string and set argument value
+ cmdarg_destructor_t free; // [user,req] free argument value
+ cmdarg_completor_t complete; // [user,req]
@@ -4455,7 +4927,7 @@
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 Tue Mar 05 01:08:31 2013 +0200
++++ b/mcabber/mcabber/roster.c Mon Mar 11 01:32:27 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,
@@ -4496,7 +4968,7 @@
}
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 Tue Mar 05 01:08:31 2013 +0200
++++ b/mcabber/mcabber/screen.c Mon Mar 11 01:32:27 2013 +0200
@@ -3626,7 +3626,7 @@
{
scr_check_auto_away(TRUE);
@@ -4508,7 +4980,7 @@
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 Tue Mar 05 01:08:31 2013 +0200
++++ b/mcabber/mcabber/xmpp_iq.c Mon Mar 11 01:32:27 2013 +0200
@@ -289,10 +289,7 @@
if (value) {
for (s = adhoc_status_list; !s->name || strcmp(s->name, value); s++);