--- a/cmdopts.diff Mon Feb 25 15:45:24 2013 +0200
+++ b/cmdopts.diff Mon Feb 25 22:09:55 2013 +0200
@@ -9,10 +9,14 @@
* /color uses parser
* /status and /status_to use parser
* cmd_setstatus() now expects separate status and message arguments
+ * /add uses parser
+ * /del uses parser
+ * allows specifying jid, as /add does
+ * -n(--dryrun) switch for debugging purposes
diff -r 92fa48ef53c9 mcabber/mcabber/commands.c
--- a/mcabber/mcabber/commands.c Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/mcabber/commands.c Mon Feb 25 15:15:43 2013 +0200
++++ b/mcabber/mcabber/commands.c Mon Feb 25 22:07:41 2013 +0200
@@ -755,7 +755,7 @@
g_slist_free(notes);
}
@@ -40,7 +44,7 @@
} else { // Display a note
struct annotation *note = xmpp_get_storage_rosternotes(bjid, FALSE);
if (note) {
-@@ -819,164 +814,246 @@
+@@ -819,175 +814,253 @@
/* All these do_*() functions will be called with a "arg" parameter */
/* (with arg not null) */
@@ -87,24 +91,24 @@
+ (subcmd_t[23]){
+ ROSTER_SCMD_NOARG(bottom),
+ ROSTER_SCMD_NOARG(top),
-+ ROSTER_SCMD(up, 0, "1"),
-+ ROSTER_SCMD(down, 0, "1"),
++ ROSTER_SCMD(up, 0, "1"), // num lines
++ ROSTER_SCMD(down, 0, "1"), // num lines
+ ROSTER_SCMD_NOARG(group_prev),
+ ROSTER_SCMD_NOARG(group_next),
+ ROSTER_SCMD_NOARG(alternate),
+ ROSTER_SCMD_NOARG(unread_first),
+ ROSTER_SCMD_NOARG(unread_next),
-+ ROSTER_SCMD(search, CMDOPT_REQUIRED, NULL),
-+ ROSTER_SCMD(display, 0, NULL),
++ ROSTER_SCMD(search, CMDOPT_REQUIRED | CMDOPT_CATCHALL, NULL), // to find
++ ROSTER_SCMD(display, 0, NULL), // status mask
+ ROSTER_SCMD_NOARG(hide_offline),
+ ROSTER_SCMD_NOARG(show_offline),
+ ROSTER_SCMD_NOARG(toggle_offline),
-+ ROSTER_SCMD(item_lock, 0, "."),
-+ ROSTER_SCMD(item_unlock, 0, "."),
-+ ROSTER_SCMD(item_toggle_lock, 0, "."),
-+ ROSTER_SCMD(note, 0, NULL),
-+ ROSTER_SCMD(resource_lock, 0, NULL),
-+ ROSTER_SCMD(resource_unlock, 0, NULL),
++ ROSTER_SCMD(item_lock, 0, "."), // jid
++ ROSTER_SCMD(item_unlock, 0, "."), // jid
++ ROSTER_SCMD(item_toggle_lock, 0, "."), // jid
++ ROSTER_SCMD(note, CMDOPT_CATCHALL, NULL), // note
++ ROSTER_SCMD(resource_lock, 0, NULL), // resource/jid
++ ROSTER_SCMD(resource_unlock, 0, NULL), // resource/jid
+ ROSTER_SCMD_NOARG(hide),
+ ROSTER_SCMD_NOARG(show),
+ { CMDOPT_LAST, "toggle", { NULL, NULL, NULL, NULL },
@@ -404,8 +408,388 @@
+ cmdopts_free(&options);
}
- // cmd_setstatus(recipient, arg)
-@@ -1634,130 +1711,109 @@
+-// cmd_setstatus(recipient, arg)
++// cmd_setstatus(recipient, status, message)
+ // Set your Jabber status.
+-// - if recipient is not NULL, the status is sent to this contact only
+-// - arg must be "status message" (message is optional)
+-void cmd_setstatus(const char *recipient, const char *arg)
++// If recipient is not NULL, the status is sent to this contact only.
++void cmd_setstatus(const char *recipient, const char *status, const char *msg)
+ {
+- char **paramlst;
+- char *status;
+- char *msg;
+ enum imstatus st;
+
+ if (!xmpp_is_online())
+@@ -1000,15 +1073,15 @@
+ if (!recipient)
+ scr_check_auto_away(TRUE);
+
+- paramlst = split_arg(arg, 2, 1); // status, message
+- status = *paramlst;
+- msg = *(paramlst+1);
+-
+ if (!status) {
+- free_arg_lst(paramlst);
+ return;
+ }
+
++ // Use provided message
++ if (msg && !*msg) {
++ msg = NULL;
++ }
++
+ if (!strcasecmp(status, IMSTATUS_OFFLINE)) st = offline;
+ else if (!strcasecmp(status, IMSTATUS_ONLINE)) st = available;
+ else if (!strcasecmp(status, IMSTATUS_AVAILABLE)) st = available;
+@@ -1020,65 +1093,82 @@
+ else if (!strcasecmp(status, IMSTATUS_NOTAVAILABLE)) st = notavail;
+ else if (!strcasecmp(status, IMSTATUS_FREE4CHAT)) st = freeforchat;
+ else if (!strcasecmp(status, "message")) {
+- if (!msg || !*msg) {
++ if (!msg) {
+ // We want a message. If there's none, we give up.
+ scr_LogPrint(LPRINT_NORMAL, "Missing parameter.");
+- free_arg_lst(paramlst);
+ return;
+ }
+ st = xmpp_getstatus(); // Preserve current status
+ } else {
+ scr_LogPrint(LPRINT_NORMAL, "Unrecognized status!");
+- free_arg_lst(paramlst);
+ return;
+ }
+
+- // Use provided message
+- if (msg && !*msg) {
+- msg = NULL;
+- }
+-
+ // If a recipient is specified, let's don't use default status messages
+ if (recipient && !msg)
+ msg = "";
+
+ xmpp_setstatus(st, recipient, msg, FALSE);
+-
+- free_arg_lst(paramlst);
+ }
+
+ static void do_status(char *arg)
+ {
+- if (!*arg) {
++ cmdopts_t options = {
++ NULL,
++ (cmdarg_t[2]){
++ { 0, { .arg = NULL } }, // status
++ { CMDOPT_CATCHALL | CMDOPT_LAST, { .arg = NULL } }, // message
++ },
++ NULL,
++ NULL,
++ };
++
++ {
++ const char *error = cmdopts_parse(arg, &options);
++ if (error != NULL) {
++ scr_log_print(LPRINT_NORMAL, error);
++ return;
++ }
++ }
++
++ if (options.args[0].value.arg == NULL) {
+ const char *sm = xmpp_getstatusmsg();
+ scr_LogPrint(LPRINT_NORMAL, "Your status is: [%c] %s",
+ imstatus2char[xmpp_getstatus()],
+ (sm ? sm : ""));
+- return;
++ } else {
++ cmd_setstatus(NULL, options.args[0].value.arg, options.args[1].value.arg);
+ }
+- arg = to_utf8(arg);
+- cmd_setstatus(NULL, arg);
+- g_free(arg);
++
++ cmdopts_free(&options);
+ }
+
+ static void do_status_to(char *arg)
+ {
+- char **paramlst;
++ cmdopts_t options = {
++ NULL,
++ (cmdarg_t[3]){
++ { CMDOPT_REQUIRED, { .arg = NULL } }, // jid
++ { CMDOPT_REQUIRED, { .arg = NULL } }, // status
++ { CMDOPT_CATCHALL | CMDOPT_LAST, { .arg = "" } }, // message
++ },
++ NULL,
++ NULL,
++ };
+ char *fjid, *st, *msg;
+- char *jid_utf8 = NULL;
+-
+- paramlst = split_arg(arg, 3, 1); // jid, status, [message]
+- fjid = *paramlst;
+- st = *(paramlst+1);
+- msg = *(paramlst+2);
+-
+- if (!fjid || !st) {
+- scr_LogPrint(LPRINT_NORMAL,
+- "Please specify both a Jabber ID and a status.");
+- free_arg_lst(paramlst);
+- return;
++
++ {
++ const char *error = cmdopts_parse(arg, &options);
++ if (error != NULL) {
++ scr_log_print(LPRINT_NORMAL, error);
++ return;
++ }
+ }
+
++ fjid = options.args[0].value.arg;
++ st = options.args[1].value.arg;
++ msg = options.args[2].value.arg;
++
+ // Allow things like /status_to "" away
+ if (!*fjid || !strcmp(fjid, "."))
+ fjid = NULL;
+@@ -1086,15 +1176,13 @@
+ if (fjid) {
+ // The JID has been specified. Quick check...
+ if (check_jid_syntax(fjid)) {
+- scr_LogPrint(LPRINT_NORMAL|LPRINT_NOTUTF8,
+- "<%s> is not a valid Jabber ID.", fjid);
++ scr_LogPrint(LPRINT_NORMAL, "<%s> is not a valid Jabber ID.", fjid);
+ fjid = NULL;
+ } else {
+ // Convert jid to lowercase
+ char *p = fjid;
+ for ( ; *p && *p != JID_RESOURCE_SEPARATOR; p++)
+ *p = tolower(*p);
+- fjid = jid_utf8 = to_utf8(fjid);
+ }
+ } else {
+ // Add the current buddy
+@@ -1105,103 +1193,154 @@
+ }
+
+ if (fjid) {
+- char *cmdline;
+- if (!msg)
+- msg = "";
+- msg = to_utf8(msg);
+- cmdline = g_strdup_printf("%s %s", st, msg);
+- scr_LogPrint(LPRINT_LOGNORM, "Sending to <%s> /status %s", fjid, cmdline);
+- cmd_setstatus(fjid, cmdline);
+- g_free(msg);
+- g_free(cmdline);
+- g_free(jid_utf8);
++ scr_LogPrint(LPRINT_LOGNORM,
++ "Sending to <%s> /status %s %s", fjid, st, msg);
++ cmd_setstatus(fjid, st, msg);
+ }
+- free_arg_lst(paramlst);
++
++ cmdopts_free(&options);
+ }
+
+ static void do_add(char *arg)
+ {
+- char **paramlst;
+- char *id, *nick;
+- char *jid_utf8 = NULL;
++ cmdopts_t options = {
++ NULL,
++ (cmdarg_t[2]){
++ { 0, { .arg = "." } }, // jid
++ { CMDOPT_CATCHALL | CMDOPT_LAST, { .arg = NULL } }, // rostername
++ },
++ NULL,
++ NULL,
++ };
++ gchar *jid, *nick;
+
+ if (!xmpp_is_online()) {
+ scr_LogPrint(LPRINT_NORMAL, "You are not connected.");
+ return;
+ }
+
+- paramlst = split_arg(arg, 2, 0); // jid, [nickname]
+- id = *paramlst;
+- nick = *(paramlst+1);
+-
+- if (!id)
+- nick = NULL; // Allow things like: /add "" nick
+- else if (!*id || !strcmp(id, "."))
+- id = NULL;
+-
+- if (id) {
++ {
++ const char *error = cmdopts_parse(arg, &options);
++ if (error) {
++ scr_log_print(LPRINT_NORMAL, error);
++ return;
++ }
++ }
++
++ jid = options.args[0].value.arg;
++ nick = options.args[1].value.arg;
++
++ if (jid && (!*jid || !strcmp(jid, ".")))
++ jid = NULL;
++
++ if (jid) {
+ // The JID has been specified. Quick check...
+- if (check_jid_syntax(id)) {
+- scr_LogPrint(LPRINT_NORMAL|LPRINT_NOTUTF8,
+- "<%s> is not a valid Jabber ID.", id);
+- id = NULL;
++ if (check_jid_syntax(jid)) {
++ scr_LogPrint(LPRINT_NORMAL, "<%s> is not a valid Jabber ID.", jid);
++ jid = NULL;
+ } else {
+- mc_strtolower(id);
+- id = jid_utf8 = to_utf8(id);
++ mc_strtolower(jid);
+ }
+ } else {
+ // Add the current buddy
+ if (current_buddy)
+- id = (char*)buddy_getjid(BUDDATA(current_buddy));
+- if (!id)
++ jid = (char*)buddy_getjid(BUDDATA(current_buddy));
++ if (!jid)
+ scr_LogPrint(LPRINT_NORMAL, "Please specify a Jabber ID.");
+ }
+
+- if (nick)
+- nick = to_utf8(nick);
+-
+- if (id) {
++ if (jid) {
+ // 2nd parameter = optional nickname
+- xmpp_addbuddy(id, nick, NULL);
++ xmpp_addbuddy(jid, nick, NULL);
+ scr_LogPrint(LPRINT_LOGNORM, "Sent presence notification request to <%s>.",
+- id);
++ jid);
+ }
+
+- g_free(jid_utf8);
+- g_free(nick);
+- free_arg_lst(paramlst);
++ cmdopts_free(&options);
+ }
+
+ static void do_del(char *arg)
+ {
+- const char *bjid;
+-
+- if (*arg) {
+- scr_LogPrint(LPRINT_NORMAL, "This action does not require a parameter; "
+- "the currently-selected buddy will be deleted.");
++ cmdopts_t options = {
++ (cmdopt_t[1]){
++ { CMDOPT_SWITCH | CMDOPT_LAST, 'n', "dryrun", { .swc = 0 } },
++ },
++ (cmdarg_t[1]){
++ { CMDOPT_LAST, { .arg = "." } }, // jid
++ },
++ NULL,
++ NULL,
++ };
++ gchar *jid;
++ gpointer buddy;
++
++ if (!xmpp_is_online()) {
++ scr_LogPrint(LPRINT_NORMAL, "You are not connected.");
+ return;
+ }
+
+- if (!current_buddy)
+- return;
+- bjid = buddy_getjid(BUDDATA(current_buddy));
+- if (!bjid)
+- return;
+-
+- if (buddy_gettype(BUDDATA(current_buddy)) & ROSTER_TYPE_ROOM) {
+- // This is a chatroom
+- if (buddy_getinsideroom(BUDDATA(current_buddy))) {
+- scr_LogPrint(LPRINT_NORMAL, "You haven't left this room!");
++ {
++ const char *error = cmdopts_parse(arg, &options);
++ if (error) {
++ scr_log_print(LPRINT_NORMAL, error);
+ return;
+ }
+ }
+
+- // Close the buffer
+- scr_buffer_purge(1, NULL);
+-
+- scr_LogPrint(LPRINT_LOGNORM, "Removing <%s>...", bjid);
+- xmpp_delbuddy(bjid);
+- scr_update_buddy_window();
++ jid = options.args[0].value.arg;
++
++ if (jid && (!*jid || !strcmp(jid, ".")))
++ jid = NULL;
++
++ if (jid) {
++ // The JID has been specified. Quick check...
++ if (check_jid_syntax(jid)) {
++ scr_LogPrint(LPRINT_NORMAL, "<%s> is not a valid Jabber ID.", jid);
++ jid = NULL;
++ } else {
++ GSList *found;
++ mc_strtolower(jid);
++ found = roster_find(jid, jidsearch, ROSTER_TYPE_USER |
++ ROSTER_TYPE_AGENT | ROSTER_TYPE_GROUP);
++ if (!found) {
++ scr_log_print(LPRINT_NORMAL, "Jabber ID <%s> is not in roster.", jid);
++ jid = NULL;
++ } else {
++ buddy = found -> data;
++ }
++ }
++ } else {
++ // Use current buddy
++ if (current_buddy)
++ jid = (char*)buddy_getjid(BUDDATA(current_buddy));
++ if (!jid)
++ scr_LogPrint(LPRINT_NORMAL, "Please specify a Jabber ID.");
++ else
++ buddy = BUDDATA(current_buddy);
++ }
++
++ if (jid) {
++ if (buddy_gettype(buddy) & ROSTER_TYPE_ROOM) {
++ // This is a chatroom
++ if (buddy_getinsideroom(buddy)) {
++ scr_LogPrint(LPRINT_NORMAL, "You haven't left this room!");
++ cmdopts_free(&options);
++ return;
++ }
++ }
++
++ scr_LogPrint(LPRINT_LOGNORM, "Removing <%s>...", jid);
++
++ if (!options.opts[0].value.swc) {
++ // Close the buffer
++ scr_buffer_purge(1, jid);
++
++ xmpp_delbuddy(jid);
++ scr_update_buddy_window();
++ }
++ }
++
++ cmdopts_free(&options);
+ }
+
+ static void do_group(char *arg)
+@@ -1634,130 +1773,109 @@
static void do_say_to(char *arg)
{
@@ -593,9 +977,22 @@
}
// buffer_updown(updown, nblines)
+diff -r 92fa48ef53c9 mcabber/mcabber/commands.h
+--- a/mcabber/mcabber/commands.h Sun Jan 27 00:40:37 2013 +0200
++++ b/mcabber/mcabber/commands.h Mon Feb 25 22:07:41 2013 +0200
+@@ -29,7 +29,8 @@
+
+ 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 cmd_setstatus(const char *recipient,
++ const char *status, const char *message);
+ void say_cmd(char *arg, int parse_flags);
+
+ #endif /* __MCABBER_COMMANDS_H__ */
diff -r 92fa48ef53c9 mcabber/mcabber/roster.c
--- a/mcabber/mcabber/roster.c Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/mcabber/roster.c Mon Feb 25 15:15:43 2013 +0200
++++ b/mcabber/mcabber/roster.c Mon Feb 25 22:07:41 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,
@@ -636,7 +1033,7 @@
}
diff -r 92fa48ef53c9 mcabber/mcabber/utils.c
--- a/mcabber/mcabber/utils.c Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/mcabber/utils.c Mon Feb 25 15:15:43 2013 +0200
++++ b/mcabber/mcabber/utils.c Mon Feb 25 22:07:41 2013 +0200
@@ -555,6 +555,317 @@
*str = tolower(*str);
}
@@ -855,14 +1252,14 @@
+ }
+ state = in_space;
+ } else if (*p == '\\' && !(flags & CMDOPT_PLAIN)) { // next char escape
-+ memmove(p, p+1, e-(p+1));
++ memmove(p, p+1, e-(p+1)+1);
+ e --;
+ if (*p == '\0') {
+ error = "Escape at the end of line";
+ }
+ p ++;
+ } else if (*p == '"' && !(flags & CMDOPT_PLAIN)) { // quotation start/end
-+ memmove(p, p+1, e-(p+1));
++ memmove(p, p+1, e-(p+1)+1);
+ e --;
+ quotes = !quotes;
+ } else { // still argument
@@ -957,7 +1354,7 @@
// Only quotes need a backslash
diff -r 92fa48ef53c9 mcabber/mcabber/utils.h
--- a/mcabber/mcabber/utils.h Sun Jan 27 00:40:37 2013 +0200
-+++ b/mcabber/mcabber/utils.h Mon Feb 25 15:15:43 2013 +0200
++++ b/mcabber/mcabber/utils.h Mon Feb 25 22:07:41 2013 +0200
@@ -43,6 +43,101 @@
char **split_arg(const char *arg, unsigned int n, int dontstriplast);
void free_arg_lst(char **arglst);
@@ -1060,3 +1457,18 @@
void replace_nl_with_dots(char *bufstr);
char *ut_expand_tabs(const char *text);
char *ut_unescape_tabs_cr(const char *text);
+diff -r 92fa48ef53c9 mcabber/mcabber/xmpp_iq.c
+--- a/mcabber/mcabber/xmpp_iq.c Sun Jan 27 00:40:37 2013 +0200
++++ b/mcabber/mcabber/xmpp_iq.c Mon Feb 25 22:07:41 2013 +0200
+@@ -289,10 +289,7 @@
+ if (value) {
+ for (s = adhoc_status_list; !s->name || strcmp(s->name, value); s++);
+ if (s->name) {
+- char *status = g_strdup_printf("%s %s", s->status,
+- message ? message : "");
+- cmd_setstatus(NULL, status);
+- g_free(status);
++ cmd_setstatus(NULL, s->status, message ? message : "");
+ lm_message_node_set_attribute(command, "status", "completed");
+ lm_message_node_add_dataform_result(command,
+ "Status has been changed");