--- a/cmdopts.diff Wed Mar 13 17:54:09 2013 +0200
+++ b/cmdopts.diff Mon Mar 18 02:26:50 2013 +0200
@@ -2,40 +2,44 @@
# Parent 1b0b563a81e6425da07c1da7ea4f947c4f3326cb
[work-in-progress] Unified command option parsing
- * wrecking chaos all over the place
- * started integration with cmd subsystem
- * broke everything
+ * complete change of commands.h interface
+ - uses different symbols to make compatibility layer possible
+ * completion system is broken now
+ * usable commands:
+ - roster
+ - color
+ - status/status_to
+ - add/del
+ - group
+ - say
+ * it does compile, but have not tested at all
+ * privatized say_cmd()
+ * dropped cmd_setstatus()
+ * process_line() still expects line to be in local encoding,
+ while cmd_execute() expects utf8 and rw
+ * process_line() can return error values, different from 255
** PREVIOUS ACHIEVEMENTS **
- * cmdopts_parse() & cmdopts_free() in utils.c/h
- * /roster uses parser
+ * function interface changes:
* buddy_search() now expects argument in utf8
- * /say_to uses parser
- * /color uses parser
- * /status and /status_to use parser
* cmd_setstatus() now expects separate status and message arguments
- * /add uses parser
- * /del uses parser
+ * say_cmd()'s second argument is now of new type msgtype_t
+ * scr_multi* now store multiline in utf8
+ * /del:
* allows specifying jid, as /add does
* -n(--dryrun) switch for debugging purposes
- * /group uses parser
- * /say uses parser
- * say_cmd()'s second argument is now of new type msgtype_t
- * /msay uses parser
- * scr_multi* now store multiline in utf8
- * /buffer uses parser
- * fix help for /buffer date
- * /rename uses parser
+ * /rename:
* -r(--reset) instead of '-'
* -j(--jid), -g(--group), -n(--name)
- * /move uses parser
+ * /move:
* -j(--jid), -n(--name)
- * /rawxml uses parser
+ * misc:
+ * fix help for /buffer date
diff -r 1b0b563a81e6 mcabber/doc/help/cs/hlp_buffer.txt
--- a/mcabber/doc/help/cs/hlp_buffer.txt Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/cs/hlp_buffer.txt Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/doc/help/cs/hlp_buffer.txt Mon Mar 18 02:16:22 2013 +0200
@@ -25,7 +25,7 @@
Přesune se o [n] řádků nahoru (výchozí: polovina obrazovky).
/buffer down [n]
@@ -47,7 +51,7 @@
Přesune se na procentuální pozici n%.
diff -r 1b0b563a81e6 mcabber/doc/help/cs/hlp_del.txt
--- a/mcabber/doc/help/cs/hlp_del.txt Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/cs/hlp_del.txt Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/doc/help/cs/hlp_del.txt Mon Mar 18 02:16:22 2013 +0200
@@ -1,4 +1,4 @@
- /DEL
@@ -56,7 +60,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 1b0b563a81e6 mcabber/doc/help/cs/hlp_move.txt
--- a/mcabber/doc/help/cs/hlp_move.txt Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/cs/hlp_move.txt Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/doc/help/cs/hlp_move.txt Mon Mar 18 02:16:22 2013 +0200
@@ -1,5 +1,6 @@
- /MOVE [skupina]
@@ -67,7 +71,7 @@
Tip: V módu rozhovoru lze použít "/roster alternate" pro skok na přesunutý kontakt.
diff -r 1b0b563a81e6 mcabber/doc/help/cs/hlp_rename.txt
--- a/mcabber/doc/help/cs/hlp_rename.txt Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/cs/hlp_rename.txt Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/doc/help/cs/hlp_rename.txt Mon Mar 18 02:16:22 2013 +0200
@@ -1,4 +1,6 @@
- /RENAME jméno
@@ -79,7 +83,7 @@
+Optionally you can use one of --jid, --group or --name to select object, different from current.
diff -r 1b0b563a81e6 mcabber/doc/help/de/hlp_buffer.txt
--- a/mcabber/doc/help/de/hlp_buffer.txt Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/de/hlp_buffer.txt Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/doc/help/de/hlp_buffer.txt Mon Mar 18 02:16:22 2013 +0200
@@ -25,7 +25,7 @@
Scrollt den Puffer um n Zeilen hoch. Gibt man keine Zahl an, scrollt er um einen halben Bildschirm
/buffer down [n]
@@ -91,7 +95,7 @@
Springe zur Position "n" im Chatpuffer
diff -r 1b0b563a81e6 mcabber/doc/help/de/hlp_del.txt
--- a/mcabber/doc/help/de/hlp_del.txt Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/de/hlp_del.txt Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/doc/help/de/hlp_del.txt Mon Mar 18 02:16:22 2013 +0200
@@ -1,4 +1,4 @@
- /DEL
@@ -100,7 +104,7 @@
Löscht den gerade ausgewählten Buddy vom Roster. Außerdem werden die automatischen Presence Benachrichtigungen vom/zum Buddy gestoppt.
diff -r 1b0b563a81e6 mcabber/doc/help/de/hlp_move.txt
--- a/mcabber/doc/help/de/hlp_move.txt Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/de/hlp_move.txt Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/doc/help/de/hlp_move.txt Mon Mar 18 02:16:22 2013 +0200
@@ -1,6 +1,7 @@
- /MOVE [groupname]
@@ -112,7 +116,7 @@
Tipp: Wenn der Chatmodus aktiviert ist, kannst du "/roster alternate" benutzen um zu dem gerade bewegten Buddy zu springen.
diff -r 1b0b563a81e6 mcabber/doc/help/de/hlp_rename.txt
--- a/mcabber/doc/help/de/hlp_rename.txt Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/de/hlp_rename.txt Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/doc/help/de/hlp_rename.txt Mon Mar 18 02:16:22 2013 +0200
@@ -1,4 +1,6 @@
- /RENAME name
@@ -124,7 +128,7 @@
+Optionally you can use one of --jid, --group or --name to select object, different from current.
diff -r 1b0b563a81e6 mcabber/doc/help/en/hlp_buffer.txt
--- a/mcabber/doc/help/en/hlp_buffer.txt Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/en/hlp_buffer.txt Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/doc/help/en/hlp_buffer.txt Mon Mar 18 02:16:22 2013 +0200
@@ -25,7 +25,7 @@
Scroll the buffer up [n] lines (default: half a screen)
/buffer down [n]
@@ -136,7 +140,7 @@
Jump to position %n of the buddy chat buffer
diff -r 1b0b563a81e6 mcabber/doc/help/en/hlp_del.txt
--- a/mcabber/doc/help/en/hlp_del.txt Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/en/hlp_del.txt Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/doc/help/en/hlp_del.txt Mon Mar 18 02:16:22 2013 +0200
@@ -1,4 +1,4 @@
- /DEL
@@ -146,7 +150,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 1b0b563a81e6 mcabber/doc/help/en/hlp_move.txt
--- a/mcabber/doc/help/en/hlp_move.txt Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/en/hlp_move.txt Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/doc/help/en/hlp_move.txt Mon Mar 18 02:16:22 2013 +0200
@@ -1,5 +1,6 @@
- /MOVE [groupname]
@@ -157,7 +161,7 @@
Tip: if the chatmode is enabled, you can use "/roster alternate" to jump to the moved buddy.
diff -r 1b0b563a81e6 mcabber/doc/help/en/hlp_rename.txt
--- a/mcabber/doc/help/en/hlp_rename.txt Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/en/hlp_rename.txt Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/doc/help/en/hlp_rename.txt Mon Mar 18 02:16:22 2013 +0200
@@ -1,4 +1,6 @@
- /RENAME name
@@ -169,7 +173,7 @@
+Optionally you can use one of --jid, --group or --name to select object, different from current.
diff -r 1b0b563a81e6 mcabber/doc/help/fr/hlp_buffer.txt
--- a/mcabber/doc/help/fr/hlp_buffer.txt Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/fr/hlp_buffer.txt Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/doc/help/fr/hlp_buffer.txt Mon Mar 18 02:16:22 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 +185,7 @@
Va à la position n% du tampon
diff -r 1b0b563a81e6 mcabber/doc/help/fr/hlp_del.txt
--- a/mcabber/doc/help/fr/hlp_del.txt Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/fr/hlp_del.txt Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/doc/help/fr/hlp_del.txt Mon Mar 18 02:16:22 2013 +0200
@@ -1,4 +1,4 @@
- /DEL
@@ -190,7 +194,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 1b0b563a81e6 mcabber/doc/help/fr/hlp_move.txt
--- a/mcabber/doc/help/fr/hlp_move.txt Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/fr/hlp_move.txt Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/doc/help/fr/hlp_move.txt Mon Mar 18 02:16:22 2013 +0200
@@ -1,5 +1,6 @@
- /MOVE [groupname]
@@ -201,7 +205,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 1b0b563a81e6 mcabber/doc/help/fr/hlp_rename.txt
--- a/mcabber/doc/help/fr/hlp_rename.txt Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/fr/hlp_rename.txt Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/doc/help/fr/hlp_rename.txt Mon Mar 18 02:16:22 2013 +0200
@@ -1,4 +1,6 @@
- /RENAME nom
@@ -213,7 +217,7 @@
+Optionally you can use one of --jid, --group or --name to select object, different from current.
diff -r 1b0b563a81e6 mcabber/doc/help/it/hlp_buffer.txt
--- a/mcabber/doc/help/it/hlp_buffer.txt Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/it/hlp_buffer.txt Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/doc/help/it/hlp_buffer.txt Mon Mar 18 02:16:22 2013 +0200
@@ -25,7 +25,7 @@
Fa scorrere indietro il buffer di [n] linee (default: metà schermo)
/buffer down [n]
@@ -225,7 +229,7 @@
Salta alla posizione %n del buffer di chat corrente
diff -r 1b0b563a81e6 mcabber/doc/help/it/hlp_del.txt
--- a/mcabber/doc/help/it/hlp_del.txt Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/it/hlp_del.txt Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/doc/help/it/hlp_del.txt Mon Mar 18 02:16:22 2013 +0200
@@ -1,4 +1,4 @@
- /DEL
@@ -234,7 +238,7 @@
Elimina il contatto corrente dal roster, cancellando la sottoscrizione alle reciproche notifiche della propria presenza.
diff -r 1b0b563a81e6 mcabber/doc/help/it/hlp_move.txt
--- a/mcabber/doc/help/it/hlp_move.txt Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/it/hlp_move.txt Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/doc/help/it/hlp_move.txt Mon Mar 18 02:16:22 2013 +0200
@@ -1,5 +1,6 @@
- /MOVE [gruppo]
@@ -245,7 +249,7 @@
Trucco: se la modalità chat è abilitata, puoi usare "/roster alternate" per spostarti sul contatto appena mosso.
diff -r 1b0b563a81e6 mcabber/doc/help/it/hlp_rename.txt
--- a/mcabber/doc/help/it/hlp_rename.txt Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/it/hlp_rename.txt Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/doc/help/it/hlp_rename.txt Mon Mar 18 02:16:22 2013 +0200
@@ -1,4 +1,6 @@
- /RENAME nome
@@ -257,7 +261,7 @@
+Optionally you can use one of --jid, --group or --name to select object, different from current.
diff -r 1b0b563a81e6 mcabber/doc/help/nl/hlp_buffer.txt
--- a/mcabber/doc/help/nl/hlp_buffer.txt Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/nl/hlp_buffer.txt Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/doc/help/nl/hlp_buffer.txt Mon Mar 18 02:16:22 2013 +0200
@@ -25,7 +25,7 @@
Scroll de buffer [n] regels omhoog (standaard: een half scherm)
/buffer down [n]
@@ -269,7 +273,7 @@
Spring naar positie %n in de buddy chat buffer
diff -r 1b0b563a81e6 mcabber/doc/help/nl/hlp_del.txt
--- a/mcabber/doc/help/nl/hlp_del.txt Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/nl/hlp_del.txt Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/doc/help/nl/hlp_del.txt Mon Mar 18 02:16:22 2013 +0200
@@ -1,4 +1,4 @@
- /DEL
@@ -278,7 +282,7 @@
Verwijder de actieve buddy uit ons roster, en zet het wederzijds toezenden van status veranderingen stop.
diff -r 1b0b563a81e6 mcabber/doc/help/nl/hlp_move.txt
--- a/mcabber/doc/help/nl/hlp_move.txt Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/nl/hlp_move.txt Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/doc/help/nl/hlp_move.txt Mon Mar 18 02:16:22 2013 +0200
@@ -1,5 +1,6 @@
- /MOVE [groepsnaam]
@@ -289,7 +293,7 @@
Tip: indien chatmode actief is, kun je "/roster alternate" gebruiken om direct naar de verplaatste buddy te springen.
diff -r 1b0b563a81e6 mcabber/doc/help/nl/hlp_rename.txt
--- a/mcabber/doc/help/nl/hlp_rename.txt Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/nl/hlp_rename.txt Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/doc/help/nl/hlp_rename.txt Mon Mar 18 02:16:22 2013 +0200
@@ -1,4 +1,6 @@
- /RENAME naam
@@ -301,7 +305,7 @@
+Optionally you can use one of --jid, --group or --name to select object, different from current.
diff -r 1b0b563a81e6 mcabber/doc/help/pl/hlp_del.txt
--- a/mcabber/doc/help/pl/hlp_del.txt Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/pl/hlp_del.txt Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/doc/help/pl/hlp_del.txt Mon Mar 18 02:16:22 2013 +0200
@@ -1,4 +1,4 @@
- /DEL
@@ -310,7 +314,7 @@
Usuwa aktualnie zaznaczoną osobę z rostera, usuwa subskrypcję powiadomienia dostępności u danej osoby oraz u nas.
diff -r 1b0b563a81e6 mcabber/doc/help/pl/hlp_move.txt
--- a/mcabber/doc/help/pl/hlp_move.txt Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/pl/hlp_move.txt Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/doc/help/pl/hlp_move.txt Mon Mar 18 02:16:22 2013 +0200
@@ -1,5 +1,6 @@
- /MOVE [nazwa grupy]
@@ -321,7 +325,7 @@
Podpowiedź: jeśli jest włączony tryb czatu, możesz użyć "/roster alternate" aby skoczyć do przeniesionej osoby.
diff -r 1b0b563a81e6 mcabber/doc/help/pl/hlp_rename.txt
--- a/mcabber/doc/help/pl/hlp_rename.txt Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/pl/hlp_rename.txt Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/doc/help/pl/hlp_rename.txt Mon Mar 18 02:16:22 2013 +0200
@@ -1,4 +1,6 @@
- /RENAME nazwa
@@ -333,7 +337,7 @@
+Optionally you can use one of --jid, --group or --name to select object, different from current.
diff -r 1b0b563a81e6 mcabber/doc/help/ru/hlp_buffer.txt
--- a/mcabber/doc/help/ru/hlp_buffer.txt Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/ru/hlp_buffer.txt Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/doc/help/ru/hlp_buffer.txt Mon Mar 18 02:16:22 2013 +0200
@@ -25,7 +25,7 @@
Перемещает на [n] строк вверх в буфере (истории переписки) (по умолчанию: половина экрана)
/buffer down [n]
@@ -345,7 +349,7 @@
Перемещает на позицию %n в текущем буфере (истории переписки)
diff -r 1b0b563a81e6 mcabber/doc/help/ru/hlp_del.txt
--- a/mcabber/doc/help/ru/hlp_del.txt Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/ru/hlp_del.txt Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/doc/help/ru/hlp_del.txt Mon Mar 18 02:16:22 2013 +0200
@@ -1,4 +1,4 @@
- /DEL
@@ -355,7 +359,7 @@
+Удаляет текущего пользователя (или указанного с помощью jid) из списка контактов, отключает уведомления о его статусе и отключает уведомление пользователя о вашем статусе.
diff -r 1b0b563a81e6 mcabber/doc/help/ru/hlp_move.txt
--- a/mcabber/doc/help/ru/hlp_move.txt Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/ru/hlp_move.txt Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/doc/help/ru/hlp_move.txt Mon Mar 18 02:16:22 2013 +0200
@@ -1,6 +1,7 @@
- /MOVE [groupname]
@@ -367,7 +371,7 @@
diff -r 1b0b563a81e6 mcabber/doc/help/ru/hlp_rename.txt
--- a/mcabber/doc/help/ru/hlp_rename.txt Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/ru/hlp_rename.txt Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/doc/help/ru/hlp_rename.txt Mon Mar 18 02:16:22 2013 +0200
@@ -1,4 +1,6 @@
- /RENAME name
@@ -379,7 +383,7 @@
+Для указания обьекта, отличного от текущего, можно использовать опции --jid, --group и --name.
diff -r 1b0b563a81e6 mcabber/doc/help/uk/hlp_buffer.txt
--- a/mcabber/doc/help/uk/hlp_buffer.txt Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/uk/hlp_buffer.txt Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/doc/help/uk/hlp_buffer.txt Mon Mar 18 02:16:22 2013 +0200
@@ -25,7 +25,7 @@
Посунути буфер вверх на n рядків (якщо не вказано - пів екрану).
/buffer down [n]
@@ -391,7 +395,7 @@
Перейти до вказаної у процентах позиції.
diff -r 1b0b563a81e6 mcabber/doc/help/uk/hlp_del.txt
--- a/mcabber/doc/help/uk/hlp_del.txt Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/uk/hlp_del.txt Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/doc/help/uk/hlp_del.txt Mon Mar 18 02:16:22 2013 +0200
@@ -1,4 +1,4 @@
- /DEL
@@ -401,7 +405,7 @@
+Потерти поточний контакт (або контакт, що має вказаний jid) зі списку. Також відписатися від його сповіщень про статус і відписати його від ваших.
diff -r 1b0b563a81e6 mcabber/doc/help/uk/hlp_move.txt
--- a/mcabber/doc/help/uk/hlp_move.txt Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/uk/hlp_move.txt Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/doc/help/uk/hlp_move.txt Mon Mar 18 02:16:22 2013 +0200
@@ -1,5 +1,6 @@
- /MOVE [група]
@@ -413,7 +417,7 @@
Примітка: в режимі розмови можна використати "/roster alternate", щоб перейти до нового місця контакту контакту.
diff -r 1b0b563a81e6 mcabber/doc/help/uk/hlp_rename.txt
--- a/mcabber/doc/help/uk/hlp_rename.txt Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/doc/help/uk/hlp_rename.txt Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/doc/help/uk/hlp_rename.txt Mon Mar 18 02:16:22 2013 +0200
@@ -1,4 +1,6 @@
- /RENAME ім'я
@@ -424,7 +428,7 @@
+Опції --jid, --group та --name дозволяють перейменовувати об’єкти, відмінні від поточного.
diff -r 1b0b563a81e6 mcabber/mcabber/commands.c
--- a/mcabber/mcabber/commands.c Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/mcabber/commands.c Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/mcabber/commands.c Mon Mar 18 02:16:22 2013 +0200
@@ -19,7 +19,7 @@
* USA
*/
@@ -434,7 +438,7 @@
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
-@@ -43,512 +43,631 @@
+@@ -43,512 +43,671 @@
#include "xmpp.h"
#include "main.h"
@@ -457,21 +461,27 @@
+ scmd_group_fold = 1,
+ scmd_group_toggle = -1,
+} scmd_group_t;
++typedef enum {
++ msgtype_not_set,
++ msgtype_normal,
++ msgtype_headline,
++} msgtype_t;
+
+static void group_cmd (gpointer group, scmd_group_t action);
++static void say_cmd (char *arg, msgtype_t msgtype);
+
+//static void room_bookmark(gpointer bud, char *arg);
+
-+#define BUILTIN_COUNT 4
++#define BUILTIN_COUNT 8
+static cmdopts_t def_roster,
+ def_color,
+ def_status,
+ def_status_to,
+ def_add,
+ def_del,
-+ def_group;
++ def_group,
++ def_say;
+#if 0
-+ def_say,
+ def_msay,
+ def_say_to,
+ def_buffer,
@@ -586,8 +596,8 @@
+ cmd_list[4] = &def_add;
+ cmd_list[5] = &def_del;
+ cmd_list[6] = &def_group;
++ cmd_list[7] = &def_say;
+#if 0
-+ cmd_list[7] = &def_say;
+ cmd_list[8] = &def_msay;
+ cmd_list[9] = &def_say_to;
+ cmd_list[10] = &def_buffer;
@@ -631,18 +641,51 @@
+ cmd_count = 0;
+}
+
-+// XXX:
-+// * if command is found, maybe still put it at the start of queue?
++static size_t cmdopts_count_values (cmdopts_t *command)
++{
++ size_t max = -1;
++ if (command -> opts) {
++ cmdopt_t *opt;
++ for (opt = command -> opts; opt -> shortopt != 0; opt ++)
++ if (opt -> arg.pos > max)
++ max = opt -> arg.pos;
++ }
++ if (command -> args) {
++ cmdarg_t *arg;
++ for (arg = command -> args; arg -> name != NULL; arg ++)
++ if (arg -> pos > max)
++ max = arg -> pos;
++ }
++ if (command -> cmds) {
++ cmdopts_t *scmd;
++ for (scmd = command -> cmds; scmd -> name != NULL; scmd ++) {
++ size_t cnt = cmdopts_count_values (scmd);
++ if (cnt > max)
++ max = cnt;
+ }
++ }
++ return max;
++}
++
+void cmd_define (cmdopts_t *command)
+{
-+ cmdopts_t **cmd;
-+ for (cmd = cmd_list; *cmd != NULL; cmd ++)
-+ if (*cmd == command)
++ size_t n;
++ // we update value count even for existing commands - user may
++ // have screwed something up in struct.
++ command -> valno = cmdopts_count_values (command) + 1;
++ // check if command already exists
++ for (n = cmd_count; n > 0; n --)
++ if (cmd_list[n-1] == command) {
++ // raise it's priority
++ g_memmove(cmd_list+n-1, cmd_list+n, sizeof(cmdopts_t *) * (cmd_count-n-1));
++ cmd_list[cmd_count-1] = command;
+ return;
++ }
++ // register new command
+ cmd_list = g_renew (cmdopts_t *, cmd_list, cmd_count+2);
-+ cmd_list[cmd_count] = command;
++ cmd_list[cmd_count] = command;
++ cmd_list[cmd_count+1] = NULL;
+ cmd_count ++;
-+ cmd_list[cmd_count] = NULL;
+}
+
+void cmd_undef (cmdopts_t *command)
@@ -654,17 +697,10 @@
+ cmd_list = g_renew (cmdopts_t *, cmd_list, cmd_count);
+ cmd_count --;
+ return;
- }
-- return NULL;
++ }
+ num ++;
+ }
- }
--#endif
--
--// cmd_add()
--// Adds a command to the commands list and to the CMD completion list
--gpointer cmd_add(const char *name, const char *help, guint flags_row1,
-- guint flags_row2, void (*f)(char*), gpointer userdata)
++}
+
+// error cmdopts_parse_argument ( startptr, endptr, flags )
+// Parses next argument according to flags and finishes it with zero.
@@ -672,18 +708,7 @@
+// String may shrink in size (quotation/escapes), thus endpointer is also
+// updated.
+const char *cmdopts_parse_argument(gchar **pr, gchar **er, cmdarg_flags_t flags)
- {
-- cmd *n_cmd = g_slice_new0(cmd);
-- strncpy(n_cmd->name, name, 32-1);
-- n_cmd->help = help;
-- n_cmd->completion_flags[0] = flags_row1;
-- n_cmd->completion_flags[1] = flags_row2;
-- n_cmd->func = f;
-- n_cmd->userdata = userdata;
-- Commands = g_slist_prepend(Commands, n_cmd);
-- // Add to completion CMD category
-- compl_add_category_word(COMPL_CMD, name);
-- return n_cmd;
++{
+ gchar *p = *pr;
+ gchar *e = *er;
+ const char *error = NULL;
@@ -723,28 +748,35 @@
+ *pr = p;
+ *er = e;
+ return error;
- }
-
--// cmd_set_safe(name, safe)
--// Sets if command can be used in startup configuration file.
--gboolean cmd_set_safe(const gchar *name, gboolean safe)
++}
++
++static cmdarg_value_t *cmdopts_allocate_values (cmdopts_t *command)
++{
++ cmdarg_value_t *values;
++ size_t n = command -> valno;
++
++ if (n == 0)
++ return NULL;
++
++ values = g_slice_alloc (sizeof(cmdarg_value_t) * n);
++
++ while (n > 0) {
++ n --;
++ values[n].src = NULL;
++ values[n].flags = cmdval_default;
++ values[n].value.arg = NULL;
++ }
++
++ return values;
++}
++
+// error cmdopts_parse_internal ( startptr, endptr, commanddef )
+// Parses command arguments according to command definition.
+// Parsed string MUST be writable. Regardless of success or error, input
+// string should be considered corrupted by parsing process.
+// Even in case of error, commanddef should be passed to cmdopts_free().
-+static gchar *cmdopts_parse_internal(gchar **pr, gchar **er, cmdopts_t *command)
- {
-- GSList *sel;
-- if (!name)
-- return FALSE;
-- for (sel = safe_commands; sel; sel = sel->next)
-- if (!strcmp((const char *)sel->data, name)) {
-- if (safe)
-- return FALSE;
-- else {
-- g_free(sel->data);
-- safe_commands = g_slist_delete_link(safe_commands, sel);
++static gchar *cmdopts_parse_internal(gchar **pr, gchar **er, cmdopts_t *command, cmdarg_value_t *values)
++{
+ enum { // Parser state transitions:
+ in_space, // -> in_space, in_optstart, in_argstart
+ in_optstart, // -> in_shortoptend, in_longoptstart, in_argstart ("-")
@@ -761,43 +793,46 @@
+ size_t argno = 0; // number of current positional argument
+ gchar *error = NULL; // error message to return
+
-+ // general environment checking
-+ if (command -> check) {
-+ if ((error = command -> check (command))) {
-+ gchar *err = error;
-+ error = g_strdup_printf("%s: %s", command -> name, err);
-+ g_free (err);
-+ }
-+ }
-+
+ // prepare: set default values for arguments and unset some fields
+ if (error == NULL) {
+ gsize n;
+ if (command -> opts) {
+ for (n = 0; command -> opts[n].shortopt != 0; n ++) {
-+ cmdopt_t *opt = command -> opts + n;
-+ if (opt -> flags & cmdopt_switch) {
-+ opt -> arg.value.swc = 0;
-+ } else {
-+ opt -> arg.value.roarg = opt -> arg.defval;
++ cmdopt_t *opt = command -> opts + n;
++ cmdarg_value_t *val = values + opt -> arg.pos;
++ // do not overwrite already specified values
++ if (val -> src == NULL || !(val -> flags & cmdval_visited)) {
++ if (opt -> arg.flags & cmdarg_switch) {
++ val -> value.swc = 0;
++ } else {
++ val -> value.roarg = opt -> arg.defval; // XXX ro
++ }
++ val -> src = &(opt -> arg);
+ }
-+ opt -> arg.flags &= ~(cmdarg_ppclear);
- }
- }
-- if (safe)
-- safe_commands = g_slist_append(safe_commands, g_strdup(name));
-- else
-- return FALSE;
-- return TRUE;
++ }
++ }
+ if (command -> args) {
+ for (n = 0; command -> args[n].name != NULL; n ++) {
-+ cmdarg_t *arg = command -> args + n;
-+ arg -> value.roarg = arg -> defval;
-+ arg -> flags &= ~(cmdarg_ppclear);
++ cmdarg_t *arg = command -> args + n;
++ cmdarg_value_t *val = values + arg -> pos;
++ // do not overwrite already specified values
++ if (val -> src == NULL || !(val -> flags & cmdval_visited)) {
++ val -> value.roarg = arg -> defval; // XXX ro
++ val -> src = arg;
++ }
+ }
+ }
+ }
+
++ // general environment checking
++ if (command -> check) {
++ if ((error = command -> check (command, values))) {
++ gchar *err = error;
++ error = g_strdup_printf("%s: %s", command -> name, err);
++ g_free (err);
++ }
++ }
++
+ // we allow parser to do one extra run on final '\0'
+ while (p <= e && error == NULL) {
+ if (state == in_space) { // space between args/options
@@ -836,8 +871,11 @@
+ }
+ }
+ if (option != NULL) { // option is known
-+ if (option -> flags & cmdopt_switch) { // it is switch
-+ option -> arg.value.swc ++;
++ if (option -> arg.flags & cmdarg_switch) { // it is switch
++ cmdarg_value_t *val = values + option -> arg.pos;
++ val -> value.swc ++;
++ val -> src = &(option -> arg);
++ val -> flags |= cmdval_visited;
+ option = NULL;
+ } else if (p == e) {
+ error = g_strdup_printf ("%s: Option -%c needs an argument.", command -> name, option -> shortopt);
@@ -878,8 +916,11 @@
+ }
+ }
+ if (option != NULL) { // option is known
-+ if (option -> flags & cmdopt_switch) { // it is switch
-+ option -> arg.value.swc ++;
++ if (option -> arg.flags & cmdarg_switch) { // it is switch
++ cmdarg_value_t *val = values + option -> arg.pos;
++ val -> value.swc ++;
++ val -> src = &(option -> arg);
++ val -> flags |= cmdval_visited;
+ option = NULL;
+ } else if (p == e) {
+ error = g_strdup_printf ("%s: Option --%s needs an argument.", command -> name, option -> longopt);
@@ -904,32 +945,30 @@
+ arg = command -> args + argno;
+ }
+
-+ if ((err = cmdopts_parse_argument(&p, &e, arg -> flags))) { // get argument value
++ if ((err = cmdopts_parse_argument (&p, &e, arg -> flags))) { // get argument value
+ if (!option) {
+ error = g_strdup_printf ("%s: Can't parse argument %s (%lu): %s", command -> name, arg -> name, argno + 1, err);
-+ } else if (option -> shortopt) {
++ } else if (option -> longopt) {
++ error = g_strdup_printf ("%s: Can't parse argument for option --%s: %s", command -> name, option -> longopt, err);
++ } else {
+ error = g_strdup_printf ("%s: Can't parse argument for option -%c: %s", command -> name, option -> shortopt, err);
-+ } else {
-+ error = g_strdup_printf ("%s: Can't parse argument for option --%s: %s", command -> name, option -> longopt, err);
+ }
+ } else {
-+ arg -> value.arg = s;
-+ arg -> flags |= cmdarg_visited;
++ cmdarg_value_t *val = values + arg -> pos;
++ val -> value.arg = s;
++ val -> src = arg;
++ val -> flags |= cmdval_visited;
+ if (option) { // option argument
+ option = NULL;
+ } else { // normal argument
+ if (arg -> flags & cmdarg_subcmd) { // subcommand
+ cmdopts_t *subcmd;
-+ gsize n; // XXX put command list into chkdata
-+ for (n = 0; command -> cmds[n].name != NULL; n ++) {
-+ if (!strcmp (s, command -> cmds[n].name)) {
-+ subcmd = command -> cmds + n;
++ for (subcmd = command -> cmds; subcmd -> name != NULL; subcmd ++)
++ if (!strcmp (s, subcmd -> name))
+ break;
-+ }
-+ }
-+ if (subcmd != NULL) { // found subcommand
-+ arg -> value.cmd = subcmd;
-+ if ((error = cmdopts_parse_internal (&p, &e, subcmd))) {
++ if (subcmd -> name != NULL) { // found subcommand
++ val -> value.cmd = subcmd;
++ if ((error = cmdopts_parse_internal (&p, &e, subcmd, values))) {
+ gchar *err = error;
+ error = g_strdup_printf("%s %s", command -> name, err);
+ g_free (err);
@@ -948,86 +987,232 @@
+ *pr = p;
+ *er = e;
+
-+ // perform option argument checking
-+ if (error == NULL && command -> opts) {
-+ gsize n;
-+ for (n = 0; command -> opts[n].shortopt != 0; n ++) {
-+ cmdopt_t *opt = command -> opts + n;
-+ if (!(opt -> flags & cmdopt_switch)) { // not a switch
-+ // 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 ((err = opt -> arg.type -> check (&(opt -> arg)))) {
-+ if (opt -> arg.flags & cmdarg_required) {
-+ if (opt -> longopt) {
-+ error = g_strdup_printf ("%s: Error in argument for option --%s: %s", command -> name, opt -> longopt, err);
-+ } else {
-+ error = g_strdup_printf ("%s: Error in argument for option -%c: %s", command -> name, opt -> shortopt, err);
-+ }
-+ g_free (err);
-+ break;
-+ } else {
-+ if (opt -> longopt) {
-+ scr_log_print (LPRINT_NORMAL, "Warning: %s: Error in argument for option --%s: %s", command -> name, opt -> longopt, err);
-+ } else {
-+ scr_log_print (LPRINT_NORMAL, "Warning: %s: Error in argument for option -%c: %s", command -> name, opt -> shortopt, err);
-+ }
-+ g_free (err);
-+ }
-+ }
++ return error;
++}
++
++// value types: type check required
++// - switch no effect toboolean() no effect?
++// - option check call checker fatal check error
++// - argument check call checker fatal check error
++// - subcommand no effect check for required fail if missing
++static gchar *cmdopts_check_values (cmdopts_t *command, cmdarg_value_t *values)
++{
++ size_t n = command -> valno;
++
++ if (n == 0)
++ return NULL;
++
++ // XXX reverse order?
++ while (n > 0) {
++ cmdarg_value_t *val = values + n - 1;
++ n --;
++ if ((val -> flags & cmdval_visited) || ((val -> src != NULL) && (val -> src -> flags & cmdarg_check))) {
++ if (val -> src -> flags & cmdarg_subcmd) { // subcommand - fail if required and missing
++ if ((val -> src -> flags & cmdarg_required) && (val -> value.cmd == NULL))
++ return g_strdup_printf ("%s: Not specified %s.", command -> name, val -> src -> name);
++ } else if (val -> src -> flags & cmdarg_switch) { // switch - toboolean if check
++ if (val -> src -> flags & cmdarg_check)
++ val -> value.swc %= 2;
++ } else if (val -> src -> type && val -> src -> type -> check) { // typed argument
++ gchar *err;
++ if ((err = val -> src -> type -> check (val))) {
++ // FIXME option name
++ if (val -> src -> flags & cmdarg_required) {
++ gchar *error = g_strdup_printf ("Error in argument value \"%s\": %s", val -> src -> name, err);
++ g_free (err);
++ return error;
++ } else {
++ scr_log_print (LPRINT_NORMAL, "Warning: %s: Error in argument value \"%s\": %s", command -> name, val -> src -> name, err);
++ g_free (err);
+ }
+ }
+ }
+ }
+ }
+
-+ // perform positional argument checking
-+ if (error == NULL && command -> args) {
-+ size_t n;
-+ for (n = 0; command -> args[n].name != NULL; n ++) {
-+ cmdarg_t *arg = command -> args + n;
-+ // needs checking and not checked already
-+ if ((arg -> flags & (cmdarg_check | cmdarg_visited)) && !(arg -> flags & cmdarg_checked)) {
-+ if (arg -> flags & cmdarg_subcmd) { // subcommand
-+ if (!arg -> value.cmd) {
-+ 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 ((err = arg -> type -> check (arg))) {
-+ if (arg -> flags & cmdarg_required) {
-+ error = g_strdup_printf ("%s: Error in argument %s (%lu): %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 (%lu): %s", command -> name, arg -> name, n, err);
-+ g_free (err);
-+ }
-+ }
-+ }
-+ }
-+ }
+ return NULL;
+ }
+-#endif
+-
+-// cmd_add()
+-// Adds a command to the commands list and to the CMD completion list
+-gpointer cmd_add(const char *name, const char *help, guint flags_row1,
+- guint flags_row2, void (*f)(char*), gpointer userdata)
++
++// cmdopts_free ( commanddef )
++// Free various parser data, used in parsing process
++static void cmdopts_free_values (cmdopts_t *command, cmdarg_value_t *values)
+ {
+- cmd *n_cmd = g_slice_new0(cmd);
+- strncpy(n_cmd->name, name, 32-1);
+- n_cmd->help = help;
+- n_cmd->completion_flags[0] = flags_row1;
+- n_cmd->completion_flags[1] = flags_row2;
+- n_cmd->func = f;
+- n_cmd->userdata = userdata;
+- Commands = g_slist_prepend(Commands, n_cmd);
+- // Add to completion CMD category
+- compl_add_category_word(COMPL_CMD, name);
+- return n_cmd;
++ size_t n = command -> valno;
++
++ if (n == 0)
++ return;
++
++ while (n > 0) {
++ cmdarg_value_t *val = values + n - 1;
++ n --;
++ if ((val -> flags & cmdval_freeme) &&
++ val -> src && val -> src -> type &&
++ val -> src -> type -> free) {
++ val -> src -> type -> free (val);
+ }
+ }
+
-+ return error;
++ g_slice_free1 (sizeof(cmdarg_value_t) * n, values);
+ }
+
+-// cmd_set_safe(name, safe)
+-// Sets if command can be used in startup configuration file.
+-gboolean cmd_set_safe(const gchar *name, gboolean safe)
++cmd_result_t cmd_execute (gchar *commandline, cmdexe_flags_t flags)
+ {
+- GSList *sel;
+- if (!name)
+- return FALSE;
+- for (sel = safe_commands; sel; sel = sel->next)
+- if (!strcmp((const char *)sel->data, name)) {
+- if (safe)
+- return FALSE;
+- else {
+- g_free(sel->data);
+- safe_commands = g_slist_delete_link(safe_commands, sel);
+- }
++ gchar *s = commandline;
++ gchar *p, *e;
++ gchar *freeme = NULL;
++ const char *err;
++ gchar *error;
++ cmdopts_t *command = NULL;
++ const char *alias = NULL;
++ cmdarg_value_t *values;
++ size_t n;
++
++ // skip command indicator and spaces at the beginning
++ while (*s == COMMAND_CHAR || *s == ' ')
++ s ++;
++ p = s;
++ e = s + strlen (s);
++
++ // separate first word - command name
++ if ((err = cmdopts_parse_argument (&p, &e, cmdarg_default))) {
++ scr_log_print (LPRINT_NORMAL, "error: Can't comprehend command name: %s.", err);
++ return cmd_result_syntax_error;
++ }
++
++ // check for quit command
++ if (!strcmp (s, "quit")) {
++ return cmd_result_quit;
++ }
++
++ // check if we're in verbatim mode
++ if ((flags & cmdexe_check_verbatim) && scr_get_multimode () == 2) {
++ if (strcmp (s, "msay")) { // it is not msay
++ return cmd_result_verbatim;
+ }
+- if (safe)
+- safe_commands = g_slist_append(safe_commands, g_strdup(name));
+- else
+- return FALSE;
+- return TRUE;
++ }
++
++ // check and expand alias
++ if ((alias = settings_get (SETTINGS_TYPE_ALIAS, s))) {
++ freeme = s = g_strdup_printf ("%s %s", alias, p);
++ p = s;
++ e = s + strlen (s);
++
++ if ((err = cmdopts_parse_argument (&p, &e, cmdarg_default))) {
++ scr_log_print (LPRINT_NORMAL, "error: Can't comprehend command name: %s.", err);
++ g_free (freeme);
++ return cmd_result_syntax_error;
++ }
++
++ // check for quit command again
++ if (!strcmp (s, "quit")) {
++ g_free (freeme);
++ return cmd_result_quit;
++ }
++ }
++
++ // find command with this name (reverse - see cmd_define())
++ for (n = cmd_count; n > 0; n --) {
++ if (!strcmp (s, cmd_list[n-1] -> name)) {
++ command = cmd_list[n-1];
++ break;
++ }
++ }
++ if (command == NULL) {
++ scr_log_print (LPRINT_NORMAL, "error: Unable to find command \"%s\".", s);
++ g_free (freeme);
++ return cmd_result_not_found;
++ }
++
++ // check safety
++ if ((flags & cmdexe_check_safe) && !(command -> flags & cmd_safe)) {
++ scr_log_print (LPRINT_NORMAL, "error: Command \"%s\" is not safe to execute here.", command -> name);
++ g_free (freeme);
++ return cmd_result_not_found;
++ }
++
++ // allocate dynamic storage for arguments
++ values = cmdopts_allocate_values (command);
++
++ // parse command line
++ if ((error = cmdopts_parse_internal (&p, &e, command, values))) {
++ scr_log_print (LPRINT_NORMAL, "%s", error);
++ g_free (error);
++ cmdopts_free_values (command, values);
++ g_free (freeme);
++ return cmd_result_syntax_error;
++ }
++
++ // do type checking on arguments
++ if ((error = cmdopts_check_values (command, values))) {
++ scr_log_print (LPRINT_NORMAL, "%s: %s", command -> name, error);
++ g_free (error);
++ cmdopts_free_values (command, values);
++ g_free (freeme);
++ return cmd_result_value_error;
++ }
++
++ // execute command handler
++ if (command -> handle) {
++ if ((error = command -> handle (command, values))) {
++ scr_log_print (LPRINT_NORMAL, "%s: %s", command -> name, error);
++ g_free (error);
++ cmdopts_free_values (command, values);
++ g_free (freeme);
++ return cmd_result_runtime_error;
++ }
++ }
++
++ // free resources
++ cmdopts_free_values (command, values);
++ g_free (freeme);
++ return cmd_result_ok;
}
-// cmd_is_safe(name)
-// Returns if command is safe or not
-gboolean cmd_is_safe(const gchar *name)
-+// cmdopts_free ( commanddef )
-+// Free various parser data, used in parsing process
-+static void cmdopts_free(cmdopts_t *command)
++// process_line(line)
++// Process a command/message line. If this isn't a command, this is a message
++// and it is sent to the currently selected buddy.
++// Returns 255 if the line is the /quit command, 0 on success and some other
++// error codes.
++cmd_result_t process_line(const char *line)
{
- GSList *sel;
- if (!name)
@@ -1036,40 +1221,8 @@
- if (!strcmp((const char *)sel->data, name))
- return TRUE;
- return FALSE;
-+ gsize n;
-+ if (command -> opts) {
-+ for (n = 0; command -> opts[n].shortopt != 0; n ++) {
-+ cmdopt_t *opt = command -> opts + n;
-+ if (!(opt -> flags & cmdopt_switch)) { // not switch
-+ 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));
-+ }
-+ }
-+ }
-+ }
-+ }
-+ if (command -> args) {
-+ for (n = 0; command -> args[n].name != NULL; n ++) {
-+ cmdarg_t *arg = command -> args + n;
-+ if (arg -> flags & cmdarg_subcmd) { // subcommand
-+ if (arg -> value.cmd) {
-+ cmdopts_free (arg -> value.cmd);
-+ arg -> value.cmd = NULL;
-+ }
-+ } else { // normal argument
-+ 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);
-+ }
-+ }
-+ }
-+ }
-+ }
- }
-
+-}
+-
-// cmd_init()
-// Commands table initialization
-// !!!
@@ -1077,8 +1230,7 @@
-// ones in init_bindings()!
-//
-void cmd_init(void)
-+cmd_result_t cmd_execute (gchar *commandline, cmdexe_flags_t flags)
- {
+-{
- cmd_add("add", "Add a jabber user", COMPL_JID, 0, &do_add, NULL);
- cmd_add("alias", "Add an alias", 0, 0, &do_alias, NULL);
- cmd_add("authorization", "Manage subscription authorizations",
@@ -1287,117 +1439,15 @@
- compl_add_category_word(COMPL_MODULE, "load");
- compl_add_category_word(COMPL_MODULE, "unload");
-#endif
-+ gchar *s = commandline;
-+ gchar *p, *e;
-+ gchar *freeme = NULL;
-+ const char *err;
-+ gchar *error;
-+ cmdopts_t *command = NULL;
-+ const char *alias = NULL;
-+ size_t n;
-+
-+ // skip command indicator and spaces at the beginning
-+ while (*s == COMMAND_CHAR || *s == ' ')
-+ s ++;
-+ p = s;
-+ e = s + strlen (s);
-+
-+ // separate first word - command name
-+ if ((err = cmdopts_parse_argument (&p, &e, cmdarg_default))) {
-+ scr_log_print (LPRINT_NORMAL, "error: Can't comprehend command name: %s.", err);
-+ return cmd_result_syntax_error;
-+ }
-+
-+ // check for quit command
-+ if (!strcmp (s, "quit")) {
-+ return cmd_result_quit;
-+ }
-+
-+ // check if we're in verbatim mode
-+ if ((flags & cmdexe_check_verbatim) && scr_get_multimode () == 2) {
-+ if (strcmp (s, "msay")) { // it is not msay
-+ return cmd_result_verbatim;
-+ }
-+ }
-+
-+ // check and expand alias
-+ if ((alias = settings_get (SETTINGS_TYPE_ALIAS, s))) {
-+ freeme = s = g_strdup_printf ("%s %s", alias, p);
-+ p = s;
-+ e = s + strlen (s);
-+
-+ if ((err = cmdopts_parse_argument (&p, &e, cmdarg_default))) {
-+ scr_log_print (LPRINT_NORMAL, "error: Can't comprehend command name: %s.", err);
-+ g_free (freeme);
-+ return cmd_result_syntax_error;
-+ }
-+
-+ // check for quit command again
-+ if (!strcmp (s, "quit")) {
-+ g_free (freeme);
-+ return cmd_result_quit;
-+ }
-+ }
-+
-+ // find command with this name (reverse - see cmd_define())
-+ for (n = cmd_count - 1; n >= 0; n --) {
-+ if (!strcmp (s, cmd_list[n] -> name)) {
-+ command = cmd_list[n];
-+ break;
-+ }
-+ }
-+ if (command == NULL) {
-+ scr_log_print (LPRINT_NORMAL, "error: Unable to find command \"%s\".", s);
-+ g_free (freeme);
-+ return cmd_result_not_found;
-+ }
-+
-+ // check safety
-+ if ((flags & cmdexe_check_safe) && !(command -> flags & cmd_safe)) {
-+ scr_log_print (LPRINT_NORMAL, "error: Command \"%s\" is not safe to execute here.", command -> name);
-+ g_free (freeme);
-+ return cmd_result_not_found;
-+ }
-+
-+ // parse command line
-+ if ((error = cmdopts_parse_internal (&p, &e, command))) {
-+ scr_log_print (LPRINT_NORMAL, "%s", error);
-+ g_free (error);
-+ cmdopts_free (command);
-+ g_free (freeme);
-+ return cmd_result_syntax_error;
-+ }
-+
-+ // execute command handler
-+ if (command -> handle) {
-+ if ((error = command -> handle (command))) {
-+ scr_log_print (LPRINT_NORMAL, "%s: %s", command -> name, error);
-+ g_free (error);
-+ cmdopts_free (command);
-+ g_free (freeme);
-+ return cmd_result_runtime_error;
-+ }
-+ }
-+
-+ // free resources
-+ cmdopts_free (command);
-+ g_free (freeme);
-+ return cmd_result_ok;
- }
-
+-}
+-
-// expandalias(line)
-// If there is one, expand the alias in line and returns a new allocated line
-// If no alias is found, returns line
-// Note: if the returned pointer is different from line, the caller should
-// g_free() the pointer after use
-char *expandalias(const char *line)
-+// process_line(line)
-+// Process a command/message line. If this isn't a command, this is a message
-+// and it is sent to the currently selected buddy.
-+// Returns 255 if the line is the /quit command, 0 on success and some other
-+// error codes.
-+cmd_result_t process_line(const char *line)
- {
+-{
- const char *p1, *p2;
- char *word;
- const gchar *value;
@@ -1552,7 +1602,7 @@
if (!*line) { // User only pressed enter
if (scr_get_multimode()) {
scr_append_multiline("");
-@@ -556,141 +675,584 @@
+@@ -556,141 +715,585 @@
}
if (current_buddy) {
if (buddy_gettype(BUDDATA(current_buddy)) & ROSTER_TYPE_GROUP)
@@ -1663,7 +1713,7 @@
+// * cmdarg_type_roster_group - in roster, on '.' select group of current buddy -> bud
+// + cmdarg_type_bjid - any bjid -> bjid
+// + cmdarg_type_fjid - any fjid -> fjid
-+// + cmdarg_type_statusmask - string -> string
++// + cmdarg_type_charset - string -> string
+// + cmdarg_type_uint - string -> uint
+// + cmdarg_type_nonspace - strip, space only -> null
+// * cmdarg_type_bjidmask
@@ -1675,7 +1725,7 @@
+// generic destructors
+//
+
-+void cmdarg_free_gfree (cmdarg_t *arg)
++void cmdarg_free_gfree (cmdarg_value_t *arg)
+{
+ g_free (arg -> value.arg);
+}
@@ -1684,7 +1734,7 @@
+// command environment checkers
+//
+
-+gchar *cmd_check_online (cmdopts_t *command)
++gchar *cmd_check_online (cmdopts_t *command, cmdarg_value_t *values)
+{
+ if (!xmpp_is_online())
+ return g_strdup ("You are not connected!");
@@ -1699,7 +1749,7 @@
+// Replaces value.arg.
+// Does not need freeing.
+// No trailing spaces in defvalue - needs RW access for that.
-+gchar *cmdarg_check_nonspace (cmdarg_t *arg)
++gchar *cmdarg_check_nonspace (cmdarg_value_t *arg)
+{
+ gchar *val = arg -> value.arg;
+
@@ -1743,28 +1793,28 @@
+//
+
+// Uses chkdata as guint with allowed ROSTER_TYPE_*.
-+// Returns buddy roster entry in value.bud.
++// Returns buddy roster entry in value.rjid.bud.
+// Recognizes as current ".", but not "" or NULL - use defvalue.
+// Does not require freeing.
-+gchar *cmdarg_check_roster_bjid (cmdarg_t *arg)
++gchar *cmdarg_check_roster_bjid (cmdarg_value_t *arg)
+{
+ gchar *error = NULL;
+
+ if (!(error = cmdarg_check_nonspace(arg))) {
+ const char *bjid = arg -> value.arg;
-+ guint types = (guint) arg -> chkdata;
++ guint types = (guint) arg -> src -> 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);
++ arg -> value.rjid.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;
++ arg -> value.rjid.bud = found->data;
+ else
+ error = g_strdup_printf("Jid <%s> is not in the roster.", bjid);
+ } else { // jid is invalid
@@ -1772,8 +1822,9 @@
+ }
+ }
+
++ arg -> value.rjid.resource = NULL;
+ if (error)
-+ arg -> value.bud = NULL;
++ arg -> value.rjid.bud = NULL;
+ return error;
+}
+
@@ -1794,9 +1845,8 @@
+// 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
+// * merge with roster_bjid and use own flags in chkdata to signify types and resource allowed/required conditions
-+gchar *cmdarg_check_roster_resource (cmdarg_t *arg)
++gchar *cmdarg_check_roster_resource (cmdarg_value_t *arg)
+{
+ gchar *error = NULL;
+ gpointer bud = NULL;
@@ -1804,7 +1854,7 @@
+
+ if (!(error = cmdarg_check_nonspace(arg))) {
+ char *fjid = arg -> value.arg;
-+ guint types = (guint) arg -> chkdata;
++ guint types = (guint) arg -> src -> chkdata;
+
+ if (fjid[0] == '.' && fjid[1] == JID_RESOURCE_SEPARATOR) {
+ // current buddy
@@ -1831,7 +1881,7 @@
+ 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.");
++ error = g_strdup("Currently selected buddy is of wrong type.");
+ }
+ if (bud) {
+ GSList *resources, *p_res;
@@ -1850,8 +1900,8 @@
+ }
+
+ if (error) {
-+ arg -> userdata = NULL;
-+ arg -> value.arg = NULL;
++ arg -> value.rjid.bud = NULL;
++ arg -> value.rjid.resource = NULL;
} else {
- char *tmp;
- if (!check_jid_syntax(jidres) &&
@@ -1862,8 +1912,8 @@
- GSList *roster_elt;
- roster_elt = roster_find(jidres, jidsearch,
- ROSTER_TYPE_USER|ROSTER_TYPE_AGENT);
-+ arg -> userdata = bud;
-+ arg -> value.arg = resource;
++ arg -> value.rjid.bud = bud;
++ arg -> value.rjid.resource = resource;
+ }
+ return error;
+}
@@ -1883,7 +1933,9 @@
+// Does not require freeing.
+// XXX:
+// * group, named "."?
-+gchar *cmdarg_check_roster_group (cmdarg_t *arg)
++// * group, named " "? is it even possible?
++// * check only that it is not NULL, and use "" as current?
++gchar *cmdarg_check_roster_group (cmdarg_value_t *arg)
+{
+ gchar *error;
+ gpointer group = NULL;
@@ -1922,7 +1974,7 @@
- if (!g_strcmp0((char*)p_res->data, resource))
- found = TRUE;
- g_free(p_res->data);
-+ arg -> value.bud = group;
++ arg -> value.rjid.bud = group;
+ return error;
+}
+
@@ -1941,7 +1993,7 @@
+// Requires freeing.
+// XXX:
+// * g_strdup jid?
-+gchar *cmdarg_check_fjid (cmdarg_t *arg)
++gchar *cmdarg_check_fjid (cmdarg_value_t *arg)
+{
+ gchar *error = NULL;
+
@@ -1950,15 +2002,15 @@
+
+ if (fjid[0] == '.' && (fjid[1] == JID_RESOURCE_SEPARATOR || fjid[1] == '\0')) {
+ const char *jid;
-+ if (!current_buddy)
++ if (!current_buddy) {
+ error = g_strdup_printf ("No buddy selected.");
-+ else if (!(jid = buddy_getjid(BUDDATA(current_buddy)))) {
++ } else if (!(jid = buddy_getjid(BUDDATA(current_buddy)))) {
+ error = g_strdup_printf ("Current buddy have no jid.");
+ } else if (fjid[1] == '\0') {
+ arg -> value.roarg = jid;
+ } else {
+ arg -> value.arg = g_strdup_printf ("%s%c%s", jid, JID_RESOURCE_SEPARATOR, fjid + 2);
-+ arg -> flags |= cmdarg_freeme;
++ arg -> flags |= cmdval_freeme;
}
- g_slist_free(resources);
- if (!found) {
@@ -1989,7 +2041,7 @@
+// Recognizes as current "." and "./res" (but still removes resource).
+// Needs RW access to trim the resource - no resources in default values!
+// Requires freeing (as fjid).
-+gchar *cmdarg_check_bjid (cmdarg_t *arg)
++gchar *cmdarg_check_bjid (cmdarg_value_t *arg)
+{
+ gchar *error = NULL;
+
@@ -2020,7 +2072,7 @@
+// XXX:
+// * use gulong? (strtoul allows to check conversion errors, while atoi - not)
+// * use flags in chkdata to specify signedness - it only affects two checks
-+gchar *cmdarg_check_uint (cmdarg_t *arg)
++gchar *cmdarg_check_uint (cmdarg_value_t *arg)
+{
+ gchar *error;
+
@@ -2050,11 +2102,12 @@
+};
+
+//
-+// string -> statusmask
++// string -> set of valid chars
+//
+
-+// Strips/checks for any non-valid status chars in mask.
-+// Returns mask in value.arg.
++// Strips/checks for any non-valid chars in argument.
++// Gets set of valid chars from chkdata.
++// Returns filtered string in value.arg.
+// Recognizes "*" as glob.
+// Does not require freeing.
+// No errors in default vaules - needs RW for that.
@@ -2063,17 +2116,15 @@
+// * string2flags?
+// * canonicize?
+// * string2enum?
-+// * common strchr callback with valid chars in chkdata?
-+// * Then argument name should go into cmdarg struct - message would be too generic
-+gchar *cmdarg_check_statusmask (cmdarg_t *arg)
++// * g_strdup (valid)?
++gchar *cmdarg_check_charset (cmdarg_value_t *arg)
+{
+ gchar *error;
+
+ if (!(error = cmdarg_check_nonspace(arg)) && arg -> value.arg) {
-+ const char *valid = "foand_?";
++ const char *valid = arg -> src -> chkdata;
+ if (!strcmp(arg -> value.arg, "*")) {
-+ arg -> value.arg = g_strdup (valid);
-+ arg -> flags |= cmdarg_freeme;
++ arg -> value.roarg = valid;
+ } else {
+ gchar *p = arg -> value.arg;
+ gchar *e = p + strlen (p);
@@ -2082,9 +2133,9 @@
+ 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);
++ return g_strdup_printf ("Character '%c' not in set [%s].", *p, valid);
+ } else {
-+ scr_log_print (LPRINT_NORMAL, "Warning: Wrong %s character [%c]", arg -> name, *p);
++ scr_log_print (LPRINT_NORMAL, "Warning: Wrong %s character [%c]", arg -> src -> name, *p);
+ g_memmove (p, p+1, e-p-1);
+ e --;
+ }
@@ -2101,9 +2152,9 @@
+ return error;
+}
+
-+const cmdarg_type_t cmdarg_type_statusmask = {
-+ cmdarg_check_statusmask,
-+ cmdarg_free_gfree,
++const cmdarg_type_t cmdarg_type_charset = {
++ cmdarg_check_charset,
++ NULL,
+ NULL,
+};
+
@@ -2116,21 +2167,21 @@
+// Returns 0 if not recognized and not required.
+// Does not require freeing.
+// XXX:
++// * default value on error?
+// * also, print list of possible values on error?
-+// * default value on error?
-+gchar *cmdarg_check_string2enum (cmdarg_t *arg)
++gchar *cmdarg_check_string2enum (cmdarg_value_t *arg)
+{
+ gchar *error;
+
+ if (!(error = cmdarg_check_nonspace(arg))) {
+ const string2enum_t *list;
-+ for (list = arg -> chkdata; list -> name != NULL; list ++)
++ for (list = arg -> src -> chkdata; list -> name != NULL; list ++)
+ if (!strcmp(list -> name, arg -> value.arg)) { // found
+ arg -> value.uint = list -> value;
+ return NULL;
+ }
+ // not found, error
-+ error = g_strdup_printf ("Value \"%s\" is invalid for %s.", arg -> value.arg, arg -> name);
++ error = g_strdup_printf ("Value \"%s\" is invalid.", arg -> value.arg);
+ }
+
+ if (error)
@@ -2169,7 +2220,7 @@
+// * 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 *cmdarg_check_color (cmdarg_value_t *arg)
+{
+ gchar *error;
+
@@ -2241,7 +2292,7 @@
static void display_and_free_note(struct annotation *note, const char *winId)
{
gchar tbuf[128];
-@@ -755,41 +1317,15 @@
+@@ -755,41 +1358,15 @@
g_slist_free(notes);
}
@@ -2291,14 +2342,14 @@
struct annotation *note = xmpp_get_storage_rosternotes(bjid, FALSE);
if (note) {
display_and_free_note(note, bjid);
-@@ -800,484 +1336,568 @@
+@@ -800,484 +1377,618 @@
}
}
-// roster_updown(updown, nitems)
-// updown: -1=up, +1=down
-inline static void roster_updown(int updown, char *nitems)
-+static gchar *do_roster (cmdopts_t *command);
++static gchar *do_roster (cmdopts_t *command, cmdarg_value_t *values);
+
+typedef enum {
+ scmd_roster_bottom, scmd_roster_top, scmd_roster_up, scmd_roster_down,
@@ -2314,6 +2365,19 @@
+ scmd_roster_hide, scmd_roster_show, scmd_roster_toggle,
+} scmd_roster_t;
+
++typedef enum {
++ pos_roster_scmd = 0,
++ pos_roster_up_n = 1,
++ pos_roster_down_n = 1,
++ pos_roster_search_name = 1,
++ pos_roster_display_mask = 1,
++ pos_roster_itemlock_jid = 1,
++ pos_roster_note_jid = 1,
++ pos_roster_note_rst = 2,
++ pos_roster_note_text = 3,
++ pos_roster_reslock_jid = 1,
++} pos_roster_t;
++
+#define SCMD_ROSTER(NAME, ARGS...) \
+ { #NAME, cmd_default, NULL, NULL, NULL, ARGS, NULL, (gpointer)scmd_roster_##NAME }
+static cmdopts_t def_roster = {
@@ -2322,40 +2386,40 @@
+ NULL,
+ do_roster,
+ NULL,
-+ (cmdarg_t[2]){{"subcommand", cmdarg_subcmd | cmdarg_check, NULL, NULL},{NULL}},
++ (cmdarg_t[2]){{"subcommand", pos_roster_scmd, cmdarg_subcmd | cmdarg_check, NULL, NULL},{NULL}},
+ (cmdopts_t[25]){
+ SCMD_ROSTER(bottom, NULL),
+ SCMD_ROSTER(top, NULL),
-+ SCMD_ROSTER(up, (cmdarg_t[2]){{"n", cmdarg_chreq, "1", &cmdarg_type_uint},{NULL}}),
-+ SCMD_ROSTER(down, (cmdarg_t[2]){{"n", cmdarg_chreq, "1", &cmdarg_type_uint},{NULL}}),
++ SCMD_ROSTER(up, (cmdarg_t[2]){{"n", pos_roster_up_n, cmdarg_chreq, "1", &cmdarg_type_uint},{NULL}}),
++ SCMD_ROSTER(down, (cmdarg_t[2]){{"n", pos_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_t[2]){{"name", cmdarg_eol|cmdarg_required, NULL, &cmdarg_type_nonspace},{NULL}}),
-+ SCMD_ROSTER(display, (cmdarg_t[2]){{"statusmask", cmdarg_check, NULL, &cmdarg_type_statusmask},{NULL}}),
++ SCMD_ROSTER(search, (cmdarg_t[2]){{"name", pos_roster_search_name, cmdarg_eol|cmdarg_required, NULL, &cmdarg_type_nonspace},{NULL}}),
++ SCMD_ROSTER(display, (cmdarg_t[2]){{"statusmask", pos_roster_display_mask, cmdarg_check, NULL, &cmdarg_type_charset, (gpointer)"ofdna_?"},{NULL}}),
+ SCMD_ROSTER(hide_offline, NULL),
+ SCMD_ROSTER(show_offline, NULL),
+ SCMD_ROSTER(toggle_offline, NULL),
-+ SCMD_ROSTER(item_lock, (cmdarg_t[2]){{"jid", cmdarg_chreq, ".", &cmdarg_type_roster_bjid, (gpointer)(ROSTER_TYPE_USER|ROSTER_TYPE_ROOM)},{NULL}}),
-+ SCMD_ROSTER(item_unlock, (cmdarg_t[2]){{"jid", cmdarg_chreq, ".", &cmdarg_type_roster_bjid, (gpointer)(ROSTER_TYPE_USER|ROSTER_TYPE_ROOM)},{NULL}}),
-+ SCMD_ROSTER(item_toggle_lock, (cmdarg_t[2]){{"jid", cmdarg_chreq, ".", &cmdarg_type_roster_bjid, (gpointer)(ROSTER_TYPE_USER|ROSTER_TYPE_ROOM)},{NULL}}),
++ SCMD_ROSTER(item_lock, (cmdarg_t[2]){{"jid", pos_roster_itemlock_jid, cmdarg_chreq, ".", &cmdarg_type_roster_bjid, (gpointer)(ROSTER_TYPE_USER|ROSTER_TYPE_ROOM)},{NULL}}),
++ SCMD_ROSTER(item_unlock, (cmdarg_t[2]){{"jid", pos_roster_itemlock_jid, cmdarg_chreq, ".", &cmdarg_type_roster_bjid, (gpointer)(ROSTER_TYPE_USER|ROSTER_TYPE_ROOM)},{NULL}}),
++ SCMD_ROSTER(item_toggle_lock, (cmdarg_t[2]){{"jid", pos_roster_itemlock_jid, cmdarg_chreq, ".", &cmdarg_type_roster_bjid, (gpointer)(ROSTER_TYPE_USER|ROSTER_TYPE_ROOM)},{NULL}}),
+ { "note", cmd_default, NULL, NULL,
+ (cmdopt_t[3]){
-+ {'r', "reset", cmdopt_switch, {"reset", cmdarg_default, NULL, NULL, NULL}},
-+ {'j', "jid", cmdopt_default, {"jid", cmdarg_chreq, ".", &cmdarg_type_roster_bjid, (gpointer)(ROSTER_TYPE_USER|ROSTER_TYPE_ROOM|ROSTER_TYPE_AGENT)}},
++ {'r', "reset", {"reset", pos_roster_note_rst, cmdarg_switch, NULL, NULL, NULL}},
++ {'j', "jid", {"jid", pos_roster_note_jid, cmdarg_chreq, ".", &cmdarg_type_roster_bjid, (gpointer)(ROSTER_TYPE_USER|ROSTER_TYPE_ROOM|ROSTER_TYPE_AGENT)}},
+ {0}
+ },
+ (cmdarg_t[2]){
-+ {"text", cmdarg_eol, NULL, &cmdarg_type_nonspace},
++ {"text", pos_roster_note_text, cmdarg_eol, NULL, &cmdarg_type_nonspace},
+ {NULL}
+ },
+ NULL, (gpointer)scmd_roster_note
+ },
+ SCMD_ROSTER(notes, NULL),
-+ SCMD_ROSTER(resource_lock, (cmdarg_t[2]){{"resource|fjid", cmdarg_chreq, NULL, &cmdarg_type_roster_resource, (gpointer)(ROSTER_TYPE_USER|ROSTER_TYPE_AGENT)},{NULL}}),
-+ SCMD_ROSTER(resource_unlock, (cmdarg_t[2]){{"jid", cmdarg_chreq, ".", &cmdarg_type_roster_bjid, (gpointer)(ROSTER_TYPE_USER|ROSTER_TYPE_AGENT)},{NULL}}),
++ SCMD_ROSTER(resource_lock, (cmdarg_t[2]){{"resource|fjid", pos_roster_reslock_jid, cmdarg_chreq, NULL, &cmdarg_type_roster_resource, (gpointer)(ROSTER_TYPE_USER|ROSTER_TYPE_AGENT)},{NULL}}),
++ SCMD_ROSTER(resource_unlock, (cmdarg_t[2]){{"jid", pos_roster_reslock_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),
@@ -2363,7 +2427,7 @@
+ },
+};
+
-+static gchar *do_roster(cmdopts_t *options)
++static gchar *do_roster(cmdopts_t *options, cmdarg_value_t *values)
{
- int nbitems;
-
@@ -2396,11 +2460,7 @@
- }
-
- if (!strcasecmp(subcmd, "top")) {
-+ scmd_roster_t subcmd = (scmd_roster_t) (options -> args[0].value.cmd -> userdata);
-+ cmdarg_t *arg = NULL;
-+
-+ if (options -> args[0].value.cmd -> args[0].name)
-+ arg = options -> args[0].value.cmd -> args;
++ scmd_roster_t subcmd = (scmd_roster_t) (values[pos_roster_scmd].value.cmd -> userdata);
+
+ if (subcmd == scmd_roster_bottom) {
+ scr_roster_bottom();
@@ -2411,9 +2471,9 @@
- } else if (!strcasecmp(subcmd, "bottom")) {
- scr_roster_bottom();
+ } else if (subcmd == scmd_roster_up) {
-+ scr_roster_up_down(-1, arg -> value.uint);
++ scr_roster_up_down(-1, values[pos_roster_up_n].value.uint);
+ } else if (subcmd == scmd_roster_down) {
-+ scr_roster_up_down(1, arg -> value.uint);
++ scr_roster_up_down(1, values[pos_roster_down_n].value.uint);
+ } else if (subcmd == scmd_roster_group_prev) {
+ scr_roster_prev_group();
+ } else if (subcmd == scmd_roster_group_next) {
@@ -2425,7 +2485,7 @@
+ } else if (subcmd == scmd_roster_unread_next) {
+ scr_roster_unread_message(1);
+ } else if (subcmd == scmd_roster_search) {
-+ scr_roster_search(arg -> value.arg);
++ scr_roster_search(values[pos_roster_search_name].value.arg);
update_roster = TRUE;
- } else if (!strcasecmp(subcmd, "hide")) {
- scr_roster_visibility(0);
@@ -2435,7 +2495,7 @@
- scr_roster_visibility(-1);
- } else if (!strcasecmp(subcmd, "hide_offline")) {
+ } else if (subcmd == scmd_roster_display) {
-+ scr_roster_display(arg -> value.arg);
++ scr_roster_display(values[pos_roster_display_mask].value.arg);
+ } else if (subcmd == scmd_roster_hide_offline) {
buddylist_set_hide_offline_buddies(TRUE);
- if (current_buddy)
@@ -2493,22 +2553,23 @@
- scr_LogPrint(LPRINT_NORMAL, "Unrecognized parameter!");
- free_arg_lst(paramlst);
+ } else if (subcmd == scmd_roster_item_lock) {
-+ roster_buddylock(arg -> value.bud, 1);
++ roster_buddylock(values[pos_roster_itemlock_jid].value.rjid.bud, 1);
+ } else if (subcmd == scmd_roster_item_unlock) {
-+ roster_buddylock(arg -> value.bud, 0);
++ roster_buddylock(values[pos_roster_itemlock_jid].value.rjid.bud, 0);
+ } else if (subcmd == scmd_roster_item_toggle_lock) {
-+ roster_buddylock(arg -> value.bud, -1);
++ roster_buddylock(values[pos_roster_itemlock_jid].value.rjid.bud, -1);
+ } else if (subcmd == scmd_roster_note) {
-+ roster_note(options -> cmds[18].opts[1].arg.value.bud,
-+ options -> cmds[18].opts[0].arg.value.swc,
-+ arg -> value.arg);
++ roster_note(values[pos_roster_note_jid].value.rjid.bud,
++ values[pos_roster_note_rst].value.swc,
++ values[pos_roster_note_text].value.arg);
+ } else if (subcmd == scmd_roster_notes) {
+ display_all_annotations();
+ } else if (subcmd == scmd_roster_resource_lock) {
-+ buddy_setactiveresource(arg -> userdata, arg -> value.arg);
++ buddy_setactiveresource(values[pos_roster_reslock_jid].value.rjid.bud,
++ values[pos_roster_reslock_jid].value.rjid.resource);
+ scr_update_chat_status(TRUE);
+ } else if (subcmd == scmd_roster_resource_unlock) {
-+ buddy_setactiveresource(arg -> value.bud, NULL);
++ buddy_setactiveresource(values[pos_roster_reslock_jid].value.rjid.bud, NULL);
+ scr_update_chat_status(TRUE);
+ } else if (subcmd == scmd_roster_hide) {
+ scr_roster_visibility(0);
@@ -2529,7 +2590,8 @@
+// custom argument types
+
+// statusmask + "clear"
-+static gchar *cmdarg_check_color_statusmask (cmdarg_t *arg)
++// Needs status char set in chkdata.
++static gchar *cmdarg_check_color_statusmask (cmdarg_value_t *arg)
{
- char **paramlst;
- char *subcmd;
@@ -2545,7 +2607,7 @@
+ if (!g_strcmp0 (arg -> value.arg, "clear"))
+ return NULL;
+ else
-+ return cmdarg_check_statusmask (arg);
++ return cmdarg_check_charset (arg);
+}
+
+static const cmdarg_type_t cmdarg_type_color_statusmask = {
@@ -2556,16 +2618,18 @@
+
+// bjid + "*"
+// Returns string, not buddy.
-+static gchar *cmdarg_check_color_roomjid (cmdarg_t *arg)
++// XXX:
++// * strdup jid?
++// * requires type in chkdata
++static gchar *cmdarg_check_color_roomjid (cmdarg_value_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?
++ arg -> value.roarg = buddy_getjid (arg -> value.rjid.bud);
}
- if (!strcasecmp(subcmd, "roster")) {
@@ -2604,7 +2668,7 @@
+
+// command
+
-+static gchar *do_color (cmdopts_t *command);
++static gchar *do_color (cmdopts_t *command, cmdarg_value_t *values);
+
+typedef enum {
+ scmd_color_roster,
@@ -2612,6 +2676,17 @@
+ scmd_color_muc,
+} scmd_color_t;
+
++typedef enum {
++ pos_color_scmd = 0,
++ pos_color_roster_status = 1,
++ pos_color_roster_jid = 2,
++ pos_color_roster_color = 3,
++ pos_color_muc_room = 1,
++ pos_color_muc_mode = 2,
++ pos_color_nick_nick = 1,
++ pos_color_nick_color = 2,
++} pos_color_t;
++
+static const string2enum_t s2e_color_muc[] = {
+ { "on", MC_ALL },
+ { "off", MC_OFF },
@@ -2626,36 +2701,36 @@
+ NULL,
+ do_color,
+ NULL,
-+ (cmdarg_t[2]){{ "subcommand", cmdarg_subcmd | cmdarg_check, NULL, NULL },{NULL}},
++ (cmdarg_t[2]){{ "subcommand", pos_color_scmd, cmdarg_subcmd | cmdarg_check, NULL, NULL },{NULL}},
+ (cmdopts_t[4]){
+ {"roster", cmd_default, NULL, NULL, NULL, (cmdarg_t[4]){
-+ { "statusmask|clear", cmdarg_chreq, NULL, &cmdarg_type_color_statusmask },
-+ { "jidmask", cmdarg_default, NULL, &cmdarg_type_bjidmask },
-+ { "color|-", cmdarg_default, NULL, &cmdarg_type_color },
++ { "statusmask|clear", pos_color_roster_status, cmdarg_chreq, NULL, &cmdarg_type_color_statusmask, (gpointer)"ofdna_?" },
++ { "jidmask", pos_color_roster_jid, cmdarg_default, NULL, &cmdarg_type_bjidmask },
++ { "color|-", pos_color_roster_color, cmdarg_default, NULL, &cmdarg_type_color },
+ {NULL}
+ }, NULL, (gpointer)scmd_color_roster},
+ {"muc", cmd_default, NULL, NULL, NULL, (cmdarg_t[3]){
-+ { "roomjid", cmdarg_chreq, NULL, &cmdarg_type_color_roomjid },
-+ { "on|off|preset|-", cmdarg_chreq, "on", &cmdarg_type_string2enum, (gpointer)s2e_color_muc},
++ { "roomjid", pos_color_muc_room, cmdarg_chreq, NULL, &cmdarg_type_color_roomjid, (gpointer)ROSTER_TYPE_ROOM },
++ { "on|off|preset|-", pos_color_muc_mode, cmdarg_chreq, "on", &cmdarg_type_string2enum, (gpointer)s2e_color_muc },
+ {NULL}
+ }, NULL, (gpointer)scmd_color_muc},
+ {"mucnick", cmd_default, NULL, NULL, NULL, (cmdarg_t[3]){
-+ { "nick", cmdarg_chreq, NULL, &cmdarg_type_nick },
-+ { "color|-", cmdarg_chreq, NULL, &cmdarg_type_color },
++ { "nick", pos_color_nick_nick, cmdarg_chreq, NULL, &cmdarg_type_nick },
++ { "color|-", pos_color_nick_color, cmdarg_chreq, NULL, &cmdarg_type_color },
+ {NULL}
+ }, NULL, (gpointer)scmd_color_mucnick},
+ {NULL}
+ },
+};
+
-+static gchar *do_color (cmdopts_t *options)
++static gchar *do_color (cmdopts_t *options, cmdarg_value_t *values)
+{
-+ scmd_color_t subcmd = (scmd_color_t) options -> args[0].value.cmd -> userdata;
++ scmd_color_t subcmd = (scmd_color_t) (values[pos_color_scmd].value.cmd -> userdata);
+
+ if (subcmd == scmd_color_roster) {
-+ const gchar *status = options -> cmds[0].args[0].value.arg;
-+ const gchar *wildcard = options -> cmds[0].args[1].value.arg;
-+ const gchar *color = options -> cmds[0].args[2].value.arg;
++ const gchar *status = values[pos_color_roster_status].value.arg;
++ const gchar *wildcard = values[pos_color_roster_jid].value.arg;
++ const gchar *color = values[pos_color_roster_color].value.arg;
+ if (!strcmp(status, "clear")) { // Not a color command, clear all
scr_roster_clear_color();
update_roster = TRUE;
@@ -2713,11 +2788,11 @@
- scr_LogPrint(LPRINT_NORMAL, "Unrecognized parameter!");
- free_arg_lst(paramlst);
+ } else if (subcmd == scmd_color_muc) {
-+ scr_muc_color ( options -> cmds[1].args[0].value.arg,
-+ options -> cmds[1].args[1].value.uint );
++ scr_muc_color ( values[pos_color_muc_room].value.arg,
++ values[pos_color_muc_mode].value.uint );
+ } else { // scmd_color_mucnick
-+ scr_muc_nick_color( options -> cmds[2].args[0].value.arg,
-+ options -> cmds[2].args[1].value.arg );
++ scr_muc_nick_color( values[pos_color_nick_nick].value.arg,
++ values[pos_color_nick_color].value.arg );
+ }
+
+ return NULL;
@@ -2735,7 +2810,7 @@
+// custom type
+
+// needs corresponding s2e in chkdata
-+static gchar *cmdarg_check_status_status (cmdarg_t *arg)
++static gchar *cmdarg_check_status_status (cmdarg_value_t *arg)
{
- char **paramlst;
- char *status;
@@ -2779,7 +2854,12 @@
+
+// command
+
-+static gchar *do_status (cmdopts_t *command);
++static gchar *do_status (cmdopts_t *command, cmdarg_value_t *values);
++
++typedef enum {
++ pos_status_status = 0,
++ pos_status_message = 1,
++} pos_status_t;
+
+static const string2enum_t s2e_status2[] = {
+ { "away", away },
@@ -2837,17 +2917,17 @@
+ do_status,
+ NULL,
+ (cmdarg_t[3]){
-+ {"status", cmdarg_chreq, "show", &cmdarg_type_status_status, (gpointer)s2e_status2},
-+ {"message", cmdarg_eol, NULL, &cmdarg_type_nonspace},
++ {"status", pos_status_status, cmdarg_chreq, "show", &cmdarg_type_status_status, (gpointer)s2e_status2},
++ {"message", pos_status_message, cmdarg_eol, NULL, &cmdarg_type_nonspace},
+ {NULL}
+ },
+ NULL,
+};
+
-+static gchar *do_status (cmdopts_t *options)
++static gchar *do_status (cmdopts_t *options, cmdarg_value_t *values)
{
- if (!*arg) {
-+ if (options -> args[0].value.uint == imstatus_size) {
++ if (values[pos_status_status].value.uint == imstatus_size) {
const char *sm = xmpp_getstatusmsg();
scr_LogPrint(LPRINT_NORMAL, "Your status is: [%c] %s",
imstatus2char[xmpp_getstatus()],
@@ -2857,8 +2937,8 @@
+ 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);
++ xmpp_setstatus(values[pos_status_status].value.uint, NULL,
++ values[pos_status_message].value.arg, FALSE);
}
- arg = to_utf8(arg);
- cmd_setstatus(NULL, arg);
@@ -2871,7 +2951,13 @@
+// /status_to
+//
+
-+static gchar *do_status_to (cmdopts_t *command);
++static gchar *do_status_to (cmdopts_t *command, cmdarg_value_t *values);
++
++typedef enum {
++ pos_statusto_jid = 0,
++ pos_statusto_status = 1,
++ pos_statusto_message = 2,
++} pos_statusto_t;
+
+// no "show" here
+static const string2enum_t s2e_status[] = {
@@ -2895,15 +2981,15 @@
+ do_status_to,
+ NULL,
+ (cmdarg_t[4]){
-+ {"jid", cmdarg_chreq, NULL, &cmdarg_type_fjid},
-+ {"status", cmdarg_chreq, NULL, &cmdarg_type_status_status, (gpointer)s2e_status},
-+ {"message", cmdarg_eol, NULL, &cmdarg_type_nonspace},
++ {"jid", pos_statusto_jid, cmdarg_chreq, NULL, &cmdarg_type_fjid},
++ {"status", pos_statusto_status, cmdarg_chreq, NULL, &cmdarg_type_status_status, (gpointer)s2e_status},
++ {"message", pos_statusto_message, cmdarg_eol, NULL, &cmdarg_type_nonspace},
+ {NULL}
+ },
+ NULL,
+};
+
-+static gchar *do_status_to (cmdopts_t *options)
++static gchar *do_status_to (cmdopts_t *options, cmdarg_value_t *values)
{
- char **paramlst;
- char *fjid, *st, *msg;
@@ -2922,9 +3008,9 @@
+ const char *fjid, *stname, *msg;
+ enum imstatus st;
+
-+ fjid = options -> args[0].value.arg;
-+ st = options -> args[1].value.uint;
-+ msg = options -> args[2].value.arg;
++ fjid = values[pos_statusto_jid].value.arg;
++ st = values[pos_statusto_status].value.uint;
++ msg = values[pos_statusto_message].value.arg;
+
+ { // get status name
+ const string2enum_t *list;
@@ -2974,7 +3060,12 @@
+// /add
+//
+
-+static gchar *do_add (cmdopts_t *command);
++static gchar *do_add (cmdopts_t *command, cmdarg_value_t *values);
++
++typedef enum {
++ pos_add_jid = 0,
++ pos_add_name = 1,
++} pos_add_t;
+
+static cmdopts_t def_add = {
+ "add",
@@ -2983,21 +3074,21 @@
+ do_add,
+ NULL,
+ (cmdarg_t[3]){
-+ {"jid", cmdarg_chreq, ".", &cmdarg_type_bjid},
-+ {"name", cmdarg_default, NULL, &cmdarg_type_nonspace},
++ {"jid", pos_add_jid, cmdarg_chreq, ".", &cmdarg_type_bjid},
++ {"name", pos_add_name, cmdarg_default, NULL, &cmdarg_type_nonspace},
+ {NULL}
+ },
+ NULL,
+};
+
-+static gchar *do_add (cmdopts_t *options)
++static gchar *do_add (cmdopts_t *options, cmdarg_value_t *values)
+{
-+ gchar *jid = options -> args[0].value.arg;
++ gchar *jid = values[pos_add_jid].value.arg;
+
+ // XXX
+ //mc_strtolower(jid);
+
-+ xmpp_addbuddy(jid, options -> args[1].value.arg, NULL);
++ xmpp_addbuddy(jid, values[pos_add_name].value.arg, NULL);
+ scr_LogPrint(LPRINT_LOGNORM, "Sent presence notification request to <%s>.",
+ jid);
+
@@ -3008,7 +3099,12 @@
+// /del
+//
+
-+static gchar *do_del (cmdopts_t *command);
++static gchar *do_del (cmdopts_t *command, cmdarg_value_t *values);
++
++typedef enum {
++ pos_del_jid = 0,
++ pos_del_dryrun = 1,
++} pos_del_t;
+
+static cmdopts_t def_del = {
+ "del",
@@ -3016,19 +3112,19 @@
+ cmd_check_online,
+ do_del,
+ (cmdopt_t[2]){
-+ {'n', "dryrun", cmdopt_switch, {"dryrun", cmdarg_default, NULL, NULL}},
++ {'n', "dryrun", {"dryrun", pos_del_dryrun, cmdarg_switch|cmdarg_check, NULL, NULL}},
+ {0}
+ },
+ (cmdarg_t[2]){
-+ {"jid", cmdarg_chreq, ".", &cmdarg_type_roster_bjid, (gpointer)(ROSTER_TYPE_USER|ROSTER_TYPE_AGENT|ROSTER_TYPE_GROUP)},
++ {"jid", pos_del_jid, cmdarg_chreq, ".", &cmdarg_type_roster_bjid, (gpointer)(ROSTER_TYPE_USER|ROSTER_TYPE_AGENT|ROSTER_TYPE_GROUP)},
+ {NULL}
+ },
+ NULL,
+};
+
-+static gchar *do_del (cmdopts_t *options)
++static gchar *do_del (cmdopts_t *options, cmdarg_value_t *values)
+{
-+ gpointer buddy = options -> args[0].value.bud;
++ gpointer buddy = values[pos_del_jid].value.rjid.bud;
+ const char *jid = buddy_getjid (buddy);
+
+ if (buddy_gettype(buddy) & ROSTER_TYPE_ROOM)
@@ -3038,7 +3134,7 @@
+
+ scr_LogPrint(LPRINT_LOGNORM, "Removing <%s>...", jid);
+
-+ if (!(options -> opts[0].arg.value.swc)) {
++ if (!(values[pos_del_dryrun].value.swc)) {
+ // Close the buffer
+ scr_buffer_purge(1, jid);
+
@@ -3229,7 +3325,12 @@
- free_arg_lst(paramlst);
}
-+static gchar *do_group (cmdopts_t *command);
++static gchar *do_group (cmdopts_t *command, cmdarg_value_t *values);
++
++typedef enum {
++ pos_group_group = 0,
++ pos_group_action = 1,
++} pos_group_t;
+
+static const string2enum_t s2e_group_scmd[] = {
+ {"expand", scmd_group_unfold},
@@ -3250,21 +3351,21 @@
+ do_group,
+ NULL,
+ (cmdarg_t[3]){
-+ {"subcommand", cmdarg_chreq, NULL, &cmdarg_type_string2enum,
++ {"subcommand", pos_group_action, cmdarg_chreq, NULL, &cmdarg_type_string2enum,
+ (gpointer)s2e_group_scmd},
-+ {"group", cmdarg_chreq|cmdarg_eol, ".", &cmdarg_type_roster_group},
++ {"group", pos_group_group, cmdarg_chreq|cmdarg_eol, ".", &cmdarg_type_roster_group},
+ {NULL}
+ },
+ NULL,
+};
+
-+static gchar *do_group(cmdopts_t *options)
++static gchar *do_group(cmdopts_t *options, cmdarg_value_t *values)
+{
+ //if (!current_buddy) // XXX do we need this still?
+ // return g_strdup("Command needs selected buddy.");
+
-+ group_cmd (options -> args[0].value.bud,
-+ options -> args[1].value.uint);
++ group_cmd (values[pos_group_group].value.rjid.bud,
++ values[pos_group_action].value.uint);
+
+ return NULL;
+}
@@ -3279,7 +3380,7 @@
{
char *bare_jid, *rp;
char *hmsg;
-@@ -1285,6 +1905,7 @@
+@@ -1285,6 +1996,7 @@
gint retval = 0;
int isroom;
gpointer xep184 = NULL;
@@ -3287,7 +3388,7 @@
if (!xmpp_is_online()) {
scr_LogPrint(LPRINT_NORMAL, "You are not connected.");
-@@ -1299,11 +1920,15 @@
+@@ -1299,11 +2011,15 @@
return 1;
}
if (check_jid_syntax((char*)fjid)) {
@@ -3305,7 +3406,7 @@
// We must use the bare jid in hk_message_out()
rp = strchr(fjid, JID_RESOURCE_SEPARATOR);
if (rp)
-@@ -1354,8 +1979,7 @@
+@@ -1354,8 +2070,7 @@
// send_message(msg, subj, type_overwrite)
// Write the message in the buddy's window and send the message on
// the network.
@@ -3315,7 +3416,7 @@
{
const char *bjid;
char *jid;
-@@ -1378,34 +2002,13 @@
+@@ -1378,34 +2093,13 @@
else
jid = g_strdup(bjid);
@@ -3345,14 +3446,14 @@
-}
-
-void say_cmd(char *arg, int parse_flags)
-+void say_cmd(char *arg, msgtype_t msgtype)
++static void say_cmd(char *arg, msgtype_t msgtype)
{
gpointer bud;
- LmMessageSubType msgtype = LM_MESSAGE_SUB_TYPE_NOT_SET;
scr_set_chatmode(TRUE);
scr_show_buddy_window();
-@@ -1424,80 +2027,133 @@
+@@ -1424,80 +2118,137 @@
}
buddy_setflags(bud, ROSTER_FLAG_LOCK, TRUE);
@@ -3363,37 +3464,42 @@
- g_free(arg);
}
-+#if 0
-+
- static void do_say(char *arg) {
+-static void do_say(char *arg) {
- say_cmd(arg, 1);
-+ cmdopts_t options = {
-+ "say",
-+ (cmdopt_t[2]){
-+ { CMDOPT_SWITCH, 'n', "normal", { .swc = 0 } },
-+ { CMDOPT_SWITCH | CMDOPT_LAST, 'h', "headline", { .swc = 0 } },
-+ },
-+ (cmdarg_t[1]){
-+ { CMDOPT_CATCHALL | CMDOPT_PLAIN | CMDOPT_REQUIRED | CMDOPT_LAST,
-+ { .arg = NULL } },
-+ },
-+ NULL,
-+ };
-+ msgtype_t msgtype = msgtype_not_set;
-+
-+ if (cmdopts_parse(arg, &options))
-+ return;
-+
-+ if (options.opts[0].value.swc)
-+ msgtype = msgtype_normal;
-+ else if (options.opts[1].value.swc)
-+ msgtype = msgtype_headline;
-+
-+ say_cmd(options.args[0].value.arg, msgtype);
-+
-+ cmdopts_free(&options);
++static gchar *do_say (cmdopts_t *command, cmdarg_value_t *values);
++
++typedef enum {
++ pos_say_msg = 0,
++ pos_say_msgtype = 1,
++} pos_say_t;
++
++static cmdopts_t def_say = {
++ "say",
++ cmd_default,
++ NULL,
++ do_say,
++ (cmdopt_t[4]){
++ {'n', "normal", {"normal", pos_say_msgtype, cmdarg_switch, NULL, NULL, NULL, (gpointer)msgtype_normal}},
++ {'h', "headline", {"headline", pos_say_msgtype, cmdarg_switch, NULL, NULL, NULL, (gpointer)msgtype_headline}},
++ {'d', "default", {"default", pos_say_msgtype, cmdarg_switch, NULL, NULL, NULL, (gpointer)msgtype_not_set}},
++ {0}
++ },
++ (cmdarg_t[2]){
++ {"message", pos_say_msg, cmdarg_eol | cmdarg_chreq, NULL, &cmdarg_type_nonspace},
++ {NULL}
++ },
++ NULL,
++};
++
++static gchar *do_say (cmdopts_t *options, cmdarg_value_t *values)
++{
++ say_cmd(values[pos_say_msg].value.arg,
++ (msgtype_t) (values[pos_say_msgtype].src -> userdata));
++ return NULL;
}
++#if 0
++
static void do_msay(char *arg)
{
- /* Parameters: begin verbatim abort send send_to */
@@ -3535,7 +3641,7 @@
if (!scr_get_multimode()) {
scr_LogPrint(LPRINT_NORMAL, "No message to send. "
-@@ -1508,49 +2164,47 @@
+@@ -1508,49 +2259,47 @@
scr_set_chatmode(TRUE);
scr_show_buddy_window();
@@ -3621,7 +3727,7 @@
}
// load_message_from_file(filename)
-@@ -1566,7 +2220,7 @@
+@@ -1566,7 +2315,7 @@
char *next_utf8_char;
size_t len;
@@ -3630,7 +3736,7 @@
if (!fd || fstat(fileno(fd), &buf)) {
scr_LogPrint(LPRINT_LOGNORM, "Cannot open message file (%s)", filename);
-@@ -1634,130 +2288,103 @@
+@@ -1634,130 +2383,103 @@
static void do_say_to(char *arg)
{
@@ -3817,7 +3923,7 @@
}
// buffer_updown(updown, nblines)
-@@ -1775,27 +2402,10 @@
+@@ -1775,27 +2497,10 @@
scr_buffer_scroll_up_down(updown, nblines);
}
@@ -3845,7 +3951,7 @@
t = from_iso8601(date, 0);
if (t)
scr_buffer_date(t);
-@@ -1804,98 +2414,156 @@
+@@ -1804,98 +2509,156 @@
"not correctly formatted or invalid.");
}
@@ -4084,7 +4190,7 @@
}
static void do_info(char *arg)
-@@ -2033,29 +2701,20 @@
+@@ -2033,29 +2796,20 @@
}
}
@@ -4123,7 +4229,7 @@
// Enter chat mode
scr_set_chatmode(TRUE);
-@@ -2075,12 +2734,12 @@
+@@ -2075,12 +2829,12 @@
rstatus = buddy_getstatus(bud, p_res->data);
rst_msg = buddy_getstatusmsg(bud, p_res->data);
@@ -4138,7 +4244,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 +2755,12 @@
+@@ -2096,12 +2850,12 @@
snprintf(buffer, 4095, "[%c] %s", imstatus2char[rstatus],
(char*)p_res->data);
scr_WriteIncomingMessage(bjid, buffer, 0, HBB_PREFIX_INFO, 0);
@@ -4153,7 +4259,7 @@
enum imrole role = buddy_getrole(bud, p_res->data);
enum imaffiliation affil = buddy_getaffil(bud, p_res->data);
-@@ -2145,16 +2804,69 @@
+@@ -2145,16 +2899,69 @@
static void do_rename(char *arg)
{
@@ -4228,7 +4334,7 @@
bjid = buddy_getjid(bud);
group = buddy_getgroupname(bud);
type = buddy_gettype(bud);
-@@ -2162,11 +2874,13 @@
+@@ -2162,11 +2969,13 @@
if (type & ROSTER_TYPE_SPECIAL) {
scr_LogPrint(LPRINT_NORMAL, "You can't rename this item.");
@@ -4243,7 +4349,7 @@
return;
}
-@@ -2181,90 +2895,117 @@
+@@ -2181,90 +2990,117 @@
// }
//}
@@ -4392,7 +4498,7 @@
} else {
// This is a local item, we move it without adding to roster.
guint msgflag;
-@@ -2276,7 +3017,7 @@
+@@ -2276,7 +3112,7 @@
msgflag = buddy_getflags(bud) & ROSTER_FLAG_MSG;
if (msgflag)
roster_msg_setflag(bjid, FALSE, FALSE);
@@ -4401,7 +4507,7 @@
if (msgflag)
roster_msg_setflag(bjid, FALSE, TRUE);
if ((type & ROSTER_TYPE_ROOM) && xmpp_is_bookmarked(bjid) &&
-@@ -2285,8 +3026,7 @@
+@@ -2285,8 +3121,7 @@
}
}
@@ -4411,7 +4517,7 @@
update_roster = TRUE;
}
-@@ -2468,50 +3208,33 @@
+@@ -2468,50 +3303,33 @@
static void do_rawxml(char *arg)
{
@@ -4482,7 +4588,7 @@
}
// check_room_subcommand(arg, param_needed, buddy_must_be_a_room)
-@@ -2815,6 +3538,8 @@
+@@ -2815,6 +3633,8 @@
free_arg_lst(paramlst);
}
@@ -4491,7 +4597,7 @@
void cmd_room_leave(gpointer bud, char *arg)
{
gchar *roomid, *desc;
-@@ -2833,6 +3558,8 @@
+@@ -2833,6 +3653,8 @@
g_free(roomid);
}
@@ -4500,7 +4606,7 @@
static void room_nick(gpointer bud, char *arg)
{
if (!buddy_getinsideroom(bud)) {
-@@ -2874,7 +3601,7 @@
+@@ -2874,7 +3696,7 @@
fjid_utf8 = g_strdup_printf("%s/%s", buddy_getjid(bud), nick_utf8);
g_free (nick_utf8);
msg = to_utf8(arg);
@@ -4509,7 +4615,7 @@
g_free(fjid_utf8);
g_free(msg);
free_arg_lst(paramlst);
-@@ -3052,6 +3779,8 @@
+@@ -3052,6 +3874,8 @@
free_arg_lst(paramlst);
}
@@ -4518,7 +4624,7 @@
// cmd_room_whois(..)
// If interactive is TRUE, chatmode can be enabled.
// Please note that usernick is expected in UTF-8 locale iff interactive is
-@@ -3146,6 +3875,8 @@
+@@ -3146,6 +3970,8 @@
free_arg_lst(paramlst);
}
@@ -4527,7 +4633,7 @@
static void room_bookmark(gpointer bud, char *arg)
{
const char *roomid;
-@@ -3290,6 +4021,207 @@
+@@ -3290,6 +4116,207 @@
static void do_room(char *arg)
{
@@ -4735,7 +4841,7 @@
char **paramlst;
char *subcmd;
gpointer bud;
-@@ -3347,7 +4279,7 @@
+@@ -3347,7 +4374,7 @@
cmd_room_leave(bud, arg);
} else if (!strcasecmp(subcmd, "names")) {
if ((arg = check_room_subcommand(arg, FALSE, bud)) != NULL)
@@ -4744,7 +4850,7 @@
} else if (!strcasecmp(subcmd, "nick")) {
if ((arg = check_room_subcommand(arg, FALSE, bud)) != NULL)
room_nick(bud, arg);
-@@ -4162,5 +5094,6 @@
+@@ -4162,5 +5189,6 @@
}
mcabber_set_terminate_ui();
}
@@ -4753,22 +4859,38 @@
/* vim: set expandtab cindent cinoptions=>2\:2(0 sw=2 ts=2: For Vim users... */
diff -r 1b0b563a81e6 mcabber/mcabber/commands.h
--- a/mcabber/mcabber/commands.h Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/mcabber/commands.h Wed Mar 13 17:51:29 2013 +0200
-@@ -5,32 +5,246 @@
++++ b/mcabber/mcabber/commands.h Mon Mar 18 02:16:22 2013 +0200
+@@ -5,32 +5,338 @@
#include <mcabber/config.h>
-// Command structure
+//
-+// TODO:
++// DONE(?):
+//
+// * Clustering of options/switches
-+// * Multivalue options
-+// - list
-+// - special checker
-+// - or run checker multiple times
-+// - or run command several times
-+// - what if there are several of such arguments?
++// - with separate values - just specify the same index
++// - use the same flags on all of the clustered options, or result may be a bit unpredictable
++// * for now we'll do without multi-options.
++// * checks
++// - argument type == public struct with name and callbacks, simple!
++// - command checks should be just single callbacks
++// - argument checker needs:
++// - [in] value string (current or default)
++// - [in] additional input data for some generic checkers (like string2enum wordlist)
++// - [out] replacement value (not necessary string)
++// - replacement value may need freeing
++// - [out] error string
++// - that may need freeing
++//
++// TODO:
++//
++// * checkers can use visited flag to check if value is rw
++// - but what if in-checker assigns ro value, like buddy_getjid()?
++// - maybe need separate flag for that
++// * now, that we have rjid, merge bjid/fjid checkers into one
++// * Usable documentation in sources/howto
++// * Changelog entry
+// * --help
+// - use argument type names and clarify, if needed in descriptions
+// - command/subcommand descriptions
@@ -4789,81 +4911,107 @@
+// - defined lists (restrictive)
+// - date (restrictive)
+// - percent (numerical, restrictive)
-+// - number (result - int)
++// - number (result - uint)
+// - filename (expand_filename(), g_utf8_to_filename()?)
+// - custom (maybe some helpers for constant stringlists)
+// - text message (compl: nicks in rooms, dictionary?)
+// * Non-argument checks for commands/subcommands:
+// - xmpp_is_online()
+// - current_buddy
-+// * Subcommands with fallback to argument?
++// * Usable subsystem for completion, based on user-supplied completors
++//
++// XXX:
++//
++// * while escaped aliases should not be expanded, we should still unquote them for command search
++// * allow escaping in options?
++// * merge cmdopt_t and cmdarg_t?
++// - improve the checker error messages
++// - extra NULLs to specify in arg definition
++// - inconvenient positioning of shortopt/longopt or argname in sequence
++// - merge options/arguments?
++// - describe values, not opt/args?
++// * command ref and name in special value 0 and indexing starts from 1?
++// - requires allocation of values always
++// - though there's not that many commands without arguments
++// * command checker is not quite effective
++// - I'd like to run it before allocating anything
++// - so far only one of them
++// * unable to put checker before allocation because in many cases it will be in subcommand.
++// - separate command/subcommand values and use subcommand callbacks?
++// - ignore command options and always go directly to subcommand parsing if present?
++// (i.e. subcommand is always first argument and consumes the end of the line
++// * type name generator callback
++// for generic types to construct something like "foo|bar|baz"
+// * [+foo|-foo] support?
-+// * Usable subsystem for completion, based on user-supplied completors
-+
-+// * for now we'll do without multi-options.
-+// * and without clustering.
-+// * checks
-+// - argument type == public struct with name and callbacks, simple!
-+// - command checks should be just single callbacks
-+// * now, what checker needs?
-+// - [in] value string (current or default)
-+// - [in] additional input data for some generic checkers (like string2enum wordlist)
-+// - [out] replacement value (not necessary string)
-+// - replacement value may need freeing
-+// - [out] error string
-+// - that may need freeing
++// * Subcommands with fallback to argument?
++// * Multivalue options
++// - list
++// - special checker
++// - or run checker multiple times
++// - or run command several times
++// - what if there are several of such arguments?
++//
++
++//
++// Type predeclarations
++//
+
+typedef struct cmdopts_struct cmdopts_t;
+typedef struct cmdopt_struct cmdopt_t;
+typedef struct cmdarg_struct cmdarg_t;
+typedef struct cmdarg_type_struct cmdarg_type_t;
-+
-+// note, this is called before options are parsed!
-+typedef gchar *(*cmd_checker_t)(cmdopts_t *opts);
-+// command function itself
-+typedef gchar *(*cmd_handler_t)(cmdopts_t *opts);
-+// should check arg -> val -> val.arg and replace, if needed
-+typedef gchar *(*cmdarg_checker_t)(cmdarg_t *arg);
-+// free resources, used in arg -> val -> val.arg, if needed
-+typedef void (*cmdarg_destructor_t)(cmdarg_t *arg);
-+// todo
-+typedef void (*cmdarg_completor_t)(void); // FIXME
-+
-+typedef union {
-+ guint uint; // unsigned integer
-+ gint sint; // signed integer
-+ guint swc; // switch count
-+ const gchar *roarg; // default value
-+ gchar *arg; // string argument
-+ cmdopts_t *cmd; // subcommand
-+ gpointer bud; // buddy data (roster entry)
-+ gpointer ptr; // anything else
-+} cmdarg_value_t;
-+
++typedef struct cmdarg_value_struct cmdarg_value_t;
++
++//
++// Callback type definitions
++//
++
++// Command execution environment check function.
++// Note: This is called before options are parsed, but values are already allocated.
++typedef gchar *(*cmd_checker_t)(cmdopts_t *command, cmdarg_value_t *args);
++// Command function itself.
++// Command definition is provided for userdata access, should not be modified.
++typedef gchar *(*cmd_handler_t)(cmdopts_t *command, cmdarg_value_t *args);
++// Should check value -> value.arg and replace, if needed.
++// Can set cmdarg_freeme flag to request type destructor call.
++// Can access argument definition via value -> src (but not modify it).
++typedef gchar *(*cmdarg_checker_t)(cmdarg_value_t *value);
++// Free resources, used in value, if needed.
++typedef void (*cmdarg_destructor_t)(cmdarg_value_t *value);
++// TODO Return possible completions for given argument.
++typedef void (*cmdarg_completor_t)(void);
++
++//
++// Data type definitions
++//
++
++// command description flags
+typedef enum {
-+ cmd_default = 0, // no flags
-+ cmd_safe = 1<<0, // command is safe to use in mcabberrc
++ cmd_default = 0x0000, // no flags
++ cmd_safe = 0x0001, // command is safe to use in mcabberrc
+} cmd_flags_t;
-+typedef enum {
-+ cmdopt_default = 0, // no flags
-+ cmdopt_switch = 1<<0, // option have no argument
-+} cmdopt_flags_t;
++// argument description flags
+typedef enum {
-+ 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_default = 0x0000, // no flags
++ cmdarg_catchall = 0x0001, // argument consumes the end of command line
++ cmdarg_plain = 0x0002, // quotes and escapes are not processed
++ cmdarg_check = 0x0004, // forse checker call on argument
++ cmdarg_required = 0x0008, // checker errors are fatal (checker may use as well)
++ cmdarg_subcmd = 0x0010, // argument is subcommand
++ cmdarg_switch = 0x0020, // option without argument, value is count
++ // shortcuts:
+ cmdarg_eol = 0x0003, // catchall + plain
-+ cmdarg_chreq = 0x0018, // check + required
-+ cmdarg_ppclear = 0x00E0, // pre-parse clear = visited + checked + freeme
++ cmdarg_chreq = 0x000C, // check + required
++ cmdarg_special = 0x0030, // subcmd + switch
+} cmdarg_flags_t;
-+
++// argument value flags (internal)
++typedef enum {
++ cmdval_default = 0x0000, // no flags
++ cmdval_visited = 0x0100, // marks initialized arguments
++ cmdval_freeme = 0x0200, // marks argument, that needs freeing
++} cmdval_flags_t;
++
++// command description
+struct cmdopts_struct {
+ const char *name; // [user,req] command name (error messages, help, subcommands)
+ cmd_flags_t flags; // [user,req] safe
@@ -4873,30 +5021,56 @@
+ cmdarg_t *args; // [user,req] arguments
+ cmdopts_t *cmds; // [user,req] subcommands
+ gpointer userdata; // [user]
++ size_t valno; // internal, number of values to allocate
+};
++// positional/option argument description
+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
-+ const cmdarg_type_t *type; // [user,req] type cbs - checker and completor
-+ gpointer chkdata; // [user] instance data for type checker - eg string2enum list
-+ gpointer userdata; // [user]
-+ cmdarg_value_t value; // [parser,chk] current value
++ const char *name; // [user,req] argument name - errors, help (unused for switches, but must be initialized)
++ const guint pos; // [user,req] value positional number
++ const cmdarg_flags_t flags; // [user,req] catchall, plain, check, required, subcommand, switch
++ const char *defval; // [user,req] default value (unused for switches)
++ const cmdarg_type_t *type; // [user,req] type cbs - checker and completor (unused for switches and subcommands)
++ gconstpointer chkdata; // [user] instance data for type checker - eg string2enum list (unused for switches and subcommands)
++ gconstpointer userdata; // [user]
+};
++// option description
+struct cmdopt_struct {
-+ char shortopt; // [user,req]
-+ const char *longopt; // [user,req]
-+ cmdopt_flags_t flags; // [user,req] switch
-+ cmdarg_t arg; // [user,req]
++ const char shortopt; // [user,req]
++ const char *longopt; // [user,req]
++ cmdarg_t arg; // [user,req]
+};
-+
++// argument type description
+struct cmdarg_type_struct {
-+ 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]
++ 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]
+};
-+
++// argument value
++struct cmdarg_value_struct {
++ cmdarg_t *src; // source of value
++ cmdval_flags_t flags; // visited, freeme
++ union { // value:
++ guint uint; // - unsigned integer
++ gint sint; // - signed integer
++ guint swc; // - switch count
++ const gchar *roarg; // - XXX default value
++ gchar *arg; // - string argument
++ cmdopts_t *cmd; // - subcommand
++ struct { // - roster jid:
++ gpointer bud; // - buddy struct
++ gchar *resource; // - resource (optional)
++ } rjid; //
++ gpointer ptr; // - anything else
++ } value; //
++};
++
++//
++// Public functions
++//
++
++// add command definition
+void cmd_define (cmdopts_t *command);
++// remove command definition
+void cmd_undef (cmdopts_t *command);
+
+// error cmdopts_parse_argument ( startptr, endptr, flags )
@@ -4906,14 +5080,17 @@
+// updated.
+const char *cmdopts_parse_argument(gchar **pr, gchar **er, cmdarg_flags_t flags);
+
++// flags for cmd_execute()
+typedef enum {
+ cmdexe_default = 0, // no flags
+ cmdexe_check_safe = 1<<0, // we're parsing main config file
+ cmdexe_check_verbatim = 1<<1, // check for verbatim input mode
+} cmdexe_flags_t;
++// return codes for cmd_execute() and process_line()
+typedef enum {
+ cmd_result_ok = 0, // all is ok
-+ cmd_result_syntax_error, // syntax, environment or argument check error
++ cmd_result_syntax_error, // syntax or environment check error
++ cmd_result_value_error, // argument value missing or type check error
+ cmd_result_not_found, // no such command
+ cmd_result_runtime_error, // error while executing command
+ cmd_result_verbatim, // we're in verbatim mode and this is not "msay"
@@ -4931,13 +5108,14 @@
+
+// process_line(line)
+// Process a command/message line. If this isn't a command, this is a message
-+// and it is sent to the currently selected buddy.
++// and it is sent to the currently selected buddy. The line is converted from
++// local encoding to utf8.
+// Returns 255 if the line is the /quit command, 0 on success and some other
+// error codes.
+cmd_result_t process_line(const char *line);
+
+//
-+// Standard types
++// Standard argument types
+//
+
typedef struct {
@@ -4961,18 +5139,31 @@
-gpointer cmd_add(const char *name, const char *help, guint flags1, guint flags2,
- void (*f)(char*), gpointer userdata);
-gboolean cmd_set_safe(const gchar *name, gboolean safe);
-+void cmdarg_free_gfree (cmdarg_t *arg);
-+
-+gchar *cmdarg_check_nonspace (cmdarg_t *arg);
-+gchar *cmdarg_check_roster_bjid (cmdarg_t *arg);
-+gchar *cmdarg_check_roster_resource (cmdarg_t *arg);
-+gchar *cmdarg_check_roster_group (cmdarg_t *arg);
-+gchar *cmdarg_check_fjid (cmdarg_t *arg);
-+gchar *cmdarg_check_bjid (cmdarg_t *arg);
-+gchar *cmdarg_check_uint (cmdarg_t *arg);
-+gchar *cmdarg_check_statusmask (cmdarg_t *arg);
-+gchar *cmdarg_check_string2enum (cmdarg_t *arg);
-+
++// destructor, that g_free()s value.arg
++void cmdarg_free_gfree (cmdarg_value_t *arg);
++
++// strips space at the start/end and ensures, that string have non-zero length
++gchar *cmdarg_check_nonspace (cmdarg_value_t *arg);
++// checks, that jid is in roster and returns buddy
++gchar *cmdarg_check_roster_bjid (cmdarg_value_t *arg);
++// checks, that jid is in roster and have specified resource, returns buddy and resource
++gchar *cmdarg_check_roster_resource (cmdarg_value_t *arg);
++// checks for group with given name and returns buddy
++gchar *cmdarg_check_roster_group (cmdarg_value_t *arg);
++// checks correctness of jid syntax
++gchar *cmdarg_check_fjid (cmdarg_value_t *arg);
++// checks correctness of jid syntax, strips resource
++gchar *cmdarg_check_bjid (cmdarg_value_t *arg);
++// transforms to guint
++gchar *cmdarg_check_uint (cmdarg_value_t *arg);
++// checks, that string consists of characters from a given set
++gchar *cmdarg_check_charset (cmdarg_value_t *arg);
++// checks, that string is from the given list, and returns corresponding guint value
++gchar *cmdarg_check_string2enum (cmdarg_value_t *arg);
++// checks mcabber color name syntax
++gchar *cmdarg_check_color (cmdarg_value_t *arg);
++
++// ready for use standard type descriptions
+const cmdarg_type_t cmdarg_type_nonspace;
+const cmdarg_type_t cmdarg_type_roster_bjid;
+const cmdarg_type_t cmdarg_type_roster_resource;
@@ -4980,7 +5171,7 @@
+const cmdarg_type_t cmdarg_type_fjid;
+const cmdarg_type_t cmdarg_type_bjid;
+const cmdarg_type_t cmdarg_type_uint;
-+const cmdarg_type_t cmdarg_type_statusmask;
++const cmdarg_type_t cmdarg_type_charset;
+const cmdarg_type_t cmdarg_type_string2enum;
+const cmdarg_type_t cmdarg_type_color;
+
@@ -4992,38 +5183,45 @@
+void cmd_uninit (void);
+
+#if 0
-+// error cmdopts_parse_internal ( startptr, endptr, commanddef )
++// return highest index for value, used in command
++size_t cmdopts_count_values (cmdopts_t *command);
++
++// allocate values array to store arguments
++cmdarg_value_t *cmdopts_allocate_values (cmdopts_t *command);
++
++// error cmdopts_parse_internal ( startptr, endptr, commanddef, values )
+// Parses command arguments according to command definition.
+// Parsed string MUST be writable. Regardless of success or error, input
+// string should be considered corrupted by parsing process.
-+// Even in case of error, commanddef should be passed to cmdopts_free().
-+gchar *cmdopts_parse_internal(gchar **pr, gchar **er, cmdopts_t *command);
-+
-+// cmdopts_free ( commanddef )
-+// Free various parser data, used in parsing process
-+void cmdopts_free(cmdopts_t *command);
- #endif
--gboolean cmd_is_safe(const gchar *name);
++gchar *cmdopts_parse_internal(gchar **pr, gchar **er, cmdopts_t *command, cmdarg_value_t *values);
++
++// perform type checking/conversion on parsed values
++gchar *cmdopts_check_values (cmdopts_t *command, cmdarg_value_t *values);
++
++// cmdopts_free_values ( commanddef, values )
++// Free allocated by checkers resources and values array.
++void cmdopts_free_values(cmdopts_t *command, cmdarg_value_t *values);
+
+typedef enum {
+ msgtype_not_set,
+ msgtype_normal,
+ msgtype_headline,
+} msgtype_t;
++
++void say_cmd(char *arg, msgtype_t msgtype);
+ #endif
+-gboolean cmd_is_safe(const gchar *name);
void cmd_room_whois(gpointer bud, const char *nick, guint interactive);
void cmd_room_leave(gpointer bud, char *arg);
-void cmd_setstatus(const char *recipient, const char *arg);
-void say_cmd(char *arg, int parse_flags);
-+void cmd_setstatus(const char *recipient,
-+ const char *status, const char *message);
-+void say_cmd(char *arg, msgtype_t msgtype);
#endif /* __MCABBER_COMMANDS_H__ */
diff -r 1b0b563a81e6 mcabber/mcabber/hooks.c
--- a/mcabber/mcabber/hooks.c Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/mcabber/hooks.c Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/mcabber/hooks.c Mon Mar 18 02:16:22 2013 +0200
@@ -638,10 +638,9 @@
scr_LogPrint(LPRINT_LOGNORM, "Running hook-post-connect...");
@@ -5052,7 +5250,7 @@
diff -r 1b0b563a81e6 mcabber/mcabber/roster.c
--- a/mcabber/mcabber/roster.c Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/mcabber/roster.c Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/mcabber/roster.c Mon Mar 18 02:16:22 2013 +0200
@@ -1586,13 +1586,14 @@
// Look for a buddy whose name or jid contains string.
// Search begins at current_buddy; if no match is found in the the buddylist,
@@ -5093,7 +5291,7 @@
}
diff -r 1b0b563a81e6 mcabber/mcabber/screen.c
--- a/mcabber/mcabber/screen.c Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/mcabber/screen.c Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/mcabber/screen.c Mon Mar 18 02:16:22 2013 +0200
@@ -3630,7 +3630,7 @@
{
scr_check_auto_away(TRUE);
@@ -5163,7 +5361,7 @@
}
diff -r 1b0b563a81e6 mcabber/mcabber/settings.c
--- a/mcabber/mcabber/settings.c Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/mcabber/settings.c Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/mcabber/settings.c Mon Mar 18 02:16:22 2013 +0200
@@ -183,28 +183,12 @@
if ((*line == '\n') || (*line == '\0') || (*line == '#'))
continue;
@@ -5200,7 +5398,7 @@
fclose(fp);
diff -r 1b0b563a81e6 mcabber/mcabber/xmpp_iq.c
--- a/mcabber/mcabber/xmpp_iq.c Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/mcabber/xmpp_iq.c Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/mcabber/xmpp_iq.c Mon Mar 18 02:16:22 2013 +0200
@@ -71,20 +71,20 @@
struct adhoc_status {
char *name; // the name used by adhoc
@@ -5249,12 +5447,12 @@
"Status has been changed");
diff -r 1b0b563a81e6 mcabber/modules/beep/beep.c
--- a/mcabber/modules/beep/beep.c Wed Mar 13 16:11:16 2013 +0200
-+++ b/mcabber/modules/beep/beep.c Wed Mar 13 17:51:29 2013 +0200
++++ b/mcabber/modules/beep/beep.c Mon Mar 18 02:16:22 2013 +0200
@@ -31,6 +31,7 @@
static void beep_init (void);
static void beep_uninit (void);
-+static gchar *do_beep (cmdopts_t *command);
++static gchar *do_beep (cmdopts_t *command, cmdarg_value_t *values);
/* Module description */
module_info_t info_beep = {
@@ -5269,7 +5467,7 @@
/* Event handler */
static guint beep_hh(const gchar *hookname, hk_arg_t *args, gpointer userdata)
-@@ -61,20 +60,38 @@
+@@ -61,20 +60,42 @@
return HOOK_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
}
@@ -5284,6 +5482,10 @@
+ { NULL, 0 },
+};
+
++typedef enum {
++ pos_beep_enable = 0,
++} pos_beep_t;
++
+static cmdopts_t def_beep = {
+ "beep",
+ cmd_default,
@@ -5291,7 +5493,7 @@
+ do_beep,
+ NULL,
+ (cmdarg_t[2]){
-+ {"on|off", cmdarg_chreq, "show", &cmdarg_type_string2enum, (gpointer)s2e_onoff},
++ {"on|off", pos_beep_enable, cmdarg_chreq, "show", &cmdarg_type_string2enum, (gpointer)s2e_onoff},
+ {NULL}
+ },
+ NULL
@@ -5299,7 +5501,7 @@
+
/* beep command handler */
-static void do_beep(char *args)
-+static gchar *do_beep(cmdopts_t *command)
++static gchar *do_beep(cmdopts_t *command, cmdarg_value_t *values)
{
/* Check arguments, and if recognized,
* set mcabber option accordingly */
@@ -5307,17 +5509,17 @@
- !strcmp(args, "on") ||
- !strcmp(args, "yes") ||
- !strcmp(args, "1"))
-+ if (command -> args[0].value.uint == 1)
++ if (values[pos_beep_enable].value.uint == 1)
settings_set(SETTINGS_TYPE_OPTION, "beep_enable", "1");
- else if (!strcmp(args, "disable") ||
- !strcmp(args, "off") ||
- !strcmp(args, "no") ||
- !strcmp(args, "0"))
-+ else if (command -> args[0].value.uint == 0)
++ else if (values[pos_beep_enable].value.uint == 0)
settings_set(SETTINGS_TYPE_OPTION, "beep_enable", "0");
/* Output current state, either if state is
-@@ -83,19 +100,14 @@
+@@ -83,19 +104,14 @@
scr_log_print(LPRINT_NORMAL, "Beep on messages is enabled");
else
scr_log_print(LPRINT_NORMAL, "Beep on messages is disabled");
@@ -5339,7 +5541,7 @@
/* Add handler
* We are only interested in incoming message events
*/
-@@ -109,11 +121,7 @@
+@@ -109,11 +125,7 @@
/* Unregister event handler */
hk_del_handler(HOOK_POST_MESSAGE_IN, beep_hid);
/* Unregister command */