# HG changeset patch # User Myhailo Danylenko # Date 1362958406 -7200 # Node ID 17cd00b2e722090ca12001f2f33cc051096f5783 # Parent a879ea17987702d00e6158a32c4f86b4617002ba [cmdopts] Struggling in chaos diff -r a879ea179877 -r 17cd00b2e722 cmdopts.diff --- 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 #include #include -@@ -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 @@ -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++);