diff mcabber/src/jab_iq.c @ 1213:4a7db2870685

Improve Private Storage detection. MCabber now correctly detects Private Storage support when receiving an item-not-found error (which doesn't mean the server has no support for P.S., but that it's empty). I've added a return value to the callback functions. For now the return value is only used for IQ error handling.
author Mikael Berthe <mikael@lilotux.net>
date Tue, 01 May 2007 18:16:11 +0200
parents 2de8f8ba1f34
children 80c095886fb5
line wrap: on
line diff
--- a/mcabber/src/jab_iq.c	Tue May 01 16:33:26 2007 +0200
+++ b/mcabber/src/jab_iq.c	Tue May 01 18:16:11 2007 +0200
@@ -172,6 +172,7 @@
 int iqs_callback(const char *iqid, xmlnode xml_result, guint iqcontext)
 {
   eviqs *i;
+  int retval = 0;
 
   i = iqs_find(iqid);
   if (!i) return -1;
@@ -179,10 +180,10 @@
   // IQ processing
   // Note: If xml_result is NULL, this is a timeout
   if (i->callback)
-    (*i->callback)(i, xml_result, iqcontext);
+    retval = (*i->callback)(i, xml_result, iqcontext);
 
   iqs_del(iqid);
-  return 0;
+  return retval;
 }
 
 void iqs_check_timeout(time_t now_t)
@@ -288,7 +289,7 @@
     scr_UpdateBuddyWindow();
 }
 
-static void iqscallback_version(eviqs *iqp, xmlnode xml_result, guint iqcontext)
+static int iqscallback_version(eviqs *iqp, xmlnode xml_result, guint iqcontext)
 {
   xmlnode ansqry;
   char *p;
@@ -296,18 +297,18 @@
   char *buf;
 
   // Leave now if we cannot process xml_result
-  if (!xml_result || iqcontext) return;
+  if (!xml_result || iqcontext) return -1;
 
   ansqry = xmlnode_get_tag(xml_result, "query");
   if (!ansqry) {
     scr_LogPrint(LPRINT_LOGNORM, "Invalid IQ:version result!");
-    return;
+    return 0;
   }
   // Display IQ result sender...
   p = xmlnode_get_attrib(xml_result, "from");
   if (!p) {
     scr_LogPrint(LPRINT_LOGNORM, "Invalid IQ:version result (no sender name).");
-    return;
+    return 0;
   }
   bjid = p;
 
@@ -340,6 +341,7 @@
     scr_WriteIncomingMessage(bjid, buf, 0, HBB_PREFIX_NONE);
     g_free(buf);
   }
+  return 0;
 }
 
 void request_version(const char *fulljid)
@@ -352,7 +354,7 @@
   jab_send(jc, iqn->xmldata);
 }
 
-static void iqscallback_time(eviqs *iqp, xmlnode xml_result, guint iqcontext)
+static int iqscallback_time(eviqs *iqp, xmlnode xml_result, guint iqcontext)
 {
   xmlnode ansqry;
   char *p;
@@ -360,18 +362,18 @@
   char *buf;
 
   // Leave now if we cannot process xml_result
-  if (!xml_result || iqcontext) return;
+  if (!xml_result || iqcontext) return -1;
 
   ansqry = xmlnode_get_tag(xml_result, "query");
   if (!ansqry) {
     scr_LogPrint(LPRINT_LOGNORM, "Invalid IQ:time result!");
-    return;
+    return 0;
   }
   // Display IQ result sender...
   p = xmlnode_get_attrib(xml_result, "from");
   if (!p) {
     scr_LogPrint(LPRINT_LOGNORM, "Invalid IQ:time result (no sender name).");
-    return;
+    return 0;
   }
   bjid = p;
 
@@ -404,6 +406,7 @@
     scr_WriteIncomingMessage(bjid, buf, 0, HBB_PREFIX_NONE);
     g_free(buf);
   }
+  return 0;
 }
 
 void request_time(const char *fulljid)
@@ -416,7 +419,7 @@
   jab_send(jc, iqn->xmldata);
 }
 
-static void iqscallback_last(eviqs *iqp, xmlnode xml_result, guint iqcontext)
+static int iqscallback_last(eviqs *iqp, xmlnode xml_result, guint iqcontext)
 {
   xmlnode ansqry;
   char *p;
@@ -424,18 +427,18 @@
   char *buf;
 
   // Leave now if we cannot process xml_result
-  if (!xml_result || iqcontext) return;
+  if (!xml_result || iqcontext) return -1;
 
   ansqry = xmlnode_get_tag(xml_result, "query");
   if (!ansqry) {
     scr_LogPrint(LPRINT_LOGNORM, "Invalid IQ:last result!");
-    return;
+    return 0;
   }
   // Display IQ result sender...
   p = xmlnode_get_attrib(xml_result, "from");
   if (!p) {
     scr_LogPrint(LPRINT_LOGNORM, "Invalid IQ:last result (no sender name).");
-    return;
+    return 0;
   }
   bjid = p;
 
@@ -477,6 +480,7 @@
     scr_WriteIncomingMessage(bjid, buf, 0, HBB_PREFIX_INFO);
     g_free(buf);
   }
+  return 0;
 }
 
 void request_last(const char *fulljid)
@@ -600,7 +604,7 @@
   }
 }
 
-static void iqscallback_vcard(eviqs *iqp, xmlnode xml_result, guint iqcontext)
+static int iqscallback_vcard(eviqs *iqp, xmlnode xml_result, guint iqcontext)
 {
   xmlnode ansqry;
   char *p;
@@ -608,13 +612,13 @@
   char *buf;
 
   // Leave now if we cannot process xml_result
-  if (!xml_result || iqcontext) return;
+  if (!xml_result || iqcontext) return -1;
 
   // Display IQ result sender...
   p = xmlnode_get_attrib(xml_result, "from");
   if (!p) {
     scr_LogPrint(LPRINT_LOGNORM, "Invalid IQ:vCard result (no sender name).");
-    return;
+    return 0;
   }
   bjid = p;
 
@@ -625,7 +629,7 @@
   ansqry = xmlnode_get_tag(xml_result, "vCard");
   if (!ansqry) {
     scr_LogPrint(LPRINT_LOGNORM, "Empty IQ:vCard result!");
-    return;
+    return 0;
   }
 
   // bjid should really be the "bare JID", let's strip the resource
@@ -637,6 +641,7 @@
 
   // Get result data...
   handle_vcard_node(bjid, ansqry);
+  return 0;
 }
 
 void request_vcard(const char *bjid)
@@ -707,20 +712,36 @@
   g_free(bjid);
 }
 
-static void iqscallback_storage_bookmarks(eviqs *iqp, xmlnode xml_result,
-                                          guint iqcontext)
+static int iqscallback_storage_bookmarks(eviqs *iqp, xmlnode xml_result,
+                                         guint iqcontext)
 {
   xmlnode x, ansqry;
   char *p;
 
+  if (iqcontext == IQS_CONTEXT_ERROR) {
+    // No server support, or no bookmarks?
+    p = xmlnode_get_name(xmlnode_get_firstchild(xml_result));
+    if (p && !strcmp(p, "item-not-found")) {
+      // item-no-found means the server has Private Storage, but it's
+      // currently empty.
+      xmlnode_free(bookmarks);
+      bookmarks = xmlnode_new_tag("storage");
+      xmlnode_put_attrib(bookmarks, "xmlns", "storage:bookmarks");
+      // We return 0 so that the IQ error message be
+      // not displayed, as it isn't a real error.
+      return 0;
+    }
+    return -1; // Unhandled error
+  }
+
   // Leave now if we cannot process xml_result
-  if (!xml_result || iqcontext) return;
+  if (!xml_result || iqcontext) return 0;
 
   ansqry = xmlnode_get_tag(xml_result, "query");
   ansqry = xmlnode_get_tag(ansqry, "storage");
   if (!ansqry) {
     scr_LogPrint(LPRINT_LOG, "Invalid IQ:private result! (storage:bookmarks)");
-    return;
+    return 0;
   }
 
   // Walk through the storage tags
@@ -734,6 +755,7 @@
   // Copy the bookmarks node
   xmlnode_free(bookmarks);
   bookmarks = xmlnode_dup(ansqry);
+  return 0;
 }
 
 static void request_storage_bookmarks(void)
@@ -750,24 +772,42 @@
   jab_send(jc, iqn->xmldata);
 }
 
-static void iqscallback_storage_rosternotes(eviqs *iqp, xmlnode xml_result,
-                                            guint iqcontext)
+static int iqscallback_storage_rosternotes(eviqs *iqp, xmlnode xml_result,
+                                           guint iqcontext)
 {
   xmlnode ansqry;
 
+  if (iqcontext == IQS_CONTEXT_ERROR) {
+    const char *p;
+    // No server support, or no roster notes?
+    p = xmlnode_get_name(xmlnode_get_firstchild(xml_result));
+    if (p && !strcmp(p, "item-not-found")) {
+      // item-no-found means the server has Private Storage, but it's
+      // currently empty.
+      xmlnode_free(rosternotes);
+      rosternotes = xmlnode_new_tag("storage");
+      xmlnode_put_attrib(rosternotes, "xmlns", "storage:rosternotes");
+      // We return 0 so that the IQ error message be
+      // not displayed, as it isn't a real error.
+      return 0;
+    }
+    return -1; // Unhandled error
+  }
+
   // Leave now if we cannot process xml_result
-  if (!xml_result || iqcontext) return;
+  if (!xml_result || iqcontext) return 0;
 
   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;
+    return 0;
   }
   // Copy the rosternotes node
   xmlnode_free(rosternotes);
   rosternotes = xmlnode_dup(ansqry);
+  return 0;
 }
 
 static void request_storage_rosternotes(void)
@@ -784,7 +824,7 @@
   jab_send(jc, iqn->xmldata);
 }
 
-void iqscallback_auth(eviqs *iqp, xmlnode xml_result)
+int iqscallback_auth(eviqs *iqp, xmlnode xml_result)
 {
   if (jstate == STATE_GETAUTH) {
     eviqs *iqn;
@@ -806,6 +846,7 @@
     request_storage_rosternotes();
     jstate = STATE_LOGGED;
   }
+  return 0;
 }
 
 static void handle_iq_result(jconn conn, char *from, xmlnode xmldata)
@@ -1429,10 +1470,10 @@
   } else if (!strcmp(type, "set")) {
     handle_iq_set(conn, from, xmldata);
   } else if (!strcmp(type, TMSG_ERROR)) {
+    // Display a message only if the error isn't caught by a callback.
     xmlnode x = xmlnode_get_tag(xmldata, TMSG_ERROR);
-    if (x)
+    if (iqs_callback(xmlnode_get_attrib(xmldata, "id"), x, IQS_CONTEXT_ERROR))
       display_server_error(x);
-    iqs_callback(xmlnode_get_attrib(xmldata, "id"), NULL, IQS_CONTEXT_ERROR);
   }
 }