Add /roster note
Implement XEP-0145 (Annotations)
Usage: /roster note [-|note_text]
--- 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__ */