changeset 1016:4d3c48844746

Add /roster note Implement XEP-0145 (Annotations) Usage: /roster note [-|note_text]
author Mikael Berthe <mikael@lilotux.net>
date Wed, 15 Nov 2006 00:04:57 +0100
parents 579299b1c9b2
children 41f9a2a4c1de
files mcabber/src/commands.c mcabber/src/jab_iq.c mcabber/src/jab_priv.h mcabber/src/jabglue.c mcabber/src/jabglue.h
diffstat 5 files changed, 190 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/mcabber/src/commands.c	Mon Nov 13 21:58:18 2006 +0100
+++ b/mcabber/src/commands.c	Wed Nov 15 00:04:57 2006 +0100
@@ -157,6 +157,7 @@
   compl_add_category_word(COMPL_ROSTER, "search");
   compl_add_category_word(COMPL_ROSTER, "unread_first");
   compl_add_category_word(COMPL_ROSTER, "unread_next");
+  compl_add_category_word(COMPL_ROSTER, "note");
 
   // Roster category
   compl_add_category_word(COMPL_BUFFER, "clear");
@@ -466,6 +467,47 @@
   }
 }
 
+static void roster_note(char *arg)
+{
+  const char *jid;
+  gchar *msg, *note;
+  guint type;
+
+  if (!current_buddy)
+    return;
+
+  jid = buddy_getjid(BUDDATA(current_buddy));
+  type = buddy_gettype(BUDDATA(current_buddy));
+
+  if (!jid || (type != ROSTER_TYPE_USER &&
+               type != ROSTER_TYPE_ROOM &&
+               type != ROSTER_TYPE_AGENT)) {
+    scr_LogPrint(LPRINT_NORMAL, "This item can't have a note.");
+    return;
+  }
+
+  if (arg && *arg)
+    msg = to_utf8(arg);
+  else
+    msg = NULL;
+
+  if (msg) {    // Set a note
+    if (!strcmp(msg, "-"))
+      note = NULL; // delete note
+    else
+      note = msg;
+    jb_set_storage_rosternotes(jid, note);
+  } else {      // Display a note
+    note = jb_get_storage_rosternotes(jid);
+    if (note)
+      msg = g_strdup_printf("Note: %s", note);
+    else
+      msg = g_strdup_printf("This item doesn't have a note.");
+    scr_WriteIncomingMessage(jid, msg, 0, HBB_PREFIX_INFO);
+  }
+  g_free(msg);
+}
+
 /* Commands callback functions */
 /* All these do_*() functions will be called with a "arg" parameter */
 /* (with arg not null)                                              */
@@ -533,6 +575,8 @@
     scr_RosterUp();
   } else if (!strcasecmp(subcmd, "down")) {
     scr_RosterDown();
+  } else if (!strcasecmp(subcmd, "note")) {
+    roster_note(arg);
   } else
     scr_LogPrint(LPRINT_NORMAL, "Unrecognized parameter!");
   free_arg_lst(paramlst);
@@ -1216,7 +1260,6 @@
                  type == ROSTER_TYPE_GROUP ? "group" :
                  (type == ROSTER_TYPE_SPECIAL ? "special" : "unknown"));
   }
-
   g_free(buffer);
 }
 
--- a/mcabber/src/jab_iq.c	Mon Nov 13 21:58:18 2006 +0100
+++ b/mcabber/src/jab_iq.c	Wed Nov 15 00:04:57 2006 +0100
@@ -36,6 +36,8 @@
 
 // Bookmarks for IQ:private storage
 xmlnode bookmarks;
+// Roster notes for IQ:private storage
+xmlnode rosternotes;
 
 static GSList *iqs_list;
 
@@ -684,6 +686,7 @@
     if (p && !strcmp(p, "conference"))
       storage_bookmarks_parse_conference(x);
   }
+  // Copy the bookmarks node
   xmlnode_free(bookmarks);
   bookmarks = xmlnode_dup(ansqry);
 }
@@ -702,6 +705,40 @@
   jab_send(jc, iqn->xmldata);
 }
 
+static void iqscallback_storage_rosternotes(eviqs *iqp, xmlnode xml_result,
+                                            guint iqcontext)
+{
+  xmlnode ansqry;
+
+  // Leave now if we cannot process xml_result
+  if (!xml_result || iqcontext) return;
+
+  ansqry = xmlnode_get_tag(xml_result, "query");
+  ansqry = xmlnode_get_tag(ansqry, "storage");
+  if (!ansqry) {
+    scr_LogPrint(LPRINT_LOG, "Invalid IQ:private result! "
+                 "(storage:rosternotes)");
+    return;
+  }
+  // Copy the rosternotes node
+  xmlnode_free(rosternotes);
+  rosternotes = xmlnode_dup(ansqry);
+}
+
+static void request_storage_rosternotes(void)
+{
+  eviqs *iqn;
+  xmlnode x;
+
+  iqn = iqs_new(JPACKET__GET, NS_PRIVATE, "storage", IQS_DEFAULT_TIMEOUT);
+
+  x = xmlnode_insert_tag(xmlnode_get_tag(iqn->xmldata, "query"), "storage");
+  xmlnode_put_attrib(x, "xmlns", "storage:rosternotes");
+
+  iqn->callback = &iqscallback_storage_rosternotes;
+  jab_send(jc, iqn->xmldata);
+}
+
 void iqscallback_auth(eviqs *iqp, xmlnode xml_result)
 {
   if (jstate == STATE_GETAUTH) {
@@ -721,6 +758,7 @@
   } else if (jstate == STATE_SENDAUTH) {
     request_roster();
     request_storage_bookmarks();
+    request_storage_rosternotes();
     jstate = STATE_LOGGED;
   }
 }
@@ -989,4 +1027,20 @@
   iqs_del(iqn->id); // XXX
 }
 
+//  send_storage_rosternotes()
+// Send the current rosternotes node to update the server.
+// Note: the sender should check we're online.
+void send_storage_rosternotes(void)
+{
+  eviqs *iqn;
+
+  if (!rosternotes) return;
+
+  iqn = iqs_new(JPACKET__SET, NS_PRIVATE, "storage", IQS_DEFAULT_TIMEOUT);
+  xmlnode_insert_node(xmlnode_get_tag(iqn->xmldata, "query"), rosternotes);
+
+  jab_send(jc, iqn->xmldata);
+  iqs_del(iqn->id); // XXX
+}
+
 /* vim: set expandtab cindent cinoptions=>2\:2(0:  For Vim users... */
--- a/mcabber/src/jab_priv.h	Mon Nov 13 21:58:18 2006 +0100
+++ b/mcabber/src/jab_priv.h	Wed Nov 15 00:04:57 2006 +0100
@@ -29,7 +29,7 @@
 #define IQS_CONTEXT_ERROR   2U
 
 extern enum enum_jstate jstate;
-extern xmlnode bookmarks;
+extern xmlnode bookmarks, rosternotes;
 
 extern char *mcabber_version(void);
 
@@ -47,6 +47,7 @@
 void request_last(const char *fulljid);
 void request_vcard(const char *barejid);
 void send_storage_bookmarks(void);
+void send_storage_rosternotes(void);
 
 #endif /* __JAB_PRIV_H__ */
 
--- a/mcabber/src/jabglue.c	Mon Nov 13 21:58:18 2006 +0100
+++ b/mcabber/src/jabglue.c	Wed Nov 15 00:04:57 2006 +0100
@@ -1232,6 +1232,94 @@
                  "Warning: you're not connected to the server.");
 }
 
+//  jb_get_storage_rosternotes(barejid)
+// Return thenote associated to this jid.
+// The caller should g_free the string after use.
+char *jb_get_storage_rosternotes(const char *barejid)
+{
+  xmlnode x;
+
+  if (!barejid)
+    return NULL;
+
+  // If we have no rosternotes, probably the server doesn't support them.
+  if (!rosternotes) {
+    scr_LogPrint(LPRINT_LOGNORM,
+                 "Sorry, your server doesn't seem to support private storage.");
+    return NULL;
+  }
+
+  // Walk through the storage tags
+  x = xmlnode_get_firstchild(rosternotes);
+  for ( ; x; x = xmlnode_get_nextsibling(x)) {
+    const char *jid;
+    const char *p;
+    p = xmlnode_get_name(x);
+    // If the current node is a conference item, see if we have to replace it.
+    if (p && !strcmp(p, "note")) {
+      jid = xmlnode_get_attrib(x, "jid");
+      if (!jid)
+        continue;
+      if (!strcmp(jid, barejid)) {
+        // We've found a note for this contact.
+        return g_strdup(xmlnode_get_data(x));
+      }
+    }
+  }
+  return NULL;  // No note found
+}
+
+//  jb_set_storage_rosternotes(barejid, note)
+// Update the private storage rosternotes: add/delete a note.
+// If note is nil, we remove the existing note.
+void jb_set_storage_rosternotes(const char *barejid, const char *note)
+{
+  xmlnode x;
+
+  if (!barejid)
+    return;
+
+  // If we have no rosternotes, probably the server doesn't support them.
+  if (!rosternotes) {
+    scr_LogPrint(LPRINT_LOGNORM,
+                 "Sorry, your server doesn't seem to support private storage.");
+    return;
+  }
+
+  // Walk through the storage tags
+  x = xmlnode_get_firstchild(rosternotes);
+  for ( ; x; x = xmlnode_get_nextsibling(x)) {
+    const char *jid;
+    const char *p;
+    p = xmlnode_get_name(x);
+    // If the current node is a conference item, see if we have to replace it.
+    if (p && !strcmp(p, "note")) {
+      jid = xmlnode_get_attrib(x, "jid");
+      if (!jid)
+        continue;
+      if (!strcmp(jid, barejid)) {
+        // We've found a note for this jid.  Let's hide it and we'll
+        // create a new one.
+        xmlnode_hide(x);
+        break;
+      }
+    }
+  }
+
+  // Let's create a node for this jid, if the note is not NULL.
+  if (note) {
+    x = xmlnode_insert_tag(rosternotes, "note");
+    xmlnode_put_attrib(x, "jid", barejid);
+    xmlnode_insert_cdata(x, note, -1);
+  }
+
+  if (online)
+    send_storage_rosternotes();
+  else
+    scr_LogPrint(LPRINT_LOGNORM,
+                 "Warning: you're not connected to the server.");
+}
+
 static void gotmessage(char *type, const char *from, const char *body,
                        const char *enc, time_t timestamp)
 {
--- a/mcabber/src/jabglue.h	Mon Nov 13 21:58:18 2006 +0100
+++ b/mcabber/src/jabglue.h	Wed Nov 15 00:04:57 2006 +0100
@@ -71,6 +71,8 @@
 void jb_set_storage_bookmark(const char *roomid, const char *name,
                              const char *nick, const char *passwd,
                              int autojoin);
+char *jb_get_storage_rosternotes(const char *barejid);
+void jb_set_storage_rosternotes(const char *barejid, const char *note);
 
 #endif /* __JABGLUE_H__ */