From 8e79a912cf41d41da558aeae44e0389a6f8a2e21 Mon Sep 17 00:00:00 2001
From: Tomasz Sterna <tomek@xiaoka.com>
Date: Tue, 6 Dec 2011 23:31:10 +0100
Subject: [PATCH] Updated flash patch

---
 c2s/c2s.c |  130 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 c2s/c2s.h |    4 ++
 2 files changed, 134 insertions(+), 0 deletions(-)

diff --git a/c2s/c2s.c b/c2s/c2s.c
index 5d58407..1fcda9d 100644
--- a/c2s/c2s.c
+++ b/c2s/c2s.c
@@ -22,6 +22,65 @@
 #include "c2s.h"
 #include <stringprep.h>
 
+/*
+ * M.Bootsma, LogicaCMG Hoofddorp, Netherlands
+ * October 2004
+ *
+ * Added a patch for flash:stream support
+ *
+ * Flash is not 100% compatible with the XML stream standard:
+ * 1. it terminates every XML message with a '\0'
+ * 2. it terminates the stream header with a /
+ *    (this would close the stream)
+ * 3. it starts the stream with a flash:stream header instead of
+ *    a stream:stream header.
+ *
+ * The patch checks the first message of a starting session stream
+ * for any '\0'. If found it flags the session as a Flash session
+ * and replases the complete header with a Jabber compatible
+ * header.
+ * After that every incoming message is filtered and '\0' is 
+ * replaced with ' '.
+ * For every outgoing message, a '\0' is appended and the response
+ * of the header is replaced for a flash friendly version
+ *
+ * The whole flash patch can be switched off by undefining CP2005_FLASH_PATCH
+ * in config.h(.in)
+ */
+
+#ifdef CP2005_FLASH_PATCH
+
+#define FLASH_BUFFER_SIZE 256
+
+static const char caStreamHeader [] = "<?xml version='1.0'?><stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:client' to='%s' >";
+static const char caFlashHeader []  = "<?xml version='1.0'?><flash:stream xmlns:flash='http://www.jabber.com/streams/flash' xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:client' from='%s' id='%s' />";
+
+static void ExtractValue(char *pMessage, char *pVariable, char *pValue) { 
+    int iLen; 
+    char *p;
+    char *pEnd;
+
+    /*
+     * extract the value of an attribute from a XML message
+     * eg: <.... id='1234567890' ....> returns 1234567890
+     */
+
+    p = strstr(pMessage, pVariable);
+    if (p != NULL) {
+        p += (strlen(pVariable) + 1);
+        /* find end of value, search for closing ' or " */
+        pEnd = strchr(p, p [-1]);
+        iLen = pEnd - p;
+        if (iLen < FLASH_BUFFER_SIZE) {
+            memcpy(pValue, p, iLen);
+            pValue[iLen] = '\0';
+            log_debug(ZONE, "++++ Extracted Var %s: [%s]\n", pVariable, pValue);
+        }
+    }
+}
+#endif
+
+
 static int _c2s_client_sx_callback(sx_t s, sx_event_t e, void *data, void *arg) {
     sess_t sess = (sess_t) arg;
     sx_buf_t buf = (sx_buf_t) data;
@@ -31,6 +90,12 @@ static int _c2s_client_sx_callback(sx_t s, sx_event_t e, void *data, void *arg)
     char root[9];
     bres_t bres, ires;
 
+#ifdef CP2005_FLASH_PATCH
+    char *p, *pEnd;
+    char caHost[FLASH_BUFFER_SIZE] = "";
+    char caID[FLASH_BUFFER_SIZE];
+#endif
+
     switch(e) {
         case event_WANT_READ:
             log_debug(ZONE, "want read");
@@ -137,11 +202,76 @@ static int _c2s_client_sx_callback(sx_t s, sx_event_t e, void *data, void *arg)
 
             buf->len = len;
 
+#ifdef CP2005_FLASH_PATCH
+            /* check for 0 bytes in the first packet
+             * if found it must be a flash client
+             * remove any 0 in the data and
+             * the / that ends the <?xml... header
+             */
+
+            pEnd = &buf->data[len];
+
+            if (sess->s->state == state_NONE) {
+                /* stream is new, look for 0 bytes */
+                p = memchr(buf->data, '\0', buf->len);
+                if ((p != NULL) && (p < pEnd)) {
+                    log_debug(ZONE, "++++ Flash Stream detected\n%.*s", buf->len, buf->data);
+                    sess->flash_client = 1;
+
+                    /* extract destination host */
+                    ExtractValue(buf->data, "to=", caHost);
+
+                    /* create normal stream:stream header, resize data buffer first */
+                    _sx_buffer_alloc_margin(buf, 0, sizeof(caStreamHeader) + strlen(caHost) + 8 + 10 /*sw paranoid*/);
+                    snprintf(buf->data, buf->len, caStreamHeader, caHost);
+                    buf->len = strlen(buf->data);
+                    pEnd = &buf->data[buf->len];
+
+                    log_debug(ZONE, "++++ Converted to\n%.*s", buf->len, buf->data);
+                }
+            }
+
+            /* Check all other messages in the stream to remove \0's etc */
+            if (sess->flash_client) 
+                /* remove 0's from flash packets */
+                for (p = buf->data; p < pEnd; p++)
+                    if (*p == '\0')
+                        *p = ' ';
+#endif
+
             return len;
 
         case event_WRITE:
             log_debug(ZONE, "writing to %d", sess->fd->fd);
 
+#ifdef CP2005_FLASH_PATCH
+            if (sess->flash_client) {
+                /* look for the header <? xml ...*/
+                if (strncmp(buf->data, "<?xml ", 6) == 0) {
+                    /* replace normal stream header with flash friendly header */
+                    log_debug(ZONE, "++++ Found <?xml..., \n%.*s", buf->len, buf->data);
+
+                    /* extract id from id="123456567778765" or id='45454545454' */
+                    ExtractValue(buf->data, "from=", caHost);
+                    ExtractValue(buf->data, "id=", caID);
+
+                    /* create flash:stream header, realloc buffer first */
+                    _sx_buffer_alloc_margin(buf, 0, sizeof(caFlashHeader) + strlen(caHost) + strlen(caID) + 8);
+                    sprintf(buf->data, caFlashHeader, caHost, caID);
+                    buf->len = strlen(buf->data);
+
+                    log_debug(ZONE, "++++ Converted to %s", buf->data);
+                } else {
+                    // Add some space for the junk we are going to add at the end
+                    _sx_buffer_alloc_margin(buf, 0, 8);
+                }
+
+                /* add a 0 to flash packets */
+                buf->data[buf->len] = '\0';
+                buf->len++;
+            }
+#endif
+
             len = send(sess->fd->fd, buf->data, buf->len, 0);
             if(len >= 0) {
                 log_debug(ZONE, "%d bytes written", len);
diff --git a/c2s/c2s.h b/c2s/c2s.h
index 48c57d9..7b71dab 100644
--- a/c2s/c2s.h
+++ b/c2s/c2s.h
@@ -104,6 +104,10 @@ struct sess_st {
 
     int                 active;
 
+#ifdef CP2005_FLASH_PATCH
+    int                 flash_client;
+#endif
+
     /* session related packet waiting for sm response */
     nad_t               result;
 
-- 
1.7.7.3

