changeset 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 3b21353e4ad3
children 9f5c5f176953
files mcabber/src/events.c mcabber/src/events.h mcabber/src/jab_iq.c mcabber/src/jab_priv.h mcabber/src/jabglue.c
diffstat 5 files changed, 89 insertions(+), 44 deletions(-) [+]
line wrap: on
line diff
--- a/mcabber/src/events.c	Tue May 01 16:33:26 2007 +0200
+++ b/mcabber/src/events.c	Tue May 01 18:16:11 2007 +0200
@@ -110,7 +110,7 @@
   // IQ processing
   // Note: If xml_result is NULL, this is a timeout
   if (i->callback)
-    (*i->callback)(i, evcontext);
+    (void)(*i->callback)(i, evcontext);
 
   evs_del(evid);
   return 0;
--- a/mcabber/src/events.h	Tue May 01 16:33:26 2007 +0200
+++ b/mcabber/src/events.h	Tue May 01 18:16:11 2007 +0200
@@ -23,7 +23,7 @@
   time_t ts_expire;
   guint8 type;
   gpointer data;
-  void (*callback)();
+  int (*callback)();
   xmlnode xmldata;
   char *desc;
 } eviqs;
--- 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);
   }
 }
 
--- a/mcabber/src/jab_priv.h	Tue May 01 16:33:26 2007 +0200
+++ b/mcabber/src/jab_priv.h	Tue May 01 18:16:11 2007 +0200
@@ -41,7 +41,7 @@
 int  iqs_del(const char *iqid);
 int  iqs_callback(const char *iqid, xmlnode xml_result, guint iqcontext);
 void iqs_check_timeout(time_t now_t);
-void iqscallback_auth(eviqs *iqp, xmlnode xml_result);
+int  iqscallback_auth(eviqs *iqp, xmlnode xml_result);
 void request_version(const char *fulljid);
 void request_time(const char *fulljid);
 void request_last(const char *fulljid);
--- a/mcabber/src/jabglue.c	Tue May 01 16:33:26 2007 +0200
+++ b/mcabber/src/jabglue.c	Tue May 01 18:16:11 2007 +0200
@@ -58,7 +58,7 @@
 static void packethandler(jconn, jpacket);
 static void handle_state_events(char* from, xmlnode xmldata);
 
-static void evscallback_invitation(eviqs *evp, guint evcontext);
+static int evscallback_invitation(eviqs *evp, guint evcontext);
 
 static void logger(jconn j, int io, const char *buf)
 {
@@ -1746,6 +1746,8 @@
   char *s;
   const char *p;
 
+  if (!x) return;
+
   /* RFC3920:
    *    The <error/> element:
    *       o  MUST contain a child element corresponding to one of the defined
@@ -2142,8 +2144,8 @@
   if (type && !strcmp(type, TMSG_ERROR)) {
     xmlnode x;
     scr_LogPrint(LPRINT_LOGNORM, "Error presence packet from <%s>", r);
-    if ((x = xmlnode_get_tag(xmldata, TMSG_ERROR)) != NULL)
-      display_server_error(x);
+    x = xmlnode_get_tag(xmldata, TMSG_ERROR);
+    display_server_error(x);
 
     // Let's check it isn't a nickname conflict.
     // XXX Note: We should handle the <conflict/> string condition.
@@ -2331,8 +2333,8 @@
   timestamp = xml_get_timestamp(xmldata);
 
   if (type && !strcmp(type, TMSG_ERROR)) {
-    if ((x = xmlnode_get_tag(xmldata, TMSG_ERROR)) != NULL)
-      display_server_error(x);
+    x = xmlnode_get_tag(xmldata, TMSG_ERROR);
+    display_server_error(x);
 #if defined JEP0022 || defined JEP0085
     // If the JEP85/22 support is probed, set it back to unknown so that
     // we probe it again.
@@ -2467,7 +2469,7 @@
 #endif
 }
 
-static void evscallback_subscription(eviqs *evp, guint evcontext)
+static int evscallback_subscription(eviqs *evp, guint evcontext)
 {
   char *barejid;
   char *buf;
@@ -2475,20 +2477,20 @@
   if (evcontext == EVS_CONTEXT_TIMEOUT) {
     scr_LogPrint(LPRINT_LOGNORM, "Event %s timed out, cancelled.",
                  evp->id);
-    return;
+    return 0;
   }
   if (evcontext == EVS_CONTEXT_CANCEL) {
     scr_LogPrint(LPRINT_LOGNORM, "Event %s cancelled.", evp->id);
-    return;
+    return 0;
   }
   if (!(evcontext & EVS_CONTEXT_USER))
-    return;
+    return 0;
 
   // Sanity check
   if (!evp->data) {
     // Shouldn't happen, data should be set to the barejid.
     scr_LogPrint(LPRINT_LOGNORM, "Error in evs callback.");
-    return;
+    return 0;
   }
 
   // Ok, let's work now.
@@ -2514,6 +2516,7 @@
   scr_WriteIncomingMessage(barejid, buf, 0, HBB_PREFIX_INFO);
   scr_LogPrint(LPRINT_LOGNORM, "%s", buf);
   g_free(buf);
+  return 0;
 }
 
 static void decline_invitation(event_muc_invitation *invitation, char *reason)
@@ -2542,7 +2545,7 @@
   jb_reset_keepalive();
 }
 
-static void evscallback_invitation(eviqs *evp, guint evcontext)
+static int evscallback_invitation(eviqs *evp, guint evcontext)
 {
   event_muc_invitation *invitation = evp->data;
 
@@ -2550,7 +2553,7 @@
   if (!invitation) {
     // Shouldn't happen.
     scr_LogPrint(LPRINT_LOGNORM, "Error in evs callback.");
-    return;
+    return 0;
   }
 
   if (evcontext == EVS_CONTEXT_TIMEOUT) {
@@ -2582,6 +2585,7 @@
   g_free(invitation->reason);
   g_free(invitation);
   evp->data = NULL;
+  return 0;
 }
 
 static void handle_packet_s10n(jconn conn, char *type, char *from,