changeset 2013:8dc418af3e72

Allow to select to which buddy resource messages go. Closes issue #55
author Hermitifier
date Thu, 01 Mar 2012 15:10:41 +0100
parents 2039ea6bd7a5
children 99db5d4ed047
files mcabber/doc/help/en/hlp_roster.txt mcabber/mcabber/commands.c mcabber/mcabber/hooks.c mcabber/mcabber/roster.c mcabber/mcabber/roster.h mcabber/mcabber/screen.c mcabber/mcabber/xmpp.c mcabber/mcabberrc.example
diffstat 8 files changed, 163 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- 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