Allow to select to which buddy resource messages go. Closes issue #55
--- a/mcabber/doc/help/en/hlp_roster.txt Thu Mar 01 14:46:49 2012 +0100
+++ b/mcabber/doc/help/en/hlp_roster.txt Thu Mar 01 15:10:41 2012 +0100
@@ -6,6 +6,7 @@
/ROSTER item_lock|item_unlock|item_toggle_lock
/ROSTER hide|show|toggle
/ROSTER note [-|text]
+ /ROSTER resource_lock|resource_unlock
The 'roster' command manipulates the roster/buddylist.
Here are the available parameters:
@@ -57,3 +58,7 @@
Set/update/delete an annotation.
If there is no text, the current item's annotation is displayed -- if you are in the status buffer, all notes are displayed.
If text is "-", the note is erased.
+/roster resource_lock [full jid|resource]
+ Sets active resource for a buddy in roster. Accepts special jid "./resource" for current buddy, or just a resource name.
+/roster resource_unlock [jid]
+ Unsets active resource for a buddy. Accepts special jid "." for current buddy.
--- a/mcabber/mcabber/commands.c Thu Mar 01 14:46:49 2012 +0100
+++ b/mcabber/mcabber/commands.c Thu Mar 01 15:10:41 2012 +0100
@@ -280,6 +280,8 @@
compl_add_category_word(COMPL_ROSTER, "unread_first");
compl_add_category_word(COMPL_ROSTER, "unread_next");
compl_add_category_word(COMPL_ROSTER, "note");
+ compl_add_category_word(COMPL_ROSTER, "resource_lock");
+ compl_add_category_word(COMPL_ROSTER, "resource_unlock");
// Buffer category
compl_add_category_word(COMPL_BUFFER, "clear");
@@ -620,6 +622,69 @@
}
}
+static void roster_resourcelock(char *jidres, gboolean lock) {
+ gpointer bud = NULL;
+ char *resource = NULL;
+
+ if (!jidres) {
+ if (lock) return;
+ jidres = ".";
+ }
+
+ if (jidres[0] == '.' &&
+ (jidres[1] == '\0' || jidres[1] == JID_RESOURCE_SEPARATOR)) {
+ //Special jid: . or ./resource
+ switch (jidres[1]) {
+ case JID_RESOURCE_SEPARATOR:
+ resource = jidres+2;
+ case '\0':
+ if (current_buddy)
+ bud = BUDDATA(current_buddy);
+ }
+ } else {
+ char *tmp;
+ if (!check_jid_syntax(jidres) &&
+ (tmp = strchr(jidres, JID_RESOURCE_SEPARATOR))) {
+ //Any other valid full jid
+ *tmp = '\0'; // for roster search by bare jid;
+ resource = tmp+1;
+ GSList *roster_elt;
+ roster_elt = roster_find(jidres, jidsearch,
+ ROSTER_TYPE_USER|ROSTER_TYPE_AGENT);
+ if (roster_elt)
+ bud = roster_elt->data;
+ *tmp = JID_RESOURCE_SEPARATOR;
+ }
+ if (!bud) {
+ //Resource for current buddy
+ if (current_buddy)
+ bud = BUDDATA(current_buddy);
+ resource = jidres;
+ }
+ }
+
+ if (bud && buddy_gettype(bud) & (ROSTER_TYPE_USER|ROSTER_TYPE_AGENT)) {
+ if (lock) {
+ GSList *resources, *p_res;
+ gboolean found = FALSE;
+ resources = buddy_getresources(bud);
+ for (p_res = resources ; p_res ; p_res = g_slist_next(p_res)) {
+ if (!g_strcmp0((char*)p_res->data, resource))
+ found = TRUE;
+ g_free(p_res->data);
+ }
+ g_slist_free(resources);
+ if (!found) {
+ scr_LogPrint(LPRINT_NORMAL, "No such resource <%s>...", jidres);
+ return;
+ }
+ } else {
+ resource = NULL;
+ }
+ buddy_setactiveresource(bud, resource);
+ scr_update_chat_status(TRUE);
+ }
+}
// display_and_free_note(note, winId)
// Display the note information in the winId buffer, and free note
// (winId is a bare jid or NULL for the status window, in which case we
@@ -825,6 +890,10 @@
scr_roster_next_group();
} else if (!strcasecmp(subcmd, "note")) {
roster_note(arg);
+ } else if (!strcasecmp(subcmd, "resource_lock")) {
+ roster_resourcelock(arg, TRUE);
+ } else if (!strcasecmp(subcmd, "resource_unlock")) {
+ roster_resourcelock(arg, FALSE);
} else
scr_LogPrint(LPRINT_NORMAL, "Unrecognized parameter!");
free_arg_lst(paramlst);
@@ -1286,6 +1355,8 @@
LmMessageSubType type_overwrite)
{
const char *bjid;
+ char *jid;
+ const char *activeres;
if (!current_buddy) {
scr_LogPrint(LPRINT_NORMAL, "No buddy is currently selected.");
@@ -1298,7 +1369,14 @@
return;
}
- send_message_to(bjid, msg, subj, type_overwrite, FALSE);
+ activeres = buddy_getactiveresource(BUDDATA(current_buddy));
+ if (activeres)
+ jid = g_strdup_printf("%s/%s", bjid, activeres);
+ else
+ jid = g_strdup(bjid);
+
+ send_message_to(jid, msg, subj, type_overwrite, FALSE);
+ g_free(jid);
}
static LmMessageSubType scan_mtype(char **arg)
--- a/mcabber/mcabber/hooks.c Thu Mar 01 14:46:49 2012 +0100
+++ b/mcabber/mcabber/hooks.c Thu Mar 01 15:10:41 2012 +0100
@@ -332,6 +332,9 @@
}
}
}
+ } else if (settings_opt_get_int("roster_autolock_resource")) {
+ buddy_setactiveresource(roster_usr->data, resname);
+ scr_update_chat_status(FALSE);
}
if (error_msg_subtype) {
--- a/mcabber/mcabber/roster.c Thu Mar 01 14:46:49 2012 +0100
+++ b/mcabber/mcabber/roster.c Thu Mar 01 15:10:41 2012 +0100
@@ -94,6 +94,7 @@
guint type;
enum subscr subscription;
GSList *resource;
+ res *active_resource;
/* For groupchats */
gchar *nickname;
@@ -265,6 +266,9 @@
p_res->status_msg = NULL;
}
+ if (rost->active_resource == p_res)
+ rost->active_resource = NULL;
+
// Free allocations and delete resource node
free_resource_data(p_res);
rost->resource = g_slist_delete_link(rost->resource, p_res_elt);
@@ -279,6 +283,7 @@
if (!roster_usr)
return;
g_free((gchar*)roster_usr->jid);
+ //g_free((gchar*)roster_usr->active_resource);
g_free((gchar*)roster_usr->name);
g_free((gchar*)roster_usr->nickname);
g_free((gchar*)roster_usr->topic);
@@ -1451,6 +1456,32 @@
return reslist;
}
+// buddy_getactiveresource(roster_data)
+// Returns name of active (selected for chat) resource
+const char *buddy_getactiveresource(gpointer rosterdata)
+{
+ roster *roster_usr = rosterdata;
+ res *resource;
+
+ if (!roster_usr) {
+ if (!current_buddy) return NULL;
+ roster_usr = BUDDATA(current_buddy);
+ }
+
+ resource = roster_usr->active_resource;
+ if (!resource) return NULL;
+ return resource->name;
+}
+
+void buddy_setactiveresource(gpointer rosterdata, const char *resname)
+{
+ roster *roster_usr = rosterdata;
+ res *p_res = NULL;
+ if (resname)
+ p_res = get_resource(roster_usr, resname);
+ roster_usr->active_resource = p_res;
+}
+
/*
// buddy_isresource(roster_data)
// Return true if there is at least one resource
--- a/mcabber/mcabber/roster.h Thu Mar 01 14:46:49 2012 +0100
+++ b/mcabber/mcabber/roster.h Thu Mar 01 15:10:41 2012 +0100
@@ -238,6 +238,8 @@
//int buddy_isresource(gpointer rosterdata);
GSList *buddy_getresources(gpointer rosterdata);
GSList *buddy_getresources_locale(gpointer rosterdata);
+const char *buddy_getactiveresource(gpointer rosterdata);
+void buddy_setactiveresource(gpointer rosterdata, const char *resname);
void buddy_resource_setname(gpointer rosterdata, const char *resname,
const char *newname);
void buddy_resource_setevents(gpointer rosterdata, const char *resname,
--- a/mcabber/mcabber/screen.c Thu Mar 01 14:46:49 2012 +0100
+++ b/mcabber/mcabber/screen.c Thu Mar 01 15:10:41 2012 +0100
@@ -1790,6 +1790,8 @@
unsigned short btype, isgrp, ismuc, isspe;
const char *btypetext = "Unknown";
const char *fullname;
+ char *fullnameres = NULL;
+ const char *activeres;
const char *msg = NULL;
char status;
char *buf, *buf_locale;
@@ -1856,6 +1858,8 @@
status = '?';
+ activeres = buddy_getactiveresource(BUDDATA(current_buddy));
+
if (ismuc) {
if (buddy_getinsideroom(BUDDATA(current_buddy)))
status = 'C';
@@ -1863,24 +1867,30 @@
status = 'x';
} else if (xmpp_getstatus() != offline) {
enum imstatus budstate;
- budstate = buddy_getstatus(BUDDATA(current_buddy), NULL);
+ budstate = buddy_getstatus(BUDDATA(current_buddy), activeres);
if (budstate < imstatus_size)
status = imstatus2char[budstate];
}
// No status message for MUC rooms
if (!ismuc) {
- GSList *resources, *p_res, *p_next_res;
- resources = buddy_getresources(BUDDATA(current_buddy));
-
- for (p_res = resources ; p_res ; p_res = p_next_res) {
- p_next_res = g_slist_next(p_res);
- // Store the status message of the latest resource (highest priority)
- if (!p_next_res)
- msg = buddy_getstatusmsg(BUDDATA(current_buddy), p_res->data);
- g_free(p_res->data);
+ if (activeres) {
+ fullnameres = g_strdup_printf("%s/%s", fullname, activeres);
+ fullname = fullnameres;
+ msg = buddy_getstatusmsg(BUDDATA(current_buddy), activeres);
+ } else {
+ GSList *resources, *p_res, *p_next_res;
+ resources = buddy_getresources(BUDDATA(current_buddy));
+
+ for (p_res = resources ; p_res ; p_res = p_next_res) {
+ p_next_res = g_slist_next(p_res);
+ // Store the status message of the latest resource (highest priority)
+ if (!p_next_res)
+ msg = buddy_getstatusmsg(BUDDATA(current_buddy), p_res->data);
+ g_free(p_res->data);
+ }
+ g_slist_free(resources);
}
- g_slist_free(resources);
} else {
msg = buddy_gettopic(BUDDATA(current_buddy));
}
@@ -1892,6 +1902,7 @@
replace_nl_with_dots(buf);
buf_locale = from_utf8(buf);
mvwprintw(chatstatusWnd, 0, 1, "%s", buf_locale);
+ g_free(fullnameres);
g_free(buf_locale);
g_free(buf);
@@ -1900,9 +1911,9 @@
char eventchar = 0;
guint event;
- // We do not specify the resource here, so one of the resources with the
- // highest priority will be used.
- event = buddy_resource_getevents(BUDDATA(current_buddy), NULL);
+ // We specify active resource here, so when there is none then the resource
+ // with the highest priority will be used.
+ event = buddy_resource_getevents(BUDDATA(current_buddy), activeres);
if (event == ROSTER_EVENT_ACTIVE)
eventchar = 'A';
@@ -2703,7 +2714,12 @@
hbuf_free(&win_entry->bd->hbuf);
if (*p_closebuf) {
+ GSList *roster_elt;
retval = TRUE;
+ roster_elt = roster_find(key, jidsearch,
+ ROSTER_TYPE_USER|ROSTER_TYPE_AGENT);
+ if (roster_elt)
+ buddy_setactiveresource(roster_elt->data, NULL);
} else {
win_entry->bd->cleared = FALSE;
win_entry->bd->top = NULL;
@@ -2749,7 +2765,6 @@
roster_msg_setflag(cjid, FALSE, FALSE);
g_free(p_closebuf);
if (closebuf && !hold_chatmode) {
- //buddy_setactiveresource(bud, resource);
scr_set_chatmode(FALSE);
currentWindow = NULL;
}
--- a/mcabber/mcabber/xmpp.c Thu Mar 01 14:46:49 2012 +0100
+++ b/mcabber/mcabber/xmpp.c Thu Mar 01 15:10:41 2012 +0100
@@ -639,6 +639,7 @@
void xmpp_send_chatstate(gpointer buddy, guint chatstate)
{
const char *bjid;
+ const char *activeres;
#ifdef XEP0085
GSList *resources, *p_res, *p_next;
struct xep0085 *xep85 = NULL;
@@ -649,6 +650,7 @@
bjid = buddy_getjid(buddy);
if (!bjid) return;
+ activeres = buddy_getactiveresource(buddy);
#ifdef XEP0085
/* Send the chatstate to the last resource (which should have the highest
@@ -662,9 +664,11 @@
xep85 = buddy_resource_xep85(buddy, p_res->data);
if (xep85 && xep85->support == CHATSTATES_SUPPORT_OK) {
// If p_next is NULL, this is the highest (prio) resource, i.e.
- // the one we are probably writing to.
- if (!p_next || (xep85->last_state_sent != ROSTER_EVENT_ACTIVE &&
- chatstate == ROSTER_EVENT_ACTIVE))
+ // the one we are probably writing to - unless there is defined an
+ // active resource
+ if (!g_strcmp0(p_res->data, activeres) || (!p_next && !activeres) ||
+ (xep85->last_state_sent != ROSTER_EVENT_ACTIVE &&
+ chatstate == ROSTER_EVENT_ACTIVE))
xmpp_send_xep85_chatstate(bjid, p_res->data, chatstate);
}
g_free(p_res->data);
@@ -676,7 +680,7 @@
return;
#endif
#ifdef XEP0022
- xep22 = buddy_resource_xep22(buddy, NULL);
+ xep22 = buddy_resource_xep22(buddy, activeres);
if (xep22 && xep22->support == CHATSTATES_SUPPORT_OK) {
xmpp_send_xep22_event(bjid, chatstate);
}
--- a/mcabber/mcabberrc.example Thu Mar 01 14:46:49 2012 +0100
+++ b/mcabber/mcabberrc.example Thu Mar 01 15:10:41 2012 +0100
@@ -482,6 +482,11 @@
#
# Set 'info' to anything you'd like to see in your lower status line.
#set info = woot
+#
+# Automatic locking on buddy resource that messages are coming from.
+# Useful when your buddies are chatting from their non-highest priority
+# resources, forcing you to use /say_to command.
+#set roster_autolock_resource = 1
# Contacts PGP information
# You can provide a PGP key to be used for a given Jabber user, or