+ add C-to-Json serializer
authorWilfried Göesgens <willi@citadel.org>
Sun, 25 Jan 2009 16:03:49 +0000 (16:03 +0000)
committerWilfried Göesgens <willi@citadel.org>
Sun, 25 Jan 2009 16:03:49 +0000 (16:03 +0000)
+ add Wildfire implementation

libcitadel/Makefile.in
libcitadel/configure.in
libcitadel/debian/rules
libcitadel/lib/json.c [new file with mode: 0644]
libcitadel/lib/libcitadel.h
libcitadel/lib/wildfire.c [new file with mode: 0644]

index 0d80c40e0647e4ee6ec5542f3c3b0a42b1f72dbc..a0730d2e771c3bd249514624b3c9b96a85aeeab5 100755 (executable)
@@ -57,7 +57,7 @@ install-pkgconfigDATA: $(pkgconfig_DATA)
 
 
 clean:
-       cd lib && rm -f $(LIBRARY) *.o *.lo && rm -rf .libs _libs
+       cd lib && rm -f $(LIBRARY) *.o *.lo && rm -rf .libs _libs xdgmime/*.o xdgmime/*.lo xdgmime/.libs
        rm -rf .libs libcitadel.la
 
 clobber: clean
@@ -110,6 +110,8 @@ LIB_OBJS = lib/libcitadel.lo \
        lib/hash.lo \
        lib/lookup3.lo \
        lib/stringbuf.lo \
+       lib/json.lo \
+       lib/wildfire.lo \
        lib/xdgmime/xdgmime.lo \
        lib/xdgmime/xdgmimeglob.lo \
        lib/xdgmime/xdgmimeint.lo \
@@ -129,6 +131,8 @@ lib/vcard.lo: lib/vcard.c lib/libcitadel.h
 lib/vnote.lo: lib/vnote.c lib/libcitadel.h
 lib/lookup3.lo: lib/lookup3.c lib/libcitadel.h
 lib/hash.lo: lib/hash.c lib/libcitadel.h
+lib/json.lo: lib/json.c lib/libcitadel.h
+lib/wildfire.lo: lib/wildfire.c lib/libcitadel.h
 lib/xdgmime/xdgmime.lo: lib/xdgmime/xdgmime.c 
 lib/xdgmime/xdgmimeglob.lo:  lib/xdgmime/xdgmimeglob.c 
 lib/xdgmime/xdgmimeint.lo:  lib/xdgmime/xdgmimeint.c 
index 8d8e27490e9436858f5015e8086fc09399ee6fda..432b4de3a3592da5a75c9560e2987a84010cf345 100755 (executable)
@@ -131,6 +131,17 @@ else
        AC_MSG_RESULT(libcitadel will be built without character set conversion.)
 fi
 
+dnl disable backtrace if we don't want it.
+AC_ARG_WITH(backtrace, 
+                   [  --with-backtrace          enable backtrace dumps in the syslog],
+                       [ if test "x$withval" != "xno" ; then
+                            CFLAGS="$CFLAGS  -rdynamic "
+                            LDFLAGS="$LDFLAGS  -rdynamic "
+                             AC_CHECK_FUNCS(backtrace)
+                         fi
+                       ]
+)
+
 
 AC_ARG_WITH(with_zlib,    [  --with-zlib             use zlib compression if present])
 dnl Checks for the zlib compression library.
index 4b88c184f1287fe2049b79bf77768660ae18e51c..f2977731ade2d869358413dffb6e202ed8538182 100755 (executable)
@@ -13,6 +13,7 @@ CFLAGS = -Wall -g
 LDFALGS = 
 ifneq (,$(findstring debug,$(DEB_BUILD_OPTIONS)))
        CFLAGS += -O0 -ggdb -rdynamic -MD -MP -D DEBUG -D VALGRIND
+       EXTRA_ARGS =  --with-backtrace
 else
        CFLAGS += -O2
 endif
@@ -28,6 +29,7 @@ build-stamp:
 
 # ./configure
        CFLAGS="$(CFLAGS)"; LDFLAGS="$(LDFLAGS)";  ./configure --host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) \
+               $(EXTRA_ARGS) \
                --prefix=/usr
 
 # Build libcitadel
diff --git a/libcitadel/lib/json.c b/libcitadel/lib/json.c
new file mode 100644 (file)
index 0000000..044be9c
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * $Id: wildfire.c 6962 2009-01-18 19:33:45Z dothebart $
+ */
+/**
+ * \defgroup Subst Variable substitution type stuff
+ * \ingroup CitadelConfig
+ */
+
+/*@{*/
+
+#include "sysdep.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "libcitadel.h"
+
+
+#define JSON_STRING 0
+#define JSON_NUM 1
+#define JSON_NULL 2
+#define JSON_BOOL 3
+#define JSON_ARRAY 4
+#define JSON_OBJECT 7
+
+struct JsonValue {
+       int Type;
+       StrBuf *Name;
+       StrBuf *Value;
+       HashList *SubValues;
+};
+
+
+void DeleteJSONValue(void *vJsonValue)
+{
+       JsonValue *Val = (JsonValue*) vJsonValue;
+       FreeStrBuf(&Val->Name);
+       FreeStrBuf(&Val->Value);
+       DeleteHash(&Val->SubValues);
+       free(Val);
+}
+
+JsonValue *NewJsonObject(const char *Key, long keylen)
+{
+       JsonValue *Ret;
+
+       Ret = (JsonValue*) malloc(sizeof(JsonValue));
+       memset(Ret, 0, sizeof(JsonValue));
+       Ret->Type = JSON_OBJECT;
+       if (Key != NULL)
+               Ret->Name = NewStrBufPlain(Key, keylen);
+       Ret->SubValues = NewHash(1, NULL);
+       return Ret;
+}
+
+JsonValue *NewJsonArray(const char *Key, long keylen)
+{
+       JsonValue *Ret;
+
+       Ret = (JsonValue*) malloc(sizeof(JsonValue));
+       memset(Ret, 0, sizeof(JsonValue));
+       Ret->Type = JSON_ARRAY;
+       if (Key != NULL)
+               Ret->Name = NewStrBufPlain(Key, keylen);
+       Ret->SubValues = NewHash(1, Flathash);
+       return Ret;
+}
+
+
+JsonValue *NewJsonNumber(const char *Key, long keylen, long Number)
+{
+       JsonValue *Ret;
+
+       Ret = (JsonValue*) malloc(sizeof(JsonValue));
+       memset(Ret, 0, sizeof(JsonValue));
+       Ret->Type = JSON_NUM;
+       if (Key != NULL)
+               Ret->Name = NewStrBufPlain(Key, keylen);
+       Ret->Value = NewStrBufPlain(NULL, 64);
+       StrBufPrintf(Ret->Value, "%ld", Number);
+       return Ret;
+}
+
+
+
+JsonValue *NewJsonBigNumber(const char *Key, long keylen, double Number)
+{
+       JsonValue *Ret;
+
+       Ret = (JsonValue*) malloc(sizeof(JsonValue));
+       memset(Ret, 0, sizeof(JsonValue));
+       Ret->Type = JSON_NUM;
+       if (Key != NULL)
+               Ret->Name = NewStrBufPlain(Key, keylen);
+       Ret->Value = NewStrBufPlain(NULL, 128);
+       StrBufPrintf(Ret->Value, "%f", Number);
+       return Ret;
+}
+
+JsonValue *NewJsonString(const char *Key, long keylen, StrBuf *CopyMe)
+{
+       JsonValue *Ret;
+
+       Ret = (JsonValue*) malloc(sizeof(JsonValue));
+       memset(Ret, 0, sizeof(JsonValue));
+       Ret->Type = JSON_STRING;
+       if (Key != NULL)
+               Ret->Name = NewStrBufPlain(Key, keylen);
+       Ret->Value = NewStrBufDup(CopyMe);
+       return Ret;
+}
+
+JsonValue *NewJsonPlainString(const char *Key, long keylen, const char *CopyMe, long len)
+{
+       JsonValue *Ret;
+
+       Ret = (JsonValue*) malloc(sizeof(JsonValue));
+       memset(Ret, 0, sizeof(JsonValue));
+       Ret->Type = JSON_STRING;
+       if (Key != NULL)
+               Ret->Name = NewStrBufPlain(Key, keylen);
+       Ret->Value = NewStrBufPlain(CopyMe, len);
+       return Ret;
+}
+
+JsonValue *NewJsonNull(const char *Key, long keylen)
+{
+       JsonValue *Ret;
+
+       Ret = (JsonValue*) malloc(sizeof(JsonValue));
+       memset(Ret, 0, sizeof(JsonValue));
+       Ret->Type = JSON_NULL;
+       if (Key != NULL)
+               Ret->Name = NewStrBufPlain(Key, keylen);
+       Ret->Value = NewStrBufPlain(HKEY("nulll"));
+       return Ret;
+}
+
+JsonValue *NewJsonBool(const char *Key, long keylen, int value)
+{
+       JsonValue *Ret;
+
+       Ret = (JsonValue*) malloc(sizeof(JsonValue));
+       memset(Ret, 0, sizeof(JsonValue));
+       Ret->Type = JSON_BOOL;
+       if (Key != NULL)
+               Ret->Name = NewStrBufPlain(Key, keylen);
+       if (value)
+               Ret->Value = NewStrBufPlain(HKEY("true"));
+       else
+               Ret->Value = NewStrBufPlain(HKEY("false"));
+       return Ret;
+}
+
+void JsonArrayAppend(JsonValue *Array, JsonValue *Val)
+{
+       long n;
+       if (Array->Type != JSON_ARRAY)
+               return; /* todo assert! */
+
+       n = GetCount(Array->SubValues);
+       Put(Array->SubValues, (const char*) &n, sizeof(n), Val, DeleteJSONValue);
+}
+
+void JsonObjectAppend(JsonValue *Array, JsonValue *Val)
+{
+       if ((Array->Type != JSON_OBJECT) || (Val->Name == NULL))
+               return; /* todo assert! */
+
+       Put(Array->SubValues, SKEY(Val->Name), Val, DeleteJSONValue);
+}
+
+
+
+
+
+void SerializeJson(StrBuf *Target, JsonValue *Val)
+{
+       void *vValue, *vPrevious;
+       JsonValue *SubVal;
+       HashPos *It;
+       const char *Key;
+       long keylen;
+
+
+       switch (Val->Type) {
+       case JSON_STRING:
+               StrBufAppendBufPlain(Target, HKEY("\""), 0);
+               StrECMAEscAppend(Target, Val->Value, NULL);
+               StrBufAppendBufPlain(Target, HKEY("\""), 0);
+               break;
+       case JSON_NUM:
+               StrBufAppendBuf(Target, Val->Value, 0);
+               break;
+       case JSON_BOOL:
+               StrBufAppendBuf(Target, Val->Value, 0);
+               break;
+       case JSON_NULL:
+               StrBufAppendBuf(Target, Val->Value, 0);
+               break;
+       case JSON_ARRAY:
+               vPrevious = NULL;
+               StrBufAppendBufPlain(Target, HKEY("["), 0);
+               It = GetNewHashPos(Val->SubValues, 0);
+               while (GetNextHashPos(Val->SubValues, 
+                                     It,
+                                     &keylen, &Key, 
+                                     &vValue)){
+                       if (vPrevious != NULL) 
+                               StrBufAppendBufPlain(Target, HKEY(","), 0);
+
+                       SubVal = (JsonValue*) vValue;
+                       SerializeJson(Target, SubVal);
+                       vPrevious = vValue;
+               }
+               StrBufAppendBufPlain(Target, HKEY("]"), 0);
+               break;
+       case JSON_OBJECT:
+               vPrevious = NULL;
+               StrBufAppendBufPlain(Target, HKEY("{"), 0);
+               It = GetNewHashPos(Val->SubValues, 0);
+               while (GetNextHashPos(Val->SubValues, 
+                                     It,
+                                     &keylen, &Key, 
+                                     &vValue)){
+                       SubVal = (JsonValue*) vValue;
+
+                       if (vPrevious != NULL) {
+                               StrBufAppendBufPlain(Target, HKEY(","), 0);
+                       }
+                       StrBufAppendBufPlain(Target, HKEY("\""), 0);
+                       StrBufAppendBuf(Target, SubVal->Name, 0);
+                       StrBufAppendBufPlain(Target, HKEY("\":"), 0);
+
+                       SerializeJson(Target, SubVal);
+                       vPrevious = vValue;
+               }
+               StrBufAppendBufPlain(Target, HKEY("}"), 0);
+               break;
+       }
+
+}
+
+
index 78b3e68ea430bd94d4133f4216087e69355ba7f4..a20bf1a1d9ec454b98feed75acaa8d6e43e0208d 100644 (file)
@@ -454,4 +454,81 @@ char *vnote_serialize(struct vnote *v);
 void vnote_serialize_output_field(char *append_to, char *field, char *label);
 
 
+
+
+/*
+ * Create JSON style structures in C plus serialize them to one string
+ */
+
+typedef struct JsonValue JsonValue;
+
+
+void DeleteJSONValue(void *vJsonValue);
+
+JsonValue *NewJsonObject(const char *Key, long keylen);
+
+JsonValue *NewJsonArray(const char *Key, long keylen);
+
+JsonValue *NewJsonNumber(const char *Key, long keylen, long Number);
+
+JsonValue *NewJsonBigNumber(const char *Key, long keylen, double Number);
+
+JsonValue *NewJsonString(const char *Key, long keylen, StrBuf *CopyMe);
+
+JsonValue *NewJsonPlainString(const char *Key, long keylen, const char *CopyMe, long len);
+
+JsonValue *NewJsonNull(const char *Key, long keylen);
+
+JsonValue *NewJsonBool(const char *Key, long keylen, int value);
+
+void JsonArrayAppend(JsonValue *Array, JsonValue *Val);
+
+void JsonObjectAppend(JsonValue *Array, JsonValue *Val);
+
+void SerializeJson(StrBuf *Target, JsonValue *Val);
+
+
+
+/*
+ * Citadels Wildfire implementation, see 
+ * http://www.firephp.org/Wiki/Reference/Protocol
+ * and http://wildfirehq.org/ for details
+ */
+typedef void (*AddHeaderFunc)(const char *HdrName, const char *HdrValue);
+
+typedef enum _WF_MessageType {
+       eLOG, 
+       eINFO,
+       eWARN,
+       eERROR,
+       eTRACE,
+       eEXCEPTION
+} WF_MessageType;
+
+JsonValue *WildFireException(StrBuf *Message,
+                            const char *Filename, long FileLen,
+                            long LineNo,
+                            int StackOffset);
+
+void WildFireAddArray(JsonValue *ReportBase, JsonValue *Array, WF_MessageType Type);
+
+JsonValue *WildFireMessagePlain(const char *Filename, long fnlen,
+                                  long LineNo,
+                                  const char *Message, long len, 
+                                  WF_MessageType Type);
+
+JsonValue *WildFireMessage(const char *Filename, long fnlen,
+                          long lineno,
+                          StrBuf *Msg, 
+                          WF_MessageType Type);
+
+void WildFireInitBacktrace(const char *argvNull, int AddBaseFrameSkip);
+
+void WildFireSerializePayload(StrBuf *JsonBuffer, StrBuf *OutBuf, int *MsgCount, AddHeaderFunc AddHdr);
+
+#define WF_MAJOR "1"
+#define WF_STRUCTINDEX "1"
+#define WF_SUB "1"
+
+
 #endif // LIBCITADEL_H
diff --git a/libcitadel/lib/wildfire.c b/libcitadel/lib/wildfire.c
new file mode 100644 (file)
index 0000000..9fe53fa
--- /dev/null
@@ -0,0 +1,513 @@
+/*
+ * $Id: wildfire.c 6962 2009-01-18 19:33:45Z dothebart $
+ */
+
+/*@{*/
+
+#include "sysdep.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+
+#if HAVE_BACKTRACE
+#include <execinfo.h>
+#endif
+
+#include "libcitadel.h"
+
+
+
+ConstStr WF_MsgStrs[] = {
+       {HKEY("INFO")},
+       {HKEY("WARN")},
+       {HKEY("ERROR")},
+       {HKEY("LOG")},
+       {HKEY("TRACE")},
+       {HKEY("EXCEPTION")}
+};
+
+static JsonValue *WFInfo(const char *Filename, long fnlen,
+                        long LineNo, 
+                        WF_MessageType Type)
+{
+       JsonValue *Val;
+
+       Val = NewJsonObject(NULL, 0);
+       JsonObjectAppend(Val, 
+                        NewJsonPlainString(HKEY("Type"),
+                                           WF_MsgStrs[Type].Key, 
+                                           WF_MsgStrs[Type].len));
+       JsonObjectAppend(Val, 
+                        NewJsonPlainString(HKEY("File"), 
+                                           Filename, fnlen));
+       JsonObjectAppend(Val, 
+                        NewJsonNumber(HKEY("Line"), LineNo));
+       return Val;
+}
+                           
+
+JsonValue *WildFireMessage(const char *Filename, long fnlen,
+                          long LineNo,
+                          StrBuf *Msg, 
+                          WF_MessageType Type)
+{
+       JsonValue *Ret;
+
+       Ret = NewJsonArray(NULL, 0);
+       JsonArrayAppend(Ret, WFInfo(Filename, fnlen,
+                                   LineNo, Type));
+
+       JsonArrayAppend(Ret, 
+                       NewJsonString(NULL, 0, Msg));
+       return Ret;
+}
+
+JsonValue *WildFireMessagePlain(const char *Filename, long fnlen,
+                               long LineNo,
+                               const char *Message, long len, 
+                               WF_MessageType Type)
+{
+       JsonValue *Val;
+       Val = NewJsonArray(NULL, 0);
+
+       JsonArrayAppend(Val, WFInfo(Filename, fnlen,
+                                   LineNo, Type));
+       JsonArrayAppend(Val, 
+                       NewJsonPlainString(NULL, 0, Message, len));
+       return Val;
+}
+
+void WildFireAddArray(JsonValue *ReportBase, JsonValue *Array, WF_MessageType Type)
+{
+       JsonValue *Val;
+       Val = NewJsonArray(NULL, 0);
+       JsonArrayAppend(Val, 
+                       NewJsonPlainString(NULL, 0, 
+                                          WF_MsgStrs[Type].Key, 
+                                          WF_MsgStrs[Type].len));
+
+       JsonArrayAppend(Val, Array);
+}
+
+int addr2line_write_pipe[2];
+int addr2line_read_pipe[2];
+pid_t addr2line_pid;
+
+#ifdef HAVE_BACKTRACE
+/* 
+ * Start up the addr2line daemon so we can decode function pointers
+ */
+static void start_addr2line_daemon(const char *binary) 
+{
+       struct stat filestats;
+       int i;
+       const char *addr2line = "/usr/bin/addr2line";
+       const char minuse[] = "-e";
+
+       printf("Starting addr2line daemon for decoding of backtraces\n");
+
+       if ((stat(addr2line, &filestats)==-1) ||
+           (filestats.st_size==0)){
+               printf("didn't find addr2line daemon in %s: %s\n", addr2line, strerror(errno));
+               abort();
+       }
+       if (pipe(addr2line_write_pipe) != 0) {
+               printf("Unable to create pipe for addr2line daemon: %s\n", strerror(errno));
+               abort();
+       }
+       if (pipe(addr2line_read_pipe) != 0) {
+               printf("Unable to create pipe for addr2line daemon: %s\n", strerror(errno));
+               abort();
+       }
+
+       addr2line_pid = fork();
+       if (addr2line_pid < 0) {
+               printf("Unable to fork addr2line daemon: %s\n", strerror(errno));
+               abort();
+       }
+       if (addr2line_pid == 0) {
+               dup2(addr2line_write_pipe[0], 0);
+               dup2(addr2line_read_pipe[1], 1);
+               for (i=2; i<256; ++i) close(i);
+               execl(addr2line, addr2line, minuse, binary, NULL);
+               printf("Unable to exec addr2line daemon: %s\n", strerror(errno));
+               abort();
+               exit(errno);
+       }
+}
+
+static int addr2lineBacktrace(StrBuf *Function, 
+                             StrBuf *FileName, 
+                             StrBuf *Pointer, 
+                             StrBuf *Buf,
+                             unsigned int *FunctionLine)
+
+{
+       const char *err;
+       const char *pch, *pche;
+
+       write(addr2line_write_pipe[1], SKEY(Pointer));
+       if (StrBufTCP_read_line(Buf, &addr2line_read_pipe[0], 0, &err) <= 0)
+       {
+               StrBufAppendBufPlain(Buf, err, -1, 0);
+               return 0;
+       }
+       pch = ChrPtr(Buf);
+       pche = strchr(pch, ':');
+       FlushStrBuf(FileName);
+       StrBufAppendBufPlain(FileName, pch, pche - pch, 0);
+       pche++;
+       *FunctionLine = atoi(pche);
+
+       return 1;
+}
+
+static int ParseBacktrace(char *Line, 
+                         StrBuf *Function, 
+                         StrBuf *FileName, 
+                         unsigned int *FunctionLine)
+{
+       char *pch, *pche;
+
+       pch = Line;
+       pche = strchr(pch, '(');
+       if (pche == NULL) return 0;
+       StrBufAppendBufPlain(FileName, pch, pche - pch, 0);
+       pch = pche + 1;
+       pche = strchr(pch, '+');
+       if (pche == NULL) return 0;
+       StrBufAppendBufPlain(Function, pch, pche - pch, 0);
+       pch = pche + 1;
+       pche = strchr(pch, ')');
+       if (pche == NULL) return 0;
+       *pche = '\0';
+       sscanf(pch, "%x", FunctionLine);
+       StrBufAppendBufPlain(Function, pche + 1, -1, 0);
+       return 1;
+}
+#endif
+long BaseFrames = 0;
+StrBuf *FullBinaryName = NULL;
+
+void WildFireInitBacktrace(const char *argvNull, int AddBaseFrameSkip)
+{
+
+#ifdef HAVE_BACKTRACE
+       void *stack_frames[100];
+       size_t size;
+       long i;
+       char **strings;
+       StrBuf *FileName;
+       StrBuf *Function;
+       StrBuf *Pointer;
+       StrBuf *Buf;
+       unsigned int FunctionLine;
+       struct stat filestats;
+
+       FileName = NewStrBuf();
+       Function = NewStrBuf();
+       Pointer = NewStrBuf();
+       Buf = NewStrBuf();
+
+       BaseFrames = size = backtrace(stack_frames, sizeof(stack_frames) / sizeof(void*));
+       BaseFrames --;
+       BaseFrames += AddBaseFrameSkip;
+       strings = backtrace_symbols(stack_frames, size);
+       for (i = 0; i < size; i++) {
+               if (strings != NULL){
+                       ParseBacktrace(strings[i], Function, 
+                                      FileName, 
+                                      &FunctionLine);
+                       FullBinaryName = NewStrBufDup(FileName);
+                       size = i;
+               }
+               else {
+                       char path[256];
+                       getcwd(path, sizeof(path));
+                       FullBinaryName = NewStrBufPlain(path, -1);
+                       StrBufAppendBufPlain(FullBinaryName, HKEY("/"), 0);
+                       StrBufAppendBufPlain(FullBinaryName, argvNull, -1, 0);
+                       i = size;
+                }
+       }
+       if ((stat(ChrPtr(FullBinaryName), &filestats)==-1) ||
+           (filestats.st_size==0)){
+               FlushStrBuf(FullBinaryName);
+               StrBufAppendBufPlain(FullBinaryName, argvNull, -1, 0);
+               if ((stat(ChrPtr(FullBinaryName), &filestats)==-1) ||
+                   (filestats.st_size==0)){
+                       FlushStrBuf(FullBinaryName);
+                       fprintf(stderr, "unable to open my binary for addr2line checking, verbose backtraces won't work.\n");
+               }
+       }
+       free(strings);
+       FreeStrBuf(&FileName);
+       FreeStrBuf(&Function);
+       FreeStrBuf(&Pointer);
+       FreeStrBuf(&Buf);
+       if (StrLength(FullBinaryName) > 0)
+               start_addr2line_daemon(ChrPtr(FullBinaryName));
+#endif
+
+
+}
+
+
+JsonValue *WildFireException(StrBuf *Message,
+                            const char *Filename, long FileLen,
+                            long LineNo,
+                            int StackOffset)
+{
+       JsonValue *ExcClass;
+       JsonValue *Val;
+       Val = NewJsonArray(NULL, 0);
+
+       JsonArrayAppend(Val, WFInfo(Filename, FileLen,
+                                   LineNo, eEXCEPTION));
+
+       ExcClass = NewJsonObject(WF_MsgStrs[eTRACE].Key, 
+                                WF_MsgStrs[eTRACE].len);
+       
+       JsonArrayAppend(Val, ExcClass);
+       JsonObjectAppend(ExcClass, 
+                        NewJsonPlainString(HKEY("Class"), 
+                                           HKEY("Exception")));
+       JsonObjectAppend(ExcClass, 
+                        NewJsonString(HKEY("Message"), Message));
+       JsonObjectAppend(ExcClass, 
+                        NewJsonPlainString(HKEY("File"), 
+                                           Filename, FileLen));
+/*
+       JsonObjectAppend(ExcClass, 
+                        NewJsonPlainString(HKEY("Type"), 
+                                           HKEY("throw")));
+*/
+       JsonObjectAppend(ExcClass, 
+                        NewJsonNumber(HKEY("Line"), LineNo));
+
+#ifdef HAVE_BACKTRACE
+       {
+               void *stack_frames[100];
+               size_t size;
+               long i;
+               char **strings;
+               JsonValue *Trace;
+               JsonValue *Frame;
+               StrBuf *FileName;
+               StrBuf *Function;
+               StrBuf *Pointer;
+               StrBuf *Buf;
+               unsigned int FunctionLine;
+
+               Trace = NewJsonArray(HKEY("Trace"));
+               JsonObjectAppend(ExcClass, Trace);
+               FileName = NewStrBuf();
+               Function = NewStrBuf();
+               Pointer = NewStrBuf();
+               Buf = NewStrBuf();
+
+               size = backtrace(stack_frames, sizeof(stack_frames) / sizeof(void*));
+               strings = backtrace_symbols(stack_frames, size);
+               for (i = StackOffset + 1; i < size; i++) {
+                       if (strings != NULL){
+                               ParseBacktrace(strings[i], Function, 
+                                              FileName,
+                                              &FunctionLine);
+                               
+                       }
+                       StrBufPrintf(Pointer, "%p\n", stack_frames[i]);
+                       
+                       addr2lineBacktrace(Function, 
+                                          FileName, 
+                                          Pointer, 
+                                          Buf, 
+                                          &FunctionLine);
+
+                       Frame = NewJsonObject(NULL, 0);
+                       JsonArrayAppend(Trace, Frame);
+                       JsonObjectAppend(Frame, 
+                                        NewJsonString(HKEY("function"), Function));
+                       JsonObjectAppend(Frame, 
+                                        NewJsonString(HKEY("file"), FileName));
+                       JsonObjectAppend(Frame, 
+                                        NewJsonNumber(HKEY("line"), FunctionLine));
+                       JsonObjectAppend(Frame, 
+                                        NewJsonArray(HKEY("args")));/* not supportet... */
+
+                       FunctionLine = 0;
+                       FlushStrBuf(FileName);
+                       FlushStrBuf(Function);
+                       FlushStrBuf(Pointer);
+               }
+               free(strings);
+               FreeStrBuf(&FileName);
+               FreeStrBuf(&Function);
+               FreeStrBuf(&Pointer);
+               FreeStrBuf(&Buf);
+       }
+#endif
+       return Val;
+}
+
+void WildFireSerializePayload(StrBuf *JsonBuffer, StrBuf *OutBuf, int *MsgCount, AddHeaderFunc AddHdr)
+{
+       int n = *MsgCount;
+       StrBuf *Buf;
+       StrBuf *HeaderName;
+       StrBuf *N; 
+       const char Concatenate[] = "\\";
+       const char empty[] = "";
+       const char *Cat;
+       StrBuf *Header;
+
+       if (*MsgCount == 0) {
+               if (OutBuf != NULL) {
+                       StrBufAppendBufPlain(OutBuf, 
+                                            HKEY( 
+                                                    "X-Wf-Protocol-1" 
+                                                    ": "
+                                                    "http://meta.wildfirehq.org/Protocol/JsonStream/0.2\r\n"), 0);
+                       StrBufAppendBufPlain(OutBuf, 
+                                            HKEY( 
+                                                    "X-Wf-1-Plugin-1" 
+                                                    ": " 
+                                                    "http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.2.0\r\n"), 0);
+                       StrBufAppendBufPlain(OutBuf, 
+                                            HKEY(
+                                                    "X-Wf-1-Structure-1"
+                                                    ": "
+                                                    "http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1\r\n"), 0);
+               }
+               else {
+                       Header = NewStrBuf();
+                       AddHdr("X-Wf-Protocol-1", 
+                              "http://meta.wildfirehq.org/Protocol/JsonStream/0.2");
+                       AddHdr("X-Wf-1-Plugin-1",
+                              "http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.2.0");
+                       AddHdr("X-Wf-1-Structure-1",
+                              "http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1");
+               }
+       }
+
+       N = NewStrBuf();
+       StrBufPrintf(N, "%d", StrLength(JsonBuffer));
+       Buf = NewStrBufPlain(NULL, 1024);
+       HeaderName = NewStrBuf();
+
+       while (StrLength(JsonBuffer) > 0) {
+               FlushStrBuf(Buf);
+               StrBufPrintf(HeaderName, "X-Wf-"WF_MAJOR"-"WF_STRUCTINDEX"-"WF_SUB"-%d", n);
+               if (StrLength(JsonBuffer) > 800) {
+                       StrBufAppendBufPlain(Buf, ChrPtr(JsonBuffer), 800, 0);
+                       StrBufCutLeft(JsonBuffer, 800);
+                       Cat = Concatenate;
+               }
+               else {
+                       StrBufAppendBuf(Buf, JsonBuffer, 0);
+                       FlushStrBuf(JsonBuffer);
+                       Cat = empty;
+               }
+               if (OutBuf != NULL) {
+                       StrBufAppendPrintf(OutBuf, 
+                                          "%s: %s|%s|%s\r\n", 
+                                          ChrPtr(HeaderName), 
+                                          ChrPtr(N),
+                                          ChrPtr(Buf), 
+                                          Cat);
+               }
+               else {
+                       StrBufAppendPrintf(Header, 
+                                          "%s|%s|%s", 
+                                          ChrPtr(N),
+                                          ChrPtr(Buf), 
+                                          Cat);
+                       AddHdr(ChrPtr(HeaderName), ChrPtr(Header));
+                       
+               }
+
+               FlushStrBuf(N);
+               n++;
+       }
+       *MsgCount = n;
+       if (OutBuf == NULL) {
+               FreeStrBuf(&Header);
+       }
+}
+
+
+
+
+
+
+/* this is how we do it...
+void CreateWildfireSampleMessage(void)
+{
+       JsonValue *Error;
+               
+       StrBuf *Buf;
+       StrBuf *Header;
+       StrBuf *Json;
+       int n = 1;
+
+       Header = NewStrBuf();
+       Json = NewStrBuf();
+
+       Error = WildFireMessagePlain(HKEY(__FILE__), __LINE__, HKEY("Info message"), eINFO);
+       SerializeJson(Json, Error);
+       WildFireSerializePayload(Json, Header, &n, NULL);
+       StrBufAppendBuf(WC->HBuf, Header, 0);
+       DeleteJSONValue(Error);
+       FlushStrBuf(Json);
+       FlushStrBuf(Header);
+
+       Error = WildFireMessagePlain(HKEY(__FILE__), __LINE__,  HKEY("Warn message"), eWARN);
+       SerializeJson(Json, Error);
+       WildFireSerializePayload(Json, Header, &n, NULL);
+       StrBufAppendBuf(WC->HBuf, Header, 0);
+       DeleteJSONValue(Error);
+       FlushStrBuf(Json);
+       FlushStrBuf(Header);
+
+       Error = WildFireMessagePlain(HKEY(__FILE__), __LINE__, HKEY("Error message"), eERROR);
+       SerializeJson(Json, Error);
+       WildFireSerializePayload(Json, Header, &n, NULL);
+       StrBufAppendBuf(WC->HBuf, Header, 0);
+       DeleteJSONValue(Error);
+       FlushStrBuf(Json);
+       FlushStrBuf(Header);
+
+       Error = WildFireMessagePlain(HKEY(__FILE__), __LINE__, HKEY("Info message"), eINFO);
+       SerializeJson(Json, Error);
+       WildFireSerializePayload(Json, Header, &n, NULL);
+       StrBufAppendBuf(WC->HBuf, Header, 0);
+       DeleteJSONValue(Error);
+       FlushStrBuf(Json);
+       FlushStrBuf(Header);
+
+       Error = WildFireMessagePlain(HKEY(__FILE__), __LINE__, HKEY("Info message"), eINFO);
+       SerializeJson(Json, Error);
+       WildFireSerializePayload(Json, Header, &n, NULL);
+       StrBufAppendBuf(WC->HBuf, Header, 0);
+       DeleteJSONValue(Error);
+       FlushStrBuf(Json);
+       FlushStrBuf(Header);
+
+
+       Buf = NewStrBufPlain(HKEY("test error message"));
+       Error = WildFireException(Buf, HKEY(__FILE__), __LINE__, 1);
+       SerializeJson(Json, Error);
+       WildFireSerializePayload(Json, Header, &n, NULL);
+       StrBufAppendBuf(WC->HBuf, Header, 0);
+       DeleteJSONValue(Error);
+
+       FlushStrBuf(Json);
+       FlushStrBuf(Header);
+
+}
+
+*/