[Opensrf-commits] SPAM: r1121 - in branches/autotools: . bin examples examples/math_xul_client/math/content include/objson include/opensrf src src/c-apps src/gateway src/java src/java/org/opensrf src/java/org/opensrf/net/xmpp src/java/org/opensrf/test src/java/org/opensrf/util src/javascript src/jserver src/libopensrf src/objson src/perlmods/OpenSRF src/perlmods/OpenSRF/DomainObject src/perlmods/OpenSRF/Utils src/python src/python/osrf src/router src/srfsh

svn at svn.open-ils.org svn at svn.open-ils.org
Mon Nov 5 08:55:42 EST 2007


Author: asmodai
Date: 2007-11-05 08:40:16 -0500 (Mon, 05 Nov 2007)
New Revision: 1121

Added:
   branches/autotools/include/opensrf/osrf_json.h
   branches/autotools/include/opensrf/osrf_json_utils.h
   branches/autotools/include/opensrf/osrf_json_xml.h
   branches/autotools/include/opensrf/osrf_legacy_json.h
   branches/autotools/src/java/org/opensrf/test/TestLog.java
   branches/autotools/src/java/org/opensrf/test/TestThread.java
   branches/autotools/src/java/org/opensrf/util/FileLogger.java
   branches/autotools/src/java/org/opensrf/util/Logger.java
   branches/autotools/src/javascript/JSON_v0.js
   branches/autotools/src/javascript/JSON_v1.js
   branches/autotools/src/libopensrf/Makefile.json
   branches/autotools/src/libopensrf/osrf_json_object.c
   branches/autotools/src/libopensrf/osrf_json_parser.c
   branches/autotools/src/libopensrf/osrf_json_test.c
   branches/autotools/src/libopensrf/osrf_json_tools.c
   branches/autotools/src/libopensrf/osrf_json_xml.c
   branches/autotools/src/libopensrf/osrf_legacy_json.c
Removed:
   branches/autotools/src/javascript/JSON.js
Modified:
   branches/autotools/
   branches/autotools/Makefile
   branches/autotools/bin/osrf_ctl.sh
   branches/autotools/examples/math_xul_client/math/content/math.xul
   branches/autotools/examples/opensrf.xml.example
   branches/autotools/examples/opensrf_core.xml.example
   branches/autotools/examples/srfsh.xml.example
   branches/autotools/include/objson/json2xml.h
   branches/autotools/include/objson/json_parser.h
   branches/autotools/include/objson/object.h
   branches/autotools/include/objson/xml2json.h
   branches/autotools/include/opensrf/osrfConfig.h
   branches/autotools/include/opensrf/osrf_app_session.h
   branches/autotools/include/opensrf/osrf_application.h
   branches/autotools/include/opensrf/osrf_cache.h
   branches/autotools/include/opensrf/osrf_message.h
   branches/autotools/include/opensrf/osrf_settings.h
   branches/autotools/include/opensrf/string_array.h
   branches/autotools/include/opensrf/utils.h
   branches/autotools/include/opensrf/xml_utils.h
   branches/autotools/install.conf
   branches/autotools/src/Makefile
   branches/autotools/src/c-apps/Makefile
   branches/autotools/src/c-apps/osrf_dbmath.c
   branches/autotools/src/c-apps/osrf_math.c
   branches/autotools/src/c-apps/osrf_version.c
   branches/autotools/src/gateway/Makefile
   branches/autotools/src/gateway/apachetools.c
   branches/autotools/src/gateway/osrf_json_gateway.c
   branches/autotools/src/java/Makefile
   branches/autotools/src/java/org/opensrf/ClientSession.java
   branches/autotools/src/java/org/opensrf/MethodException.java
   branches/autotools/src/java/org/opensrf/Request.java
   branches/autotools/src/java/org/opensrf/Session.java
   branches/autotools/src/java/org/opensrf/Sys.java
   branches/autotools/src/java/org/opensrf/net/xmpp/XMPPReader.java
   branches/autotools/src/java/org/opensrf/net/xmpp/XMPPSession.java
   branches/autotools/src/java/org/opensrf/test/TestClient.java
   branches/autotools/src/java/org/opensrf/util/OSRFObject.java
   branches/autotools/src/jserver/Makefile
   branches/autotools/src/jserver/osrf_chat.c
   branches/autotools/src/libopensrf/Makefile
   branches/autotools/src/libopensrf/basic_client.c
   branches/autotools/src/libopensrf/log.c
   branches/autotools/src/libopensrf/opensrf.c
   branches/autotools/src/libopensrf/osrf_app_session.c
   branches/autotools/src/libopensrf/osrf_application.c
   branches/autotools/src/libopensrf/osrf_cache.c
   branches/autotools/src/libopensrf/osrf_hash.c
   branches/autotools/src/libopensrf/osrf_message.c
   branches/autotools/src/libopensrf/osrf_prefork.c
   branches/autotools/src/libopensrf/osrf_settings.c
   branches/autotools/src/libopensrf/osrf_stack.c
   branches/autotools/src/libopensrf/osrf_system.c
   branches/autotools/src/libopensrf/osrf_transgroup.c
   branches/autotools/src/libopensrf/sha.c
   branches/autotools/src/libopensrf/socket_bundle.c
   branches/autotools/src/libopensrf/string_array.c
   branches/autotools/src/libopensrf/transport_client.c
   branches/autotools/src/libopensrf/transport_message.c
   branches/autotools/src/libopensrf/transport_session.c
   branches/autotools/src/libopensrf/utils.c
   branches/autotools/src/objson/json_parser.c
   branches/autotools/src/objson/objson_test.c
   branches/autotools/src/perlmods/OpenSRF/AppSession.pm
   branches/autotools/src/perlmods/OpenSRF/Application.pm
   branches/autotools/src/perlmods/OpenSRF/DomainObject/oilsMessage.pm
   branches/autotools/src/perlmods/OpenSRF/DomainObject/oilsResponse.pm
   branches/autotools/src/perlmods/OpenSRF/Transport.pm
   branches/autotools/src/perlmods/OpenSRF/UnixServer.pm
   branches/autotools/src/perlmods/OpenSRF/Utils/JSON.pm
   branches/autotools/src/perlmods/OpenSRF/Utils/Logger.pm
   branches/autotools/src/python/osrf/gateway.py
   branches/autotools/src/python/osrf/json.py
   branches/autotools/src/python/osrf/log.py
   branches/autotools/src/python/osrf/net.py
   branches/autotools/src/python/osrf/net_obj.py
   branches/autotools/src/python/osrf/ses.py
   branches/autotools/src/python/osrf/stack.py
   branches/autotools/src/python/osrf/system.py
   branches/autotools/src/python/srfsh.py
   branches/autotools/src/router/Makefile
   branches/autotools/src/router/osrf_router.c
   branches/autotools/src/srfsh/Makefile
   branches/autotools/src/srfsh/srfsh.c
Log:
Merged revisions 1045-1120 via svnmerge.



Property changes on: branches/autotools
___________________________________________________________________
Name: svnmerge-integrated
   - /trunk:1-1044
   + /trunk:1-1120

Modified: branches/autotools/Makefile
===================================================================
--- branches/autotools/Makefile	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/Makefile	2007-11-05 13:40:16 UTC (rev 1121)
@@ -14,6 +14,9 @@
 jserver-install:
 	source install.conf && make -s -C src jserver-install
 
+javascript-install:
+	source install.conf && make -s -C src javascript-install
+
 clean:
 	make -s -C src clean
 

Modified: branches/autotools/bin/osrf_ctl.sh
===================================================================
--- branches/autotools/bin/osrf_ctl.sh	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/bin/osrf_ctl.sh	2007-11-05 13:40:16 UTC (rev 1121)
@@ -12,9 +12,17 @@
 
 function usage {
 	echo "";
-	echo "usage: $0 -d <pid_dir> -c <c_config> -a <action>";
+	echo "usage: $0 [OPTION]... -c <c_config> -a <action>";
 	echo "";
-	echo "Actions include:"
+	echo "Mandatory parameters:";
+	echo -e "  -a\t\taction to perform";
+	echo -e "  -c\t\tfull path to C configuration file (opensrf_core.xml)";
+	echo "";
+	echo "Optional parameters:";
+	echo -e "  -d\t\tstore PID files in this directory";
+	echo -e "  -l\t\taccept 'localhost' as the fully-qualified domain name";
+	echo "";
+	echo "Actions include:";
 	echo -e "\tstart_router"
 	echo -e "\tstop_router"
 	echo -e "\trestart_router"
@@ -31,9 +39,10 @@
 	echo -e "\tstart_all"
 	echo -e "\trestart_all"
 	echo "";
-    echo "Example:";
-    echo "  $0 -c opensrf_core.xml -a restart_all";
-    echo "";
+	echo "Examples:";
+	echo "  $0 -c opensrf_core.xml -a restart_all";
+	echo "  $0 -l -c opensrf_core.xml -a restart_all";
+	echo "";
 	exit;
 }
 
@@ -41,11 +50,12 @@
 # ---------------------------------------------------------------------------
 # Load the command line options and set the global vars
 # ---------------------------------------------------------------------------
-while getopts  "c:a:d:h" flag; do
+while getopts  "c:a:d:lh" flag; do
 	case $flag in	
 		"a")		OPT_ACTION="$OPTARG";;
 		"c")		OPT_CONFIG="$OPTARG";;
 		"d")		OPT_PID_DIR="$OPTARG";;
+		"l")		export OSRF_HOSTNAME="localhost";;
 		"h"|*)	usage;;
 	esac;
 done

Modified: branches/autotools/examples/math_xul_client/math/content/math.xul
===================================================================
--- branches/autotools/examples/math_xul_client/math/content/math.xul	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/examples/math_xul_client/math/content/math.xul	2007-11-05 13:40:16 UTC (rev 1121)
@@ -16,7 +16,7 @@
 
 	<!-- OpenSRF -->
 	<script>var myPackageDir = "math";</script>
-	<script src="OpenSRF/JSON.js" />
+	<script src="OpenSRF/JSON_v1.js" />
 	<script src="OpenSRF/md5.js" />
 	<script src="OpenSRF/opensrf_utils.js" />
 	<script src="OpenSRF/opensrf_config.js" />

Modified: branches/autotools/examples/opensrf.xml.example
===================================================================
--- branches/autotools/examples/opensrf.xml.example	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/examples/opensrf.xml.example	2007-11-05 13:40:16 UTC (rev 1121)
@@ -175,7 +175,7 @@
 
   <hosts>
 
-    <myhost.mydomain.org>
+    <localhost>
 <!-- ^-=-
 	Must match the fully qualified domain name of the host 
 	on Linux, this is usually the output of "hostname -f"
@@ -200,7 +200,7 @@
 
       </apps>
 
-    </myhost.mydomain.org>
+    </localhost>
 
   </hosts>
 

Modified: branches/autotools/examples/opensrf_core.xml.example
===================================================================
--- branches/autotools/examples/opensrf_core.xml.example	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/examples/opensrf_core.xml.example	2007-11-05 13:40:16 UTC (rev 1121)
@@ -80,11 +80,6 @@
 -->
     <services>
       <service>opensrf.math</service>
-      <service>open-ils.cat</service>
-      <service>open-ils.search</service>
-      <service>open-ils.circ</service>
-      <service>open-ils.actor</service>
-      <service>open-ils.auth</service>
     </services>
 
     <!-- jabber login info -->

Modified: branches/autotools/examples/srfsh.xml.example
===================================================================
--- branches/autotools/examples/srfsh.xml.example	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/examples/srfsh.xml.example	2007-11-05 13:40:16 UTC (rev 1121)
@@ -3,7 +3,7 @@
 <srfsh>
   <router_name>router</router_name>
   <domains>
-    <domain>127.0.0.1</domain>
+    <domain>localhost</domain>
   </domains>
   <username>myusername</username>
   <passwd>mypassword</passwd>

Modified: branches/autotools/include/objson/json2xml.h
===================================================================
--- branches/autotools/include/objson/json2xml.h	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/include/objson/json2xml.h	2007-11-05 13:40:16 UTC (rev 1121)
@@ -1,11 +1,10 @@
+/*
+ * Header to support legacy objson library
+ */
+#ifndef OBJSON_JSON2XML_H
+#define OBJSON_JSON2XML_H
+#include <opensrf/osrf_json.h>
+#include <opensrf/osrf_json_xml.h>
+#include <opensrf/osrf_legacy_json.h>
+#endif
 
-#include <string.h>
-#include <stdio.h>
-
-/* the JSON parser, so we can read the response we're XMLizing */
-#include <objson/object.h>
-#include <objson/json_parser.h>
-#include <opensrf/utils.h>
-
-char* jsonObjectToXML(jsonObject*);
-

Modified: branches/autotools/include/objson/json_parser.h
===================================================================
--- branches/autotools/include/objson/json_parser.h	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/include/objson/json_parser.h	2007-11-05 13:40:16 UTC (rev 1121)
@@ -1,84 +1,9 @@
 /*
-Copyright (C) 2005  Georgia Public Library Service 
-Bill Erickson <highfalutin at gmail.com>
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-*/
-
-
-
-
-/* ---------------------------------------------------------------------------------------
-	JSON parser.
- * --------------------------------------------------------------------------------------- */
-#ifndef JSON_PARSER_H
-#define JSON_PARSER_H
-
-#include <stdio.h>
-#include <ctype.h>
-#include <objson/object.h>
-#include <opensrf/utils.h>
-
-
-
-/* Parses the given JSON string and returns the built object. 
- *	returns NULL (and prints parser error to stderr) on error.  
+ * Header to support legacy objson library
  */
-
-jsonObject* json_parse_string(char* string);
-
-jsonObject* jsonParseString(char* string);
-jsonObject* jsonParseStringFmt( char* string, ... );
-
-jsonObject* json_parse_file( const char* filename );
-
-jsonObject* jsonParseFile( const char* string );
-
-
-
-/* does the actual parsing work.  returns 0 on success.  -1 on error and
- * -2 if there was no object to build (string was all comments) 
- */
-int _json_parse_string(char* string, unsigned long* index, jsonObject* obj, int current_strlen);
-
-/* returns 0 on success and turns obj into a string object */
-int json_parse_json_string(char* string, unsigned long* index, jsonObject* obj, int current_strlen);
-
-/* returns 0 on success and turns obj into a number or double object */
-int json_parse_json_number(char* string, unsigned long* index, jsonObject* obj, int current_strlen);
-
-/* returns 0 on success and turns obj into an 'object' object */
-int json_parse_json_object(char* string, unsigned long* index, jsonObject* obj, int current_strlen);
-
-/* returns 0 on success and turns object into an array object */
-int json_parse_json_array(char* string, unsigned long* index, jsonObject* obj, int current_strlen);
-
-/* churns through whitespace and increments index as it goes.
- * eat_all == true means we should eat newlines, tabs
- */
-void json_eat_ws(char* string, unsigned long* index, int eat_all, int current_strlen);
-
-int json_parse_json_bool(char* string, unsigned long* index, jsonObject* obj, int current_strlen);
-
-/* removes comments from a json string.  if the comment contains a class hint
- * and class_hint isn't NULL, an allocated char* with the class name will be
- * shoved into *class_hint.  returns 0 on success, -1 on parse error.
- * 'index' is assumed to be at the second character (*) of the comment
- */
-int json_eat_comment(char* string, unsigned long* index, char** class_hint, int parse_class, int current_strlen);
-
-/* prints a useful error message to stderr. always returns -1 */
-int json_handle_error(char* string, unsigned long* index, char* err_msg);
-
-int json_parse_json_null(char* string, unsigned long* index, jsonObject* obj, int current_strlen);
-
-
+#ifndef OBJSON_XML2JSON_H
+#define OBJSON_XML2JSON_H
+#include <opensrf/osrf_json.h>
+#include <opensrf/osrf_json_xml.h>
+#include <opensrf/osrf_legacy_json.h>
 #endif

Modified: branches/autotools/include/objson/object.h
===================================================================
--- branches/autotools/include/objson/object.h	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/include/objson/object.h	2007-11-05 13:40:16 UTC (rev 1121)
@@ -1,286 +1,8 @@
 /*
-Copyright (C) 2005  Georgia Public Library Service 
-Bill Erickson <highfalutin at gmail.com>
-
-This program is free software; you can redistribute it and/or
-modify it under the terms of the GNU General Public License
-as published by the Free Software Foundation; either version 2
-of the License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-*/
-
-
-/* ---------------------------------------------------------------------------------------
-	libjson
- * --------------------------------------------------------------------------------------- */
-
-#ifndef _JSON_OBJECT_H
-#define _JSON_OBJECT_H
-
-#include <stdio.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <opensrf/utils.h>
-
-/* json object types */
-#define JSON_HASH 	0
-#define JSON_ARRAY	1
-#define JSON_STRING 	2
-#define JSON_NUMBER 	3
-#define JSON_NULL 	4	
-#define JSON_BOOL 	5
-
-
-/* top level generic object structure */
-struct _jsonObjectStruct {
-
-	/* how many sub-objects do we contain if we're an array or an object.  
-		Note that this includes null array elements in sparse arrays */
-	unsigned long size;
-
-	/* optional class hint */
-	char* classname;
-
-	/* see JSON types above */
-	int type;
-
-
-	/* our cargo */
-	union _jsonObjectValue {
-		struct _jsonObjectNodeStruct* c; /* our list of sub-objects if we're an array or a hash */
-		char* 		s; /* string */
-		int 			b; /* bool */
-		double		n; /* number */
-	} value;
-	
-
-	/* client may provide a comment string which will be 
-	 * added to the object when stringified */
-	char* comment;
-
-};
-typedef struct _jsonObjectStruct jsonObject;
-
-
-/** 
-	String parsing function.  This is assigned by the json_parser code.
-	to avoid circular dependency, declare the parse function here,
- 	and have the json parse code set the variable to a real function 
-*/
-//jsonObject* (*jsonParseString) (char* str);
-
-
-/* this contains a single element of the object along with the elements 
- * index (if this object is an array) and key (if this object is a hash)
+ * Header to support legacy objson library
  */
-struct _jsonObjectNodeStruct {
-
-	unsigned long index; /* our array position */
-	char* key; /* our hash key */
-
-	jsonObject* item; /* our object */
-	struct _jsonObjectNodeStruct* next; /* pointer to the next object node */
-};
-typedef struct _jsonObjectNodeStruct jsonObjectNode;
-
-
-
-/* utility object for iterating over hash objects */
-struct _jsonObjectIteratorStruct {
-	const jsonObject* obj; /* the topic object */
-	jsonObjectNode* current; /* the current node within the object */
-};
-typedef struct _jsonObjectIteratorStruct jsonObjectIterator;
-
-
-/** Allocates a new iterator 
-	@param obj The object over which to iterate.
-*/
-jsonObjectIterator* jsonNewObjectIterator(const jsonObject* obj);
-
-/** 
-	De-allocates an iterator 
-	@param iter The iterator object to free
-*/
-void jsonObjectIteratorFree(jsonObjectIterator* iter);
-
-/** 
-	Returns the object_node currently pointed to by the iterator
-  	and increments the pointer to the next node
-	@param iter The iterator in question.
- */
-jsonObjectNode* jsonObjectIteratorNext(jsonObjectIterator* iter);
-
-/** 
-	@param iter The iterator.
-	@return True if there is another node after the current node.
- */
-int jsonObjectIteratorHasNext(const jsonObjectIterator* iter);
-
-
-/** 
-	Allocates a new object. 
-	@param string The string data if this object is to be a string.  
-	if not, string should be NULL 
-	@return The newly allocated object or NULL on memory error.
-*/
-jsonObject* jsonNewObjectFmt(const char* string, ...);
-jsonObject* jsonNewObject(const char* string);
-
-/**
-	Allocates a new JSON number object.
-	@param num The number this object is to hold
-	@return The newly allocated object.
-*/
-jsonObject* jsonNewNumberObject( double num );
-
-
-/** 
-	Returns a pointer to the object at the given index.  This call is
-	only valid if the object has a type of JSON_ARRAY.
-	@param obj The object
-	@param index The position within the object
-	@return The object at the given index.
-*/
-jsonObject* jsonObjectGetIndex( const jsonObject* obj, unsigned long index );
-
-
-/** 
-	Returns a pointer to the object with the given key 
-	@param obj The object
-	@param key The key
-	@return The object with the given key.
-*/
-jsonObject* jsonObjectGetKey( const jsonObject* obj, const char* key );
-
-/** 
-	De-allocates an object.  Note that this function should only be called 
-	on objects that are _not_ children of other objects or there will be
-	double-free's
-	@param obj The object to free.
-*/
-void jsonObjectFree(jsonObject* obj);
-
-
-/** 
-	Allocates a new object node.
-	@param obj The object to which the node will be appended.
-	@return The new object node.
-*/
-jsonObjectNode* jsonNewObjectNode(jsonObject* obj);
-
-/** 
-	De-allocates an object node 
-	@param obj The object node to de-allocate.
-*/
-void jsonObjectNodeFree(jsonObjectNode* obj);
-
-
-/** 
-	Pushes the given object onto the end of the list.  This coerces an object
-	into becoming an array.  _Only_ use this function on objects that you
-	want to become an array.
-  	If obj is NULL, inserts a new NULL object into the list.
-  	@return array size on success, -1 on error 
- */
-unsigned long jsonObjectPush(jsonObject* dest, jsonObject* newObj);
-
-/* removes (and deallocates) the object at the given index (if one exists) and inserts 
- * the new one.  returns the size on success, -1 on error 
- * If obj is NULL, inserts a new object into the list with is_null set to true
- */
-unsigned long jsonObjectSetIndex(jsonObject* dest, unsigned long index, jsonObject* newObj);
-
-/* inserts the new object, overwriting (removing, deallocating) any 
- * previous object with the given key.
- * returns the size on success, -1 on error 
- * if 'obj' is NULL, a new object is inserted at key 'key' with 'is_null' 
- * set to true
- */
-unsigned long jsonObjectSetKey(jsonObject* dest, const char* key, jsonObject* newObj);
-
-/* removes the object at the given index and, if more items exist,
- * re-indexes (shifts down by 1) the rest of the objects in the array
- */
-unsigned long jsonObjectRemoveIndex(jsonObject* dest, unsigned long index);
-
-/* removes (and deallocates) the object with key 'key' if it exists */
-unsigned long jsonObjectRemoveKey( jsonObject* dest, const char* key);
-
-/* returns a pointer to the string data held by this object if this object
-	is a string.  Otherwise returns NULL*/
-char* jsonObjectGetString(const jsonObject*);
-
-double jsonObjectGetNumber( const jsonObject* obj );
-
-/* sets the string data */
-void jsonObjectSetString(jsonObject* dest, const char* string);
-
-/* sets the number value for the object */
-void jsonObjectSetNumber(jsonObject* dest, double num);
-
-/* sets the class hint for this object */
-void jsonObjectSetClass(jsonObject* dest, const char* classname );
-
-/* converts an object to a json string.  client is responsible for freeing the return string */
-char* jsonObjectToJSON( const jsonObject* obj );
-
-/* set this object's comment string */
-void jsonObjectSetComment(jsonObject* dest, const char* classname);
-
-/* utility method.  starting at index 'index', shifts all indices down by one and 
- * decrements the objects size by 1 
- */
-void _jsonObjectShiftIndex(jsonObject* dest, unsigned long index);
-
-/* formats a JSON string from printing.  User must free returned string */
-char* jsonFormatString( const char* jsonString );
-
-jsonObject* jsonObjectClone( const jsonObject* o );
-
-/* tries to extract the string data from an object.
-	if object -> NULL (the C NULL)
-	if array ->	NULL  (the C NULL)
-	if null	 -> NULL (the C NULL)
-	if true/false -> true/false
-	if string/number/double the string version of either of those
-	The caller is responsible for freeing the returned string
-	*/
-char* jsonObjectToSimpleString( const jsonObject* o );
-
-int jsonBoolIsTrue( const jsonObject* o );
-
-
-/* ------------------------------------------------------------------------ */
-/* XPATH */
-
-/* provides an XPATH style search interface (e.g. /some/node/here) and 
-	return the object at that location if one exists.  Naturally,  
-	every element in the path must be a proper object ("hash" / {}).
-	Returns NULL if the specified node is not found 
-	Note also that the object returned is a clone and
-	must be freed by the caller
-*/
-jsonObject* jsonObjectFindPath( const jsonObject* obj, char* path, ... );
-
-
-/* Utility method. finds any object in the tree that matches the path.  
-	Use this for finding paths that start with '//' */
-jsonObject* _jsonObjectFindPathRecurse( const jsonObject* o, char* root, char* path );
-
-/* returns a list of object whose key is 'root'.  These are used as
-	potential objects when doing a // search */
-jsonObject* __jsonObjectFindPathRecurse( const jsonObject* o, char* root );
-
-/* ------------------------------------------------------------------------ */
-
-
+#ifndef OBJSON_OBJECT_H
+#define OBJSON_OBJECT_H
+#include <opensrf/osrf_json.h>
+#include <opensrf/osrf_legacy_json.h>
 #endif
-
-

Modified: branches/autotools/include/objson/xml2json.h
===================================================================
--- branches/autotools/include/objson/xml2json.h	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/include/objson/xml2json.h	2007-11-05 13:40:16 UTC (rev 1121)
@@ -1,19 +1,11 @@
+/*
+ * Header to support legacy objson library
+ */
+#ifndef OBJSON_XML2JSON_H
+#define OBJSON_XML2JSON_H
+#include <opensrf/osrf_json.h>
+#include <opensrf/osrf_json_xml.h>
+#include <opensrf/osrf_legacy_json.h>
+#endif
 
-#include <stdio.h>
-#include <string.h>
-#include <libxml/globals.h>
-#include <libxml/xmlerror.h>
-#include <libxml/parser.h>
-#include <libxml/tree.h>
-#include <libxml/xmlmemory.h>
 
-#include <objson/object.h>
-#include <objson/json_parser.h>
-#include <opensrf/utils.h>
-#include <opensrf/osrf_list.h>
-
-
-jsonObject* jsonXMLToJSONObject(const char* xml);
-
-
-

Modified: branches/autotools/include/opensrf/osrfConfig.h
===================================================================
--- branches/autotools/include/opensrf/osrfConfig.h	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/include/opensrf/osrfConfig.h	2007-11-05 13:40:16 UTC (rev 1121)
@@ -19,7 +19,7 @@
 #include <opensrf/xml_utils.h>
 #include <opensrf/utils.h>
 #include <opensrf/string_array.h>
-#include <objson/object.h>
+#include <opensrf/osrf_json.h>
 
 typedef struct {
 	jsonObject* config;

Modified: branches/autotools/include/opensrf/osrf_app_session.h
===================================================================
--- branches/autotools/include/opensrf/osrf_app_session.h	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/include/opensrf/osrf_app_session.h	2007-11-05 13:40:16 UTC (rev 1121)
@@ -9,8 +9,7 @@
 #include <opensrf/osrf_hash.h>
 #include <opensrf/osrf_list.h>
 
-#include <objson/object.h>
-#include <objson/json_parser.h>
+#include <opensrf/osrf_json.h>
 
 
 
@@ -76,6 +75,9 @@
 	/** SERVER or CLIENT */
 	enum OSRF_SESSION_TYPE type;
 
+	/** the current locale for this session **/
+	char* session_locale;
+
 	/* let the user use the session to store their own session data */
 	void* userData;
 
@@ -100,6 +102,9 @@
 osrf_app_session* osrf_app_server_session_init( 
 		char* session_id, char* our_app, char* remote_id );
 
+/** sets the default locale for a session **/
+char* osrf_app_session_set_locale( osrf_app_session*, const char* );
+
 /** returns a session from the global session hash */
 osrf_app_session* osrf_app_session_find_session( char* session_id );
 
@@ -115,6 +120,14 @@
 		osrf_app_session* session, jsonObject* params, 
 		char* method_name, int protocol, string_array* param_strings);
 
+int osrfAppSessionMakeLocaleRequest(
+		osrf_app_session* session, jsonObject* params, 
+		char* method_name, int protocol, string_array* param_strings, char* locale);
+
+int osrf_app_session_make_locale_req( 
+		osrf_app_session* session, jsonObject* params, 
+		char* method_name, int protocol, string_array* param_strings, char* locale);
+
 /** Sets the given request to complete state */
 void osrf_app_session_set_complete( osrf_app_session* session, int request_id );
 

Modified: branches/autotools/include/opensrf/osrf_application.h
===================================================================
--- branches/autotools/include/opensrf/osrf_application.h	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/include/opensrf/osrf_application.h	2007-11-05 13:40:16 UTC (rev 1121)
@@ -3,7 +3,7 @@
 #include <opensrf/osrf_app_session.h>
 #include <opensrf/osrf_hash.h>
 
-#include <objson/object.h>
+#include <opensrf/osrf_json.h>
 #include <stdio.h>
 #include <dlfcn.h>
 

Modified: branches/autotools/include/opensrf/osrf_cache.h
===================================================================
--- branches/autotools/include/opensrf/osrf_cache.h	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/include/opensrf/osrf_cache.h	2007-11-05 13:40:16 UTC (rev 1121)
@@ -14,8 +14,7 @@
 */
 
 
-#include <objson/object.h>
-#include <objson/json_parser.h>
+#include <opensrf/osrf_json.h>
 #include <memcache.h>
 #include <opensrf/log.h>
 
@@ -81,3 +80,7 @@
 
 
 
+/**
+ * Clean up the global cache handles, etc.
+ */
+void osrfCacheCleanup();

Copied: branches/autotools/include/opensrf/osrf_json.h (from rev 1120, trunk/include/opensrf/osrf_json.h)
===================================================================
--- branches/autotools/include/opensrf/osrf_json.h	                        (rev 0)
+++ branches/autotools/include/opensrf/osrf_json.h	2007-11-05 13:40:16 UTC (rev 1121)
@@ -0,0 +1,381 @@
+/*
+Copyright (C) 2006  Georgia Public Library Service 
+Bill Erickson <billserickson at gmail.com>
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+*/
+
+
+#include <opensrf/utils.h>
+#include <opensrf/osrf_list.h>
+#include <opensrf/osrf_hash.h>
+
+#ifndef _JSON_H
+#define _JSON_H
+
+
+/* parser states */
+#define JSON_STATE_IN_OBJECT	0x1
+#define JSON_STATE_IN_ARRAY		0x2
+#define JSON_STATE_IN_STRING	0x4
+#define JSON_STATE_IN_UTF		0x8
+#define JSON_STATE_IN_ESCAPE	0x10
+#define JSON_STATE_IN_KEY		0x20
+#define JSON_STATE_IN_NULL		0x40
+#define JSON_STATE_IN_TRUE		0x80
+#define JSON_STATE_IN_FALSE		0x100
+#define JSON_STATE_IN_NUMBER	0x200
+#define JSON_STATE_IS_INVALID	0x400
+#define JSON_STATE_IS_DONE		0x800
+#define JSON_STATE_START_COMMEN	0x1000
+#define JSON_STATE_IN_COMMENT	0x2000
+#define JSON_STATE_END_COMMENT	0x4000
+
+
+/* object and array (container) states are pushed onto a stack so we
+ * can keep track of the object nest.  All other states are
+ * simply stored in the state field of the parser */
+#define JSON_STATE_SET(ctx,s) ctx->state |= s; /* set a state */
+#define JSON_STATE_REMOVE(ctx,s) ctx->state &= ~s; /* unset a state */
+#define JSON_STATE_CHECK(ctx,s) (ctx->state & s) ? 1 : 0 /* check if a state is set */
+#define JSON_STATE_POP(ctx) osrfListPop( ctx->stateStack ); /* remove a state from the stack */
+#define JSON_STATE_PUSH(ctx, state) osrfListPush( ctx->stateStack,(void*) state );/* push a state on the stack */
+#define JSON_STATE_PEEK(ctx) osrfListGetIndex(ctx->stateStack, ctx->stateStack->size -1) /* check which container type we're currently in */
+#define JSON_STATE_CHECK_STACK(ctx, s) (JSON_STATE_PEEK(ctx) == (void*) s ) ? 1 : 0  /* compare stack values */
+
+/* JSON types */
+#define JSON_HASH 	0
+#define JSON_ARRAY	1
+#define JSON_STRING	2
+#define JSON_NUMBER	3
+#define JSON_NULL 	4	
+#define JSON_BOOL 	5
+
+#define JSON_PARSE_LAST_CHUNK 0x1 /* this is the last part of the string we're parsing */
+
+#define JSON_PARSE_FLAG_CHECK(ctx, f) (ctx->flags & f) ? 1 : 0 /* check if a parser state is set */
+
+#ifndef JSON_CLASS_KEY
+#define JSON_CLASS_KEY "__c"
+#endif
+#ifndef JSON_DATA_KEY
+#define JSON_DATA_KEY "__p"
+#endif
+
+
+struct jsonParserContextStruct {
+	int state;						/* what are we currently parsing */
+	const char* chunk;				/* the chunk we're currently parsing */
+	int index;						/* where we are in parsing the current chunk */
+	int chunksize;					/* the size of the current chunk */
+	int flags;						/* parser flags */
+	osrfList* stateStack;		/* represents the nest of object/array states */
+	growing_buffer* buffer;		/* used to hold JSON strings, number, true, false, and null sequences */
+	growing_buffer* utfbuf;		/* holds the current unicode characters */
+	void* userData;				/* opaque user pointer.  we ignore this */
+	struct jsonParserHandlerStruct* handler; /* the event handler struct */
+};
+typedef struct jsonParserContextStruct jsonParserContext;
+
+struct jsonParserHandlerStruct {
+	void (*handleStartObject)	(void* userData);
+	void (*handleObjectKey)		(void* userData, char* key);
+	void (*handleEndObject)		(void* userData);
+	void (*handleStartArray)	(void* userData);
+	void (*handleEndArray)		(void* userData);
+	void (*handleNull)			(void* userData);
+	void (*handleString)			(void* userData, char* string);
+	void (*handleBool)			(void* userData, int boolval);
+	void (*handleNumber)			(void* userData, double num);
+	void (*handleError)			(void* userData, char* err, ...);
+};
+typedef struct jsonParserHandlerStruct jsonParserHandler;
+
+struct _jsonObjectStruct {
+	unsigned long size;	/* number of sub-items */
+	char* classname;		/* optional class hint (not part of the JSON spec) */
+	int type;				/* JSON type */
+	struct _jsonObjectStruct* parent;	/* who we're attached to */
+	union __jsonValue {	/* cargo */
+		osrfHash*	h;		/* object container */
+		osrfList*	l;		/* array container */
+		char* 		s;		/* string */
+		int 			b;		/* bool */
+//		double	n;		/* number */
+		double	n;		/* number */
+	} value;
+};
+typedef struct _jsonObjectStruct jsonObject;
+
+struct _jsonIteratorStruct {
+	jsonObject* obj; /* the object we're traversing */
+	osrfHashIterator* hashItr; /* the iterator for this hash */
+	char* key; /* if this object is an object, the current key */
+	unsigned long index; /* if this object is an array, the index */
+};
+typedef struct _jsonIteratorStruct jsonIterator;
+
+
+
+/** 
+ * Allocates a new parser context object
+ * @param handler The event handler struct
+ * @param userData Opaque user pointer which is available in callbacks
+ * and ignored by the parser
+ * @return An allocated parser context, NULL on error
+ */
+jsonParserContext* jsonNewParser( jsonParserHandler* handler, void* userData);
+
+/**
+ * Deallocates a parser context
+ * @param ctx The context object
+ */
+void jsonParserFree( jsonParserContext* ctx );
+
+/**
+ * Parse a chunk of data.
+ * @param ctx The parser context
+ * @param data The data to parse
+ * @param datalen The size of the chunk to parser
+ * @param flags Reserved
+ */
+int jsonParseChunk( jsonParserContext* ctx, const char* data, int datalen, int flags );
+
+
+/**
+ * Parses a JSON string;
+ * @param str The string to parser
+ * @return The resulting JSON object or NULL on error
+ */
+jsonObject* jsonParseString( const char* str );
+jsonObject* jsonParseStringRaw( const char* str );
+
+jsonObject* jsonParseStringFmt( const char* str, ... );
+
+/**
+ * Parses a JSON string;
+ * @param str The string to parser
+ * @return The resulting JSON object or NULL on error
+ */
+jsonObject* jsonParseStringHandleError( void (*errorHandler) (const char*), char* str, ... );
+
+
+
+/**
+ * Creates a new json object
+ * @param data The string data this object will hold if 
+ * this object happens to be a JSON_STRING, NULL otherwise
+ * @return The allocated json object.  Must be freed with 
+ * jsonObjectFree()
+ */
+jsonObject* jsonNewObject(const char* data);
+jsonObject* jsonNewObjectFmt(const char* data, ...);
+
+/**
+ * Creates a new object of the given type
+ */
+jsonObject* jsonNewObjectType(int type);
+
+/**
+ * Creates a new number object
+ */
+jsonObject* jsonNewNumberObject( double num );
+
+
+/**
+ * Creates a new json bool
+ */
+jsonObject* jsonNewBoolObject(int val);
+
+/**
+ * Deallocates an object
+ */
+void jsonObjectFree( jsonObject* o );
+
+/**
+ * Forces the given object to become an array (if it isn't already one) 
+ * and pushes the new object into the array
+ */
+unsigned long jsonObjectPush(jsonObject* o, jsonObject* newo);
+
+/**
+ * Forces the given object to become a hash (if it isn't already one)
+ * and assigns the new object to the key of the hash
+ */
+unsigned long jsonObjectSetKey(
+		jsonObject* o, const char* key, jsonObject* newo);
+
+
+/**
+ * Turns the object into a JSON string.  The string must be freed by the caller */
+char* jsonObjectToJSON( const jsonObject* obj );
+char* jsonObjectToJSONRaw( const jsonObject* obj );
+
+
+/**
+ * Retrieves the object at the given key
+ */
+jsonObject* jsonObjectGetKey( const jsonObject* obj, const char* key );
+const jsonObject* jsonObjectGetKeyConst( const jsonObject* obj, const char* key );
+
+
+
+
+
+/** Allocates a new iterator 
+	@param obj The object over which to iterate.
+*/
+jsonIterator* jsonNewIterator(const jsonObject* obj);
+
+
+/** 
+	De-allocates an iterator 
+	@param iter The iterator object to free
+*/
+void jsonIteratorFree(jsonIterator* iter);
+
+/** 
+	Returns the object_node currently pointed to by the iterator
+  	and increments the pointer to the next node
+	@param iter The iterator in question.
+ */
+jsonObject* jsonIteratorNext(jsonIterator* iter);
+
+
+/** 
+	@param iter The iterator.
+	@return True if there is another node after the current node.
+ */
+int jsonIteratorHasNext(const jsonIterator* iter);
+
+
+/** 
+	Returns a pointer to the object at the given index.  This call is
+	only valid if the object has a type of JSON_ARRAY.
+	@param obj The object
+	@param index The position within the object
+	@return The object at the given index.
+*/
+jsonObject* jsonObjectGetIndex( const jsonObject* obj, unsigned long index );
+
+
+/* removes (and deallocates) the object at the given index (if one exists) and inserts 
+ * the new one.  returns the size on success, -1 on error 
+ * If obj is NULL, inserts a new object into the list with is_null set to true
+ */
+unsigned long jsonObjectSetIndex(jsonObject* dest, unsigned long index, jsonObject* newObj);
+
+/* removes the object at the given index and, if more items exist,
+ * re-indexes (shifts down by 1) the rest of the objects in the array
+ */
+unsigned long jsonObjectRemoveIndex(jsonObject* dest, unsigned long index);
+
+/* removes (and deallocates) the object with key 'key' if it exists */
+unsigned long jsonObjectRemoveKey( jsonObject* dest, const char* key);
+
+/* returns a pointer to the string data held by this object if this object
+	is a string.  Otherwise returns NULL*/
+char* jsonObjectGetString(const jsonObject*);
+
+double jsonObjectGetNumber( const jsonObject* obj );
+
+/* sets the string data */
+void jsonObjectSetString(jsonObject* dest, const char* string);
+
+/* sets the number value for the object */
+void jsonObjectSetNumber(jsonObject* dest, double num);
+
+/* sets the class hint for this object */
+void jsonObjectSetClass(jsonObject* dest, const char* classname );
+const char* jsonObjectGetClass(const jsonObject* dest);
+
+int jsonBoolIsTrue( jsonObject* boolObj );
+
+void jsonSetBool(jsonObject* bl, int val);
+
+jsonObject* jsonObjectClone( const jsonObject* o );
+
+
+/* tries to extract the string data from an object.
+	if object	-> NULL (the C NULL)
+	if array		->	NULL  
+	if null		-> NULL 
+	if bool		-> NULL
+	if string/number the string version of either of those
+	The caller is responsible for freeing the returned string
+	*/
+char* jsonObjectToSimpleString( const jsonObject* o );
+
+
+
+/* provides an XPATH style search interface (e.g. /some/node/here) and 
+	return the object at that location if one exists.  Naturally,  
+	every element in the path must be a proper object ("hash" / {}).
+	Returns NULL if the specified node is not found 
+	Note also that the object returned is a clone and
+	must be freed by the caller
+*/
+jsonObject* jsonObjectFindPath( const jsonObject* obj, char* path, ... );
+
+
+/* formats a JSON string from printing.  User must free returned string */
+char* jsonFormatString( const char* jsonString );
+
+/* sets the error handler for all parsers */
+void jsonSetGlobalErrorHandler(void (*errorHandler) (const char*));
+
+jsonObject* jsonParseFile( char* filename );
+
+/* ------------------------------------------------------------------------- */
+/**
+ * The following methods provide a facility for serializing and
+ * deserializing "classed" JSON objects.  To give a JSON object a 
+ * class, simply call jsonObjectSetClass().  
+ * Then, calling jsonObjectEncodeClass() will convert the JSON
+ * object (and any sub-objects) to a JSON object with class 
+ * wrapper objects like so:
+ * { _c : "classname", _d : <json_thing> }
+ * In this example _c is the class key and _d is the data (object)
+ * key.  The keys are defined by the constants 
+ * OSRF_JSON_CLASS_KEY and OSRF_JSON_DATA_KEY
+ * To revive a serialized object, simply call
+ * jsonObjectDecodeClass()
+ */
+
+
+/** Converts a class-wrapped object into an object with the
+ * classname set
+ * Caller must free the returned object 
+ */ 
+jsonObject* jsonObjectDecodeClass( const jsonObject* obj );
+
+
+/** Converts an object with a classname into a
+ * class-wrapped (serialized) object
+ * Caller must free the returned object 
+ */ 
+jsonObject* jsonObjectEncodeClass( const jsonObject* obj );
+
+/* ------------------------------------------------------------------------- */
+
+
+/**
+ *	Generates an XML representation of a JSON object */
+char* jsonObjectToXML(jsonObject*);
+
+
+/*
+ * Builds a JSON object from the provided XML 
+ */
+jsonObject* jsonXMLToJSONObject(const char* xml);
+
+
+#endif

Copied: branches/autotools/include/opensrf/osrf_json_utils.h (from rev 1120, trunk/include/opensrf/osrf_json_utils.h)
===================================================================
--- branches/autotools/include/opensrf/osrf_json_utils.h	                        (rev 0)
+++ branches/autotools/include/opensrf/osrf_json_utils.h	2007-11-05 13:40:16 UTC (rev 1121)
@@ -0,0 +1,107 @@
+/*
+Copyright (C) 2006  Georgia Public Library Service 
+Bill Erickson <billserickson at gmail.com>
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+*/
+
+
+/* ----------------------------------------------------------------------- */
+/* Clients need not include this file.  These are internal utilities only	*/
+/* ----------------------------------------------------------------------- */
+
+#define JSON_EAT_WS(ctx)	\
+	while( ctx->index < ctx->chunksize ) {	\
+		if(!isspace(ctx->chunk[ctx->index])) break; \
+		ctx->index++;	\
+	} \
+	if( ctx->index >= ctx->chunksize ) return 0; \
+	c = ctx->chunk[ctx->index];
+
+#define JSON_CACHE_DATA(ctx, buf, size) \
+	while( (buf->n_used < size) && (ctx->index < ctx->chunksize) ) \
+		buffer_add_char(buf, ctx->chunk[ctx->index++]); 
+
+#define JSON_LOG_MARK __FILE__,__LINE__
+
+#define JSON_NUMBER_CHARS "0123456789.+-e"
+
+/**
+ * These are the callbacks through which the top level parser 
+ * builds objects via the push parser
+ */
+void _jsonHandleStartObject(void*);
+void _jsonHandleObjectKey(void*, char* key);
+void _jsonHandleEndObject(void*);
+void _jsonHandleStartArray(void*);
+void _jsonHandleEndArray(void*);
+void _jsonHandleNull(void*);
+void _jsonHandleString(void*, char* string);
+void _jsonHandleBool(void*, int boolval);
+void _jsonHandleNumber(void*, double num);
+void _jsonHandleError(void*, char* str, ...);
+
+struct jsonInternalParserStruct {
+	jsonParserContext* ctx;
+	jsonObject* obj;
+	jsonObject* current;
+	char* lastkey;
+	void (*handleError) (const char*);
+};
+typedef struct jsonInternalParserStruct jsonInternalParser;
+
+jsonInternalParser* _jsonNewInternalParser();
+void _jsonInternalParserFree(jsonInternalParser* p);
+
+/**
+ * Calls the defined error handler with the given error message.
+ * @return -1
+ */
+int _jsonParserError( jsonParserContext* ctx, char* err, ... );
+
+
+/**
+ *
+ * @return 0 on continue, 1 if it goes past the end of the string, -1 on error
+ */
+int _jsonParserHandleUnicode( jsonParserContext* ctx );
+
+
+/**
+ * @param type 0 for null, 1 for true, 2 for false
+ * @return 0 on continue, 1 if it goes past the end of the string, -1 on error
+ */
+int _jsonParserHandleMatch( jsonParserContext* ctx, int type );
+
+/**
+ * @return 0 on continue, 1 on end of chunk, -1 on error 
+ */
+int _jsonParserHandleString( jsonParserContext* ctx );
+
+/**
+ * @return 0 on continue, 1 on end of chunk, -1 on error 
+ */
+int _jsonParserHandleNumber( jsonParserContext* ctx );
+
+
+void _jsonInsertParserItem( jsonInternalParser* p, jsonObject* newo );
+
+
+/* Utility method. finds any object in the tree that matches the path.  
+	Use this for finding paths that start with '//' */
+jsonObject* _jsonObjectFindPathRecurse( const jsonObject* o, char* root, char* path );
+
+
+/* returns a list of object whose key is 'root'.  These are used as
+	potential objects when doing a // search */
+jsonObject* __jsonObjectFindPathRecurse( const jsonObject* o, char* root );
+
+

Copied: branches/autotools/include/opensrf/osrf_json_xml.h (from rev 1120, trunk/include/opensrf/osrf_json_xml.h)
===================================================================
--- branches/autotools/include/opensrf/osrf_json_xml.h	                        (rev 0)
+++ branches/autotools/include/opensrf/osrf_json_xml.h	2007-11-05 13:40:16 UTC (rev 1121)
@@ -0,0 +1,26 @@
+#ifdef OSRF_JSON_ENABLE_XML_UTILS
+
+#include <stdio.h>
+#include <string.h>
+#include <libxml/globals.h>
+#include <libxml/xmlerror.h>
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/xmlmemory.h>
+
+#include <opensrf/osrf_json.h>
+#include <opensrf/utils.h>
+#include <opensrf/osrf_list.h>
+
+
+/**
+ *	Generates an XML representation of a JSON object */
+char* jsonObjectToXML(jsonObject*);
+
+
+/*
+ * Builds a JSON object from the provided XML 
+ */
+jsonObject* jsonXMLToJSONObject(const char* xml);
+
+#endif

Copied: branches/autotools/include/opensrf/osrf_legacy_json.h (from rev 1120, trunk/include/opensrf/osrf_legacy_json.h)
===================================================================
--- branches/autotools/include/opensrf/osrf_legacy_json.h	                        (rev 0)
+++ branches/autotools/include/opensrf/osrf_legacy_json.h	2007-11-05 13:40:16 UTC (rev 1121)
@@ -0,0 +1,135 @@
+/*
+Copyright (C) 2005  Georgia Public Library Service 
+Bill Erickson <highfalutin at gmail.com>
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+*/
+
+
+
+
+/* ---------------------------------------------------------------------------------------
+	JSON parser.
+ * --------------------------------------------------------------------------------------- */
+#ifndef LEGACY_JSON_H
+#define LEGACY_JSON_H
+
+#include <opensrf/osrf_json.h>
+#include <ctype.h>
+
+
+
+/* Parses the given JSON string and returns the built object. 
+ *	returns NULL (and prints parser error to stderr) on error.  
+ */
+
+jsonObject* json_parse_string(char* string);
+
+jsonObject* legacy_jsonParseString(const char* string);
+jsonObject* legacy_jsonParseStringFmt( const char* string, ... );
+
+jsonObject* json_parse_file( const char* filename );
+
+jsonObject* legacy_jsonParseFile( const char* string );
+
+
+
+/* does the actual parsing work.  returns 0 on success.  -1 on error and
+ * -2 if there was no object to build (string was all comments) 
+ */
+int _json_parse_string(char* string, unsigned long* index, jsonObject* obj, int current_strlen);
+
+/* returns 0 on success and turns obj into a string object */
+int json_parse_json_string(char* string, unsigned long* index, jsonObject* obj, int current_strlen);
+
+/* returns 0 on success and turns obj into a number or double object */
+int json_parse_json_number(char* string, unsigned long* index, jsonObject* obj, int current_strlen);
+
+/* returns 0 on success and turns obj into an 'object' object */
+int json_parse_json_object(char* string, unsigned long* index, jsonObject* obj, int current_strlen);
+
+/* returns 0 on success and turns object into an array object */
+int json_parse_json_array(char* string, unsigned long* index, jsonObject* obj, int current_strlen);
+
+/* churns through whitespace and increments index as it goes.
+ * eat_all == true means we should eat newlines, tabs
+ */
+void json_eat_ws(char* string, unsigned long* index, int eat_all, int current_strlen);
+
+int json_parse_json_bool(char* string, unsigned long* index, jsonObject* obj, int current_strlen);
+
+/* removes comments from a json string.  if the comment contains a class hint
+ * and class_hint isn't NULL, an allocated char* with the class name will be
+ * shoved into *class_hint.  returns 0 on success, -1 on parse error.
+ * 'index' is assumed to be at the second character (*) of the comment
+ */
+int json_eat_comment(char* string, unsigned long* index, char** class_hint, int parse_class, int current_strlen);
+
+/* prints a useful error message to stderr. always returns -1 */
+int json_handle_error(char* string, unsigned long* index, char* err_msg);
+
+int json_parse_json_null(char* string, unsigned long* index, jsonObject* obj, int current_strlen);
+
+
+char* legacy_jsonObjectToJSON( const jsonObject* obj );
+
+
+
+/* LEGACY ITERATOR CODE ---------------------------------------------------  
+   ------------------------------------------------------------------------ */
+
+struct _jsonObjectNodeStruct {
+	unsigned long index; /* our array position */
+	char* key; /* our hash key */
+	jsonObject* item; /* our object */
+};
+typedef struct _jsonObjectNodeStruct jsonObjectNode;
+
+
+
+/* utility object for iterating over hash objects */
+struct _jsonObjectIteratorStruct {
+    jsonIterator* iterator;
+	const jsonObject* obj; /* the topic object */
+	jsonObjectNode* current; /* the current node within the object */
+    int done;
+};
+typedef struct _jsonObjectIteratorStruct jsonObjectIterator;
+
+
+/** Allocates a new iterator 
+	@param obj The object over which to iterate.
+*/
+jsonObjectIterator* jsonNewObjectIterator(const jsonObject* obj);
+
+/** 
+	De-allocates an iterator 
+	@param iter The iterator object to free
+*/
+void jsonObjectIteratorFree(jsonObjectIterator* iter);
+
+/** 
+	Returns the object_node currently pointed to by the iterator
+  	and increments the pointer to the next node
+	@param iter The iterator in question.
+ */
+jsonObjectNode* jsonObjectIteratorNext(jsonObjectIterator* iter);
+
+/** 
+	@param iter The iterator.
+	@return True if there is another node after the current node.
+ */
+int jsonObjectIteratorHasNext(const jsonObjectIterator* iter);
+
+
+#endif
+
+

Modified: branches/autotools/include/opensrf/osrf_message.h
===================================================================
--- branches/autotools/include/opensrf/osrf_message.h	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/include/opensrf/osrf_message.h	2007-11-05 13:40:16 UTC (rev 1121)
@@ -1,8 +1,7 @@
 #include <opensrf/string_array.h>
 #include <opensrf/utils.h>
 #include <opensrf/log.h>
-#include <objson/object.h>
-#include <objson/json_parser.h>
+#include <opensrf/osrf_json.h>
 
 
 /* libxml stuff for the config reader */
@@ -76,22 +75,44 @@
 
 	char* full_param_string;
 
+	/* magical LOCALE hint */
+	char* sender_locale;
+
+	/* timezone offset from GMT of sender, in seconds */
+	int sender_tz_offset;
+
 };
 typedef struct osrf_message_struct osrf_message;
 typedef struct osrf_message_struct osrfMessage;
 
+/* Set the locale hint for this message.
+   default_locale is used if not set.
+   Returns NULL if msg or locale is not set, char* to msg->sender_locale on success.
+*/
+char* osrf_message_set_locale( osrf_message* msg, const char* locale );
 
+/* Set the default locale hint to be used for future outgoing messages.
+   Returns NULL if locale is NULL, const char* to default_locale otherwise.
+*/
+const char* osrf_message_set_default_locale( const char* locale );
+
+/* Get the current locale hint -- either the default or most recently received locale.
+   Returns const char* to current_locale.
+*/
+const char* osrf_message_get_current_locale(void);
+
 osrf_message* osrf_message_init( enum M_TYPE type, int thread_trace, int protocol );
 //void osrf_message_set_request_info( osrf_message*, char* param_name, json* params );
-void osrf_message_set_status_info( osrf_message*, char* status_name, char* status_text, int status_code );
-void osrf_message_set_result_content( osrf_message*, char* json_string );
+void osrf_message_set_status_info( osrf_message*,
+		const char* status_name, const char* status_text, int status_code );
+void osrf_message_set_result_content( osrf_message*, const char* json_string );
 void osrfMessageFree( osrfMessage* );
 void osrf_message_free( osrf_message* );
 char* osrf_message_to_xml( osrf_message* );
-char* osrf_message_serialize(osrf_message*);
+char* osrf_message_serialize(const osrf_message*);
 
 /* count is the max number of messages we'll put into msgs[] */
-int osrf_message_deserialize(char* json, osrf_message* msgs[], int count);
+int osrf_message_deserialize(const char* json, osrf_message* msgs[], int count);
 
 
 
@@ -101,10 +122,10 @@
   */
 int osrf_message_from_xml( char* xml, osrf_message* msgs[] );
 
-void osrf_message_set_params( osrf_message* msg, jsonObject* o );
-void osrf_message_set_method( osrf_message* msg, char* method_name );
-void osrf_message_add_object_param( osrf_message* msg, jsonObject* o );
-void osrf_message_add_param( osrf_message*, char* param_string );
+void osrf_message_set_params( osrf_message* msg, const jsonObject* o );
+void osrf_message_set_method( osrf_message* msg, const char* method_name );
+void osrf_message_add_object_param( osrf_message* msg, const jsonObject* o );
+void osrf_message_add_param( osrf_message*, const char* param_string );
 
 
 jsonObject* osrfMessageGetResult( osrfMessage* msg );
@@ -113,7 +134,7 @@
   Returns the message as a jsonObject
   @return The jsonObject which must be freed by the caller.
   */
-jsonObject* osrfMessageToJSON( osrfMessage* msg );
+jsonObject* osrfMessageToJSON( const osrfMessage* msg );
 
 char* osrfMessageSerializeBatch( osrfMessage* msgs [], int count );
 

Modified: branches/autotools/include/opensrf/osrf_settings.h
===================================================================
--- branches/autotools/include/opensrf/osrf_settings.h	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/include/opensrf/osrf_settings.h	2007-11-05 13:40:16 UTC (rev 1121)
@@ -12,8 +12,7 @@
 #include <opensrf/utils.h>
 #include <opensrf/osrf_app_session.h>
 
-#include <objson/object.h>
-#include <objson/json_parser.h>
+#include <opensrf/osrf_json.h>
 
 typedef struct { 
 	char* hostname; 
@@ -21,11 +20,11 @@
 } osrf_host_config;
 
 
-osrf_host_config* osrf_settings_new_host_config(char* hostname);
+osrf_host_config* osrf_settings_new_host_config(const char* hostname);
 void osrf_settings_free_host_config(osrf_host_config*);
-char* osrf_settings_host_value(char* path, ...);
-jsonObject* osrf_settings_host_value_object(char* format, ...);
-int osrf_settings_retrieve(char* hostname);
+char* osrf_settings_host_value(const char* path, ...);
+jsonObject* osrf_settings_host_value_object(const char* format, ...);
+int osrf_settings_retrieve(const char* hostname);
 
 #endif
 

Modified: branches/autotools/include/opensrf/string_array.h
===================================================================
--- branches/autotools/include/opensrf/string_array.h	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/include/opensrf/string_array.h	2007-11-05 13:40:16 UTC (rev 1121)
@@ -2,17 +2,20 @@
 
 #include <opensrf/utils.h>
 #include <opensrf/log.h>
+#include <opensrf/osrf_list.h>
 
-#define STRING_ARRAY_MAX_SIZE 1024
+#define STRING_ARRAY_MAX_SIZE 4096
 
 #ifndef STRING_ARRAY_H
 #define STRING_ARRAY_H
 
+#define OSRF_STRING_ARRAY_FREE(arr)\
+    if(arr) {osrfListFree(arr->list); free(arr);}
+        
+
 struct string_array_struct {
-		char** array;	
-		int size;
-		int arr_size;
-		int total_string_size;
+    osrfList* list;
+    int size;
 };
 typedef struct string_array_struct string_array;
 typedef struct string_array_struct osrfStringArray;

Modified: branches/autotools/include/opensrf/utils.h
===================================================================
--- branches/autotools/include/opensrf/utils.h	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/include/opensrf/utils.h	2007-11-05 13:40:16 UTC (rev 1121)
@@ -41,6 +41,18 @@
 		memset( ptr, 0, size );\
 	} while(0)
 
+#ifndef NDEBUG
+// The original ... replace with noop once no more errors occur in NDEBUG mode
+#define osrf_clearbuf( s, n ) memset( s, 0, n )
+#else
+#define osrf_clearbuf( s, n ) \
+	do { \
+		char * clearbuf_temp_s = (s); \
+		size_t clearbuf_temp_n = (n); \
+		memset( clearbuf_temp_s, '!', clearbuf_temp_n ); \
+		clearbuf_temp_s[ clearbuf_temp_n - 1 ] = '\0'; \
+	} while( 0 )
+#endif
 
 #define OSRF_BUFFER_ADD(gb, data) \
 	do {\
@@ -64,6 +76,10 @@
 		}\
 	}while(0)
 
+#define OSRF_BUFFER_RESET(gb) \
+    memset(gb->buf, 0, gb->size);\
+    gb->n_used = 0;
+
 	
 
 
@@ -155,6 +171,7 @@
 int daemonize();
 
 void* safe_malloc(int size);
+void* safe_calloc(int size);
 
 // ---------------------------------------------------------------------------------
 // Generic growing buffer. Add data all you want

Modified: branches/autotools/include/opensrf/xml_utils.h
===================================================================
--- branches/autotools/include/opensrf/xml_utils.h	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/include/opensrf/xml_utils.h	2007-11-05 13:40:16 UTC (rev 1121)
@@ -1,7 +1,7 @@
 #ifndef _XML_UTILS_H
 #define _XML_UTILS_H
 
-#include <objson/object.h>
+#include <opensrf/osrf_json.h>
 #include <libxml/parser.h>
 #include <libxml/tree.h>
 

Modified: branches/autotools/install.conf
===================================================================
--- branches/autotools/install.conf	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/install.conf	2007-11-05 13:40:16 UTC (rev 1121)
@@ -12,3 +12,4 @@
 export APACHE2_HEADERS=/usr/include/apache2
 export APR_HEADERS=/usr/include/apr-1.0/
 export LIBXML2_HEADERS=/usr/include/libxml2/
+export OSRF_LEGACY_JSON=1

Modified: branches/autotools/src/Makefile
===================================================================
--- branches/autotools/src/Makefile	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/Makefile	2007-11-05 13:40:16 UTC (rev 1121)
@@ -1,18 +1,23 @@
 # TOP level 'src' makefile for OpenSRF
 
 
-export TMPDIR			= $(TMP)/opensrf
-export OPENSRF			= opensrf
-export BINDIR			= $(PREFIX)/bin
-export LIBDIR			= $(PREFIX)/lib
-export PERLDIR			= $(LIBDIR)/perl5
-export INCLUDEDIR		= $(PREFIX)/include
+export TMPDIR	= $(TMP)/opensrf
+export OPENSRF	= opensrf
+export BINDIR	= $(PREFIX)/bin
+export LIBDIR	= $(PREFIX)/lib
+export PERLDIR	= $(LIBDIR)/perl5
+export PYTHON25DIR	= $(LIBDIR)/python25
+export JSDIR	= $(LIBDIR)/javascript
+export INCLUDEDIR= $(PREFIX)/include
 
-export LDLIBS			+= 
-export LDFLAGS			+= -Wl,-rpath=$(LIBDIR) -L $(TMPDIR) -L .
-export CFLAGS			+= -pipe -g -Wall -O2 -fPIC -I ../../include/ -I$(LIBXML2_HEADERS) -I$(APACHE2_HEADERS) \
-								-I$(LIBXML2_HEADERS)/libxml -I$(APR_HEADERS) 
+export LDLIBS	+= 
+export LDFLAGS	+= -Wl,-rpath=$(LIBDIR) -L $(TMPDIR) -L .
+export CFLAGS	+= -D_LARGEFILE64_SOURCE -pipe -g -Wall -O2 -fPIC -I ../../include/ -I$(LIBXML2_HEADERS) -I$(APACHE2_HEADERS) -I$(APR_HEADERS) 
 
+ifeq ($(OSRF_LEGACY_JSON), 1)
+export LDLIBS += -lobjson
+endif
+
 all: 	prep \
 	opensrf \
 	router \
@@ -26,8 +31,9 @@
 		router-install \
 		srfsh-install \
 		jserver-install \
+		javascript-install \
 		perl-install \
-		objson-install
+		python25-install
 
 
 # --------------------------------------------------------------------------------
@@ -37,11 +43,7 @@
 prep:
 	mkdir -p $(TMPDIR)
 
-objson/libobjson.so:	prep
-	@echo $@
-	make -C objson
-
-opensrf:	objson/libobjson.so
+opensrf:	prep
 	make -C libopensrf
 	make -C c-apps
 
@@ -71,16 +73,14 @@
 	@echo $@
 	mkdir -p $(LIBDIR)
 	mkdir -p $(BINDIR)
+	mkdir -p $(JSDIR)
 	mkdir -p $(PERLDIR)
+	mkdir -p $(PYTHON25DIR)
 	mkdir -p $(INCLUDEDIR)
 	mkdir -p $(ETCDIR)
 
-objson-install:	install-prep 
-	@echo $@
-	make -C objson install
-
 # installs libopensrf.so, opensrf-c, headers, example configs, and osrf_ctl.sh
-opensrf-install:	objson-install
+opensrf-install:	install-prep
 	@echo $@
 	cp $(TMPDIR)/libopensrf.so $(LIBDIR)/libopensrf.so
 	cp -r ../include/opensrf $(INCLUDEDIR)
@@ -90,6 +90,10 @@
 	cp ../examples/opensrf.xml.example $(ETCDIR)
 	cp ../examples/opensrf_core.xml.example $(ETCDIR)
 	cp ../examples/srfsh.xml.example $(ETCDIR)
+	if [ ! -z "$(OSRF_LEGACY_JSON)" ]; then\
+		cp -r ../include/objson $(INCLUDEDIR);\
+		cp $(TMPDIR)/libobjson.so $(LIBDIR);\
+	fi
 
 gateway-install:	install-prep opensrf-install	
 	@echo $@
@@ -107,11 +111,19 @@
 	@echo $@
 	make -C jserver install
 
+javascript-install:	install-prep
+	@echo $@
+	cp -r javascript/* $(JSDIR)/
+
 perl-install:	install-prep
 	@echo $@
 	cp -r perlmods/* $(PERLDIR)/
 
+python25-install:	install-prep
+	@echo $@
+	cp -r python/* $(PYTHON25DIR)/
 
+
 # --------------------------------------------------------------------------------
 # CLEAN	
 # --------------------------------------------------------------------------------
@@ -120,7 +132,6 @@
 	make -C router clean
 	make -C gateway clean
 	make -C jserver clean
-	make -C objson clean
 	make -C srfsh clean
 	make -C c-apps clean
 	/bin/rm -rf $(TMPDIR) *.o

Modified: branches/autotools/src/c-apps/Makefile
===================================================================
--- branches/autotools/src/c-apps/Makefile	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/c-apps/Makefile	2007-11-05 13:40:16 UTC (rev 1121)
@@ -1,5 +1,5 @@
-LDLIBS += -lobjson -lopensrf
-CFLAGS += -DOSRF_LOG_PARAMS
+LDLIBS += -lopensrf
+CFLAGS += -D_LARGEFILE64_SOURCE -DOSRF_LOG_PARAMS
 
 all:	osrf_math.so osrf_dbmath.so osrf_version.so
 

Modified: branches/autotools/src/c-apps/osrf_dbmath.c
===================================================================
--- branches/autotools/src/c-apps/osrf_dbmath.c	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/c-apps/osrf_dbmath.c	2007-11-05 13:40:16 UTC (rev 1121)
@@ -1,7 +1,7 @@
-#include "opensrf/osrf_app_session.h"
-#include "opensrf/osrf_application.h"
-#include "objson/object.h"
-#include "opensrf/log.h"
+#include <opensrf/osrf_app_session.h>
+#include <opensrf/osrf_application.h>
+#include <opensrf/osrf_json.h>
+#include <opensrf/log.h>
 
 #define MODULENAME "opensrf.dbmath"
 

Modified: branches/autotools/src/c-apps/osrf_math.c
===================================================================
--- branches/autotools/src/c-apps/osrf_math.c	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/c-apps/osrf_math.c	2007-11-05 13:40:16 UTC (rev 1121)
@@ -1,7 +1,7 @@
-#include "opensrf/osrf_app_session.h"
-#include "opensrf/osrf_application.h"
-#include "objson/object.h"
-#include "opensrf/log.h"
+#include <opensrf/osrf_app_session.h>
+#include <opensrf/osrf_application.h>
+#include <opensrf/osrf_json.h>
+#include <opensrf/log.h>
 
 #define MODULENAME "opensrf.math"
 

Modified: branches/autotools/src/c-apps/osrf_version.c
===================================================================
--- branches/autotools/src/c-apps/osrf_version.c	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/c-apps/osrf_version.c	2007-11-05 13:40:16 UTC (rev 1121)
@@ -1,6 +1,6 @@
 #include "opensrf/osrf_app_session.h"
 #include "opensrf/osrf_application.h"
-#include "objson/object.h"
+#include "opensrf/osrf_json.h"
 #include "opensrf/utils.h"
 #include "opensrf/log.h"
 

Modified: branches/autotools/src/gateway/Makefile
===================================================================
--- branches/autotools/src/gateway/Makefile	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/gateway/Makefile	2007-11-05 13:40:16 UTC (rev 1121)
@@ -1,6 +1,6 @@
 #CFLAGS	+= -DASSUME_STATELESS -DOSRF_GATEWAY_NASTY_DEBUG
 CFLAGS	+= -DASSUME_STATELESS 
-LDLIBS	+= -lobjson -lopensrf
+LDLIBS	+= -lopensrf
 
 all: osrf_json_gateway.so copy
 

Modified: branches/autotools/src/gateway/apachetools.c
===================================================================
--- branches/autotools/src/gateway/apachetools.c	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/gateway/apachetools.c	2007-11-05 13:40:16 UTC (rev 1121)
@@ -24,7 +24,7 @@
 		if(ap_should_client_block(r)) {
 
 			char body[1025];
-			memset(body,0,1025);
+			memset(body,0,sizeof(body));
 			buffer = buffer_init(1025);
 
 
@@ -40,7 +40,7 @@
 				}
 
 				buffer_add( buffer, body );
-				memset(body,0,1025);
+				memset(body,0,sizeof(body));
 
 				osrfLogDebug(OSRF_LOG_MARK, 
 					"gateway read %d bytes: %d bytes of data so far", bread, buffer->n_used);
@@ -49,7 +49,7 @@
 
 				if(buffer->n_used > APACHE_TOOLS_MAX_POST_SIZE) {
 					osrfLogError(OSRF_LOG_MARK, "gateway received POST larger "
-						"than %d bytes. dropping reqeust", APACHE_TOOLS_MAX_POST_SIZE);
+						"than %d bytes. dropping request", APACHE_TOOLS_MAX_POST_SIZE);
 					buffer_free(buffer);
 					return NULL;
 				}

Modified: branches/autotools/src/gateway/osrf_json_gateway.c
===================================================================
--- branches/autotools/src/gateway/osrf_json_gateway.c	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/gateway/osrf_json_gateway.c	2007-11-05 13:40:16 UTC (rev 1121)
@@ -2,17 +2,21 @@
 #include "opensrf/osrf_app_session.h"
 #include "opensrf/osrf_system.h"
 #include "opensrf/osrfConfig.h"
-#include "objson/object.h"
-#include "objson/json2xml.h"
-#include "objson/xml2json.h"
+#include <opensrf/osrf_json.h>
+#include <opensrf/osrf_json_xml.h>
+#include <opensrf/osrf_legacy_json.h>
 #include <sys/time.h>
 #include <sys/resource.h>
 #include <unistd.h>
+#include <strings.h>
 
 
 #define MODULE_NAME "osrf_json_gateway_module"
 #define GATEWAY_CONFIG "OSRFGatewayConfig"
+#define DEFAULT_LOCALE "OSRFDefaultLocale"
 #define CONFIG_CONTEXT "gateway"
+#define JSON_PROTOCOL "OSRFGatewayLegacyJSON"
+#define GATEWAY_USE_LEGACY_JSON 1
 
 #define GATEWAY_DEFAULT_CONFIG "/openils/conf/opensrf_core.xml"
 
@@ -22,13 +26,25 @@
 	char* configfile;  /* our bootstrap config file */
 } osrf_json_gateway_config;
 
+typedef struct { 
+	int legacyJSON;
+} osrf_json_gateway_dir_config;
+
+
 module AP_MODULE_DECLARE_DATA osrf_json_gateway_module;
 
+char* osrf_json_default_locale = "en-US";
 char* osrf_json_gateway_config_file = NULL;
 int bootstrapped = 0;
 int numserved = 0;
 osrfStringArray* allowedServices = NULL;
 
+static const char* osrf_json_gateway_set_default_locale(cmd_parms *parms, void *config, const char *arg) {
+	if (arg)
+		osrf_json_default_locale = (char*) arg;
+	return NULL;
+}
+
 static const char* osrf_json_gateway_set_config(cmd_parms *parms, void *config, const char *arg) {
 	osrf_json_gateway_config  *cfg;
 	cfg = ap_get_module_config(parms->server->module_config, &osrf_json_gateway_module);
@@ -37,10 +53,20 @@
 	return NULL;
 }
 
+static const char* osrf_json_gateway_set_json_proto(cmd_parms *parms, void *config, const char *arg) {
+	osrf_json_gateway_dir_config* cfg = (osrf_json_gateway_dir_config*) config;
+	cfg->legacyJSON = (!strcasecmp((char*) arg, "false")) ? 0 : 1;
+	return NULL;
+}
+
 /* tell apache about our commands */
 static const command_rec osrf_json_gateway_cmds[] = {
 	AP_INIT_TAKE1( GATEWAY_CONFIG, osrf_json_gateway_set_config, 
 			NULL, RSRC_CONF, "osrf json gateway config file"),
+	AP_INIT_TAKE1( DEFAULT_LOCALE, osrf_json_gateway_set_default_locale, 
+			NULL, RSRC_CONF, "osrf json gateway default locale"),
+	AP_INIT_TAKE1( JSON_PROTOCOL, osrf_json_gateway_set_json_proto,
+			NULL, ACCESS_CONF, "osrf json gateway config file"),
 	{NULL}
 };
 
@@ -52,14 +78,20 @@
 	return (void*) cfg;
 }
 
+static void* osrf_json_gateway_create_dir_config( apr_pool_t* p, char* dir) {
+	osrf_json_gateway_dir_config* cfg = (osrf_json_gateway_dir_config*) 
+			apr_palloc(p, sizeof(osrf_json_gateway_dir_config));
+	cfg->legacyJSON = GATEWAY_USE_LEGACY_JSON;
+	return (void*) cfg;
+}
 
+
 static void osrf_json_gateway_child_init(apr_pool_t *p, server_rec *s) {
 
 	char* cfg = osrf_json_gateway_config_file;
 	char buf[32];
-	memset(buf, 0x0, 32);
 	int t = time(NULL);
-	snprintf(buf, 32, "%d", t);
+	snprintf(buf, sizeof(buf), "%d", t);
 
 	if( ! osrfSystemBootstrapClientResc( cfg, CONFIG_CONTEXT, buf ) ) {
 		ap_log_error( APLOG_MARK, APLOG_ERR, 0, s, 
@@ -84,6 +116,25 @@
 	/* make sure we're needed first thing*/
 	if (strcmp(r->handler, MODULE_NAME )) return DECLINED;
 
+
+	osrf_json_gateway_dir_config* dir_conf =  
+		ap_get_module_config(r->per_dir_config, &osrf_json_gateway_module);
+
+
+	/* provide 2 different JSON parsers and serializers to support legacy JSON */
+	jsonObject* (*parseJSONFunc) (const char*) = legacy_jsonParseString;
+	char* (*jsonToStringFunc) (const jsonObject*) = legacy_jsonObjectToJSON;
+
+	if(dir_conf->legacyJSON) {
+		ap_log_rerror( APLOG_MARK, APLOG_INFO, 0, r, "Using legacy JSON");
+
+	} else {
+		ap_log_rerror( APLOG_MARK, APLOG_INFO, 0, r, "Not using legacy JSON");
+		parseJSONFunc = jsonParseString;
+		jsonToStringFunc = jsonObjectToJSON;
+	}
+
+
 	osrfLogDebug(OSRF_LOG_MARK, "osrf gateway: entered request handler");
 
 	/* verify we are connected */
@@ -96,41 +147,43 @@
 
 	osrfLogSetAppname("osrf_json_gw");
 
+	char* osrf_locale	= NULL;
+	char* param_locale	= NULL;	/* locale for this call */
 	char* service		= NULL;	/* service to connect to */
 	char* method		= NULL;	/* method to perform */
 	char* format		= NULL;	/* method to perform */
-	char* a_l			= NULL;	/* request api level */
-    char* input_format  = NULL; /* POST data format, defaults to 'format' */
-	int   isXML			= 0;
-	int   api_level	= 1;
+	char* a_l		= NULL;	/* request api level */
+	char* input_format	= NULL; /* POST data format, defaults to 'format' */
+	int   isXML		= 0;
+	int   api_level		= 1;
 
 	r->allowed |= (AP_METHOD_BIT << M_GET);
 	r->allowed |= (AP_METHOD_BIT << M_POST);
 
 	osrfLogDebug(OSRF_LOG_MARK, "osrf gateway: parsing URL params");
 	string_array* mparams	= NULL;
-	string_array* params		= apacheParseParms(r); /* free me */
-	service		= apacheGetFirstParamValue( params, "service" );
-	method		= apacheGetFirstParamValue( params, "method" ); 
-	format		= apacheGetFirstParamValue( params, "format" ); 
-	input_format = apacheGetFirstParamValue( params, "input_format" ); 
+	string_array* params	= apacheParseParms(r); /* free me */
+	param_locale		= apacheGetFirstParamValue( params, "locale" );
+	service			= apacheGetFirstParamValue( params, "service" );
+	method			= apacheGetFirstParamValue( params, "method" ); 
+	format			= apacheGetFirstParamValue( params, "format" ); 
+	input_format		= apacheGetFirstParamValue( params, "input_format" ); 
 	a_l			= apacheGetFirstParamValue( params, "api_level" ); 
-	mparams		= apacheGetParamValues( params, "param" ); /* free me */
+	mparams			= apacheGetParamValues( params, "param" ); /* free me */
 
-    if(format == NULL)
-        format = "json";
-    if(input_format == NULL)
-        input_format = format;
+	if(format == NULL)
+		format = "json";
+	if(input_format == NULL)
+		input_format = format;
 
-   /* set the user defined timeout value */
-   int timeout = 60;
-   char* tout = apacheGetFirstParamValue( params, "timeout" ); /* request timeout in seconds */
-   if( tout ) {
-      timeout = atoi(tout);
-      osrfLogDebug(OSRF_LOG_MARK, "Client supplied timeout of %d", timeout);
-   }
+	/* set the user defined timeout value */
+	int timeout = 60;
+	char* tout = apacheGetFirstParamValue( params, "timeout" ); /* request timeout in seconds */
+	if( tout ) {
+		timeout = atoi(tout);
+		osrfLogDebug(OSRF_LOG_MARK, "Client supplied timeout of %d", timeout);
+	}
 
-
 	if (a_l)
 		api_level = atoi(a_l);
 
@@ -143,6 +196,38 @@
 
 	int ret = OK;
 
+	/* ----------------------------------------------------------------- */
+	/* Grab the requested locale using the Accept-Language header*/
+
+
+	if ( !param_locale ) {
+		if ( apr_table_get(r->headers_in, "X-OpenSRF-Language") ) {
+			param_locale = strdup( apr_table_get(r->headers_in, "X-OpenSRF-Language") );
+		} else if ( apr_table_get(r->headers_in, "Accept-Language") ) {
+			param_locale = strdup( apr_table_get(r->headers_in, "Accept-Language") );
+		}
+	}
+
+
+	if (param_locale) {
+		growing_buffer* osrf_locale_buf = buffer_init(16);	
+		if (index(param_locale, ',')) {
+			int ind = index(param_locale, ',') - param_locale;
+			int i;
+			for ( i = 0; i < ind && i < 128; i++ )
+				buffer_add_char( osrf_locale_buf, param_locale[i] );
+		} else {
+			buffer_add( osrf_locale_buf, param_locale );
+		}
+
+		free(param_locale);
+		osrf_locale = buffer_release( osrf_locale_buf );
+	} else {
+		osrf_locale = strdup( osrf_json_default_locale );
+	}
+	/* ----------------------------------------------------------------- */
+
+
 	if(!(service && method) || 
 		!osrfStringArrayContains(allowedServices, service)) {
 
@@ -164,33 +249,41 @@
 		*/
 
 		osrfAppSession* session = osrf_app_client_session_init(service);
+		osrf_app_session_set_locale(session, osrf_locale);
 
 		double starttime = get_timestamp_millis();
 		int req_id = -1;
 
-        if(!strcasecmp(input_format, "json")) {
-		    req_id = osrf_app_session_make_req( session, NULL, method, api_level, mparams );
+		if(!strcasecmp(input_format, "json")) {
+			jsonObject * arr = jsonNewObject(NULL);
 
-        } else {
+			char* str;
+			int i = 0;
 
-            /**
-             * If we receive XML method params, convert each param to a JSON object
-             * and pass the array of JSON object params to the method */
-            if(!strcasecmp(input_format, "xml")) {
-                jsonObject* jsonParams = jsonNewObject(NULL);
+			while( (str = osrfStringArrayGetString(mparams, i++)) ) 
+				jsonObjectPush(arr, parseJSONFunc(str));
 
-                char* str;
-                int i = 0;
-                while( (str = osrfStringArrayGetString(mparams, i++)) ) {
-                    jsonObjectPush(jsonParams, jsonXMLToJSONObject(str));
-                }
+			req_id = osrf_app_session_make_req( session, arr, method, api_level, NULL );
+		} else {
 
-		        req_id = osrf_app_session_make_req( session, jsonParams, method, api_level, NULL );
-                jsonObjectFree(jsonParams);
-            }
-        }
+			/**
+			* If we receive XML method params, convert each param to a JSON object
+			* and pass the array of JSON object params to the method */
+			if(!strcasecmp(input_format, "xml")) {
+				jsonObject* jsonParams = jsonNewObject(NULL);
 
+				char* str;
+				int i = 0;
+				while( (str = osrfStringArrayGetString(mparams, i++)) ) {
+					jsonObjectPush(jsonParams, jsonXMLToJSONObject(str));
+				}
 
+				req_id = osrf_app_session_make_req( session, jsonParams, method, api_level, NULL );
+				jsonObjectFree(jsonParams);
+			}
+		}
+
+
 		if( req_id == -1 ) {
 			osrfLogError(OSRF_LOG_MARK, "I am unable to communcate with opensrf..going away...");
 			/* we don't want to spawn an intense re-forking storm 
@@ -209,7 +302,7 @@
 		char* str; int i = 0;
 		while( (str = osrfStringArrayGetString(mparams, i++)) ) {
 			if( i == 1 ) {
-            OSRF_BUFFER_ADD(act, " ");
+				OSRF_BUFFER_ADD(act, " ");
 				OSRF_BUFFER_ADD(act, str);
 			} else {
 				OSRF_BUFFER_ADD(act, ", ");
@@ -247,7 +340,7 @@
 				if (isXML) {
 					output = jsonObjectToXML( res );
 				} else {
-					output = jsonObjectToJSON( res );
+					output = jsonToStringFunc( res );
 					if( morethan1 ) ap_rputs(",", r); /* comma between JSON array items */
 				}
 				ap_rputs(output, r);
@@ -283,18 +376,16 @@
 					"OpenSRF JSON Request returned error: %s -> %s", statusname, statustext );
 			int l = strlen(statusname) + strlen(statustext) + 32;
 			char buf[l];
-			bzero(buf,l);
 
 			if (isXML)
-				snprintf( buf, l, "<debug>\"%s : %s\"</debug>", statusname, statustext );
+				snprintf( buf, sizeof(buf), "<debug>\"%s : %s\"</debug>", statusname, statustext );
 
 			else {
 				char bb[l];
-				bzero(bb, l);
-				snprintf(bb, l,  "%s : %s", statusname, statustext);
+				snprintf(bb, sizeof(bb),  "%s : %s", statusname, statustext);
 				jsonObject* tmp = jsonNewObject(bb);
-				char* j = jsonObjectToJSON(tmp);
-				snprintf( buf, l, ",\"debug\": %s", j);
+				char* j = jsonToStringFunc(tmp);
+				snprintf( buf, sizeof(buf), ",\"debug\": %s", j);
 				free(j);
 				jsonObjectFree(tmp);
 			}
@@ -307,12 +398,11 @@
 
 		/* insert the status code */
 		char buf[32];
-		bzero(buf,32);
 
 		if (isXML)
-			snprintf(buf, 32, "<status>%d</status>", statuscode );
+			snprintf(buf, sizeof(buf), "<status>%d</status>", statuscode );
 		else
-			snprintf(buf, 32, ",\"status\":%d", statuscode );
+			snprintf(buf, sizeof(buf), ",\"status\":%d", statuscode );
 
 		ap_rputs( buf, r );
 
@@ -329,7 +419,7 @@
 	string_array_destroy(mparams);
 
 	osrfLogDebug(OSRF_LOG_MARK, "Gateway served %d requests", ++numserved);
-   osrfLogClearXid();
+	osrfLogClearXid();
 
 	return ret;
 }
@@ -344,8 +434,8 @@
 
 module AP_MODULE_DECLARE_DATA osrf_json_gateway_module = {
 	STANDARD20_MODULE_STUFF,
+	osrf_json_gateway_create_dir_config,
 	NULL,
-	NULL,
 	osrf_json_gateway_create_config,
 	NULL,
 	osrf_json_gateway_cmds,

Modified: branches/autotools/src/java/Makefile
===================================================================
--- branches/autotools/src/java/Makefile	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/java/Makefile	2007-11-05 13:40:16 UTC (rev 1121)
@@ -1,18 +1,43 @@
-#JAVA_LIBS = .:lib:ext/json-jdk1.5-2007-05-01.jar:ext/wstx-asl-3.2.1.jar:ext/stax-api-1.0.1.jar:ext/xercesImpl-1.4.4-2.jar
-JAVA_LIBDIR = .lib
+# dependencies
+STAX=stax-api-1.0.1.jar
+WSTX=wstx-lgpl-3.2.1.jar
+MEMCACHE=java_memcached-release_1.5.1.jar
+JSON=json.zip
+
+STAX_URL=http://woodstox.codehaus.org/$(STAX)
+WSTX_URL=http://woodstox.codehaus.org/3.2.1/$(WSTX)
+MEMCACHE_URL=http://img.whalin.com/memcached/jdk5/standard/$(MEMCACHE)
+JSON_URL=http://www.json.org/java/$(JSON)
+
+
 JAVAC=javac -J-Xmx256m
 JAVA=java -Xmx256m 
-JAVA_LIBS = .:$(JAVA_LIBDIR):ext/json-jdk1.5-2007-05-01.jar:ext/wstx-lgpl-3.2.1.jar:ext/stax-api-1.0.1.jar:ext/java_memcached-release_1.5.1.jar
+JAVA_LIBDIR = .lib
+JAVA_LIBS = .:$(JAVA_LIBDIR):ext/$(WSTX):ext/$(STAX):ext/$(MEMCACHE)
 JAVA_SRC = \
 	org/opensrf/net/xmpp/*.java \
 	org/opensrf/util/*.java \
 	org/opensrf/*.java \
 	org/opensrf/test/*.java 
 
-all:
+
+#------------------------------------------------------------------
+
+all:	jar
+
+
+dirs:
 	mkdir -p $(JAVA_LIBDIR)
+
+opensrf:	deps
 	$(JAVAC) -d $(JAVA_LIBDIR) -cp $(JAVA_LIBS) $(JAVA_SRC) 2>&1 
 
+jar:	opensrf
+	rm -f opensrf.jar
+	echo "creating opensrf.jar"
+	jar cf opensrf.jar -C .lib org
+	rm -r $(JAVA_LIBDIR)
+
 # only prints the first 30 lines of errors
 slim:
 	mkdir -p $(JAVA_LIBDIR)
@@ -25,14 +50,15 @@
 	@echo -e "\nTruncating at 30 lines"
 
 run:
-	@$(JAVA) -cp $(JAVA_LIBS) $(JAVA_EXE) $(JAVA_ARGS)
+	$(JAVA) -cp $(JAVA_LIBS):opensrf.jar $(JAVA_EXE) $(JAVA_ARGS)
 
 deps:
 	mkdir -p ext
-	wget 'http://woodstox.codehaus.org/stax-api-1.0.1.jar' -O ext/stax-api-1.0.1.jar
-	wget 'http://woodstox.codehaus.org/3.2.1/wstx-lgpl-3.2.1.jar' -O ext/wstx-lgpl-3.2.1.jar
-	wget 'http://img.whalin.com/memcached/jdk5/standard/java_memcached-release_1.5.1.jar' -O ext/java_memcached-release_1.5.1.jar
-	mkdir -p .tmp && cd .tmp && wget 'http://www.json.org/java/json.zip' && unzip json.zip
+	mkdir -p $(JAVA_LIBDIR)
+	if [ ! -f ext/$(STAX) ]; then wget '$(STAX_URL)' -O ext/$(STAX); fi 
+	if [ ! -f ext/wstx-lgpl-3.2.1.jar ]; then wget '$(WSTX_URL)' -O ext/$(WSTX); fi
+	if [ ! -f ext/java_memcached-release_1.5.1.jar ]; then wget '$(MEMCACHE_URL)' -O ext/$(MEMCACHE); fi
+	if [ ! -f .tmp/$(JSON) ]; then mkdir -p .tmp && cd .tmp && wget '$(JSON_URL)' && unzip $(JSON); fi
 	$(JAVAC) -d $(JAVA_LIBDIR) .tmp/org/json/*.java
 
 docs:
@@ -40,8 +66,10 @@
 	javadoc -classpath $(JAVA_LIBS) -d doc @files;
 	rm files;
 
-clean:
-	rm -r $(JAVA_LIBDIR)
-	
+clean:	
+	rm -rf $(JAVA_LIBDIR) opensrf.jar
 
+dep_clean:
+	rm -rf ext .tmp
 
+ 	

Modified: branches/autotools/src/java/org/opensrf/ClientSession.java
===================================================================
--- branches/autotools/src/java/org/opensrf/ClientSession.java	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/java/org/opensrf/ClientSession.java	2007-11-05 13:40:16 UTC (rev 1121)
@@ -51,7 +51,7 @@
         /** create a random thread */
         long time = new Date().getTime();
         Random rand = new Random(time);
-        setThread(rand.nextInt()+""+rand.nextInt()+""+time);
+        setThread(rand.nextInt()+""+rand.nextInt()+""+time+Thread.currentThread().getId());
 
         nextId = 0;
         requests = new HashMap<Integer, Request>();
@@ -115,6 +115,7 @@
         Request req = findRequest(msg.getId());
         if(req == null) {
             /** LOG that we've received a result to a non-existant request */
+            System.err.println(msg.getId() +" has no corresponding request");
             return;
         }
         OSRFObject payload = (OSRFObject) msg.get("payload");
@@ -145,5 +146,19 @@
         if(req == null) return;
         req.setComplete();
     }
+
+    public static Object atomicRequest(String service, String method, Object[] params) throws MethodException {
+        try {
+            ClientSession session = new ClientSession(service);
+            Request osrfRequest = session.request(method, params);
+            Result result = osrfRequest.recv(600000);
+            if(result.getStatusCode() != 200) 
+                throw new MethodException( 
+                    "Request "+service+":"+method+":"+" failed with status code " + result.getStatusCode());
+            return result.getContent();
+        } catch(Exception e) {
+            throw new MethodException(e);
+        }
+    }
 }
 

Modified: branches/autotools/src/java/org/opensrf/MethodException.java
===================================================================
--- branches/autotools/src/java/org/opensrf/MethodException.java	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/java/org/opensrf/MethodException.java	2007-11-05 13:40:16 UTC (rev 1121)
@@ -7,5 +7,8 @@
     public MethodException(String info) {
         super(info);
     }
+    public MethodException(Throwable cause) {
+        super(cause);
+    }
 }
 

Modified: branches/autotools/src/java/org/opensrf/Request.java
===================================================================
--- branches/autotools/src/java/org/opensrf/Request.java	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/java/org/opensrf/Request.java	2007-11-05 13:40:16 UTC (rev 1121)
@@ -73,11 +73,16 @@
 
         Result result = null;
 
+        if((result = resultQueue.poll()) != null)
+            return result;
+
         if(millis < 0 && !complete) {
             /** wait potentially forever for a result to arrive */
-            session.waitForMessage(millis);
-            if((result = resultQueue.poll()) != null)
-                return result;
+            while(!complete) {
+                session.waitForMessage(millis);
+                if((result = resultQueue.poll()) != null)
+                    return result;
+            }
 
         } else {
 

Modified: branches/autotools/src/java/org/opensrf/Session.java
===================================================================
--- branches/autotools/src/java/org/opensrf/Session.java	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/java/org/opensrf/Session.java	2007-11-05 13:40:16 UTC (rev 1121)
@@ -45,10 +45,9 @@
         xmsg.setTo(remoteNode);
         xmsg.setThread(thread);
         xmsg.setBody(new JSONWriter(Arrays.asList(new Message[] {omsg})).write());
-        XMPPSession ses = XMPPSession.getGlobalSession();
 
         try {
-            XMPPSession.getGlobalSession().send(xmsg);
+            XMPPSession.getThreadSession().send(xmsg);
         } catch(XMPPException e) {
             connectState = ConnectState.DISCONNECTED;
             throw new SessionException("Error sending message to " + remoteNode, e);
@@ -63,7 +62,7 @@
     public static void waitForMessage(long millis) throws SessionException, MethodException {
         try {
             Stack.processXMPPMessage(
-                XMPPSession.getGlobalSession().recv(millis));
+                XMPPSession.getThreadSession().recv(millis));
         } catch(XMPPException e) {
             throw new SessionException("Error waiting for message", e);
         }

Modified: branches/autotools/src/java/org/opensrf/Sys.java
===================================================================
--- branches/autotools/src/java/org/opensrf/Sys.java	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/java/org/opensrf/Sys.java	2007-11-05 13:40:16 UTC (rev 1121)
@@ -2,6 +2,9 @@
 
 import org.opensrf.util.*;
 import org.opensrf.net.xmpp.*;
+import java.util.Random;
+import java.util.Date;
+import java.net.InetAddress;
 
 
 public class Sys {
@@ -16,6 +19,14 @@
     public static void bootstrapClient(String configFile, String configContext) 
             throws ConfigException, SessionException  {
 
+        if(Logger.instance() == null) /* provide a sane default logger */
+            Logger.init(Logger.WARN, new Logger()); 
+
+        /** see if the current thread already has a connection */
+        XMPPSession existing = XMPPSession.getThreadSession();
+        if(existing != null && existing.connected())
+            return;
+
         /** create the config parser */
         Config config = new Config(configContext);
         config.parse(configFile);
@@ -27,11 +38,24 @@
         String host = (String) config.getFirst("/domains/domain");
         int port = config.getInt("/port");
 
+
+        /** Create a random login resource string */
+        String res = "java_";
         try {
+            res += InetAddress.getLocalHost().getHostAddress();
+        } catch(java.net.UnknownHostException e) {}
+        res += "_"+Math.abs(new Random(new Date().getTime()).nextInt()) 
+            + "_t"+ Thread.currentThread().getId();
+
+
+        try {
+
             /** Connect to the Jabber network */
+            Logger.info("attempting to create XMPP session "+username+"@"+host+"/"+res);
             XMPPSession xses = new XMPPSession(host, port);
-            xses.connect(username, passwd, "test-java"); /* XXX */
-            XMPPSession.setGlobalSession(xses);
+            xses.connect(username, passwd, res);
+            XMPPSession.setThreadSession(xses);
+
         } catch(XMPPException e) {
             throw new SessionException("Unable to bootstrap client", e);
         }
@@ -41,7 +65,7 @@
      * Shuts down the connection to the opensrf network
      */
     public static void shutdown() {
-        XMPPSession.getGlobalSession().disconnect();
+        XMPPSession.getThreadSession().disconnect();
     }
 }
 

Modified: branches/autotools/src/java/org/opensrf/net/xmpp/XMPPReader.java
===================================================================
--- branches/autotools/src/java/org/opensrf/net/xmpp/XMPPReader.java	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/java/org/opensrf/net/xmpp/XMPPReader.java	2007-11-05 13:40:16 UTC (rev 1121)
@@ -8,6 +8,7 @@
 import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.Date;
 
+import com.ctc.wstx.stax.WstxInputFactory;
 
 /**
  * Slim XMPP Stream reader.  This reader only understands enough XMPP
@@ -118,7 +119,7 @@
      * Each reader should have exactly one dependent session thread. 
      */
     private synchronized void notifyCoreEvent() {
-        notify();
+        notifyAll();
     }
 
 
@@ -133,11 +134,13 @@
     public synchronized long waitCoreEvent(long timeout) {
 
         if(msgQueue.peek() != null || timeout == 0) return 0;
+        long start = new Date().getTime();
 
-        long start = new Date().getTime();
         try{
-            if(timeout < 0) wait();
-            else wait(timeout);
+            if(timeout < 0) 
+                wait();
+            else 
+                wait(timeout);
         } catch(InterruptedException ie) {}
 
         return new Date().getTime() - start;
@@ -158,7 +161,8 @@
 
         try {
 
-            XMLInputFactory factory = XMLInputFactory.newInstance();
+            //XMLInputFactory factory = XMLInputFactory.newInstance();
+            XMLInputFactory factory = new com.ctc.wstx.stax.WstxInputFactory();
 
             /** disable as many unused features as possible to speed up the parsing */
             factory.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, Boolean.FALSE);

Modified: branches/autotools/src/java/org/opensrf/net/xmpp/XMPPSession.java
===================================================================
--- branches/autotools/src/java/org/opensrf/net/xmpp/XMPPSession.java	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/java/org/opensrf/net/xmpp/XMPPSession.java	2007-11-05 13:40:16 UTC (rev 1121)
@@ -2,6 +2,9 @@
 
 import java.io.*;
 import java.net.Socket;
+import java.util.Map;
+import java.util.Iterator;
+import java.util.concurrent.ConcurrentHashMap;
 
 
 /**
@@ -21,6 +24,8 @@
 
     public static final String JABBER_DISCONNECT = "</stream:stream>";
 
+    private static Map threadConnections = new ConcurrentHashMap();
+
     /** jabber domain */
     private String host;
     /** jabber port */
@@ -59,24 +64,65 @@
     /**
      * Returns the global, process-wide session
      */
+    /*
     public static XMPPSession getGlobalSession() {
         return globalSession;
     }
+    */
 
+    public static XMPPSession getThreadSession() {
+        return (XMPPSession) threadConnections.get(new Long(Thread.currentThread().getId()));
+    }
+
     /**
+     * Sets the given session as the global session for the current thread
+     * @param ses The session
+     */
+    public static void setThreadSession(XMPPSession ses) {
+        /* every time we create a new connection, clean up any dead threads. 
+         * this is cheaper than cleaning up the dead threads at every access. */
+        cleanupThreadSessions();
+        threadConnections.put(new Long(Thread.currentThread().getId()), ses);
+    }
+
+    /**
+     * Analyzes the threadSession data to see if there are any sessions
+     * whose controlling thread has gone away.  
+     */
+    private static void cleanupThreadSessions() {
+        Thread threads[] = new Thread[Thread.activeCount()]; 
+        Thread.enumerate(threads);
+        for(Iterator i = threadConnections.keySet().iterator(); i.hasNext(); ) {
+            boolean found = false;
+            Long id = (Long) i.next();
+            for(Thread t : threads) {
+                if(t.getId() == id.longValue()) {
+                    found = true;
+                    break;
+                }
+            }
+            if(!found) 
+                threadConnections.remove(id);
+        }
+    }
+
+    /**
      * Sets the global, process-wide section
      */
+    /*
     public static void setGlobalSession(XMPPSession ses) {
         globalSession = ses;
     }
+    */
 
 
     /** true if this session is connected to the server */
     public boolean connected() {
         return (
-            reader != null && 
-            reader.getXMPPStreamState() == 
-                XMPPReader.XMPPStreamState.CONNECTED);
+                reader != null && 
+                reader.getXMPPStreamState() == XMPPReader.XMPPStreamState.CONNECTED &&
+                !socket.isClosed()
+            );
     }
 
 
@@ -113,29 +159,33 @@
         thread.setDaemon(true);
         thread.start();
 
-        /* send the initial jabber message */
-        sendConnect();
-        reader.waitCoreEvent(10000);
+        synchronized(reader) {
+            /* send the initial jabber message */
+            sendConnect();
+            reader.waitCoreEvent(10000);
+        }
         if( reader.getXMPPStreamState() != XMPPReader.XMPPStreamState.CONNECT_RECV ) 
             throw new XMPPException("unable to connect to jabber server");
 
-        /* send the basic auth message */
-        sendBasicAuth(); /* XXX add support for other auth mechanisms */
-        reader.waitCoreEvent(10000);
-        if(!connected())
+        synchronized(reader) {
+            /* send the basic auth message */
+            sendBasicAuth(); 
+            reader.waitCoreEvent(10000);
+        }
+        if(!connected()) 
             throw new XMPPException("Authentication failed");
     }
 
     /** Sends the initial jabber message */
     private void sendConnect() {
+        reader.setXMPPStreamState(XMPPReader.XMPPStreamState.CONNECT_SENT);
         writer.printf(JABBER_CONNECT, host);
-        reader.setXMPPStreamState(XMPPReader.XMPPStreamState.CONNECT_SENT);
     }
 
     /** Send the basic auth message */
     private void sendBasicAuth() {
+        reader.setXMPPStreamState(XMPPReader.XMPPStreamState.AUTH_SENT);
         writer.printf(JABBER_BASIC_AUTH, username, password, resource);
-        reader.setXMPPStreamState(XMPPReader.XMPPStreamState.AUTH_SENT);
     }
 
 
@@ -186,14 +236,17 @@
         } else {
 
             while(timeout >= 0) { /* wait at most 'timeout' milleseconds for a message to arrive */
+                msg = reader.popMessageQueue();
+                if( msg != null ) return msg;
                 timeout -= reader.waitCoreEvent(timeout);
                 msg = reader.popMessageQueue();
                 if( msg != null ) return msg;
                 checkConnected();
+                if(timeout == 0) break;
             }
         }
 
-        return null;
+        return reader.popMessageQueue();
     }
 
 

Modified: branches/autotools/src/java/org/opensrf/test/TestClient.java
===================================================================
--- branches/autotools/src/java/org/opensrf/test/TestClient.java	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/java/org/opensrf/test/TestClient.java	2007-11-05 13:40:16 UTC (rev 1121)
@@ -7,48 +7,72 @@
 import java.util.ArrayList;
 import java.io.PrintStream;
 
-
 public class TestClient {
 
     public static void main(String args[]) throws Exception {
 
+        /** which opensrf service are we sending our request to */
+        String service; 
+        /** which opensrf method we're calling */
+        String method;
+        /** method params, captures from command-line args */
+        List<Object> params;
+        /** knows how to read JSON */
+        JSONReader reader;
+        /** opensrf request */
+        Request request;
+        /** request result */
+        Result result;
+        /** start time for the request */
+        long start;
+        /** for brevity */
         PrintStream out = System.out;
+
         if(args.length < 3) {
             out.println( "usage: org.opensrf.test.TestClient "+
                 "<osrfConfigFile> <service> <method> [<JSONparam1>, <JSONparam2>]");
             return;
         }
 
+        /** connect to the opensrf network,  default config context 
+         * for opensrf_core.xml is /config/opensrf */
         Sys.bootstrapClient(args[0], "/config/opensrf");
-        String service = args[1];
-        String method = args[2];
 
-        /** build the client session and send the request */
-        ClientSession session = new ClientSession(service);
-        List<Object> params = new ArrayList<Object>();
-        JSONReader reader;
-
-        for(int i = 3; i < args.length; i++) /* add the params */
+        /* grab the server, method, and any params from the command line */
+        service = args[1];
+        method = args[2];
+        params = new ArrayList<Object>();
+        for(int i = 3; i < args.length; i++) 
             params.add(new JSONReader(args[i]).read());
 
 
-        Result result;
+        /** build the client session */
+        ClientSession session = new ClientSession(service);
 
-        long start = new Date().getTime();
-        Request request = session.request(method, params);
+        /** kick off the timer */
+        start = new Date().getTime();
 
+        /** Create the request object from the session, method and params */
+        request = session.request(method, params);
+
         while( (result = request.recv(60000)) != null ) { 
             /** loop over the results and print the JSON version of the content */
 
-            if(result.getStatusCode() != 200) { /* make sure the request succeeded */
+            if(result.getStatusCode() != 200) { 
+                /** make sure the request succeeded */
                 out.println("status = " + result.getStatus());
                 out.println("status code = " + result.getStatusCode());
                 continue;
             }
 
-            out.println("result JSON: " + new JSONWriter(result.getContent()).write());
+            /** JSON-ify the resulting object and print it */
+            out.println("\nresult JSON: " + new JSONWriter(result.getContent()).write());
         }
+        
+        /** How long did the request take? */
         out.println("Request round trip took: " + (new Date().getTime() - start) + " ms.");
+
+        Sys.shutdown();
     }
 }
 

Copied: branches/autotools/src/java/org/opensrf/test/TestLog.java (from rev 1120, trunk/src/java/org/opensrf/test/TestLog.java)
===================================================================
--- branches/autotools/src/java/org/opensrf/test/TestLog.java	                        (rev 0)
+++ branches/autotools/src/java/org/opensrf/test/TestLog.java	2007-11-05 13:40:16 UTC (rev 1121)
@@ -0,0 +1,15 @@
+package org.opensrf.test;
+import org.opensrf.util.Logger;
+import org.opensrf.util.FileLogger;
+
+
+/** Simple test class for tesing the logging functionality */
+public class TestLog {
+    public static void main(String args[]) {
+       Logger.init(Logger.DEBUG, new FileLogger("test.log")); 
+       Logger.error("Hello, world");
+       Logger.warn("Hello, world");
+       Logger.info("Hello, world");
+       Logger.debug("Hello, world");
+    }
+}

Copied: branches/autotools/src/java/org/opensrf/test/TestThread.java (from rev 1120, trunk/src/java/org/opensrf/test/TestThread.java)
===================================================================
--- branches/autotools/src/java/org/opensrf/test/TestThread.java	                        (rev 0)
+++ branches/autotools/src/java/org/opensrf/test/TestThread.java	2007-11-05 13:40:16 UTC (rev 1121)
@@ -0,0 +1,68 @@
+package org.opensrf.test;
+import org.opensrf.*;
+import org.opensrf.util.*;
+import java.util.Map;
+import java.util.Date;
+import java.util.List;
+import java.util.ArrayList;
+import java.io.PrintStream;
+
+/**
+ * Connects to the opensrf network once per thread and runs
+ * and runs a series of request acccross all launched threads.
+ * The purpose is to verify that the java threaded client api 
+ * is functioning as expected
+ */
+public class TestThread implements Runnable {
+
+    String args[];
+
+    public TestThread(String args[]) {
+        this.args = args;
+    }
+
+    public void run() {
+
+        try {
+
+            Sys.bootstrapClient(args[0], "/config/opensrf");
+            ClientSession session = new ClientSession(args[3]);
+    
+            List params = new ArrayList<Object>();
+            for(int i = 5; i < args.length; i++) 
+                params.add(new JSONReader(args[3]).read());
+    
+            for(int i = 0; i < Integer.parseInt(args[2]); i++) {
+                System.out.println("thread " + Thread.currentThread().getId()+" sending request " + i);
+                Request request = session.request(args[4], params);
+                Result result = request.recv(3000);
+                if(result != null) {
+                    System.out.println("thread " + Thread.currentThread().getId()+ 
+                        " got result JSON: " + new JSONWriter(result.getContent()).write());
+                } else {
+                    System.out.println("* thread " + Thread.currentThread().getId()+ " got NO result");
+                }
+            }
+    
+            Sys.shutdown();
+        } catch(Exception e) {
+            System.err.println(e);
+        }
+    }
+
+    public static void main(String args[]) throws Exception {
+
+        if(args.length < 5) {
+            System.out.println( "usage: org.opensrf.test.TestClient "+
+                "<osrfConfigFile> <numthreads> <numiter> <service> <method> [<JSONparam1>, <JSONparam2>]");
+            return;
+        }
+
+        int numThreads = Integer.parseInt(args[1]);
+        for(int i = 0; i < numThreads; i++) 
+            new Thread(new TestThread(args)).start();
+    }
+}
+
+
+

Copied: branches/autotools/src/java/org/opensrf/util/FileLogger.java (from rev 1120, trunk/src/java/org/opensrf/util/FileLogger.java)
===================================================================
--- branches/autotools/src/java/org/opensrf/util/FileLogger.java	                        (rev 0)
+++ branches/autotools/src/java/org/opensrf/util/FileLogger.java	2007-11-05 13:40:16 UTC (rev 1121)
@@ -0,0 +1,44 @@
+package org.opensrf.util;
+import java.io.BufferedWriter;
+import java.io.FileWriter;
+
+
+public class FileLogger extends Logger {
+
+    /** File to log to */
+    private String filename;
+
+    /** 
+     * FileLogger constructor
+     * @param filename The path to the log file
+     */
+    public FileLogger(String filename) {
+        this.filename = filename;
+    }
+
+    /**
+     * Logs the mesage to a file.
+     * @param level The log level
+     * @param msg The mesage to log
+     */
+    protected synchronized void log(short level, String msg) {
+        if(level > logLevel) return;
+
+        BufferedWriter out = null;
+        try {
+            out = new BufferedWriter(new FileWriter(this.filename, true));
+            out.write(formatMessage(level, msg) + "\n");
+
+        } catch(Exception e) {
+            /** If we are unable to write our log message, go ahead and
+              * fall back to the default (stdout) logger */
+            Logger.init(logLevel, new Logger());
+            Logger.logByLevel(ERROR, "Unable to write to log file " + this.filename);
+            Logger.logByLevel(level, msg);
+        }
+
+        try {
+            out.close();
+        } catch(Exception e) {}
+    }
+}

Copied: branches/autotools/src/java/org/opensrf/util/Logger.java (from rev 1120, trunk/src/java/org/opensrf/util/Logger.java)
===================================================================
--- branches/autotools/src/java/org/opensrf/util/Logger.java	                        (rev 0)
+++ branches/autotools/src/java/org/opensrf/util/Logger.java	2007-11-05 13:40:16 UTC (rev 1121)
@@ -0,0 +1,130 @@
+package org.opensrf.util;
+import java.text.SimpleDateFormat;
+import java.text.FieldPosition;
+import java.util.Date;
+
+/**
+ * Basic OpenSRF logging API.  This default implementation
+ * logs to stderr.
+ */
+public class Logger {
+
+    /** Log levels */
+    public static final short ERROR = 1;
+    public static final short WARN  = 2;
+    public static final short INFO  = 3;
+    public static final short DEBUG = 4;
+
+    /** The global log instance */
+    private static Logger instance;
+    /** The global log level */
+    protected static short logLevel;
+
+    public Logger() {}
+
+    /** Sets the global Logger instance
+     * @param level The global log level.
+     * @param l The Logger instance to use
+     */
+    public static void init(short level, Logger l) {
+        instance = l;
+        logLevel = level;
+    }
+
+    /** 
+     * @return The global Logger instance
+     */
+    public static Logger instance() {
+        return instance;
+    }
+
+    /**
+     * Logs an error message
+     * @param msg The message to log
+     */
+    public static void error(String msg) {
+        instance.log(ERROR, msg);
+    }
+
+    /**
+     * Logs an warning message
+     * @param msg The message to log
+     */
+    public static void warn(String msg) {
+        instance.log(WARN, msg);
+    }
+
+    /**
+     * Logs an info message
+     * @param msg The message to log
+     */
+    public static void info(String msg) {
+        instance.log(INFO, msg);
+    }
+
+    /**
+     * Logs an debug message
+     * @param msg The message to log
+     */
+    public static void debug(String msg) {
+        instance.log(DEBUG, msg);
+    }
+
+    /** 
+     * Appends the text representation of the log level
+     * @param sb The stringbuffer to append to
+     * @param level The log level
+     */
+    protected static void appendLevelString(StringBuffer sb, short level) {
+        switch(level) {
+            case DEBUG:
+                sb.append("DEBG"); break;
+            case INFO:
+                sb.append("INFO"); break;
+            case WARN:
+                sb.append("WARN"); break;
+            case ERROR:
+                sb.append("ERR "); break;
+        }
+    }
+
+    /**
+     * Formats a message for logging.  Appends the current date+time
+     * and the log level string.
+     * @param level The log level
+     * @param msg The message to log
+     */
+    protected static String formatMessage(short level, String msg) {
+
+        StringBuffer sb = new StringBuffer();
+        new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(
+            new Date(), sb, new FieldPosition(0));
+
+        sb.append(" [");
+        appendLevelString(sb, level);
+        sb.append("] ");
+        sb.append(msg);
+        return sb.toString();
+    }
+
+    /**
+     * Logs a message by passing the log level explicitly
+     * @param level The log level
+     * @param msg The message to log
+     */
+    public static void logByLevel(short level, String msg) {
+        instance.log(level, msg);
+    }
+
+    /**
+     * Performs the actual logging.  Subclasses should override 
+     * this method.
+     * @param level The log level
+     * @param msg The message to log
+     */
+    protected synchronized void log(short level, String msg) {
+        if(level > logLevel) return;
+        System.err.println(formatMessage(level, msg));
+    }
+}
+

Modified: branches/autotools/src/java/org/opensrf/util/OSRFObject.java
===================================================================
--- branches/autotools/src/java/org/opensrf/util/OSRFObject.java	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/java/org/opensrf/util/OSRFObject.java	2007-11-05 13:40:16 UTC (rev 1121)
@@ -16,6 +16,7 @@
     public OSRFObject() {
     }
 
+
     /**
      * Creates a new object with the provided registry
      */
@@ -24,7 +25,16 @@
         registry = reg;
     }
 
+
     /**
+     * Creates a new OpenSRF object based on the net class string
+     * */
+    public OSRFObject(String netClass) {
+        this(OSRFRegistry.getRegistry(netClass));
+    }
+
+
+    /**
      * @return This object's registry
      */
     public OSRFRegistry getRegistry() {

Deleted: branches/autotools/src/javascript/JSON.js
===================================================================
--- branches/autotools/src/javascript/JSON.js	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/javascript/JSON.js	2007-11-05 13:40:16 UTC (rev 1121)
@@ -1,135 +0,0 @@
-// in case we run on an implimentation that doesn't have "undefined";
-var undefined;
-
-function Cast (obj, class_constructor) {
-	try {
-		if (eval(class_constructor + '["_isfieldmapper"]')) {
-			obj = eval("new " + class_constructor + "(obj)");
-		}
-	} catch( E ) {
-		alert( E + "\n");
-	} finally {
-		return obj;
-	}
-}
-
-function JSON2js (json) {
-
-	json = String(json).replace( /\/\*--\s*S\w*?\s*?\s+\w+\s*--\*\//g, 'Cast(');
-	json = String(json).replace( /\/\*--\s*E\w*?\s*?\s+(\w+)\s*--\*\//g, ', "$1")');
-
-	var obj;
-	if (json != '') {
-		try {
-			eval( 'obj = ' + json );
-		} catch(E) {
-			debug("Error building JSON object with string " + E + "\nString:\n" + json );
-			return null;
-		}
-	}
-	return obj;
-}
-
-
-function object2Array(obj) {
-	if( obj == null ) return null;
-
-	var arr = new Array();
-	for( var i  = 0; i < obj.length; i++ ) {
-		arr[i] = obj[i];
-	}
-	return arr;
-}
-
-
-function js2JSON(arg) {
-	return _js2JSON(arg);
-}
-
-function _js2JSON(arg) {
-	var i, o, u, v;
-
-		switch (typeof arg) {
-			case 'object':
-	
-				if(arg) {
-	
-					if (arg._isfieldmapper) { /* magi-c-ast for fieldmapper objects */
-	
-						if( arg.a.constructor != Array ) {
-							var arr = new Array();
-							for( var i  = 0; i < arg.a.length; i++ ) {
-								if( arg.a[i] == null ) {
-									arr[i] = null; continue;
-								}
-	
-								if( typeof arg.a[i] != 'object' ) { 
-									arr[i] = arg.a[i];
-	
-								} else if( typeof arg.a[i] == 'object' 
-											&& arg.a[i]._isfieldmapper) {
-	
-									arr[i] = arg.a[i];
-	
-								} else {
-									arr[i] = object2Array(arg.a[i]);		
-								}
-							}
-							arg.a = arr;
-						}
-	
-						return "/*--S " + arg.classname + " --*/" + js2JSON(arg.a) + "/*--E " + arg.classname + " --*/";
-	
-					} else {
-	
-						if (arg.constructor == Array) {
-							o = '';
-							for (i = 0; i < arg.length; ++i) {
-								v = js2JSON(arg[i]);
-								if (o) {
-									o += ',';
-								}
-								if (v !== u) {
-									o += v;
-								} else {
-									o += 'null';
-								}
-							}
-							return '[' + o + ']';
-	
-						} else if (typeof arg.toString != 'undefined') {
-							o = '';
-							for (i in arg) {
-								v = js2JSON(arg[i]);
-								if (v !== u) {
-									if (o) {
-										o += ',';
-									}
-									o += js2JSON(i) + ':' + v;
-								}
-							}
-	
-							o = '{' + o + '}';
-							return o;
-	
-						} else {
-							return;
-						}
-					}
-				}
-				return 'null';
-	
-			case 'unknown':
-			case 'number':
-				return arg;
-	
-			case 'undefined':
-			case 'function':
-				return u;
-	
-			case 'string':
-			default:
-				return '"' + String(arg).replace(/(["\\])/g, '\\$1') + '"';
-		}
-
-}

Copied: branches/autotools/src/javascript/JSON_v0.js (from rev 1120, trunk/src/javascript/JSON_v0.js)
===================================================================
--- branches/autotools/src/javascript/JSON_v0.js	                        (rev 0)
+++ branches/autotools/src/javascript/JSON_v0.js	2007-11-05 13:40:16 UTC (rev 1121)
@@ -0,0 +1,135 @@
+// in case we run on an implimentation that doesn't have "undefined";
+var undefined;
+
+function Cast (obj, class_constructor) {
+	try {
+		if (eval(class_constructor + '["_isfieldmapper"]')) {
+			obj = eval("new " + class_constructor + "(obj)");
+		}
+	} catch( E ) {
+		alert( E + "\n");
+	} finally {
+		return obj;
+	}
+}
+
+function JSON2js (json) {
+
+	json = String(json).replace( /\/\*--\s*S\w*?\s*?\s+\w+\s*--\*\//g, 'Cast(');
+	json = String(json).replace( /\/\*--\s*E\w*?\s*?\s+(\w+)\s*--\*\//g, ', "$1")');
+
+	var obj;
+	if (json != '') {
+		try {
+			eval( 'obj = ' + json );
+		} catch(E) {
+			debug("Error building JSON object with string " + E + "\nString:\n" + json );
+			return null;
+		}
+	}
+	return obj;
+}
+
+
+function object2Array(obj) {
+	if( obj == null ) return null;
+
+	var arr = new Array();
+	for( var i  = 0; i < obj.length; i++ ) {
+		arr[i] = obj[i];
+	}
+	return arr;
+}
+
+
+function js2JSON(arg) {
+	return _js2JSON(arg);
+}
+
+function _js2JSON(arg) {
+	var i, o, u, v;
+
+		switch (typeof arg) {
+			case 'object':
+	
+				if(arg) {
+	
+					if (arg._isfieldmapper) { /* magi-c-ast for fieldmapper objects */
+	
+						if( arg.a.constructor != Array ) {
+							var arr = new Array();
+							for( var i  = 0; i < arg.a.length; i++ ) {
+								if( arg.a[i] == null ) {
+									arr[i] = null; continue;
+								}
+	
+								if( typeof arg.a[i] != 'object' ) { 
+									arr[i] = arg.a[i];
+	
+								} else if( typeof arg.a[i] == 'object' 
+											&& arg.a[i]._isfieldmapper) {
+	
+									arr[i] = arg.a[i];
+	
+								} else {
+									arr[i] = object2Array(arg.a[i]);		
+								}
+							}
+							arg.a = arr;
+						}
+	
+						return "/*--S " + arg.classname + " --*/" + js2JSON(arg.a) + "/*--E " + arg.classname + " --*/";
+	
+					} else {
+	
+						if (arg.constructor == Array) {
+							o = '';
+							for (i = 0; i < arg.length; ++i) {
+								v = js2JSON(arg[i]);
+								if (o) {
+									o += ',';
+								}
+								if (v !== u) {
+									o += v;
+								} else {
+									o += 'null';
+								}
+							}
+							return '[' + o + ']';
+	
+						} else if (typeof arg.toString != 'undefined') {
+							o = '';
+							for (i in arg) {
+								v = js2JSON(arg[i]);
+								if (v !== u) {
+									if (o) {
+										o += ',';
+									}
+									o += js2JSON(i) + ':' + v;
+								}
+							}
+	
+							o = '{' + o + '}';
+							return o;
+	
+						} else {
+							return;
+						}
+					}
+				}
+				return 'null';
+	
+			case 'unknown':
+			case 'number':
+				return arg;
+	
+			case 'undefined':
+			case 'function':
+				return u;
+	
+			case 'string':
+			default:
+				return '"' + String(arg).replace(/(["\\])/g, '\\$1') + '"';
+		}
+
+}

Copied: branches/autotools/src/javascript/JSON_v1.js (from rev 1120, trunk/src/javascript/JSON_v1.js)
===================================================================
--- branches/autotools/src/javascript/JSON_v1.js	                        (rev 0)
+++ branches/autotools/src/javascript/JSON_v1.js	2007-11-05 13:40:16 UTC (rev 1121)
@@ -0,0 +1,201 @@
+var JSON_CLASS_KEY	= '__c';
+var JSON_DATA_KEY	= '__p';
+
+
+
+function JSON_version() { return 'wrapper' }
+
+function JSON2js(text) {
+	return decodeJS(JSON2jsRaw(text));
+}
+
+function JSON2jsRaw(text) {
+	var obj;
+	eval('obj = ' + text);
+	return obj;
+}
+
+
+/* iterates over object, arrays, or fieldmapper objects */
+function jsIterate( arg, callback ) {
+	if( arg && typeof arg == 'object' ) {
+		if( arg.constructor == Array ) {
+			for( var i = 0; i < arg.length; i++ ) 
+				callback(arg, i);
+
+		}  else if( arg.constructor == Object ) {
+				for( var i in arg ) 
+					callback(arg, i);
+
+		} else if( arg._isfieldmapper && arg.a ) {
+			for( var i = 0; i < arg.a.length; i++ ) 
+				callback(arg.a, i);
+		}
+	}
+}
+
+
+/* removes the class/paylod wrapper objects */
+function decodeJS(arg) {
+
+	if(arg == null) return null;
+
+	if(	arg && typeof arg == 'object' &&
+			arg.constructor == Object &&
+			arg[JSON_CLASS_KEY] ) {
+		eval('arg = new ' + arg[JSON_CLASS_KEY] + '(arg[JSON_DATA_KEY])');	
+	}
+
+	jsIterate( arg, 
+		function(o, i) {
+			o[i] = decodeJS(o[i]);
+		}
+	);
+
+	return arg;
+}
+
+
+function jsClone(obj) {
+	if( obj == null ) return null;
+	if( typeof obj != 'object' ) return obj;
+
+	var newobj;
+	if (obj.constructor == Array) {
+		newobj = [];
+		for( var i = 0; i < obj.length; i++ ) 
+			newobj[i] = jsClone(obj[i]);
+
+	} else if( obj.constructor == Object ) {
+		newobj = {};
+		for( var i in obj )
+			newobj[i] = jsClone(obj[i]);
+
+	} else if( obj._isfieldmapper && obj.a ) {
+		eval('newobj = new '+obj.classname + '();');
+		for( var i = 0; i < obj.a.length; i++ ) 
+			newobj.a[i] = jsClone(obj.a[i]);
+	}
+
+	return newobj;
+}
+	
+
+/* adds the class/paylod wrapper objects */
+function encodeJS(arg) {
+	if( arg == null ) return null;	
+	if( typeof arg != 'object' ) return arg;
+
+	if( arg._isfieldmapper ) {
+      var newarr = []
+      if(!arg.a) arg.a = [];
+		for( var i = 0; i < arg.a.length; i++ ) 
+			newarr[i] = encodeJS(arg.a[i]);
+
+		var a = {};
+		a[JSON_CLASS_KEY] = arg.classname;
+		a[JSON_DATA_KEY] = newarr;
+      return a;
+	}
+
+	var newobj;
+
+	if(arg.length != undefined) {
+		newobj = [];
+		for( var i = 0; i < arg.length; i++ ) 
+         newobj.push(encodeJS(arg[i]));
+      return newobj;
+	} 
+   
+	newobj = {};
+	for( var i in arg )
+		newobj[i] = encodeJS(arg[i]);
+	return newobj;
+}
+
+/* turns a javascript object into a JSON string */
+function js2JSON(arg) {
+	return js2JSONRaw(encodeJS(arg));
+}
+
+function js2JSONRaw(arg) {
+
+	if( arg == null ) 
+		return 'null';
+
+	var o;
+
+	switch (typeof arg) {
+
+		case 'object':
+
+			if (arg.constructor == Array) {
+				o = '';
+				jsIterate( arg,
+					function(obj, i) {
+						if (o) o += ',';
+						o += js2JSONRaw(obj[i]);
+					}
+				);
+				return '[' + o + ']';
+
+			} else if (typeof arg.toString != 'undefined') {
+				o = '';
+				jsIterate( arg,
+					function(obj, i) {
+						if (o) o += ',';
+						o = o + js2JSONRaw(i) + ':' + js2JSONRaw(obj[i]);
+					}
+				);
+				return '{' + o + '}';
+
+			} else {
+				return 'null';
+			}
+
+		case 'number': return arg;
+
+		case 'string':
+			var s = String(arg);
+			s = s.replace(/\\/g, '\\\\');
+			s = s.replace(/"/g, '\\"');
+			s = s.replace(/\t/g, "\\t");
+			s = s.replace(/\n/g, "\\n");
+			s = s.replace(/\r/g, "\\r");
+			s = s.replace(/\f/g, "\\f");
+			return '"' + s + '"';
+
+		default: return 'null';
+	}
+}
+
+
+function __tabs(c) { 
+	var s = ''; 
+	for( i = 0; i < c; i++ ) s += '\t';
+	return s;
+}
+
+function jsonPretty(str) {
+	if(!str) return "";
+	var s = '';
+	var d = 0;
+	for( var i = 0; i < str.length; i++ ) {
+		var c = str.charAt(i);
+		if( c == '{' || c == '[' ) {
+			s += c + '\n' + __tabs(++d);
+		} else if( c == '}' || c == ']' ) {
+			s += '\n' + __tabs(--d) + '\n';
+			if( str.charAt(i+1) == ',' ) {
+				s += '\n' + __tabs(d);
+			}
+		} else if( c == ',' ) {
+			s += ',\n' + __tabs(d);
+		} else {
+			s += c;
+		}
+	}
+	return s;
+}
+
+

Modified: branches/autotools/src/jserver/Makefile
===================================================================
--- branches/autotools/src/jserver/Makefile	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/jserver/Makefile	2007-11-05 13:40:16 UTC (rev 1121)
@@ -1,4 +1,4 @@
-LDLIBS	+= -lopensrf -lobjson -lxml2
+LDLIBS	+= -lopensrf  -lxml2
 CFLAGS	+= -D_GNU_SOURCE
 
 all: chopchop

Modified: branches/autotools/src/jserver/osrf_chat.c
===================================================================
--- branches/autotools/src/jserver/osrf_chat.c	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/jserver/osrf_chat.c	2007-11-05 13:40:16 UTC (rev 1121)
@@ -279,7 +279,7 @@
 
 	int l = strlen(toAddr);
 	char dombuf[l];
-	bzero(dombuf, l);
+	memset(dombuf, 0, sizeof(dombuf));
 	jid_get_domain( toAddr, dombuf, l );	
 
 	if( eq( dombuf, cs->domain ) ) { /* this is to a user we host */
@@ -595,8 +595,7 @@
 
 char* osrfChatMkAuthKey() {
 	char keybuf[112];
-	bzero(keybuf, 112);
-	snprintf(keybuf, 111, "%d%ld%s", (int) time(NULL), (long) getpid(), getenv("HOSTNAME"));
+	snprintf(keybuf, sizeof(keybuf), "%d%ld%s", (int) time(NULL), (long) getpid(), getenv("HOSTNAME"));
 	return strdup(shahash(keybuf));
 }
 

Modified: branches/autotools/src/libopensrf/Makefile
===================================================================
--- branches/autotools/src/libopensrf/Makefile	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/libopensrf/Makefile	2007-11-05 13:40:16 UTC (rev 1121)
@@ -1,10 +1,17 @@
-# OSRF_LOG_PARAMS log all incoming method params at OSRF_INFO log level. 
-# OSRF_STRICT_PARAMS instructs the app handler to return an error if the number of method arguments
-#	provided to any method is not at least as large as the 'argc' setting for the method
+# ------------------------------------------------------------------
+# To build the standalone JSON lib libosrf_json.so:
+# 	$ make libosrf_json.so
+# To build the standalone JSON lib libosrf_json.so with XML utils 
+# 	support, use something like the following:
+# 	$ CFLAGS="-DOSRF_JSON_ENABLE_XML_UTILS -I/usr/include/libxml2" LDLIBS=-lxml2 make libosrf_json.so
+#
+# The compiler flag -DOSRF_JSON_ALLOW_COMMENTS tells the parser to 
+# allow legacy JSON comments like /* comment */
+# ------------------------------------------------------------------
 
-CFLAGS	+=  -DASSUME_STATELESS  -DOSRF_LOG_PARAMS -DOSRF_STRICT_PARAMS -rdynamic -fno-strict-aliasing
-LDLIBS	+= -lxml2 -lobjson -ldl -lmemcache 
-OSRF_INC = ../../include/opensrf/
+CFLAGS	+=  -DASSUME_STATELESS  -DOSRF_STRICT_PARAMS -rdynamic -fno-strict-aliasing -I../../include -fPIC -Wall -DOSRF_JSON_ENABLE_XML_UTILS
+LDLIBS	+= -lxml2 -ldl -lmemcache 
+export OSRF_INC = ../../include/opensrf/
 
 TARGETS = 	osrf_message.o \
 			osrf_app_session.o \
@@ -27,12 +34,24 @@
 			utils.o\
 			socket_bundle.o\
 			sha.o\
-			string_array.o 
+			string_array.o
 
+JSON_TARGETS = 	osrf_json_object.o\
+				osrf_json_parser.o \
+				osrf_json_tools.o \
+				osrf_legacy_json.o \
+				osrf_json_xml.o
 
-all: opensrf
+# use these when building the standalone JSON module
+JSON_DEPS = osrf_list.o\
+			osrf_hash.o\
+			utils.o\
+			log.o\
+			md5.o\
+			string_array.o
 
 
+all: opensrf
 
 # Build the OpenSRF C binary
 opensrf:	opensrf.o libopensrf.so
@@ -41,10 +60,28 @@
 
 
 # Build the OpenSRF library
-libopensrf.so:	$(TARGETS)
-	$(CC) -shared -W1 $(LDFLAGS) $(LDLIBS) $(TARGETS) -o $(TMPDIR)/libopensrf.so
+libopensrf.so:	$(TARGETS) json
+	if [ ! -z "$(OSRF_LEGACY_JSON)" ]; then\
+		$(CC) -shared -W1 $(LDFLAGS) $(LDLIBS) $(TARGETS) -o $(TMPDIR)/libopensrf.so;\
+	else\
+		$(CC) -shared -W1 $(LDFLAGS) $(LDLIBS) $(TARGETS) $(JSON_TARGETS) -o $(TMPDIR)/libopensrf.so;\
+	fi; 
 
 
+json:	$(JSON_TARGETS) $(JSON_DEPS)
+	if [ ! -z "$(OSRF_LEGACY_JSON)" ]; then \
+		$(CC) -shared -W1  $(CFLAGS) \
+			$(LDFLAGS) $(JSON_TARGETS) $(JSON_DEPS) -o $(TMPDIR)/libobjson.so;\
+	fi;
+
+libosrf_json.so:	$(JSON_TARGETS) $(JSON_DEPS)
+	$(CC) -shared -W1 $(CFLAGS) \
+		$(LDFLAGS) $(LDLIBS) $(JSON_TARGETS) $(JSON_DEPS) -o $@
+
+
+osrf_json_test:	osrf_json_test.o $(JSON_TARGETS) $(JSON_DEPS)
+
+
 opensrf.o:	opensrf.c
 transport_message.o:	transport_message.c $(OSRF_INC)/transport_message.h	
 transport_session.o:	transport_session.c $(OSRF_INC)/transport_session.h	
@@ -66,8 +103,17 @@
 socket_bundle.o:	socket_bundle.c $(OSRF_INC)/socket_bundle.h
 sha.o:	sha.c $(OSRF_INC)/sha.h
 string_array.o:	string_array.c $(OSRF_INC)/string_array.h
+osrf_json_object.o:	osrf_json_object.c $(OSRF_INC)/osrf_json.h $(OSRF_INC)/osrf_json_utils.h
+osrf_json_parser.o:	osrf_json_parser.c $(OSRF_INC)/osrf_json.h $(OSRF_INC)/osrf_json_utils.h
+osrf_json_tools.o:	osrf_json_tools.c $(OSRF_INC)/osrf_json.h $(OSRF_INC)/osrf_json_utils.h
+osrf_legacy_json.o:	osrf_legacy_json.c $(OSRF_INC)/osrf_json.h $(OSRF_INC)/osrf_json_utils.h
+osrf_json_xml.o:	osrf_json_xml.c $(OSRF_INC)/osrf_json.h $(OSRF_INC)/osrf_json_xml.h
+osrf_json_test.o:	osrf_json_test.c
 
 
 clean:
-	/bin/rm -f *.o libopensrf.so opensrf
+	/bin/rm -f *.o *.so opensrf osrf_json_test
 
+
+
+

Copied: branches/autotools/src/libopensrf/Makefile.json (from rev 1120, trunk/src/libopensrf/Makefile.json)
===================================================================
--- branches/autotools/src/libopensrf/Makefile.json	                        (rev 0)
+++ branches/autotools/src/libopensrf/Makefile.json	2007-11-05 13:40:16 UTC (rev 1121)
@@ -0,0 +1,40 @@
+#-DOSRF_JSON_ALLOW_COMMENTS 
+
+# ------------------------------------------------------------------
+# To build a standalone version of libosrf_json, something 
+# like the following should work:
+# $ CFLAGS="-fPIC -I /usr/include/libxml2 -I ../../include" \
+# 	OSRF_INC="../../include/opensrf" LDLIBS="-lxml2" \
+# 	make -f Makefile.json standalone
+# ------------------------------------------------------------------
+TARGETS = osrf_json_object.o osrf_json_parser.o osrf_json_tools.o osrf_legacy_json.o osrf_json_xml.o
+
+# these are only needed when compiling the standalone version
+EXT_TARGETS = osrf_list.o osrf_hash.o utils.o log.o md5.o string_array.o
+
+all:	$(TARGETS)
+	if [ ! -z "$(OSRF_LEGACY_JSON)" ]; then \
+		$(CC) -shared -W1 $(LDFLAGS) $(TARGETS) -o $(TMPDIR)/libobjson.so;\
+	fi;
+
+standalone: $(TARGETS) $(EXT_TARGETS)
+	$(CC) -shared -W1 $(CFLAGS) $(LDFLAGS) $(LDLIBS) $(TARGETS) $(EXT_TARGETS) -o libosrf_json.so
+
+osrf_json_object.o:	osrf_json_object.c $(OSRF_INC)/osrf_json.h $(OSRF_INC)/osrf_json_utils.h
+osrf_json_parser.o:	osrf_json_parser.c $(OSRF_INC)/osrf_json.h $(OSRF_INC)/osrf_json_utils.h
+osrf_json_tools.o:	osrf_json_tools.c $(OSRF_INC)/osrf_json.h $(OSRF_INC)/osrf_json_utils.h
+osrf_legacy_json.o:	osrf_legacy_json.c $(OSRF_INC)/osrf_json.h $(OSRF_INC)/osrf_json_utils.h
+osrf_json_xml.o:	osrf_json_xml.c $(OSRF_INC)/osrf_json.h $(OSRF_INC)/osrf_json_xml.h
+
+
+osrf_list.o:	osrf_list.c $(OSRF_INC)/osrf_list.h
+osrf_hash.o:	osrf_hash.c $(OSRF_INC)/osrf_hash.h
+utils.o:	utils.c $(OSRF_INC)/utils.h
+md5.o:	md5.c $(OSRF_INC)/md5.h
+log.o:	log.c $(OSRF_INC)/log.h
+string_array.o:	string_array.c $(OSRF_INC)/string_array.h
+
+
+clean:
+	rm -f osrf_json*.o osrf_legacy_json.o libosrf_json.so
+

Modified: branches/autotools/src/libopensrf/basic_client.c
===================================================================
--- branches/autotools/src/libopensrf/basic_client.c	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/libopensrf/basic_client.c	2007-11-05 13:40:16 UTC (rev 1121)
@@ -31,10 +31,10 @@
 		signal(SIGINT, sig_int);
 		fprintf(stderr, "Listener: %ld\n", (long) getpid() );	
 		char buf[300];
-		memset(buf, 0, 300);
+		osrf_clearbuf(buf, sizeof(buf));
 		printf("=> ");
 
-		while( fgets( buf, 299, stdin) ) {
+		while( fgets( buf, sizeof(buf), stdin) ) {
 
 			// remove newline
 			buf[strlen(buf)-1] = '\0';
@@ -48,7 +48,7 @@
 			client_send_message( client, send );
 			message_free( send );
 			printf("\n=> ");
-			memset(buf, 0, 300);
+			osrf_clearbuf(buf, sizeof(buf));
 		}
 		fprintf(stderr, "Killing child %d\n", pid );
 		kill( pid, SIGKILL );

Modified: branches/autotools/src/libopensrf/log.c
===================================================================
--- branches/autotools/src/libopensrf/log.c	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/libopensrf/log.c	2007-11-05 13:40:16 UTC (rev 1121)
@@ -58,8 +58,7 @@
    if(_osrfLogIsClient) {
       static int _osrfLogXidInc = 0; /* increments with each new xid for uniqueness */
       char buf[32];
-      memset(buf, 0x0, 32);
-      snprintf(buf, 32, "%s%d", _osrfLogXidPfx, _osrfLogXidInc);
+      snprintf(buf, sizeof(buf), "%s%d", _osrfLogXidPfx, _osrfLogXidInc);
       _osrfLogSetXid(buf);
       _osrfLogXidInc++;
    }
@@ -74,8 +73,7 @@
    if(!is) return;
    /* go ahead and create the xid prefix so it will be consistent later */
    static char buff[32];
-   memset(buff, 0x0, 32);
-   snprintf(buff, 32, "%d%ld", (int)time(NULL), (long) getpid());
+   snprintf(buff, sizeof(buff), "%d%ld", (int)time(NULL), (long) getpid());
    _osrfLogXidPfx = buff;
 }
 
@@ -223,7 +221,7 @@
 
    if( logtype == OSRF_LOG_TYPE_SYSLOG ) {
 		char buf[1536];  
-		memset(buf, 0x0, 1536);
+		osrf_clearbuf(buf, sizeof(buf));
 		/* give syslog some breathing room, and be cute about it */
 		strncat(buf, msg, 1535);
 		buf[1532] = '.';

Modified: branches/autotools/src/libopensrf/opensrf.c
===================================================================
--- branches/autotools/src/libopensrf/opensrf.c	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/libopensrf/opensrf.c	2007-11-05 13:40:16 UTC (rev 1121)
@@ -1,6 +1,4 @@
 #include <opensrf/osrf_system.h>
-//#include <opensrf/osrf_hash.h>
-//#include <opensrf/osrf_list.h>
 
 int main( int argc, char* argv[] ) {
 

Modified: branches/autotools/src/libopensrf/osrf_app_session.c
===================================================================
--- branches/autotools/src/libopensrf/osrf_app_session.c	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/libopensrf/osrf_app_session.c	2007-11-05 13:40:16 UTC (rev 1121)
@@ -4,7 +4,6 @@
 /* the global app_session cache */
 osrfHash* osrfAppSessionCache = NULL;
 
-
 // --------------------------------------------------------------------------
 // --------------------------------------------------------------------------
 // Request API
@@ -111,6 +110,11 @@
 			osrf_message* ret_msg = req->result;
 			osrf_message* tmp_msg = ret_msg->next;
 			req->result = tmp_msg;
+			if (ret_msg->sender_locale) {
+				if (req->session->session_locale)
+					free(req->session->session_locale);
+				req->session->session_locale = strdup(ret_msg->sender_locale);
+			}
 			return ret_msg;
 		}
 
@@ -125,6 +129,11 @@
 			osrf_message* ret_msg = req->result;
 			osrf_message* tmp_msg = ret_msg->next;
 			req->result = tmp_msg;
+			if (ret_msg->sender_locale) {
+				if (req->session->session_locale)
+					free(req->session->session_locale);
+				req->session->session_locale = strdup(ret_msg->sender_locale);
+			}
 			return ret_msg;
 		}
 		if( req->complete )
@@ -133,7 +142,7 @@
 		if(req->reset_timeout) {
 			remaining = (time_t) timeout;
 			req->reset_timeout = 0;
-			osrfLogDebug( OSRF_LOG_MARK, "Recevied a timeout reset");
+			osrfLogDebug( OSRF_LOG_MARK, "Received a timeout reset");
 		} else {
 			remaining -= (int) (time(NULL) - start);
 		}
@@ -161,6 +170,18 @@
 // --------------------------------------------------------------------------
 
 /** returns a session from the global session hash */
+char* osrf_app_session_set_locale( osrf_app_session* session, const char* locale ) {
+	if (!session || !locale)
+		return NULL;
+
+	if(session->session_locale)
+		free(session->session_locale);
+
+	session->session_locale = strdup( locale );
+	return session->session_locale;
+}
+
+/** returns a session from the global session hash */
 osrf_app_session* osrf_app_session_find_session( char* session_id ) {
 	if(session_id) return osrfHashGet(osrfAppSessionCache, session_id);
 	return NULL;
@@ -183,6 +204,11 @@
 
 osrf_app_session* osrf_app_client_session_init( char* remote_service ) {
 
+	if (!remote_service) {
+		osrfLogWarning( OSRF_LOG_MARK, "No remote service specified in osrf_app_client_session_init");
+		return NULL;
+	}
+
 	osrf_app_session* session = safe_malloc(sizeof(osrf_app_session));	
 
 	session->transport_handle = osrf_system_get_transport_client();
@@ -192,15 +218,32 @@
 		return NULL;
 	}
 
-	char target_buf[512];
-	target_buf[ 0 ] = '\0';
-
 	osrfStringArray* arr = osrfNewStringArray(8);
 	osrfConfigGetValueList(NULL, arr, "/domains/domain");
 	char* domain = osrfStringArrayGetString(arr, 0);
+
+	if (!domain) {
+		osrfLogWarning( OSRF_LOG_MARK, "No domains specified in the OpenSRF config file");
+		free( session );
+		osrfStringArrayFree(arr);
+		return NULL;
+	}
+
 	char* router_name = osrfConfigGetValue(NULL, "/router_name");
-	
-	int len = snprintf( target_buf, 512, "%s@%s/%s",  router_name, domain, remote_service );
+	if (!router_name) {
+		osrfLogWarning( OSRF_LOG_MARK, "No router name specified in the OpenSRF config file");
+		free( session );
+		osrfStringArrayFree(arr);
+		return NULL;
+	}
+
+	char target_buf[512];
+	target_buf[ 0 ] = '\0';
+
+	int len = snprintf( target_buf, sizeof(target_buf), "%s@%s/%s",
+			router_name ? router_name : "(null)",
+			domain ? domain : "(null)",
+			remote_service ? remote_service : "(null)" );
 	osrfStringArrayFree(arr);
 	//free(domain);
 	free(router_name);
@@ -216,6 +259,7 @@
 	session->remote_id = strdup(target_buf);
 	session->orig_remote_id = strdup(session->remote_id);
 	session->remote_service = strdup(remote_service);
+	session->session_locale = NULL;
 
 	#ifdef ASSUME_STATELESS
 	session->stateless = 1;
@@ -227,9 +271,8 @@
 
 	/* build a chunky, random session id */
 	char id[256];
-	memset(id,0,256);
 
-	sprintf(id, "%f.%d%ld", get_timestamp_millis(), (int)time(NULL), (long) getpid());
+	snprintf(id, sizeof(id), "%f.%d%ld", get_timestamp_millis(), (int)time(NULL), (long) getpid());
 	session->session_id = strdup(id);
 	osrfLogDebug( OSRF_LOG_MARK,  "Building a new client session with id [%s] [%s]", 
 			session->remote_service, session->session_id );
@@ -296,6 +339,9 @@
 	if( session->userDataFree && session->userData ) 
 		session->userDataFree(session->userData);
 	
+	if(session->session_locale)
+		free(session->session_locale);
+
 	free(session->remote_id);
 	free(session->orig_remote_id);
 	free(session->session_id);
@@ -308,19 +354,42 @@
 		osrf_app_session* session, jsonObject* params, 
 		char* method_name, int protocol, string_array* param_strings ) {
 
-	return osrf_app_session_make_req( session, params, 
-			method_name, protocol, param_strings );
+	return osrf_app_session_make_locale_req( session, params, 
+			method_name, protocol, param_strings, NULL );
 }
 
+int osrfAppSessionMakeLocaleRequest(
+		osrf_app_session* session, jsonObject* params, 
+		char* method_name, int protocol, string_array* param_strings, char* locale ) {
+
+	return osrf_app_session_make_locale_req( session, params, 
+			method_name, protocol, param_strings, locale );
+}
+
 int osrf_app_session_make_req( 
 		osrf_app_session* session, jsonObject* params, 
-		char* method_name, int protocol, string_array* param_strings ) {
+		char* method_name, int protocol, string_array* param_strings) {
+
+	return osrf_app_session_make_locale_req(session, params,
+			method_name, protocol, param_strings, NULL);
+}
+
+int osrf_app_session_make_locale_req( 
+		osrf_app_session* session, jsonObject* params, 
+		char* method_name, int protocol, string_array* param_strings, char* locale ) {
 	if(session == NULL) return -1;
 
-   osrfLogMkXid();
+	osrfLogMkXid();
 
 	osrf_message* req_msg = osrf_message_init( REQUEST, ++(session->thread_trace), protocol );
 	osrf_message_set_method(req_msg, method_name);
+
+	if (locale) {
+		osrf_message_set_locale(req_msg, locale);
+	} else if (session->session_locale) {
+		osrf_message_set_locale(req_msg, session->session_locale);
+	}
+
 	if(params) {
 		osrf_message_set_params(req_msg, params);
 
@@ -341,7 +410,7 @@
 		return -1;
 	}
 
-	osrfLogDebug( OSRF_LOG_MARK,  "Pushing [%d] onto requeust queue for session [%s] [%s]",
+	osrfLogDebug( OSRF_LOG_MARK,  "Pushing [%d] onto request queue for session [%s] [%s]",
 			req->request_id, session->remote_service, session->session_id );
 	osrfListSet( session->request_queue, req, req->request_id ); 
 	return req->request_id;

Modified: branches/autotools/src/libopensrf/osrf_application.c
===================================================================
--- branches/autotools/src/libopensrf/osrf_application.c	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/libopensrf/osrf_application.c	2007-11-05 13:40:16 UTC (rev 1121)
@@ -1,11 +1,7 @@
 #include <opensrf/osrf_application.h>
-#include <objson/object.h>
 
-//osrfApplication* __osrfAppList = NULL; 
-
 osrfHash* __osrfAppHash = NULL;
 
-
 int osrfAppRegisterApplication( char* appName, char* soFile ) {
 	if(!appName || ! soFile) return -1;
 	char* error;
@@ -16,7 +12,7 @@
 
 	osrfApplication* app = safe_malloc(sizeof(osrfApplication));
 	app->handle = dlopen (soFile, RTLD_NOW);
-   app->onExit = NULL;
+	app->onExit = NULL;
 
 	if(!app->handle) {
 		osrfLogWarning( OSRF_LOG_MARK, "Failed to dlopen library file %s: %s", soFile, dlerror() );
@@ -55,28 +51,27 @@
 
 	osrfLogSetAppname(appName);
 
-   osrfAppSetOnExit(app, appName);
+	osrfAppSetOnExit(app, appName);
 
 	return 0;
 }
 
 
 void osrfAppSetOnExit(osrfApplication* app, char* appName) {
-   if(!(app && appName)) return;
+	if(!(app && appName)) return;
 
 	/* see if we can run the initialize method */
-   char* error;
+	char* error;
 	void (*onExit) (void);
 	*(void **) (&onExit) = dlsym(app->handle, "osrfAppChildExit");
 
 	if( (error = dlerror()) != NULL ) {
-      osrfLogDebug(OSRF_LOG_MARK, "No exit handler defined for %s", appName);
-      return;
-   }
+		osrfLogDebug(OSRF_LOG_MARK, "No exit handler defined for %s", appName);
+		return;
+	}
 
-   osrfLogInfo(OSRF_LOG_MARK, "registering exit handler for %s", appName);
-   app->onExit = (*onExit);
-   //if( (ret = (*onExit)()) ) {
+	osrfLogInfo(OSRF_LOG_MARK, "registering exit handler for %s", appName);
+	app->onExit = (*onExit);
 }
 
 
@@ -106,14 +101,14 @@
 
 
 void osrfAppRunExitCode() { 
-   osrfHashIterator* itr = osrfNewHashIterator(__osrfAppHash);
-   osrfApplication* app;
-   while( (app = osrfHashIteratorNext(itr)) ) {
-      if( app->onExit ) {
-         osrfLogInfo(OSRF_LOG_MARK, "Running onExit handler for app %s", itr->current);
-         app->onExit();
-      }
-   }
+	osrfHashIterator* itr = osrfNewHashIterator(__osrfAppHash);
+	osrfApplication* app;
+	while( (app = osrfHashIteratorNext(itr)) ) {
+		if( app->onExit ) {
+			osrfLogInfo(OSRF_LOG_MARK, "Running onExit handler for app %s", itr->current);
+			app->onExit();
+		}
+	}
 }
 
 

Modified: branches/autotools/src/libopensrf/osrf_cache.c
===================================================================
--- branches/autotools/src/libopensrf/osrf_cache.c	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/libopensrf/osrf_cache.c	2007-11-05 13:40:16 UTC (rev 1121)
@@ -96,4 +96,9 @@
 	return -1;
 }
 
+void osrfCacheCleanup() {
+    if(__osrfCache) 
+        mc_free(__osrfCache);
+}
 
+

Modified: branches/autotools/src/libopensrf/osrf_hash.c
===================================================================
--- branches/autotools/src/libopensrf/osrf_hash.c	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/libopensrf/osrf_hash.c	2007-11-05 13:40:16 UTC (rev 1121)
@@ -193,7 +193,7 @@
 	}
 
 	osrfListFree(hash->hash);
-	osrfStringArrayFree(hash->keys);
+    OSRF_STRING_ARRAY_FREE(hash->keys);
 	free(hash);
 }
 
@@ -201,7 +201,6 @@
 
 osrfHashIterator* osrfNewHashIterator( osrfHash* hash ) {
 	if(!hash) return NULL;
-	//osrfHashIterator* itr = safe_malloc(sizeof(osrfHashIterator));
 	osrfHashIterator* itr;
 	OSRF_MALLOC(itr, sizeof(osrfHashIterator));
 	itr->hash = hash;
@@ -214,8 +213,7 @@
 	if(!(itr && itr->hash)) return NULL;
 	if( itr->currentIdx >= itr->keys->size ) return NULL;
 	free(itr->current);
-	itr->current = strdup(
-			osrfStringArrayGetString(itr->keys, itr->currentIdx++));
+	itr->current = strdup(osrfStringArrayGetString(itr->keys, itr->currentIdx++));
 	char* val = osrfHashGet( itr->hash, itr->current );
 	return val;
 }
@@ -223,14 +221,12 @@
 void osrfHashIteratorFree( osrfHashIterator* itr ) {
 	if(!itr) return;
 	free(itr->current);
-	//osrfStringArrayFree(itr->keys);
 	free(itr);
 }
 
 void osrfHashIteratorReset( osrfHashIterator* itr ) {
 	if(!itr) return;
 	free(itr->current);
-	//osrfStringArrayFree(itr->keys);
 	itr->keys = osrfHashKeysInc(itr->hash);
 	itr->currentIdx = 0;
 	itr->current = NULL;

Copied: branches/autotools/src/libopensrf/osrf_json_object.c (from rev 1120, trunk/src/libopensrf/osrf_json_object.c)
===================================================================
--- branches/autotools/src/libopensrf/osrf_json_object.c	                        (rev 0)
+++ branches/autotools/src/libopensrf/osrf_json_object.c	2007-11-05 13:40:16 UTC (rev 1121)
@@ -0,0 +1,428 @@
+/*
+Copyright (C) 2006  Georgia Public Library Service 
+Bill Erickson <billserickson at gmail.com>
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+*/
+
+#include <limits.h>
+#include <opensrf/osrf_json.h>
+#include <opensrf/osrf_json_utils.h>
+
+/* cleans up an object if it is morphing another object, also
+ * verifies that the appropriate storage container exists where appropriate */
+#define JSON_INIT_CLEAR(_obj_, newtype)		\
+	if( _obj_->type == JSON_HASH && newtype != JSON_HASH ) {			\
+		osrfHashFree(_obj_->value.h);			\
+		_obj_->value.h = NULL; 					\
+} else if( _obj_->type == JSON_ARRAY && newtype != JSON_ARRAY ) {	\
+		osrfListFree(_obj_->value.l);			\
+		_obj_->value.l = NULL;					\
+} else if( _obj_->type == JSON_STRING && newtype != JSON_STRING ) { \
+		free(_obj_->value.s);						\
+		_obj_->value.s = NULL;					\
+} \
+	_obj_->type = newtype;\
+	if( newtype == JSON_HASH && _obj_->value.h == NULL ) {	\
+		_obj_->value.h = osrfNewHash();		\
+		_obj_->value.h->freeItem = _jsonFreeHashItem; \
+} else if( newtype == JSON_ARRAY && _obj_->value.l == NULL ) {	\
+		_obj_->value.l = osrfNewList();		\
+		_obj_->value.l->freeItem = _jsonFreeListItem;\
+}
+
+static void add_json_to_buffer( const jsonObject* obj, growing_buffer * buf );
+
+jsonObject* jsonNewObject(const char* data) {
+
+	jsonObject* o;
+	OSRF_MALLOC(o, sizeof(jsonObject));
+	o->type = JSON_NULL;
+
+	if(data) {
+		o->type = JSON_STRING;
+		o->value.s = strdup(data);
+	}
+
+	return o;
+}
+
+jsonObject* jsonNewObjectFmt(const char* data, ...) {
+
+	jsonObject* o;
+	OSRF_MALLOC(o, sizeof(jsonObject));
+	o->type = JSON_NULL;
+
+	if(data) {
+		VA_LIST_TO_STRING(data);
+		o->type = JSON_STRING;
+		o->value.s = strdup(VA_BUF);
+	}
+
+	return o;
+}
+
+jsonObject* jsonNewNumberObject( double num ) {
+	jsonObject* o = jsonNewObject(NULL);
+	o->type = JSON_NUMBER;
+	o->value.n = num;
+	return o;
+}
+
+jsonObject* jsonNewBoolObject(int val) {
+    jsonObject* o = jsonNewObject(NULL);
+    o->type = JSON_BOOL;
+    jsonSetBool(o, val);
+    return o;
+}
+
+jsonObject* jsonNewObjectType(int type) {
+	jsonObject* o = jsonNewObject(NULL);
+	o->type = type;
+	return o;
+}
+
+void jsonObjectFree( jsonObject* o ) {
+
+	if(!o || o->parent) return;
+	free(o->classname);
+
+	switch(o->type) {
+		case JSON_HASH		: osrfHashFree(o->value.h); break;
+		case JSON_ARRAY	: osrfListFree(o->value.l); break;
+		case JSON_STRING	: free(o->value.s); break;
+	}
+	free(o);
+}
+
+static void _jsonFreeHashItem(char* key, void* item){
+	if(!item) return;
+	jsonObject* o = (jsonObject*) item;
+	o->parent = NULL; /* detach the item */
+	jsonObjectFree(o);
+}
+static void _jsonFreeListItem(void* item){
+	if(!item) return;
+	jsonObject* o = (jsonObject*) item;
+	o->parent = NULL; /* detach the item */
+	jsonObjectFree(o);
+}
+
+void jsonSetBool(jsonObject* bl, int val) {
+    if(!bl) return;
+    JSON_INIT_CLEAR(bl, JSON_BOOL);
+    bl->value.b = val;
+}
+
+unsigned long jsonObjectPush(jsonObject* o, jsonObject* newo) {
+    if(!o) return -1;
+    if(!newo) newo = jsonNewObject(NULL);
+	JSON_INIT_CLEAR(o, JSON_ARRAY);
+	newo->parent = o;
+	osrfListPush( o->value.l, newo );
+	o->size = o->value.l->size;
+	return o->size;
+}
+
+unsigned long jsonObjectSetIndex(jsonObject* dest, unsigned long index, jsonObject* newObj) {
+    if(!dest) return -1;
+    if(!newObj) newObj = jsonNewObject(NULL);
+	JSON_INIT_CLEAR(dest, JSON_ARRAY);
+	newObj->parent = dest;
+	osrfListSet( dest->value.l, newObj, index );
+	dest->size = dest->value.l->size;
+	return dest->value.l->size;
+}
+
+unsigned long jsonObjectSetKey( jsonObject* o, const char* key, jsonObject* newo) {
+    if(!o) return -1;
+    if(!newo) newo = jsonNewObject(NULL);
+	JSON_INIT_CLEAR(o, JSON_HASH);
+	newo->parent = o;
+	osrfHashSet( o->value.h, newo, key );
+	o->size = o->value.h->size;
+	return o->size;
+}
+
+jsonObject* jsonObjectGetKey( const jsonObject* obj, const char* key ) {
+	if(!(obj && obj->type == JSON_HASH && obj->value.h && key)) return NULL;
+	return osrfHashGet( obj->value.h, key);
+}
+
+const jsonObject* jsonObjectGetKeyConst( const jsonObject* obj, const char* key ) {
+	if(!(obj && obj->type == JSON_HASH && obj->value.h && key)) return NULL;
+	return osrfHashGet( obj->value.h, key);
+}
+
+char* jsonObjectToJSON( const jsonObject* obj ) {
+	jsonObject* obj2 = jsonObjectEncodeClass( obj );
+	char* json = jsonObjectToJSONRaw(obj2);
+	jsonObjectFree(obj2);
+	return json;
+}
+
+char* jsonObjectToJSONRaw( const jsonObject* obj ) {
+	if(!obj) return NULL;
+	growing_buffer* buf = buffer_init(32);
+	add_json_to_buffer( obj, buf );
+	return buffer_release( buf );
+}
+
+static void add_json_to_buffer( const jsonObject* obj, growing_buffer * buf ) {
+
+	switch(obj->type) {
+
+		case JSON_BOOL :
+			if(obj->value.b) OSRF_BUFFER_ADD(buf, "true"); 
+			else OSRF_BUFFER_ADD(buf, "false"); 
+			break;
+
+		case JSON_NUMBER: {
+			double x = obj->value.n;
+			if( x <= INT_MAX && x >= INT_MIN && x == (int) x ) {
+				INT_TO_STRING((int)x);
+				OSRF_BUFFER_ADD(buf, INTSTR);
+
+			} else {
+				DOUBLE_TO_STRING(x);
+				OSRF_BUFFER_ADD(buf, DOUBLESTR);
+			}
+			break;
+		}
+
+		case JSON_NULL:
+			OSRF_BUFFER_ADD(buf, "null");
+			break;
+
+		case JSON_STRING:
+			OSRF_BUFFER_ADD_CHAR(buf, '"');
+			char* data = obj->value.s;
+			int len = strlen(data);
+			
+			char* output = uescape(data, len, 1);
+			OSRF_BUFFER_ADD(buf, output);
+			free(output);
+			OSRF_BUFFER_ADD_CHAR(buf, '"');
+			break;
+			
+		case JSON_ARRAY: {
+			OSRF_BUFFER_ADD_CHAR(buf, '[');
+			if( obj->value.l ) {
+				int i;
+				for( i = 0; i != obj->value.l->size; i++ ) {
+					if(i > 0) OSRF_BUFFER_ADD(buf, ",");
+					add_json_to_buffer( OSRF_LIST_GET_INDEX(obj->value.l, i), buf );
+				}
+			}
+			OSRF_BUFFER_ADD_CHAR(buf, ']');
+			break;
+		}
+
+		case JSON_HASH: {
+
+			OSRF_BUFFER_ADD_CHAR(buf, '{');
+			osrfHashIterator* itr = osrfNewHashIterator(obj->value.h);
+			jsonObject* item;
+			int i = 0;
+
+			while( (item = osrfHashIteratorNext(itr)) ) {
+				if(i++ > 0) OSRF_BUFFER_ADD(buf, ",");
+				buffer_fadd(buf, "\"%s\":", itr->current);
+				add_json_to_buffer( item, buf );
+			}
+
+			osrfHashIteratorFree(itr);
+			OSRF_BUFFER_ADD_CHAR(buf, '}');
+			break;
+		}
+	}
+}
+
+
+jsonIterator* jsonNewIterator(const jsonObject* obj) {
+	if(!obj) return NULL;
+	jsonIterator* itr;
+	OSRF_MALLOC(itr, sizeof(jsonIterator));
+
+	itr->obj		= (jsonObject*) obj;
+	itr->index	= 0;
+	itr->key		= NULL;
+
+	if( obj->type == JSON_HASH )
+		itr->hashItr = osrfNewHashIterator(obj->value.h);
+	
+	return itr;
+}
+
+void jsonIteratorFree(jsonIterator* itr) {
+	if(!itr) return;
+	free(itr->key);
+	osrfHashIteratorFree(itr->hashItr);
+	free(itr);
+}
+
+jsonObject* jsonIteratorNext(jsonIterator* itr) {
+	if(!(itr && itr->obj)) return NULL;
+	if( itr->obj->type == JSON_HASH ) {
+		if(!itr->hashItr) return NULL;
+		jsonObject* item = osrfHashIteratorNext(itr->hashItr);
+		free(itr->key);
+		itr->key = strdup(itr->hashItr->current);
+		return item;
+	} else {
+		return jsonObjectGetIndex( itr->obj, itr->index++ );
+	}
+}
+
+int jsonIteratorHasNext(const jsonIterator* itr) {
+	if(!(itr && itr->obj)) return 0;
+	if( itr->obj->type == JSON_HASH )
+		return osrfHashIteratorHasNext( itr->hashItr );
+	return (itr->index < itr->obj->size) ? 1 : 0;
+}
+
+jsonObject* jsonObjectGetIndex( const jsonObject* obj, unsigned long index ) {
+	if(!obj) return NULL;
+	return (obj->type == JSON_ARRAY) ? 
+        (OSRF_LIST_GET_INDEX(obj->value.l, index)) : NULL;
+}
+
+
+
+unsigned long jsonObjectRemoveIndex(jsonObject* dest, unsigned long index) {
+	if( dest && dest->type == JSON_ARRAY ) {
+		osrfListRemove(dest->value.l, index);
+		return dest->value.l->size;
+	}
+	return -1;
+}
+
+
+unsigned long jsonObjectRemoveKey( jsonObject* dest, const char* key) {
+	if( dest && key && dest->type == JSON_HASH ) {
+		osrfHashRemove(dest->value.h, key);
+		return 1;
+	}
+	return -1;
+}
+
+char* jsonObjectGetString(const jsonObject* obj) {
+	return (obj && obj->type == JSON_STRING) ? obj->value.s : NULL;
+}
+
+double jsonObjectGetNumber( const jsonObject* obj ) {
+	return (obj && obj->type == JSON_NUMBER) ? obj->value.n : 0;
+}
+
+void jsonObjectSetString(jsonObject* dest, const char* string) {
+	if(!(dest && string)) return;
+	JSON_INIT_CLEAR(dest, JSON_STRING);
+	free(dest->value.s);
+	dest->value.s = strdup(string);
+}
+
+void jsonObjectSetNumber(jsonObject* dest, double num) {
+	if(!dest) return;
+	JSON_INIT_CLEAR(dest, JSON_NUMBER);
+	dest->value.n = num;
+}
+
+void jsonObjectSetClass(jsonObject* dest, const char* classname ) {
+	if(!(dest && classname)) return;
+	free(dest->classname);
+	dest->classname = strdup(classname);
+}
+const char* jsonObjectGetClass(const jsonObject* dest) {
+    if(!dest) return NULL;
+    return dest->classname;
+}
+
+jsonObject* jsonObjectClone( const jsonObject* o ) {
+    if(!o) return jsonNewObject(NULL);
+
+    int i;
+    jsonObject* arr; 
+    jsonObject* hash; 
+    jsonIterator* itr;
+    jsonObject* tmp;
+    jsonObject* result = NULL;
+
+    switch(o->type) {
+        case JSON_NULL:
+            result = jsonNewObject(NULL);
+            break;
+        case JSON_STRING:
+            result = jsonNewObject(jsonObjectGetString(o));
+            break;
+        case JSON_NUMBER:
+            result = jsonNewNumberObject(jsonObjectGetNumber(o));
+            break;
+        case JSON_BOOL:
+            result = jsonNewBoolObject(jsonBoolIsTrue((jsonObject*) o));
+            break;
+        case JSON_ARRAY:
+            arr = jsonNewObject(NULL);
+            arr->type = JSON_ARRAY;
+            for(i=0; i < o->size; i++) 
+                jsonObjectPush(arr, jsonObjectClone(jsonObjectGetIndex(o, i)));
+            result = arr;
+            break;
+        case JSON_HASH:
+            hash = jsonNewObject(NULL);
+            hash->type = JSON_HASH;
+            itr = jsonNewIterator(o);
+            while( (tmp = jsonIteratorNext(itr)) )
+                jsonObjectSetKey(hash, itr->key, jsonObjectClone(tmp));
+            jsonIteratorFree(itr);
+            result = hash;
+            break;
+    }
+
+    jsonObjectSetClass(result, jsonObjectGetClass(o));
+    return result;
+}
+
+int jsonBoolIsTrue( jsonObject* boolObj ) {
+    if( boolObj && boolObj->type == JSON_BOOL && boolObj->value.b )
+        return 1;
+    return 0;
+}
+
+
+char* jsonObjectToSimpleString( const jsonObject* o ) {
+	if(!o) return NULL;
+
+	char* value = NULL;
+
+	switch( o->type ) {
+
+		case JSON_NUMBER: {
+
+			if( o->value.n == (int) o->value.n ) {
+				INT_TO_STRING((int) o->value.n);	
+				value = strdup(INTSTR);
+
+			} else {
+				DOUBLE_TO_STRING(o->value.n);
+				value = strdup(DOUBLESTR);
+			}
+
+			break;
+		}
+
+		case JSON_STRING:
+			value = strdup(o->value.s);
+	}
+
+	return value;
+}
+
+

Copied: branches/autotools/src/libopensrf/osrf_json_parser.c (from rev 1120, trunk/src/libopensrf/osrf_json_parser.c)
===================================================================
--- branches/autotools/src/libopensrf/osrf_json_parser.c	                        (rev 0)
+++ branches/autotools/src/libopensrf/osrf_json_parser.c	2007-11-05 13:40:16 UTC (rev 1121)
@@ -0,0 +1,632 @@
+/*
+Copyright (C) 2006  Georgia Public Library Service 
+Bill Erickson <billserickson at gmail.com>
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+*/
+
+#include <opensrf/osrf_json.h>
+#include <opensrf/osrf_json_utils.h>
+#include <ctype.h>
+
+
+/* if the client sets a global error handler, this will point to it */
+static void (*jsonClientErrorCallback) (const char*) = NULL;
+
+/* these are the handlers for our internal parser */
+static jsonParserHandler jsonInternalParserHandlerStruct = {
+	_jsonHandleStartObject,
+	_jsonHandleObjectKey,
+	_jsonHandleEndObject,
+	_jsonHandleStartArray,
+	_jsonHandleEndArray,
+	_jsonHandleNull,
+	_jsonHandleString,
+	_jsonHandleBool,
+	_jsonHandleNumber,
+	_jsonHandleError
+};
+static jsonParserHandler* 
+	jsonInternalParserHandler = &jsonInternalParserHandlerStruct; 
+
+
+jsonParserContext* jsonNewParser( jsonParserHandler* handler, void* userData) {
+	jsonParserContext* ctx;
+	OSRF_MALLOC(ctx, sizeof(jsonParserContext));
+	ctx->stateStack			= osrfNewList();
+	ctx->buffer					= buffer_init(512);
+	ctx->utfbuf					= buffer_init(5);
+	ctx->handler				= handler;
+	ctx->state					= 0;
+	ctx->index					= 0;
+	ctx->chunk					= NULL;
+	ctx->userData				= userData;
+	return ctx;
+}
+
+void jsonParserFree( jsonParserContext* ctx ) {
+	if(!ctx) return;
+	buffer_free(ctx->buffer);
+	buffer_free(ctx->utfbuf);
+	osrfListFree(ctx->stateStack);
+	free(ctx);
+}
+
+
+void jsonSetGlobalErrorHandler(void (*errorHandler) (const char*)) {
+	jsonClientErrorCallback = errorHandler;
+}
+
+
+int _jsonParserError( jsonParserContext* ctx, char* err, ... ) {
+	if( ctx->handler->handleError ) {
+		VA_LIST_TO_STRING(err);
+		int pre	= ctx->index - 15;
+		int post= ctx->index + 15;
+		while( pre < 0 ) pre++;
+		while( post >= ctx->chunksize ) post--;
+		int l = post - pre;
+		char buf[l];
+		snprintf(buf, sizeof(buf), ctx->chunk + pre);
+		ctx->handler->handleError( ctx->userData, 
+			"*JSON Parser Error\n - char  = %c\n "
+			"- index = %d\n - near  => %s\n - %s", 
+			ctx->chunk[ctx->index], ctx->index, buf, VA_BUF );
+	}
+	JSON_STATE_SET(ctx, JSON_STATE_IS_INVALID);
+	return -1;
+}
+
+
+int _jsonParserHandleUnicode( jsonParserContext* ctx ) {
+
+	/* collect as many of the utf characters as we can in this chunk */
+	JSON_CACHE_DATA(ctx, ctx->utfbuf, 4);
+
+	/* we ran off the end of the chunk */
+	if( ctx->utfbuf->n_used < 4 ) {
+		JSON_STATE_SET(ctx, JSON_STATE_IN_UTF);
+		return 1;
+	}
+
+	ctx->index--; /* push it back to index of the final utf char */
+
+	/* ----------------------------------------------------------------------- */
+	/* We have all of the escaped unicode data.  Write it to the buffer */
+	/* The following chunk is used with permission from 
+	 * json-c http://oss.metaparadigm.com/json-c/ 
+	 */
+	#define hexdigit(x) ( ((x) <= '9') ? (x) - '0' : ((x) & 7) + 9)
+	unsigned char utf_out[4];
+	memset(utf_out, 0, sizeof(utf_out));
+	char* buf = ctx->utfbuf->buf;
+
+	unsigned int ucs_char =
+		(hexdigit(buf[0] ) << 12) +
+		(hexdigit(buf[1]) << 8) +
+		(hexdigit(buf[2]) << 4) +
+		hexdigit(buf[3]);
+
+	if (ucs_char < 0x80) {
+		utf_out[0] = ucs_char;
+		OSRF_BUFFER_ADD(ctx->buffer, (char*)utf_out);
+
+	} else if (ucs_char < 0x800) {
+		utf_out[0] = 0xc0 | (ucs_char >> 6);
+		utf_out[1] = 0x80 | (ucs_char & 0x3f);
+		OSRF_BUFFER_ADD(ctx->buffer, (char*)utf_out);
+
+	} else {
+		utf_out[0] = 0xe0 | (ucs_char >> 12);
+		utf_out[1] = 0x80 | ((ucs_char >> 6) & 0x3f);
+		utf_out[2] = 0x80 | (ucs_char & 0x3f);
+		OSRF_BUFFER_ADD(ctx->buffer, (char*)utf_out);
+	}
+	/* ----------------------------------------------------------------------- */
+	/* ----------------------------------------------------------------------- */
+
+	JSON_STATE_REMOVE(ctx, JSON_STATE_IN_UTF);
+	JSON_STATE_REMOVE(ctx, JSON_STATE_IN_ESCAPE);
+	OSRF_BUFFER_RESET(ctx->utfbuf);
+	return 0;
+}
+
+
+
+/* type : 0=null, 1=true, 2=false */
+int _jsonParserHandleMatch( jsonParserContext* ctx, int type ) {
+
+	switch(type) {
+
+		case 0: /* JSON null */
+
+			/* first see if we have it all first */
+			if( ctx->chunksize > (ctx->index + 3) ) {
+				if( strncasecmp(ctx->chunk + ctx->index, "null", 4) ) 
+					return _jsonParserError(ctx, "Invalid JSON 'null' sequence");
+				if( ctx->handler->handleNull ) 
+					ctx->handler->handleNull(ctx->userData);
+				ctx->index += 4;
+				break;
+			}
+
+			JSON_CACHE_DATA(ctx, ctx->buffer, 4);
+			if( ctx->buffer->n_used < 4 ) {
+				JSON_STATE_SET(ctx, JSON_STATE_IN_NULL);
+				return 1;
+			} 
+
+			if( strncasecmp(ctx->buffer->buf, "null", 4) ) 
+				return _jsonParserError(ctx, "Invalid JSON 'null' sequence");
+			if( ctx->handler->handleNull ) 
+				ctx->handler->handleNull(ctx->userData);
+			break;
+
+		case 1: /* JSON true */
+
+			/* see if we have it all first */
+			if( ctx->chunksize > (ctx->index + 3) ) {
+				if( strncasecmp(ctx->chunk + ctx->index, "true", 4) ) 
+					return _jsonParserError(ctx, "Invalid JSON 'true' sequence");
+				if( ctx->handler->handleBool ) 
+					ctx->handler->handleBool(ctx->userData, 1);
+				ctx->index += 4;
+				break;
+			}
+
+			JSON_CACHE_DATA(ctx, ctx->buffer, 4);
+			if( ctx->buffer->n_used < 4 ) {
+				JSON_STATE_SET(ctx, JSON_STATE_IN_TRUE);
+				return 1;
+			} 
+			if( strncasecmp( ctx->buffer->buf, "true", 4 ) ) {
+				return _jsonParserError(ctx, "Invalid JSON 'true' sequence");
+			}
+			if( ctx->handler->handleBool ) 
+				ctx->handler->handleBool(ctx->userData, 1);
+			break;
+
+		case 2: /* JSON false */
+
+			/* see if we have it all first */
+			if( ctx->chunksize > (ctx->index + 4) ) {
+				if( strncasecmp(ctx->chunk + ctx->index, "false", 5) ) 
+					return _jsonParserError(ctx, "Invalid JSON 'false' sequence");
+				if( ctx->handler->handleBool ) 
+					ctx->handler->handleBool(ctx->userData, 0);
+				ctx->index += 5;
+				break;
+			}
+
+			JSON_CACHE_DATA(ctx, ctx->buffer, 5);
+			if( ctx->buffer->n_used < 5 ) {
+				JSON_STATE_SET(ctx, JSON_STATE_IN_FALSE);
+				return 1;
+			}
+			if( strncasecmp( ctx->buffer->buf, "false", 5 ) ) 
+				return _jsonParserError(ctx, "Invalid JSON 'false' sequence");
+			if( ctx->handler->handleBool ) 
+				ctx->handler->handleBool(ctx->userData, 0);
+			break;
+
+		default: 
+			fprintf(stderr, "Invalid type flag\n");
+			return -1;
+
+	}
+
+	ctx->index--; /* set it back to the index of the final sequence character */
+	OSRF_BUFFER_RESET(ctx->buffer);
+	JSON_STATE_REMOVE(ctx, JSON_STATE_IN_NULL);
+	JSON_STATE_REMOVE(ctx, JSON_STATE_IN_TRUE);
+	JSON_STATE_REMOVE(ctx, JSON_STATE_IN_FALSE);
+
+	return 0;
+}
+
+
+int _jsonParserHandleString( jsonParserContext* ctx ) {
+
+	char c = ctx->chunk[ctx->index];
+
+	if( JSON_STATE_CHECK(ctx, JSON_STATE_IN_ESCAPE) ) {
+
+		if( JSON_STATE_CHECK(ctx, JSON_STATE_IN_UTF) ) {
+
+			return _jsonParserHandleUnicode( ctx );
+						
+		} else {
+
+			switch(c) {
+
+				/* handle all of the escape chars */
+				case '\\': OSRF_BUFFER_ADD_CHAR( ctx->buffer, '\\' ); break;
+				case '"'	: OSRF_BUFFER_ADD_CHAR( ctx->buffer, '\"' ); break;
+				case 't'	: OSRF_BUFFER_ADD_CHAR( ctx->buffer, '\t' ); break;
+				case 'b'	: OSRF_BUFFER_ADD_CHAR( ctx->buffer, '\b' ); break;
+				case 'f'	: OSRF_BUFFER_ADD_CHAR( ctx->buffer, '\f' ); break;
+				case 'r'	: OSRF_BUFFER_ADD_CHAR( ctx->buffer, '\r' ); break;
+				case 'n'	: OSRF_BUFFER_ADD_CHAR( ctx->buffer, '\n' ); break;
+				case 'u'	: 
+					ctx->index++; /* progress to the first utf char */
+					return _jsonParserHandleUnicode( ctx );
+				default	: OSRF_BUFFER_ADD_CHAR( ctx->buffer, c );
+			}
+		}
+
+		JSON_STATE_REMOVE(ctx, JSON_STATE_IN_ESCAPE);
+		return 0;
+
+	} else {
+
+		switch(c) {
+
+			case '"'	: /* this string is ending */
+				if( JSON_STATE_CHECK(ctx, JSON_STATE_IN_KEY) ) {
+
+					/* object key */
+					if(ctx->handler->handleObjectKey) {
+						ctx->handler->handleObjectKey( 
+							ctx->userData, ctx->buffer->buf);
+					}
+
+				} else { /* regular json string */
+
+					if(ctx->handler->handleString) {
+						ctx->handler->handleString( 
+							ctx->userData, ctx->buffer->buf );
+					}
+
+				}
+
+				OSRF_BUFFER_RESET(ctx->buffer); /* flush the buffer and states */
+				JSON_STATE_REMOVE(ctx, JSON_STATE_IN_STRING);
+				JSON_STATE_REMOVE(ctx, JSON_STATE_IN_KEY);
+				break;
+
+			case '\\' : JSON_STATE_SET(ctx, JSON_STATE_IN_ESCAPE); break;
+			default	 : OSRF_BUFFER_ADD_CHAR( ctx->buffer, c );
+		}
+	}
+	return 0;
+}
+
+
+int _jsonParserHandleNumber( jsonParserContext* ctx ) {
+	char c = ctx->chunk[ctx->index];
+
+	do {
+		OSRF_BUFFER_ADD_CHAR(ctx->buffer, c);
+		c = ctx->chunk[++(ctx->index)];
+	} while( strchr(JSON_NUMBER_CHARS, c) && ctx->index < ctx->chunksize );
+
+	/* if we're run off the end of the chunk and we're not parsing the last chunk,
+	 * save the number and the state */
+	if( ctx->index >= ctx->chunksize && 
+			! JSON_PARSE_FLAG_CHECK(ctx, JSON_PARSE_LAST_CHUNK) ) {
+		JSON_STATE_SET(ctx, JSON_STATE_IN_NUMBER);
+		return 1;
+	}
+
+	/* make me more strict */
+	char* err = NULL;
+	double d = strtod(ctx->buffer->buf, &err);
+	if(err && err[0] != '\0') 
+		return _jsonParserError(ctx, "Invalid number sequence");
+	JSON_STATE_REMOVE(ctx, JSON_STATE_IN_NUMBER);
+	OSRF_BUFFER_RESET(ctx->buffer);
+	if(ctx->handler->handleNumber)
+		ctx->handler->handleNumber( ctx->userData, d );
+	ctx->index--; /* scooch back to the first non-digit number */
+	return 0;
+}
+
+
+
+
+int jsonParseChunk( jsonParserContext* ctx, const char* data, int datalen, int flags ) {
+
+	if( !( ctx && ctx->handler && data && datalen > 0 )) return -1;
+	ctx->chunksize  = datalen;
+	ctx->chunk		= data;
+	ctx->flags		= flags;
+	char c;
+
+	if( JSON_STATE_CHECK(ctx, JSON_STATE_IS_INVALID) )
+		return _jsonParserError( ctx, "JSON Parser cannot continue after an error" );
+
+	if( JSON_STATE_CHECK(ctx, JSON_STATE_IS_DONE) )
+		return _jsonParserError( ctx, "Extra content at end of JSON data" );
+
+	for( ctx->index = 0; (ctx->index < ctx->chunksize) && 
+				(c = ctx->chunk[ctx->index]); ctx->index++ ) {
+
+		/* middle of parsing a string */
+		if( JSON_STATE_CHECK(ctx, JSON_STATE_IN_STRING)) {
+			if( _jsonParserHandleString(ctx) == -1 )
+				return -1;
+			continue;
+		}
+
+		/* middle of parsing a number */
+		if( JSON_STATE_CHECK(ctx, JSON_STATE_IN_NUMBER) ) {
+			if( _jsonParserHandleNumber(ctx) == -1 )
+				return -1;
+			continue;
+		}
+
+
+#ifdef OSRF_JSON_ALLOW_COMMENTS
+		/* we just saw a bare '/' character */
+		if( JSON_STATE_CHECK(ctx, JSON_STATE_START_COMMENT) ) {
+			if(c == '*') {
+				JSON_STATE_REMOVE(ctx, JSON_STATE_START_COMMENT);
+				JSON_STATE_SET(ctx, JSON_STATE_IN_COMMENT);
+				continue;
+			} else {
+				return _jsonParserError( ctx, "Invalid comment initializer" );
+			}
+		}
+
+		/* we're currently in the middle of a comment block */
+		if( JSON_STATE_CHECK(ctx, JSON_STATE_IN_COMMENT) ) {
+			if(c == '*') {
+				JSON_STATE_REMOVE(ctx, JSON_STATE_IN_COMMENT);
+				JSON_STATE_SET(ctx, JSON_STATE_END_COMMENT);
+				continue;
+			} else {
+				continue;
+			}
+		}
+
+		/* we're in a comment, and we just saw a '*' character */
+		if( JSON_STATE_CHECK(ctx, JSON_STATE_END_COMMENT) ) {
+			if( c == '/' ) { /* comment is finished */
+				JSON_STATE_REMOVE(ctx, JSON_STATE_END_COMMENT);
+				continue;
+			} else {
+				/* looks like this isn't the end of the comment after all */
+				JSON_STATE_SET(ctx, JSON_STATE_IN_COMMENT);
+				JSON_STATE_REMOVE(ctx, JSON_STATE_END_COMMENT);
+			}
+		}
+#endif
+
+		/* if we're in the middle of parsing a null/true/false sequence */
+		if( JSON_STATE_CHECK(ctx, (JSON_STATE_IN_NULL | 
+					JSON_STATE_IN_TRUE | JSON_STATE_IN_FALSE)) ) {
+
+			int type = (JSON_STATE_CHECK(ctx, JSON_STATE_IN_NULL)) ? 0 :
+				(JSON_STATE_CHECK(ctx, JSON_STATE_IN_TRUE)) ? 1 : 2;
+
+			if( _jsonParserHandleMatch( ctx, type ) == -1 ) 
+				return -1;
+			continue;
+		}
+
+		JSON_EAT_WS(ctx);
+
+		/* handle all of the top level characters */
+		switch(c) {
+
+			case '{' : /* starting an object */
+				if( ctx->handler->handleStartObject) 
+					ctx->handler->handleStartObject( ctx->userData );
+				JSON_STATE_PUSH(ctx, JSON_STATE_IN_OBJECT);
+				JSON_STATE_SET(ctx, JSON_STATE_IN_KEY);
+				break;
+
+			case '}' : /* ending an object */
+				if( ctx->handler->handleEndObject) 
+					ctx->handler->handleEndObject( ctx->userData ); 
+                JSON_STATE_REMOVE(ctx, JSON_STATE_IN_KEY);
+				JSON_STATE_POP(ctx);
+				if( JSON_STATE_PEEK(ctx) == NULL )
+					JSON_STATE_SET(ctx, JSON_STATE_IS_DONE);
+				break;
+
+			case '[' : /* starting an array */
+				if( ctx->handler->handleStartArray )
+					ctx->handler->handleStartArray( ctx->userData );
+				JSON_STATE_PUSH(ctx, JSON_STATE_IN_ARRAY);
+				break;
+
+			case ']': /* ending an array */
+				if( ctx->handler->handleEndArray )
+					ctx->handler->handleEndArray( ctx->userData );
+				JSON_STATE_POP(ctx);
+				if( JSON_STATE_PEEK(ctx) == NULL )
+					JSON_STATE_SET(ctx, JSON_STATE_IS_DONE);
+				break;
+				
+			case ':' : /* done with the object key */
+				JSON_STATE_REMOVE(ctx, JSON_STATE_IN_KEY);
+				break;
+
+			case ',' : /* after object or array item */
+				if( JSON_STATE_CHECK_STACK(ctx, JSON_STATE_IN_OBJECT) )
+					JSON_STATE_SET(ctx, JSON_STATE_IN_KEY);
+				break;
+
+			case 'n' :
+			case 'N' : /* null */
+				if( _jsonParserHandleMatch( ctx, 0 ) == -1)
+					return -1;
+				break;
+
+			case 't' :
+			case 'T' :
+				if( _jsonParserHandleMatch( ctx, 1 ) == -1 )
+					return -1;
+				break;
+
+			case 'f' :
+			case 'F' :
+				if( _jsonParserHandleMatch( ctx, 2 ) == -1)
+					return -1;
+				break;
+
+			case '"' : 
+				JSON_STATE_SET(ctx, JSON_STATE_IN_STRING);
+				break;
+
+#ifdef OSRF_JSON_ALLOW_COMMENTS
+			case '/' :
+				JSON_STATE_SET(ctx, JSON_STATE_START_COMMENT);
+				break;
+#endif
+
+			default:
+				if( strchr(JSON_NUMBER_CHARS, c) ) {
+					if( _jsonParserHandleNumber( ctx ) == -1 )
+						return -1;
+				} else {
+					return _jsonParserError( ctx, "Invalid Token" );
+				}
+		}
+	}
+
+	return 0;
+}
+
+
+jsonInternalParser* _jsonNewInternalParser() {
+	jsonInternalParser* p;
+	OSRF_MALLOC(p, sizeof(jsonInternalParser));
+	p->ctx = jsonNewParser( jsonInternalParserHandler, p );
+	p->obj		= NULL;
+	p->lastkey	= NULL;
+	return p;
+}
+
+void _jsonInternalParserFree(jsonInternalParser* p) {
+	if(!p) return;
+	jsonParserFree(p->ctx);
+	free(p->lastkey);
+	free(p);
+}
+
+static jsonObject* _jsonParseStringImpl(const char* str, void (*errorHandler) (const char*) ) {
+	jsonInternalParser* parser = _jsonNewInternalParser();
+	parser->handleError = errorHandler;
+	jsonParseChunk( parser->ctx, str, strlen(str),  JSON_PARSE_LAST_CHUNK );
+	jsonObject* obj = parser->obj;
+	_jsonInternalParserFree(parser);
+	return obj;
+}
+
+jsonObject* jsonParseStringHandleError( 
+		void (*errorHandler) (const char*), char* str, ... ) {
+	if(!str) return NULL;
+	VA_LIST_TO_STRING(str);
+	return _jsonParseStringImpl(VA_BUF, errorHandler);
+}
+
+jsonObject* jsonParseString( const char* str ) {
+	if(!str) return NULL;
+	jsonObject* obj =  _jsonParseStringImpl(str, NULL);
+	jsonObject* obj2 = jsonObjectDecodeClass(obj);
+	jsonObjectFree(obj);
+	return obj2;
+}
+
+jsonObject* jsonParseStringRaw( const char* str ) {
+	if(!str) return NULL;
+	return _jsonParseStringImpl(str, NULL);
+}
+
+jsonObject* jsonParseStringFmt( const char* str, ... ) {
+	if(!str) return NULL;
+	VA_LIST_TO_STRING(str);
+	return _jsonParseStringImpl(VA_BUF, NULL);
+}
+
+
+#define JSON_SHOVE_ITEM(ctx,type)  \
+	jsonInternalParser* p = (jsonInternalParser*) ctx;\
+	_jsonInsertParserItem(p, jsonNewObjectType(type));
+
+void _jsonHandleStartObject(void* ctx) { JSON_SHOVE_ITEM(ctx, JSON_HASH); }
+void _jsonHandleStartArray(void* ctx) { JSON_SHOVE_ITEM(ctx, JSON_ARRAY); }
+void _jsonHandleNull(void* ctx) { JSON_SHOVE_ITEM(ctx, JSON_NULL); }
+
+void _jsonHandleObjectKey(void* ctx, char* key) {
+	jsonInternalParser* p = (jsonInternalParser*) ctx;
+	free(p->lastkey);
+	p->lastkey = strdup(key);
+}
+
+void _jsonHandleEndObject(void* ctx) {
+	jsonInternalParser* p = (jsonInternalParser*) ctx;
+	p->current = p->current->parent;
+}
+
+void _jsonHandleEndArray(void* ctx) {
+	jsonInternalParser* p = (jsonInternalParser*) ctx;
+	p->current = p->current->parent;
+}
+
+void _jsonHandleString(void* ctx, char* string) {
+	jsonInternalParser* p = (jsonInternalParser*) ctx;
+	_jsonInsertParserItem(p, jsonNewObject(string));
+}
+
+void _jsonHandleBool(void* ctx, int boolval) {
+	jsonInternalParser* p = (jsonInternalParser*) ctx;
+	jsonObject* obj = jsonNewObjectType(JSON_BOOL);
+	obj->value.b = boolval;
+	_jsonInsertParserItem(p, obj);
+}
+
+void _jsonHandleNumber(void* ctx, double num) {
+	jsonInternalParser* p = (jsonInternalParser*) ctx;
+	_jsonInsertParserItem(p, jsonNewNumberObject(num));
+}
+
+void _jsonHandleError(void* ctx, char* str, ...) {
+	jsonInternalParser* p = (jsonInternalParser*) ctx;
+	VA_LIST_TO_STRING(str);
+
+	if( p->handleError ) 
+		p->handleError(VA_BUF);
+	else 
+		if( jsonClientErrorCallback ) 
+			jsonClientErrorCallback(VA_BUF);
+
+	else fprintf(stderr, "%s\n", VA_BUF);
+	jsonObjectFree(p->obj);
+	p->obj = NULL;
+}
+
+
+void _jsonInsertParserItem( jsonInternalParser* p, jsonObject* newo ) {
+
+	if( !p->obj ) {
+
+		/* new parser, set the new object to our object */
+		p->obj = p->current = newo;
+
+	} else {
+
+		/* insert the new object into the current container object */
+		switch(p->current->type) { 
+			case JSON_HASH	: jsonObjectSetKey(p->current, p->lastkey, newo);  break;
+			case JSON_ARRAY: jsonObjectPush(p->current, newo); break;
+			default: fprintf(stderr, "%s:%d -> how?\n", JSON_LOG_MARK); 
+		} 
+
+		/* if the new object is a container object, make it our current container */
+		if( newo->type == JSON_ARRAY || newo->type == JSON_HASH )
+			p->current = newo;	
+	}
+}
+
+

Copied: branches/autotools/src/libopensrf/osrf_json_test.c (from rev 1120, trunk/src/libopensrf/osrf_json_test.c)
===================================================================
--- branches/autotools/src/libopensrf/osrf_json_test.c	                        (rev 0)
+++ branches/autotools/src/libopensrf/osrf_json_test.c	2007-11-05 13:40:16 UTC (rev 1121)
@@ -0,0 +1,55 @@
+/*
+ * Basic JSON test module.  Needs more strenous tests....
+ *
+ */
+#include <stdio.h>
+#include <opensrf/osrf_json.h>
+
+static void speedTest();
+
+
+int main(int argc, char* argv[]) {
+    /* XXX add support for command line test type specification */
+    speedTest(); 
+    return 0; 
+}
+
+
+
+static void speedTest() {
+
+    /* creates a giant json object, generating JSON strings
+     * of subobjects as it goes. */
+
+    int i,k;
+    int count = 50;
+    char buf[16];
+    char* jsonString;
+
+    jsonObject* array;
+    jsonObject* dupe;
+    jsonObject* hash = jsonNewObject(NULL);
+
+    for(i = 0; i < count; i++) {
+        
+        snprintf(buf, sizeof(buf), "key_%d", i);
+
+        array = jsonNewObject(NULL);
+        for(k = 0; k < count + i; k++) {
+            jsonObjectPush(array, jsonNewNumberObject(k));
+            jsonObjectPush(array, jsonNewObject(NULL));
+            jsonObjectPush(array, jsonNewObjectFmt("str %d-%d", i, k));
+        }
+        jsonObjectSetKey(hash, buf, array);
+
+        jsonString = jsonObjectToJSON(hash);
+        printf("%s\n\n", jsonString);
+        dupe = jsonParseString(jsonString);
+
+        jsonObjectFree(dupe);
+        free(jsonString);
+    }
+
+    jsonObjectFree(hash);
+}
+

Copied: branches/autotools/src/libopensrf/osrf_json_tools.c (from rev 1120, trunk/src/libopensrf/osrf_json_tools.c)
===================================================================
--- branches/autotools/src/libopensrf/osrf_json_tools.c	                        (rev 0)
+++ branches/autotools/src/libopensrf/osrf_json_tools.c	2007-11-05 13:40:16 UTC (rev 1121)
@@ -0,0 +1,297 @@
+/*
+Copyright (C) 2006  Georgia Public Library Service 
+Bill Erickson <billserickson at gmail.com>
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+*/
+
+#include <opensrf/osrf_json.h>
+
+jsonObject* _jsonObjectEncodeClass( const jsonObject* obj, int ignoreClass );
+
+
+jsonObject* jsonObjectFindPath( const jsonObject* obj, char* path, ...);
+jsonObject* _jsonObjectFindPathRecurse(const jsonObject* obj, char* root, char* path);
+jsonObject* __jsonObjectFindPathRecurse(const jsonObject* obj, char* root);
+
+
+static char* __tabs(int count) {
+	growing_buffer* buf = buffer_init(24);
+	int i;
+	for(i=0;i<count;i++) OSRF_BUFFER_ADD(buf, "  ");
+    return buffer_release(buf);
+}
+
+char* jsonFormatString( const char* string ) {
+	if(!string) return strdup("");
+
+	growing_buffer* buf = buffer_init(64);
+	int i;
+	int depth = 0;
+	char* tab = NULL;
+
+	char c;
+	for(i=0; i!= strlen(string); i++) {
+		c = string[i];
+
+		if( c == '{' || c == '[' ) {
+
+			tab = __tabs(++depth);
+			buffer_fadd( buf, "%c\n%s", c, tab);
+			free(tab);
+
+		} else if( c == '}' || c == ']' ) {
+
+			tab = __tabs(--depth);
+			buffer_fadd( buf, "\n%s%c", tab, c);
+			free(tab);
+
+			if(string[i+1] != ',') {
+				tab = __tabs(depth);
+				buffer_fadd( buf, "%s", tab );	
+				free(tab);
+			}
+
+		} else if( c == ',' ) {
+
+			tab = __tabs(depth);
+			buffer_fadd(buf, ",\n%s", tab);
+			free(tab);
+
+		} else { buffer_add_char(buf, c); }
+
+	}
+
+    return buffer_release(buf);
+}
+
+
+
+jsonObject* jsonObjectDecodeClass( const jsonObject* obj ) {
+	if(!obj) return jsonNewObject(NULL);
+
+	jsonObject* newObj			 = NULL; 
+	const jsonObject* classObj	 = NULL;
+	const jsonObject* payloadObj = NULL;
+	int i;
+
+	if( obj->type == JSON_HASH ) {
+
+		/* are we a special class object? */
+		if( (classObj = jsonObjectGetKeyConst( obj, JSON_CLASS_KEY )) ) {
+
+			/* do we have a payload */
+			if( (payloadObj = jsonObjectGetKeyConst( obj, JSON_DATA_KEY )) ) {
+				newObj = jsonObjectDecodeClass( payloadObj ); 
+				jsonObjectSetClass( newObj, jsonObjectGetString(classObj) );
+
+			} else { /* class is defined but there is no payload */
+				return NULL;
+			}
+
+		} else { /* we're a regular hash */
+
+			jsonIterator* itr = jsonNewIterator(obj);
+			jsonObject* tmp;
+			newObj = jsonNewObjectType(JSON_HASH);
+			while( (tmp = jsonIteratorNext(itr)) ) {
+				jsonObject* o = jsonObjectDecodeClass(tmp);
+				jsonObjectSetKey( newObj, itr->key, o );
+			}
+			jsonIteratorFree(itr);
+		}
+
+	} else {
+
+		if( obj->type == JSON_ARRAY ) { /* we're an array */
+			newObj = jsonNewObjectType(JSON_ARRAY);
+			for( i = 0; i != obj->size; i++ ) {
+				jsonObject* tmp = jsonObjectDecodeClass(jsonObjectGetIndex( obj, i ) );
+				jsonObjectSetIndex( newObj, i, tmp );
+			}
+
+		} else { /* not an aggregate type */
+			newObj = jsonObjectClone(obj);
+		}
+	}
+		
+	return newObj;
+}
+
+jsonObject* jsonObjectEncodeClass( const jsonObject* obj ) {
+	return _jsonObjectEncodeClass( obj, 0 );
+}
+
+jsonObject* _jsonObjectEncodeClass( const jsonObject* obj, int ignoreClass ) {
+
+	//if(!obj) return NULL;
+	if(!obj) return jsonNewObject(NULL);
+	jsonObject* newObj = NULL;
+
+	if( obj->classname && ! ignoreClass ) {
+		newObj = jsonNewObjectType(JSON_HASH);
+
+		jsonObjectSetKey( newObj, 
+			JSON_CLASS_KEY, jsonNewObject(obj->classname) ); 
+
+		jsonObjectSetKey( newObj, 
+			JSON_DATA_KEY, _jsonObjectEncodeClass(obj, 1));
+
+	} else if( obj->type == JSON_HASH ) {
+
+		jsonIterator* itr = jsonNewIterator(obj);
+		jsonObject* tmp;
+		newObj = jsonNewObjectType(JSON_HASH);
+
+		while( (tmp = jsonIteratorNext(itr)) ) {
+			jsonObjectSetKey( newObj, itr->key, 
+					_jsonObjectEncodeClass(tmp, 0));
+		}
+		jsonIteratorFree(itr);
+
+	} else if( obj->type == JSON_ARRAY ) {
+
+		newObj = jsonNewObjectType(JSON_ARRAY);
+		int i;
+		for( i = 0; i != obj->size; i++ ) {
+			jsonObjectSetIndex( newObj, i, 
+				_jsonObjectEncodeClass(jsonObjectGetIndex( obj, i ), 0 ));
+		}
+
+	} else {
+		newObj = jsonObjectClone(obj);
+	}
+
+	return newObj;
+}
+
+jsonObject* jsonParseFile( char* filename ) {
+	if(!filename) return NULL;
+	char* data = file_to_string(filename);
+	jsonObject* o = jsonParseString(data);
+	free(data);
+	return o;
+}
+
+
+
+jsonObject* jsonObjectFindPath( const jsonObject* obj, char* format, ...) {
+	if(!obj || !format || strlen(format) < 1) return NULL;	
+
+	VA_LIST_TO_STRING(format);
+	char* buf = VA_BUF;
+	char* token = NULL;
+	char* t = buf;
+	char* tt; /* strtok storage */
+
+	/* copy the path before strtok_r destroys it */
+	char* pathcopy = strdup(buf);
+
+	/* grab the root of the path */
+	token = strtok_r(t, "/", &tt);
+	if(!token) return NULL;
+
+	/* special case where path starts with //  (start anywhere) */
+	if(strlen(pathcopy) > 2 && pathcopy[0] == '/' && pathcopy[1] == '/') {
+		jsonObject* it = _jsonObjectFindPathRecurse(obj, token, pathcopy + 1);
+		free(pathcopy);
+		return it;
+	}
+
+	free(pathcopy);
+
+	t = NULL;
+	do { 
+		obj = jsonObjectGetKey(obj, token);
+	} while( (token = strtok_r(NULL, "/", &tt)) && obj);
+
+	return jsonObjectClone(obj);
+}
+
+/* --------------------------------------------------------------- */
+
+
+
+jsonObject* _jsonObjectFindPathRecurse(const jsonObject* obj, char* root, char* path) {
+
+	if(!obj || ! root || !path) return NULL;
+
+	/* collect all of the potential objects */
+	jsonObject* arr = __jsonObjectFindPathRecurse(obj, root);
+
+	/* container for fully matching objects */
+	jsonObject* newarr = jsonParseString("[]");
+	int i;
+
+	/* path is just /root or /root/ */
+	if( strlen(root) + 2 >= strlen(path) ) {
+		return arr;
+
+	} else {
+
+		/* gather all of the sub-objects that match the full path */
+		for( i = 0; i < arr->size; i++ ) {
+			const jsonObject* a = jsonObjectGetIndex(arr, i);
+			jsonObject* thing = jsonObjectFindPath(a , path + strlen(root) + 1); 
+
+			if(thing) { //jsonObjectPush(newarr, thing);
+         	if(thing->type == JSON_ARRAY) {
+            	int i;
+					for( i = 0; i != thing->size; i++ )
+						jsonObjectPush(newarr, jsonObjectClone(jsonObjectGetIndex(thing,i)));
+					jsonObjectFree(thing);
+
+				} else {
+					jsonObjectPush(newarr, thing);
+				}                                         	
+			}
+		}
+	}
+	
+	jsonObjectFree(arr);
+	return newarr;
+}
+
+jsonObject* __jsonObjectFindPathRecurse(const jsonObject* obj, char* root) {
+
+	jsonObject* arr = jsonParseString("[]");
+	if(!obj) return arr;
+
+	int i;
+
+	/* if the current object has a node that matches, add it */
+
+	jsonObject* o = jsonObjectGetKey(obj, root);
+	if(o) jsonObjectPush( arr, jsonObjectClone(o) );
+
+	jsonObject* tmp = NULL;
+	jsonObject* childarr;
+	jsonIterator* itr = jsonNewIterator(obj);
+
+	/* recurse through the children and find all potential nodes */
+	while( (tmp = jsonIteratorNext(itr)) ) {
+		childarr = __jsonObjectFindPathRecurse(tmp, root);
+		if(childarr && childarr->size > 0) {
+			for( i = 0; i!= childarr->size; i++ ) {
+				jsonObjectPush( arr, jsonObjectClone(jsonObjectGetIndex(childarr, i)) );
+			}
+		}
+		jsonObjectFree(childarr);
+	}
+
+	jsonIteratorFree(itr);
+
+	return arr;
+}
+
+
+
+

Copied: branches/autotools/src/libopensrf/osrf_json_xml.c (from rev 1120, trunk/src/libopensrf/osrf_json_xml.c)
===================================================================
--- branches/autotools/src/libopensrf/osrf_json_xml.c	                        (rev 0)
+++ branches/autotools/src/libopensrf/osrf_json_xml.c	2007-11-05 13:40:16 UTC (rev 1121)
@@ -0,0 +1,365 @@
+#include <opensrf/osrf_json_xml.h>
+
+#ifdef OSRF_JSON_ENABLE_XML_UTILS
+
+struct osrfXMLGatewayParserStruct {
+    osrfList* objStack;
+    osrfList* keyStack;
+    jsonObject* obj;
+    short inString;
+    short inNumber;
+    short error;
+};
+typedef struct osrfXMLGatewayParserStruct osrfXMLGatewayParser;
+
+/** returns the attribute value with the given attribute name */
+static char* getXMLAttr(const xmlChar** atts, char* attr_name) {
+    int i;
+    if (atts != NULL) {
+        for(i = 0; (atts[i] != NULL); i++) {
+            if(strcmp((char*) atts[i++], attr_name) == 0) {
+                if(atts[i] != NULL) 
+                    return (char*) atts[i];
+            }
+        }
+    }
+    return NULL;
+}
+
+
+static void appendChild(osrfXMLGatewayParser* p, jsonObject* obj) {
+
+    if(p->obj == NULL) 
+        p->obj = obj;
+
+    if(p->objStack->size == 0)
+        return;
+    
+    jsonObject* parent = OSRF_LIST_GET_INDEX(p->objStack, p->objStack->size - 1);
+
+    if(parent->type == JSON_ARRAY) {
+        jsonObjectPush(parent, obj);
+    } else {
+        char* key = osrfListPop(p->keyStack);
+        jsonObjectSetKey(parent, key, obj);
+        free(key); /* the list is not setup for auto-freeing */
+    }
+}
+
+
+
+static void startElementHandler(
+    void *parser, const xmlChar *name, const xmlChar **atts) {
+
+    osrfXMLGatewayParser* p = (osrfXMLGatewayParser*) parser;
+    jsonObject* obj;
+
+    char* hint = getXMLAttr(atts, "class_hint");
+
+    if(!strcmp((char*) name, "null")) {
+        appendChild(p, jsonNewObject(NULL));
+        return;
+    }
+
+    if(!strcmp((char*) name, "string")) {
+        p->inString = 1;
+        return;
+    }
+
+    if(!strcmp((char*) name, "element")) {
+       osrfListPush(p->keyStack, strdup(getXMLAttr(atts, "key")));
+       return;
+    }
+
+    if(!strcmp((char*) name, "object")) {
+        obj = jsonNewObject(NULL);
+        jsonObjectSetClass(obj, hint); /* OK if hint is NULL */
+        obj->type = JSON_HASH;
+        appendChild(p, obj);
+        osrfListPush(p->objStack, obj);
+        return;
+    }
+
+    if(!strcmp((char*) name, "array")) {
+        obj = jsonNewObject(NULL);
+        jsonObjectSetClass(obj, hint); /* OK if hint is NULL */
+        obj->type = JSON_ARRAY;
+        appendChild(p, obj);
+        osrfListPush(p->objStack, obj);
+        return;
+    }
+
+
+    if(!strcmp((char*) name, "number")) {
+        p->inNumber = 1;
+        return;
+    }
+
+    if(!strcmp((char*) name, "boolean")) {
+        obj = jsonNewObject(NULL);
+        obj->type = JSON_BOOL;
+        char* val = getXMLAttr(atts, "value");
+        if(val && !strcmp(val, "true"))
+            obj->value.b = 1;
+        
+        return;
+    }
+}
+
+static void endElementHandler( void *parser, const xmlChar *name) {
+    if(!strcmp((char*) name, "array") || !strcmp((char*) name, "object")) {
+        osrfXMLGatewayParser* p = (osrfXMLGatewayParser*) parser;
+        osrfListPop(p->objStack);
+    }
+}
+
+static void characterHandler(void *parser, const xmlChar *ch, int len) {
+
+    char data[len+1];
+    strncpy(data, (char*) ch, len);
+    data[len] = '\0';
+    osrfXMLGatewayParser* p = (osrfXMLGatewayParser*) parser;
+
+    if(p->inString) {
+        appendChild(p, jsonNewObject(data));
+        p->inString = 0;
+        return;
+    }
+
+    if(p->inNumber) {
+        appendChild(p, jsonNewNumberObject(atof(data)));
+        p->inNumber = 0;
+        return;
+    }
+}
+
+static void parseWarningHandler(void *parser, const char* msg, ...) {
+    VA_LIST_TO_STRING(msg);
+    fprintf(stderr, "Parser warning %s\n", VA_BUF);
+    fflush(stderr);
+}
+
+static void parseErrorHandler(void *parser, const char* msg, ...) {
+
+    VA_LIST_TO_STRING(msg);
+    fprintf(stderr, "Parser error %s\n", VA_BUF);
+    fflush(stderr);
+
+    osrfXMLGatewayParser* p = (osrfXMLGatewayParser*) parser;
+
+    /*  keyStack as strdup'ed strings.  The list may
+     *  not be empty, so tell it to free the items
+     *  when it's freed (from the main routine)
+     */
+    osrfListSetDefaultFree(p->keyStack);
+    jsonObjectFree(p->obj);
+
+    p->obj = NULL;
+    p->error = 1;
+}
+
+
+
+
+static xmlSAXHandler SAXHandlerStruct = {
+    NULL,                            /* internalSubset */
+    NULL,                            /* isStandalone */
+    NULL,                            /* hasInternalSubset */
+    NULL,                            /* hasExternalSubset */
+    NULL,                            /* resolveEntity */
+    NULL,                            /* getEntity */
+    NULL,                            /* entityDecl */
+    NULL,                            /* notationDecl */
+    NULL,                            /* attributeDecl */
+    NULL,                            /* elementDecl */
+    NULL,                            /* unparsedEntityDecl */
+    NULL,                            /* setDocumentLocator */
+    NULL,                            /* startDocument */
+    NULL,                            /* endDocument */
+    startElementHandler,        /* startElement */
+    endElementHandler,      /* endElement */
+    NULL,                            /* reference */
+    characterHandler,           /* characters */
+    NULL,                            /* ignorableWhitespace */
+    NULL,                            /* processingInstruction */
+    NULL,                            /* comment */
+    parseWarningHandler,     /* xmlParserWarning */
+    parseErrorHandler,       /* xmlParserError */
+    NULL,                            /* xmlParserFatalError : unused */
+    NULL,                            /* getParameterEntity */
+    NULL,                            /* cdataBlock; */
+    NULL,                            /* externalSubset; */
+    1,
+    NULL,
+    NULL,                            /* startElementNs */
+    NULL,                            /* endElementNs */
+    NULL                            /* xmlStructuredErrorFunc */
+};
+
+static const xmlSAXHandlerPtr SAXHandler = &SAXHandlerStruct;
+
+jsonObject* jsonXMLToJSONObject(const char* xml) {
+
+    osrfXMLGatewayParser parser;
+
+    /* don't define freeItem, since objects will be cleaned by freeing the parent */
+    parser.objStack = osrfNewList(); 
+    /* don't define freeItem, since the list eill end up empty if there are no errors*/
+    parser.keyStack = osrfNewList(); 
+    parser.obj = NULL;
+    parser.inString = 0;
+    parser.inNumber = 0;
+
+    xmlParserCtxtPtr ctxt = xmlCreatePushParserCtxt(SAXHandler, &parser, "", 0, NULL);
+    xmlParseChunk(ctxt, xml, strlen(xml), 1);
+
+    osrfListFree(parser.objStack);
+    osrfListFree(parser.keyStack);
+    xmlFreeParserCtxt(ctxt);
+    xmlCleanupCharEncodingHandlers();
+    xmlDictCleanup();
+    xmlCleanupParser();
+
+    return parser.obj;
+}
+
+
+
+
+
+
+static char* _escape_xml (char*);
+static int _recurse_jsonObjectToXML(jsonObject*, growing_buffer*);
+
+char* jsonObjectToXML(jsonObject* obj) {
+
+	growing_buffer * res_xml;
+	char * output;
+
+	res_xml = buffer_init(1024);
+
+	if (!obj)
+		return strdup("<null/>");
+	
+	_recurse_jsonObjectToXML( obj, res_xml );
+	output = buffer_data(res_xml);
+	
+	buffer_free(res_xml);
+
+	return output;
+
+}
+
+int _recurse_jsonObjectToXML(jsonObject* obj, growing_buffer* res_xml) {
+
+	char * hint = NULL;
+	char * bool_val = NULL;
+	int i = 0;
+	
+	if (obj->classname)
+		hint = strdup(obj->classname);
+
+	if(obj->type == JSON_NULL) {
+
+		if (hint)
+			buffer_fadd(res_xml, "<null class_hint=\"%s\"/>",hint);
+		else
+			buffer_add(res_xml, "<null/>");
+
+	} else if(obj->type == JSON_BOOL) {
+
+		if (obj->value.b)
+			bool_val = strdup("true");
+		else
+			bool_val = strdup("false");
+
+		if (hint)
+			buffer_fadd(res_xml, "<boolean value=\"%s\" class_hint=\"%s\"/>", bool_val, hint);
+		else
+			buffer_fadd(res_xml, "<boolean value=\"%s\"/>", bool_val);
+
+		free(bool_val);
+                
+	} else if (obj->type == JSON_STRING) {
+		if (hint) {
+			char * t = _escape_xml(jsonObjectGetString(obj));
+			buffer_fadd(res_xml,"<string class_hint=\"%s\">%s</string>", hint, t);
+			free(t);
+		} else {
+			char * t = _escape_xml(jsonObjectGetString(obj));
+			buffer_fadd(res_xml,"<string>%s</string>", t);
+			free(t);
+		}
+
+	} else if(obj->type == JSON_NUMBER) {
+		double x = jsonObjectGetNumber(obj);
+		if (hint) {
+			if (x == (int)x)
+				buffer_fadd(res_xml,"<number class_hint=\"%s\">%d</number>", hint, (int)x);
+			else
+				buffer_fadd(res_xml,"<number class_hint=\"%s\">%lf</number>", hint, x);
+		} else {
+			if (x == (int)x)
+				buffer_fadd(res_xml,"<number>%d</number>", (int)x);
+			else
+				buffer_fadd(res_xml,"<number>%lf</number>", x);
+		}
+
+	} else if (obj->type == JSON_ARRAY) {
+
+		if (hint) 
+        	       	buffer_fadd(res_xml,"<array class_hint=\"%s\">", hint);
+		else
+               		buffer_add(res_xml,"<array>");
+
+	       	for ( i = 0; i!= obj->size; i++ )
+			_recurse_jsonObjectToXML(jsonObjectGetIndex(obj,i), res_xml);
+
+		buffer_add(res_xml,"</array>");
+
+	} else if (obj->type == JSON_HASH) {
+
+		if (hint)
+        	       	buffer_fadd(res_xml,"<object class_hint=\"%s\">", hint);
+		else
+			buffer_add(res_xml,"<object>");
+
+		jsonIterator* itr = jsonNewIterator(obj);
+		jsonObject* tmp;
+		while( (tmp = jsonIteratorNext(itr)) ) {
+			buffer_fadd(res_xml,"<element key=\"%s\">",itr->key);
+			_recurse_jsonObjectToXML(tmp, res_xml);
+			buffer_add(res_xml,"</element>");
+		}
+		jsonIteratorFree(itr);
+
+		buffer_add(res_xml,"</object>");
+	}
+
+	if (hint)
+		free(hint);
+
+	return 1;
+}
+
+char* _escape_xml (char* text) {
+	char* out;
+	growing_buffer* b = buffer_init(256);
+	int len = strlen(text);
+	int i;
+	for (i = 0; i < len; i++) {
+		if (text[i] == '&')
+			buffer_add(b,"&amp;");
+		else if (text[i] == '<')
+			buffer_add(b,"&lt;");
+		else if (text[i] == '>')
+			buffer_add(b,"&gt;");
+		else
+			buffer_add_char(b,text[i]);
+	}
+	out = buffer_data(b);
+	buffer_free(b);
+	return out;
+}
+
+#endif

Copied: branches/autotools/src/libopensrf/osrf_legacy_json.c (from rev 1120, trunk/src/libopensrf/osrf_legacy_json.c)
===================================================================
--- branches/autotools/src/libopensrf/osrf_legacy_json.c	                        (rev 0)
+++ branches/autotools/src/libopensrf/osrf_legacy_json.c	2007-11-05 13:40:16 UTC (rev 1121)
@@ -0,0 +1,881 @@
+/*
+Copyright (C) 2006  Georgia Public Library Service 
+Bill Erickson <billserickson at gmail.com>
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+*/
+
+
+#include <opensrf/osrf_legacy_json.h>
+
+/* keep a copy of the length of the current json string so we don't 
+ * have to calculate it in each function
+ */
+int current_strlen; 
+
+
+jsonObject* legacy_jsonParseString( const char* string) {
+	return json_parse_string( (char*) string );
+}
+
+jsonObject* legacy_jsonParseStringFmt( const char* string, ... ) {
+	VA_LIST_TO_STRING(string);
+	return json_parse_string( VA_BUF );
+}
+
+
+jsonObject* json_parse_string(char* string) {
+
+	if(string == NULL) return NULL;
+
+	current_strlen = strlen(string);
+
+	if(current_strlen == 0) 
+		return NULL;
+
+	unsigned long index = 0;
+
+	json_eat_ws(string, &index, 1, current_strlen); /* remove leading whitespace */
+	if(index == current_strlen) return NULL;
+
+	jsonObject* obj = jsonNewObject(NULL);
+
+	int status = _json_parse_string(string, &index, obj, current_strlen);
+	if(!status) return obj;
+
+	if(status == -2) {
+		jsonObjectFree(obj);
+		return NULL;
+	}
+
+	return NULL;
+}
+
+
+int _json_parse_string(char* string, unsigned long* index, jsonObject* obj, int current_strlen) {
+	if( !string || !index || *index >= current_strlen) return -2;
+
+	int status = 0; /* return code from parsing routines */
+	char* classname = NULL; /* object class hint */
+	json_eat_ws(string, index, 1, current_strlen); /* remove leading whitespace */
+
+	char c = string[*index];
+
+	/* remove any leading comments */
+	if( c == '/' ) { 
+
+		while(1) {
+			(*index)++; /* move to second comment char */
+			status = json_eat_comment(string, index, &classname, 1, current_strlen);
+			if(status) return status;
+
+			json_eat_ws(string, index, 1, current_strlen);
+			c = string[*index];
+			if(c != '/')
+				break;
+		}
+	}
+
+	json_eat_ws(string, index, 1, current_strlen); /* remove leading whitespace */
+
+	if(*index >= current_strlen)
+		return -2;
+
+	switch(c) {
+				
+		/* json string */
+		case '"': 
+			(*index)++;
+			status = json_parse_json_string(string, index, obj, current_strlen);
+			break;
+
+		/* json array */
+		case '[':
+			(*index)++;
+			status = json_parse_json_array(string, index, obj, current_strlen);
+			break;
+
+		/* json object */
+		case '{':
+			(*index)++;
+			status = json_parse_json_object(string, index, obj, current_strlen);
+			break;
+
+		/* NULL */
+		case 'n':
+		case 'N':
+			status = json_parse_json_null(string, index, obj, current_strlen);
+			break;
+			
+
+		/* true, false */
+		case 'f':
+		case 'F':
+		case 't':
+		case 'T':
+			status = json_parse_json_bool(string, index, obj, current_strlen);
+			break;
+
+		default:
+			if(isdigit(c) || c == '.' || c == '-') { /* are we a number? */
+				status = json_parse_json_number(string, index, obj, current_strlen);
+				if(status) return status;
+				break;
+			}
+
+			(*index)--;
+			/* we should never get here */
+			return json_handle_error(string, index, "_json_parse_string() final switch clause");
+	}	
+
+	if(status) return status;
+
+	json_eat_ws(string, index, 1, current_strlen);
+
+	if( *index < current_strlen ) {
+		/* remove any trailing comments */
+		c = string[*index];
+		if( c == '/' ) { 
+			(*index)++;
+			status = json_eat_comment(string, index, NULL, 0, current_strlen);
+			if(status) return status;
+		}
+	}
+
+	if(classname){
+		jsonObjectSetClass(obj, classname);
+		free(classname);
+	}
+
+	return 0;
+}
+
+
+int json_parse_json_null(char* string, unsigned long* index, jsonObject* obj, int current_strlen) {
+
+	if(*index >= (current_strlen - 3)) {
+		return json_handle_error(string, index, 
+			"_parse_json_null(): invalid null" );
+	}
+
+	if(!strncasecmp(string + (*index), "null", 4)) {
+		(*index) += 4;
+		obj->type = JSON_NULL;
+		return 0;
+	} else {
+		return json_handle_error(string, index,
+			"_parse_json_null(): invalid null" );
+	}
+}
+
+/* should be at the first character of the bool at this point */
+int json_parse_json_bool(char* string, unsigned long* index, jsonObject* obj, int current_strlen) {
+	if( ! string || ! obj || *index >= current_strlen ) return -1;
+
+	char* ret = "json_parse_json_bool(): truncated bool";
+
+	if( *index >= (current_strlen - 5))
+		return json_handle_error(string, index, ret);
+	
+	if(!strncasecmp( string + (*index), "false", 5)) {
+		(*index) += 5;
+		obj->value.b = 0;
+		obj->type = JSON_BOOL;
+		return 0;
+	}
+
+	if( *index >= (current_strlen - 4))
+		return json_handle_error(string, index, ret);
+
+	if(!strncasecmp( string + (*index), "true", 4)) {
+		(*index) += 4;
+		obj->value.b = 1;
+		obj->type = JSON_BOOL;
+		return 0;
+	}
+
+	return json_handle_error(string, index, ret);
+}
+
+
+/* expecting the first character of the number */
+int json_parse_json_number(char* string, unsigned long* index, jsonObject* obj, int current_strlen) {
+	if( ! string || ! obj || *index >= current_strlen ) return -1;
+
+	growing_buffer* buf = buffer_init(64);
+	char c = string[*index];
+
+	int done = 0;
+	int dot_seen = 0;
+
+	/* negative number? */
+	if(c == '-') { buffer_add(buf, "-"); (*index)++; }
+
+	c = string[*index];
+
+	while(*index < current_strlen) {
+
+		if(isdigit(c)) {
+			buffer_add_char(buf, c);
+		}
+
+		else if( c == '.' ) {
+			if(dot_seen) {
+				buffer_free(buf);
+				return json_handle_error(string, index, 
+					"json_parse_json_number(): malformed json number");
+			}
+			dot_seen = 1;
+			buffer_add_char(buf, c);
+		} else {
+			done = 1; break;
+		}
+
+		(*index)++;
+		c = string[*index];
+		if(done) break;
+	}
+
+	obj->type = JSON_NUMBER;
+	obj->value.n = strtod(buf->buf, NULL);
+	buffer_free(buf);
+	return 0;
+}
+
+/* index should point to the character directly following the '['.  when done
+ * index will point to the character directly following the ']' character
+ */
+int json_parse_json_array(char* string, unsigned long* index, jsonObject* obj, int current_strlen) {
+
+	if( ! string || ! obj || ! index || *index >= current_strlen ) return -1;
+
+	int status = 0;
+	int in_parse = 0; /* true if this array already contains one item */
+	obj->type = JSON_ARRAY;
+	int set = 0;
+	int done = 0;
+
+	while(*index < current_strlen) {
+
+		json_eat_ws(string, index, 1, current_strlen);
+
+		if(string[*index] == ']') {
+			(*index)++;
+			done = 1;
+			break;
+		}
+
+		if(in_parse) {
+			json_eat_ws(string, index, 1, current_strlen);
+			if(string[*index] != ',') {
+				return json_handle_error(string, index,
+					"json_parse_json_array(): array item not followed by a ','");
+			}
+			(*index)++;
+			json_eat_ws(string, index, 1, current_strlen);
+		}
+
+		jsonObject* item = jsonNewObject(NULL);
+
+		#ifndef STRICT_JSON_READ
+		if(*index < current_strlen) {
+			if(string[*index] == ',' || string[*index] == ']') {
+				status = 0;
+				set = 1;
+			}
+		}
+		if(!set) status = _json_parse_string(string, index, item, current_strlen);
+
+		#else
+		status = _json_parse_string(string, index, item, current_strlen);
+		#endif
+
+		if(status) { jsonObjectFree(item); return status; }
+		jsonObjectPush(obj, item);
+		in_parse = 1;
+		set = 0;
+	}
+
+	if(!done)
+		return json_handle_error(string, index,
+			"json_parse_json_array(): array not closed");
+
+	return 0;
+}
+
+
+/* index should point to the character directly following the '{'.  when done
+ * index will point to the character directly following the '}'
+ */
+int json_parse_json_object(char* string, unsigned long* index, jsonObject* obj, int current_strlen) {
+	if( ! string || !obj || ! index || *index >= current_strlen ) return -1;
+
+	obj->type = JSON_HASH;
+	int status;
+	int in_parse = 0; /* true if we've already added one item to this object */
+	int set = 0;
+	int done = 0;
+
+	while(*index < current_strlen) {
+
+		json_eat_ws(string, index, 1, current_strlen);
+
+		if(string[*index] == '}') {
+			(*index)++;
+			done = 1;
+			break;
+		}
+
+		if(in_parse) {
+			if(string[*index] != ',') {
+				return json_handle_error(string, index,
+					"json_parse_json_object(): object missing ',' between elements" );
+			}
+			(*index)++;
+			json_eat_ws(string, index, 1, current_strlen);
+		}
+
+		/* first we grab the hash key */
+		jsonObject* key_obj = jsonNewObject(NULL);
+		status = _json_parse_string(string, index, key_obj, current_strlen);
+		if(status) return status;
+
+		if(key_obj->type != JSON_STRING) {
+			return json_handle_error(string, index, 
+				"_json_parse_json_object(): hash key not a string");
+		}
+
+		char* key = key_obj->value.s;
+
+		json_eat_ws(string, index, 1, current_strlen);
+
+		if(string[*index] != ':') {
+			return json_handle_error(string, index, 
+				"json_parse_json_object(): hash key not followed by ':' character");
+		}
+
+		(*index)++;
+
+		/* now grab the value object */
+		json_eat_ws(string, index, 1, current_strlen);
+		jsonObject* value_obj = jsonNewObject(NULL);
+
+#ifndef STRICT_JSON_READ
+		if(*index < current_strlen) {
+			if(string[*index] == ',' || string[*index] == '}') {
+				status = 0;
+				set = 1;
+			}
+		}
+		if(!set)
+			status = _json_parse_string(string, index, value_obj, current_strlen);
+
+#else
+		 status = _json_parse_string(string, index, value_obj, current_strlen);
+#endif
+
+		if(status) return status;
+
+		/* put the data into the object and continue */
+		jsonObjectSetKey(obj, key, value_obj);
+		jsonObjectFree(key_obj);
+		in_parse = 1;
+		set = 0;
+	}
+
+	if(!done)
+		return json_handle_error(string, index,
+			"json_parse_json_object(): object not closed");
+
+	return 0;
+}
+
+
+
+/* when done, index will point to the character after the closing quote */
+int json_parse_json_string(char* string, unsigned long* index, jsonObject* obj, int current_strlen) {
+	if( ! string || ! index || *index >= current_strlen ) return -1;
+
+	int in_escape = 0;	
+	int done = 0;
+	growing_buffer* buf = buffer_init(64);
+
+	while(*index < current_strlen) {
+
+		char c = string[*index]; 
+
+		switch(c) {
+
+			case '\\':
+				if(in_escape) {
+					buffer_add(buf, "\\");
+					in_escape = 0;
+				} else 
+					in_escape = 1;
+				break;
+
+			case '"':
+				if(in_escape) {
+					buffer_add(buf, "\"");
+					in_escape = 0;
+				} else 
+					done = 1;
+				break;
+
+			case 't':
+				if(in_escape) {
+					buffer_add(buf,"\t");
+					in_escape = 0;
+				} else 
+					buffer_add_char(buf, c);
+				break;
+
+			case 'b':
+				if(in_escape) {
+					buffer_add(buf,"\b");
+					in_escape = 0;
+				} else 
+					buffer_add_char(buf, c);
+				break;
+
+			case 'f':
+				if(in_escape) {
+					buffer_add(buf,"\f");
+					in_escape = 0;
+				} else 
+					buffer_add_char(buf, c);
+				break;
+
+			case 'r':
+				if(in_escape) {
+					buffer_add(buf,"\r");
+					in_escape = 0;
+				} else 
+					buffer_add_char(buf, c);
+				break;
+
+			case 'n':
+				if(in_escape) {
+					buffer_add(buf,"\n");
+					in_escape = 0;
+				} else 
+					buffer_add_char(buf, c);
+				break;
+
+			case 'u':
+				if(in_escape) {
+					(*index)++;
+
+					if(*index >= (current_strlen - 4)) {
+						buffer_free(buf);
+						return json_handle_error(string, index,
+							"json_parse_json_string(): truncated escaped unicode"); }
+
+					char buff[5];
+					osrf_clearbuf(buff, sizeof(buff));
+					memcpy(buff, string + (*index), 4);
+
+
+					/* ----------------------------------------------------------------------- */
+					/* ----------------------------------------------------------------------- */
+					/* The following chunk was borrowed with permission from 
+						json-c http://oss.metaparadigm.com/json-c/ */
+					unsigned char utf_out[3];
+					memset(utf_out, 0, sizeof(utf_out));
+
+					#define hexdigit(x) ( ((x) <= '9') ? (x) - '0' : ((x) & 7) + 9)
+
+					unsigned int ucs_char =
+						(hexdigit(string[*index] ) << 12) +
+						(hexdigit(string[*index + 1]) << 8) +
+						(hexdigit(string[*index + 2]) << 4) +
+						hexdigit(string[*index + 3]);
+	
+					if (ucs_char < 0x80) {
+						utf_out[0] = ucs_char;
+						buffer_add(buf, (char*) utf_out);
+
+					} else if (ucs_char < 0x800) {
+						utf_out[0] = 0xc0 | (ucs_char >> 6);
+						utf_out[1] = 0x80 | (ucs_char & 0x3f);
+						buffer_add(buf, (char*) utf_out);
+
+					} else {
+						utf_out[0] = 0xe0 | (ucs_char >> 12);
+						utf_out[1] = 0x80 | ((ucs_char >> 6) & 0x3f);
+						utf_out[2] = 0x80 | (ucs_char & 0x3f);
+						buffer_add(buf, (char*) utf_out);
+					}
+					/* ----------------------------------------------------------------------- */
+					/* ----------------------------------------------------------------------- */
+
+					(*index) += 3;
+					in_escape = 0;
+
+				} else {
+
+					buffer_add_char(buf, c);
+				}
+
+				break;
+
+			default:
+				buffer_add_char(buf, c);
+		}
+
+		(*index)++;
+		if(done) break;
+	}
+
+	jsonObjectSetString(obj, buf->buf);
+	buffer_free(buf);
+	return 0;
+}
+
+
+void json_eat_ws(char* string, unsigned long* index, int eat_all, int current_strlen) {
+	if( ! string || ! index ) return;
+	if(*index >= current_strlen)
+		return;
+
+	if( eat_all ) { /* removes newlines, etc */
+		while(string[*index] == ' ' 	|| 
+				string[*index] == '\n' 	||
+				string[*index] == '\t') 
+			(*index)++;
+	}
+
+	else	
+		while(string[*index] == ' ') (*index)++;
+}
+
+
+/* index should be at the '*' character at the beginning of the comment.
+ * when done, index will point to the first character after the final /
+ */
+int json_eat_comment(char* string, unsigned long* index, char** buffer, int parse_class, int current_strlen) {
+	if( ! string || ! index || *index >= current_strlen ) return -1;
+	
+
+	if(string[*index] != '*' && string[*index] != '/' )
+		return json_handle_error(string, index, 
+			"json_eat_comment(): invalid character after /");
+
+	/* chop out any // style comments */
+	if(string[*index] == '/') {
+		(*index)++;
+		char c = string[*index];
+		while(*index < current_strlen) {
+			(*index)++;
+			if(c == '\n') 
+				return 0;
+			c = string[*index];
+		}
+		return 0;
+	}
+
+	(*index)++;
+
+	int on_star			= 0; /* true if we just saw a '*' character */
+
+	/* we're just past the '*' */
+	if(!parse_class) { /* we're not concerned with class hints */
+		while(*index < current_strlen) {
+			if(string[*index] == '/') {
+				if(on_star) {
+					(*index)++;
+					return 0;
+				}
+			}
+
+			if(string[*index] == '*') on_star = 1;
+			else on_star = 0;
+
+			(*index)++;
+		}
+		return 0;
+	}
+
+
+
+	growing_buffer* buf = buffer_init(64);
+
+	int first_dash		= 0;
+	int second_dash	= 0;
+	int third_dash		= 0;
+	int fourth_dash	= 0;
+
+	int in_hint			= 0;
+	int done				= 0;
+
+	/*--S hint--*/   /* <-- Hints  look like this */
+	/*--E hint--*/
+
+	while(*index < current_strlen) {
+		char c = string[*index];
+
+		switch(c) {
+
+			case '-':
+				on_star = 0;
+				if(third_dash)			fourth_dash = 1;
+				else if(in_hint)		third_dash	= 1;
+				else if(first_dash)	second_dash = 1;
+				else						first_dash = 1;
+				break;
+
+			case 'S':
+				on_star = 0;
+				if(second_dash && !in_hint) {
+					(*index)++;
+					json_eat_ws(string, index, 1, current_strlen);
+					(*index)--; /* this will get incremented at the bottom of the loop */
+					in_hint = 1;
+					break;
+				} 
+
+				if(second_dash && in_hint) {
+					buffer_add_char(buf, c);
+					break;
+				}
+
+			case 'E':
+				on_star = 0;
+				if(second_dash && !in_hint) {
+					(*index)++;
+					json_eat_ws(string, index, 1, current_strlen);
+					(*index)--; /* this will get incremented at the bottom of the loop */
+					in_hint = 1;
+					break;
+				}
+
+				if(second_dash && in_hint) {
+					buffer_add_char(buf, c);
+					break;
+				}
+
+			case '*':
+				on_star = 1;
+				break;
+
+			case '/':
+				if(on_star) 
+					done = 1;
+				else
+				on_star = 0;
+				break;
+
+			default:
+				on_star = 0;
+				if(in_hint)
+					buffer_add_char(buf, c);
+		}
+
+		(*index)++;
+		if(done) break;
+	}
+
+	if( buf->n_used > 0 && buffer)
+		*buffer = buffer_data(buf);
+
+	buffer_free(buf);
+	return 0;
+}
+
+int json_handle_error(char* string, unsigned long* index, char* err_msg) {
+
+	char buf[60];
+	osrf_clearbuf(buf, sizeof(buf));
+
+	if(*index > 30)
+		strncpy( buf, string + (*index - 30), 59 );
+	else
+		strncpy( buf, string, 59 );
+
+	fprintf(stderr, 
+			"\nError parsing json string at charracter %c "
+			"(code %d) and index %ld\nString length: %d\nMsg:\t%s\nNear:\t%s\nFull String:\t%s\n", 
+			string[*index], string[*index], *index, current_strlen, err_msg, buf, string );
+
+	return -1;
+}
+
+
+jsonObject* legacy_jsonParseFile( const char* filename ) {
+	return json_parse_file( filename );
+}
+	
+jsonObject* json_parse_file(const char* filename) {
+	if(!filename) return NULL;
+	char* data = file_to_string(filename);
+	jsonObject* o = json_parse_string(data);
+	free(data);
+	return o;
+}
+
+
+
+char* legacy_jsonObjectToJSON( const jsonObject* obj ) {
+
+	if(obj == NULL) return strdup("null");
+
+	growing_buffer* buf = buffer_init(64);
+
+	/* add class hints if we have a class name */
+	if(obj->classname) {
+		buffer_add(buf,"/*--S ");
+		buffer_add(buf,obj->classname);
+		buffer_add(buf, "--*/");
+	}
+
+	switch( obj->type ) {
+
+		case JSON_BOOL: 
+			if(obj->value.b) buffer_add(buf, "true"); 
+			else buffer_add(buf, "false"); 
+			break;
+
+		case JSON_NUMBER: {
+			double x = obj->value.n;
+
+			/* if the number does not need to be a double,
+				turn it into an int on the way out */
+			if( x == (int) x ) {
+				INT_TO_STRING((int)x);	
+				buffer_add(buf, INTSTR);
+
+			} else {
+				DOUBLE_TO_STRING(x);
+				buffer_add(buf, DOUBLESTR);
+			}
+			break;
+		}
+
+		case JSON_NULL:
+			buffer_add(buf, "null");
+			break;
+
+		case JSON_STRING:
+			buffer_add(buf, "\"");
+			char* data = obj->value.s;
+			int len = strlen(data);
+			
+			char* output = uescape(data, len, 1);
+			buffer_add(buf, output);
+			free(output);
+			buffer_add(buf, "\"");
+			break;
+
+		case JSON_ARRAY:
+			buffer_add(buf, "[");
+			int i;
+			for( i = 0; i!= obj->size; i++ ) {
+				const jsonObject* x = jsonObjectGetIndex(obj,i);
+				char* data = legacy_jsonObjectToJSON(x);
+				buffer_add(buf, data);
+				free(data);
+				if(i != obj->size - 1)
+					buffer_add(buf, ",");
+			}
+			buffer_add(buf, "]");
+			break;	
+
+		case JSON_HASH:
+	
+			buffer_add(buf, "{");
+			jsonIterator* itr = jsonNewIterator(obj);
+			jsonObject* tmp;
+	
+			while( (tmp = jsonIteratorNext(itr)) ) {
+
+				buffer_add(buf, "\"");
+
+				char* key = itr->key;
+				int len = strlen(key);
+				char* output = uescape(key, len, 1);
+				buffer_add(buf, output);
+				free(output);
+
+				buffer_add(buf, "\":");
+				char* data =  legacy_jsonObjectToJSON(tmp);
+				buffer_add(buf, data);
+				if(jsonIteratorHasNext(itr))
+					buffer_add(buf, ",");
+				free(data);
+			}
+
+			jsonIteratorFree(itr);
+			buffer_add(buf, "}");
+			break;
+		
+			default:
+				fprintf(stderr, "Unknown object type %d\n", obj->type);
+				break;
+				
+	}
+
+	/* close out the object hint */
+	if(obj->classname) {
+		buffer_add(buf, "/*--E ");
+		buffer_add(buf, obj->classname);
+		buffer_add(buf, "--*/");
+	}
+
+	char* data = buffer_data(buf);
+	buffer_free(buf);
+	return data;
+}
+
+
+
+static jsonObjectNode* makeNode(jsonObject* obj, unsigned long index, char* key) {
+    jsonObjectNode* node = safe_malloc(sizeof(jsonObjectNode));
+    node->item = obj;
+    node->index = index;
+    node->key = key;
+    return node;
+}
+
+jsonObjectIterator* jsonNewObjectIterator(const jsonObject* obj) {
+	if(!obj) return NULL;
+	jsonObjectIterator* itr = safe_malloc(sizeof(jsonObjectIterator));
+    itr->iterator = jsonNewIterator(obj);
+	itr->obj = obj;
+    itr->done = 0;
+    itr->current = NULL;
+	return itr;
+}
+
+jsonObjectNode* jsonObjectIteratorNext( jsonObjectIterator* itr ) {
+	if(itr == NULL || itr->done) return NULL;
+
+    if(itr->current) free(itr->current);
+    jsonObject* next = jsonIteratorNext(itr->iterator);
+    if(next == NULL) {
+        itr->current = NULL;
+        itr->done = 1;
+        return NULL;
+    }
+    itr->current = makeNode(next, itr->iterator->index, itr->iterator->key);
+    return itr->current;
+}
+
+void jsonObjectIteratorFree(jsonObjectIterator* iter) { 
+    if(iter->current) free(iter->current);
+    jsonIteratorFree(iter->iterator);
+	free(iter);
+}
+
+int jsonObjectIteratorHasNext(const jsonObjectIterator* itr) {
+	return (itr && itr->current);
+}
+
+

Modified: branches/autotools/src/libopensrf/osrf_message.c
===================================================================
--- branches/autotools/src/libopensrf/osrf_message.c	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/libopensrf/osrf_message.c	2007-11-05 13:40:16 UTC (rev 1121)
@@ -1,5 +1,8 @@
 #include <opensrf/osrf_message.h>
 
+static char default_locale[17] = "en-US\0\0\0\0\0\0\0\0\0\0\0\0";
+static char* current_locale = NULL;
+
 osrf_message* osrf_message_init( enum M_TYPE type, int thread_trace, int protocol ) {
 
 	osrf_message* msg			= (osrf_message*) safe_malloc(sizeof(osrf_message));
@@ -10,18 +13,36 @@
 	msg->is_exception			= 0;
 	msg->_params				= NULL;
 	msg->_result_content		= NULL;
+	msg->sender_locale		= NULL;
 
 	return msg;
 }
 
 
-void osrf_message_set_method( osrf_message* msg, char* method_name ) {
+const char* osrf_message_get_last_locale() {
+	return current_locale;
+}
+
+char* osrf_message_set_locale( osrf_message* msg, const char* locale ) {
+	if( msg == NULL || locale == NULL ) return NULL;
+	return msg->sender_locale = strdup( locale );
+}
+
+const char* osrf_message_set_default_locale( const char* locale ) {
+	if( locale == NULL ) return NULL;
+	if( strlen(locale) > sizeof(default_locale) - 1 ) return NULL;
+
+	strcpy( default_locale, locale );
+	return (const char*) default_locale;
+}
+
+void osrf_message_set_method( osrf_message* msg, const char* method_name ) {
 	if( msg == NULL || method_name == NULL ) return;
 	msg->method_name = strdup( method_name );
 }
 
 
-void osrf_message_add_object_param( osrf_message* msg, jsonObject* o ) {
+void osrf_message_add_object_param( osrf_message* msg, const jsonObject* o ) {
 	if(!msg|| !o) return;
 	if(!msg->_params)
 		msg->_params = jsonParseString("[]");
@@ -30,16 +51,15 @@
 	free(j);
 }
 
-void osrf_message_set_params( osrf_message* msg, jsonObject* o ) {
+void osrf_message_set_params( osrf_message* msg, const jsonObject* o ) {
 	if(!msg || !o) return;
 
 	if(o->type != JSON_ARRAY) {
 		osrfLogDebug( OSRF_LOG_MARK, "passing non-array to osrf_message_set_params(), fixing...");
+		if(msg->_params) jsonObjectFree(msg->_params);
 		jsonObject* clone = jsonObjectClone(o);
-		o = jsonNewObject(NULL);
-		jsonObjectPush(o, clone);
-		if(msg->_params) jsonObjectFree(msg->_params);
-		msg->_params = o;
+		msg->_params = jsonNewObject(NULL);
+		jsonObjectPush(msg->_params, clone);
 		return;
 	}
 
@@ -49,15 +69,15 @@
 
 
 /* only works if parse_json_params is false */
-void osrf_message_add_param( osrf_message* msg, char* param_string ) {
+void osrf_message_add_param( osrf_message* msg, const char* param_string ) {
 	if(msg == NULL || param_string == NULL) return;
 	if(!msg->_params) msg->_params = jsonParseString("[]");
 	jsonObjectPush(msg->_params, jsonParseString(param_string));
 }
 
 
-void osrf_message_set_status_info( 
-		osrf_message* msg, char* status_name, char* status_text, int status_code ) {
+void osrf_message_set_status_info( osrf_message* msg,
+		const char* status_name, const char* status_text, int status_code ) {
 	if(!msg) return;
 
 	if( status_name != NULL ) 
@@ -70,7 +90,7 @@
 }
 
 
-void osrf_message_set_result_content( osrf_message* msg, char* json_string ) {
+void osrf_message_set_result_content( osrf_message* msg, const char* json_string ) {
 	if( msg == NULL || json_string == NULL) return;
 	msg->result_string =	strdup(json_string);
 	if(json_string) msg->_result_content = jsonParseString(json_string);
@@ -101,6 +121,9 @@
 	if( msg->method_name != NULL )
 		free(msg->method_name);
 
+	if( msg->sender_locale != NULL )
+		free(msg->sender_locale);
+
 	if( msg->_params != NULL )
 		jsonObjectFree(msg->_params);
 
@@ -113,7 +136,7 @@
 
 	char* j;
 	int i = 0;
-	osrfMessage* msg = NULL;
+	const osrfMessage* msg = NULL;
 	jsonObject* wrapper = jsonNewObject(NULL);
 
 	while( ((msg = msgs[i]) && (i++ < count)) ) 
@@ -126,7 +149,7 @@
 }
 
 
-char* osrf_message_serialize(osrf_message* msg) {
+char* osrf_message_serialize(const osrf_message* msg) {
 
 	if( msg == NULL ) return NULL;
 	char* j = NULL;
@@ -144,18 +167,27 @@
 }
 
 
-jsonObject* osrfMessageToJSON( osrfMessage* msg ) {
+jsonObject* osrfMessageToJSON( const osrfMessage* msg ) {
 
 	jsonObject* json = jsonNewObject(NULL);
 	jsonObjectSetClass(json, "osrfMessage");
 	jsonObject* payload;
-	char sc[64]; memset(sc,0,64);
+	char sc[64];
+	osrf_clearbuf(sc, sizeof(sc));
 
 	char* str;
 
 	INT_TO_STRING(msg->thread_trace);
 	jsonObjectSetKey(json, "threadTrace", jsonNewObject(INTSTR));
 
+	if (msg->sender_locale != NULL) {
+		jsonObjectSetKey(json, "locale", jsonNewObject(msg->sender_locale));
+	} else if (current_locale != NULL) {
+		jsonObjectSetKey(json, "locale", jsonNewObject(current_locale));
+	} else {
+		jsonObjectSetKey(json, "locale", jsonNewObject(default_locale));
+	}
+
 	switch(msg->m_type) {
 		
 		case CONNECT: 
@@ -171,7 +203,7 @@
 			payload = jsonNewObject(NULL);
 			jsonObjectSetClass(payload, msg->status_name);
 			jsonObjectSetKey(payload, "status", jsonNewObject(msg->status_text));
-         sprintf(sc,"%d",msg->status_code);
+			snprintf(sc, sizeof(sc), "%d", msg->status_code);
 			jsonObjectSetKey(payload, "statusCode", jsonNewObject(sc));
 			jsonObjectSetKey(json, "payload", payload);
 			break;
@@ -193,7 +225,7 @@
 			payload = jsonNewObject(NULL);
 			jsonObjectSetClass(payload,"osrfResult");
 			jsonObjectSetKey(payload, "status", jsonNewObject(msg->status_text));
-         sprintf(sc,"%d",msg->status_code);
+			snprintf(sc, sizeof(sc), "%d", msg->status_code);
 			jsonObjectSetKey(payload, "statusCode", jsonNewObject(sc));
 			str = jsonObjectToJSON(msg->_result_content);
 			jsonObjectSetKey(payload, "content", jsonParseString(str));
@@ -206,7 +238,7 @@
 }
 
 
-int osrf_message_deserialize(char* string, osrf_message* msgs[], int count) {
+int osrf_message_deserialize(const char* string, osrf_message* msgs[], int count) {
 
 	if(!string || !msgs || count <= 0) return 0;
 	int numparsed = 0;
@@ -223,16 +255,16 @@
 
 	for( x = 0; x < json->size && x < count; x++ ) {
 
-		jsonObject* message = jsonObjectGetIndex(json, x);
+		const jsonObject* message = jsonObjectGetIndex(json, x);
 
 		if(message && message->type != JSON_NULL && 
 			message->classname && !strcmp(message->classname, "osrfMessage")) {
 
 			osrf_message* new_msg = safe_malloc(sizeof(osrf_message));
 
-			jsonObject* tmp = jsonObjectGetKey(message, "type");
+			const jsonObject* tmp = jsonObjectGetKeyConst(message, "type");
 
-			char* t;
+			const char* t;
 			if( ( t = jsonObjectGetString(tmp)) ) {
 
 				if(!strcmp(t, "CONNECT")) 		new_msg->m_type = CONNECT;
@@ -242,49 +274,47 @@
 				if(!strcmp(t, "RESULT")) 		new_msg->m_type = RESULT;
 			}
 
-			tmp = jsonObjectGetKey(message, "threadTrace");
+			tmp = jsonObjectGetKeyConst(message, "threadTrace");
 			if(tmp) {
 				char* tt = jsonObjectToSimpleString(tmp);
 				if(tt) {
 					new_msg->thread_trace = atoi(tt);
 					free(tt);
 				}
-				/*
-				if(tmp->type == JSON_NUMBER)
-					new_msg->thread_trace = (int) jsonObjectGetNumber(tmp);
-				if(tmp->type == JSON_STRING)
-					new_msg->thread_trace = atoi(jsonObjectGetString(tmp));
-					*/
 			}
 
+			/* use the sender's locale, or the global default */
+			if (current_locale)
+				free( current_locale );
 
-			tmp = jsonObjectGetKey(message, "protocol");
+			tmp = jsonObjectGetKeyConst(message, "locale");
+			if(tmp) {
+				new_msg->sender_locale = jsonObjectToSimpleString(tmp);
+				current_locale = strdup( new_msg->sender_locale );
+			} else {
+				current_locale = NULL;
+			}
 
+			tmp = jsonObjectGetKeyConst(message, "protocol");
+
 			if(tmp) {
 				char* proto = jsonObjectToSimpleString(tmp);
 				if(proto) {
 					new_msg->protocol = atoi(proto);
 					free(proto);
 				}
-
-				/*
-				if(tmp->type == JSON_NUMBER)
-					new_msg->protocol = (int) jsonObjectGetNumber(tmp);
-				if(tmp->type == JSON_STRING)
-					new_msg->protocol = atoi(jsonObjectGetString(tmp));
-					*/
 			}
 
-			tmp = jsonObjectGetKey(message, "payload");
+			tmp = jsonObjectGetKeyConst(message, "payload");
 			if(tmp) {
 				if(tmp->classname)
 					new_msg->status_name = strdup(tmp->classname);
 
-				jsonObject* tmp0 = jsonObjectGetKey(tmp,"method");
+				const jsonObject* tmp0 = jsonObjectGetKeyConst(tmp,"method");
 				if(jsonObjectGetString(tmp0))
 					new_msg->method_name = strdup(jsonObjectGetString(tmp0));
 
-				tmp0 = jsonObjectGetKey(tmp,"params");
+				tmp0 = jsonObjectGetKeyConst(tmp,"params");
 				if(tmp0) {
 					char* s = jsonObjectToJSON(tmp0);
 					new_msg->_params = jsonParseString(s);
@@ -293,11 +323,11 @@
 					free(s);
 				}
 
-				tmp0 = jsonObjectGetKey(tmp,"status");
+				tmp0 = jsonObjectGetKeyConst(tmp,"status");
 				if(jsonObjectGetString(tmp0))
 					new_msg->status_text = strdup(jsonObjectGetString(tmp0));
 
-				tmp0 = jsonObjectGetKey(tmp,"statusCode");
+				tmp0 = jsonObjectGetKeyConst(tmp,"statusCode");
 				if(tmp0) {
 					if(jsonObjectGetString(tmp0))
 						new_msg->status_code = atoi(jsonObjectGetString(tmp0));
@@ -305,7 +335,7 @@
 						new_msg->status_code = (int) jsonObjectGetNumber(tmp0);
 				}
 
-				tmp0 = jsonObjectGetKey(tmp,"content");
+				tmp0 = jsonObjectGetKeyConst(tmp,"content");
 				if(tmp0) {
 					char* s = jsonObjectToJSON(tmp0);
 					new_msg->_result_content = jsonParseString(s);

Modified: branches/autotools/src/libopensrf/osrf_prefork.c
===================================================================
--- branches/autotools/src/libopensrf/osrf_prefork.c	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/libopensrf/osrf_prefork.c	2007-11-05 13:40:16 UTC (rev 1121)
@@ -210,7 +210,7 @@
 
 		/* if no data was reveived within the timeout interval */
 		if( !recvd && (end - start) >= keepalive ) {
-			osrfLogInfo(OSRF_LOG_MARK, "No request was reveived in %d seconds, exiting stateful session", keepalive);
+			osrfLogInfo(OSRF_LOG_MARK, "No request was received in %d seconds, exiting stateful session", keepalive);
 			osrfAppSessionStatus( 
 					session, 
 					OSRF_STATUS_TIMEOUT, 
@@ -547,9 +547,9 @@
 
 			/* now suck off the data */
 			char buf[64];
-			memset( buf, 0, 64);
+			osrf_clearbuf( buf, sizeof(buf) );
 			if( (n=read(cur_child->read_status_fd, buf, 63))  < 0 ) {
-				osrfLogWarning( OSRF_LOG_MARK, "Read error afer select in child status read with errno %d", errno);
+				osrfLogWarning( OSRF_LOG_MARK, "Read error after select in child status read with errno %d", errno);
 			}
 
 			osrfLogDebug( OSRF_LOG_MARK,  "Read %d bytes from status buffer: %s", n, buf );
@@ -566,7 +566,7 @@
 	int i,n;
 	growing_buffer* gbuf = buffer_init( READ_BUFSIZE );
 	char buf[READ_BUFSIZE];
-	memset( buf, 0, READ_BUFSIZE );
+	osrf_clearbuf( buf, sizeof(buf) );
 
 	for( i = 0; i < child->max_requests; i++ ) {
 
@@ -579,7 +579,7 @@
 			if(!gotdata)
 				set_fl(child->read_data_fd, O_NONBLOCK );
 			buffer_add( gbuf, buf );
-			memset( buf, 0, READ_BUFSIZE );
+			osrf_clearbuf( buf, sizeof(buf) );
 			gotdata = 1;
 		}
 

Modified: branches/autotools/src/libopensrf/osrf_settings.c
===================================================================
--- branches/autotools/src/libopensrf/osrf_settings.c	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/libopensrf/osrf_settings.c	2007-11-05 13:40:16 UTC (rev 1121)
@@ -2,7 +2,7 @@
 
 osrf_host_config* config = NULL;
 
-char* osrf_settings_host_value(char* format, ...) {
+char* osrf_settings_host_value(const char* format, ...) {
 	VA_LIST_TO_STRING(format);
 
 	if( ! config ) {
@@ -18,7 +18,7 @@
 	return val;
 }
 
-jsonObject* osrf_settings_host_value_object(char* format, ...) {
+jsonObject* osrf_settings_host_value_object(const char* format, ...) {
 	VA_LIST_TO_STRING(format);
 
 	if( ! config ) {
@@ -32,7 +32,7 @@
 }
 
 
-int osrf_settings_retrieve(char* hostname) {
+int osrf_settings_retrieve(const char* hostname) {
 
 	if(!config) {
 
@@ -72,10 +72,11 @@
 	return 0;
 }
 
-osrf_host_config* osrf_settings_new_host_config(char* hostname) {
+osrf_host_config* osrf_settings_new_host_config(const char* hostname) {
 	if(!hostname) return NULL;
 	osrf_host_config* c = safe_malloc(sizeof(osrf_host_config));
 	c->hostname = strdup(hostname);
+	c->config = NULL;
 	return c;
 }
 

Modified: branches/autotools/src/libopensrf/osrf_stack.c
===================================================================
--- branches/autotools/src/libopensrf/osrf_stack.c	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/libopensrf/osrf_stack.c	2007-11-05 13:40:16 UTC (rev 1121)
@@ -67,7 +67,7 @@
 
 	osrf_app_session_set_remote( session, msg->sender );
 	osrf_message* arr[OSRF_MAX_MSGS_PER_PACKET];
-	memset(arr, 0, OSRF_MAX_MSGS_PER_PACKET );
+	memset(arr, 0, sizeof(arr));
 	int num_msgs = osrf_message_deserialize(msg->body, arr, OSRF_MAX_MSGS_PER_PACKET);
 
 	osrfLogDebug( OSRF_LOG_MARK,  "We received %d messages from %s", num_msgs, msg->sender );
@@ -92,7 +92,7 @@
 
 			} else {
 				osrfLogWarning( OSRF_LOG_MARK, " * Jabber Error is for top level remote id [%s], no one "
-						"to send my message too!!!", session->remote_id );
+						"to send my message to!!!", session->remote_id );
 			}
 		}
 

Modified: branches/autotools/src/libopensrf/osrf_system.c
===================================================================
--- branches/autotools/src/libopensrf/osrf_system.c	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/libopensrf/osrf_system.c	2007-11-05 13:40:16 UTC (rev 1121)
@@ -4,9 +4,28 @@
 #include <signal.h>
 
 static int _osrfSystemInitCache( void );
+static void report_child_status( pid_t pid, int status );
+struct child_node;
+typedef struct child_node ChildNode;
 
+struct child_node
+{
+	ChildNode* pNext;
+	ChildNode* pPrev;
+	pid_t pid;
+	char* app;
+	char* libfile;
+};
+
+static ChildNode* child_list;
+
 static transport_client* osrfGlobalTransportClient = NULL;
 
+static void add_child( pid_t pid, const char* app, const char* libfile );
+static void delete_child( ChildNode* node );
+static void delete_all_children( void );
+static ChildNode* seek_child( pid_t pid );
+
 transport_client* osrfSystemGetTransportClient( void ) {
 	return osrfGlobalTransportClient;
 }
@@ -122,12 +141,14 @@
 				pid_t pid;
 		
 				if( (pid = fork()) ) { 
-					// storage pid in local table for re-launching dead children...
-					osrfLogInfo( OSRF_LOG_MARK, "Launched application child %ld", (long) pid);
+					// store pid in local list for re-launching dead children...
+					add_child( pid, appname, libfile );
+					osrfLogInfo( OSRF_LOG_MARK, "Running application child %s: process id %ld",
+								 appname, (long) pid );
 	
 				} else {
 		
-					osrfLogError( OSRF_LOG_MARK, " * Running application %s\n", appname);
+					osrfLogInfo( OSRF_LOG_MARK, " * Running application %s\n", appname);
 					if( osrfAppRegisterApplication( appname, libfile ) == 0 ) 
 						osrf_prefork_run(appname);
 	
@@ -140,7 +161,8 @@
 
 	while(1) {
 		errno = 0;
-		pid_t pid = wait(NULL);
+		int status;
+		pid_t pid = wait( &status );
 		if(-1 == pid) {
 			if(errno == ECHILD)
 				osrfLogError(OSRF_LOG_MARK, "We have no more live services... exiting");
@@ -148,13 +170,131 @@
 				osrfLogError(OSRF_LOG_MARK, "Exiting top-level system loop with error: %s", strerror(errno));
 			break;
 		} else {
-			osrfLogError(OSRF_LOG_MARK, "We lost a top-level service process with PID %ld", pid);
+			report_child_status( pid, status );
 		}
 	}
 
+	delete_all_children();
 	return 0;
 }
 
+
+static void report_child_status( pid_t pid, int status )
+{
+	const char* app;
+	const char* libfile;
+	ChildNode* node = seek_child( pid );
+
+	if( node ) {
+		app     = node->app     ? node->app     : "[unknown]";
+		libfile = node->libfile ? node->libfile : "[none]";
+	} else
+		app = libfile = NULL;
+	
+	if( WIFEXITED( status ) )
+	{
+		int rc = WEXITSTATUS( status );  // return code of child process
+		if( rc )
+			osrfLogError( OSRF_LOG_MARK, "Child process %ld (app %s) exited with return code %d",
+						  (long) pid, app, rc );
+		else
+			osrfLogInfo( OSRF_LOG_MARK, "Child process %ld (app %s) exited normally",
+						  (long) pid, app );
+	}
+	else if( WIFSIGNALED( status ) )
+	{
+		osrfLogError( OSRF_LOG_MARK, "Child process %ld (app %s) killed by signal %d",
+					  (long) pid, app, WTERMSIG( status) );
+	}
+	else if( WIFSTOPPED( status ) )
+	{
+		osrfLogError( OSRF_LOG_MARK, "Child process %ld (app %s) stopped by signal %d",
+					  (long) pid, app, (int) WSTOPSIG( status ) );
+	}
+
+	delete_child( node );
+}
+
+/*----------- Routines to manage list of children --*/
+
+static void add_child( pid_t pid, const char* app, const char* libfile )
+{
+	/* Construct new child node */
+	
+	ChildNode* node = safe_malloc( sizeof( ChildNode ) );
+
+	node->pid = pid;
+
+	if( app )
+		node->app = strdup( app );
+	else
+		node->app = NULL;
+
+	if( libfile )
+		node->libfile = strdup( libfile );
+	else
+		node->libfile = NULL;
+	
+	/* Add new child node to the head of the list */
+
+	node->pNext = child_list;
+	node->pPrev = NULL;
+
+	if( child_list )
+		child_list->pPrev = node;
+
+	child_list = node;
+}
+
+static void delete_child( ChildNode* node ) {
+
+	/* Sanity check */
+
+	if( ! node )
+		return;
+	
+	/* Detach the node from the list */
+
+	if( node->pPrev )
+		node->pPrev->pNext = node->pNext;
+	else
+		child_list = node->pNext;
+
+	if( node->pNext )
+		node->pNext->pPrev = node->pPrev;
+
+	/* Deallocate the node and its payload */
+
+	free( node->app );
+	free( node->libfile );
+	free( node );
+}
+
+static void delete_all_children( void ) {
+
+	while( child_list )
+		delete_child( child_list );
+}
+
+static ChildNode* seek_child( pid_t pid ) {
+
+	/* Return a pointer to the child node for the */
+	/* specified process ID, or NULL if not found */
+	
+	ChildNode* node = child_list;
+	while( node ) {
+		if( node->pid == pid )
+			break;
+		else
+			node = node->pNext;
+	}
+
+	return node;
+}
+
+/*----------- End of routines to manage list of children --*/
+
+
 int osrf_system_bootstrap_client_resc( char* config_file, char* contextnode, char* resource ) {
 
 	int failure = 0;
@@ -314,6 +454,7 @@
 
 int osrf_system_shutdown( void ) {
 	osrfConfigCleanup();
+    osrfCacheCleanup();
 	osrf_system_disconnect_client();
 	osrf_settings_free_host_config(NULL);
 	osrfAppSessionCleanup();

Modified: branches/autotools/src/libopensrf/osrf_transgroup.c
===================================================================
--- branches/autotools/src/libopensrf/osrf_transgroup.c	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/libopensrf/osrf_transgroup.c	2007-11-05 13:40:16 UTC (rev 1121)
@@ -89,7 +89,7 @@
 	if(!(grp && msg)) return -1;
 
 	char domain[256];
-	bzero(domain, 256);
+	osrf_clearbuf(domain, sizeof(domain));
 	jid_get_domain( msg->recipient, domain, 255 );
 
 	osrfTransportGroupNode* node = osrfHashGet(grp->nodes, domain);
@@ -108,15 +108,15 @@
 	int bufsize = 256;
 
 	char domain[bufsize];
-	bzero(domain, bufsize);
+	osrf_clearbuf(domain, sizeof(domain));
 	jid_get_domain( msg->recipient, domain, bufsize - 1 );
 
 	char msgrecip[bufsize];
-	bzero(msgrecip, bufsize);
+	osrf_clearbuf(msgrecip, sizeof(msgrecip));
 	jid_get_username(msg->recipient, msgrecip, bufsize - 1);
 
 	char msgres[bufsize];
-	bzero(msgres, bufsize);
+	osrf_clearbuf(msgres, sizeof(msgres));
 	jid_get_resource(msg->recipient, msgres, bufsize - 1);
 
 	char* firstdomain = NULL;
@@ -149,8 +149,7 @@
 		/* update the recipient domain if necessary */
 
 		if(updateRecip) {
-			bzero(newrcp, 1024);
-			sprintf(newrcp, "%s@%s/%s", msgrecip, node->domain, msgres);
+			snprintf(newrcp, sizeof(newrcp), "%s@%s/%s", msgrecip, node->domain, msgres);
 			free(msg->recipient);
 			msg->recipient = strdup(newrcp);
 		}

Modified: branches/autotools/src/libopensrf/sha.c
===================================================================
--- branches/autotools/src/libopensrf/sha.c	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/libopensrf/sha.c	2007-11-05 13:40:16 UTC (rev 1121)
@@ -208,7 +208,7 @@
 	INT64 length=0;
 
 	int strsz;
-	static char final[40];
+	static char final[41];
 	int *hashval;
 
 	hashval = (int *)malloc(20);

Modified: branches/autotools/src/libopensrf/socket_bundle.c
===================================================================
--- branches/autotools/src/libopensrf/socket_bundle.c	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/libopensrf/socket_bundle.c	2007-11-05 13:40:16 UTC (rev 1121)
@@ -707,7 +707,7 @@
 	int read_bytes;
 	int sock_fd = node->sock_fd;
 
-	memset(buf, 0, RBUFSIZE);
+	osrf_clearbuf(buf, sizeof(buf));
 	set_fl(sock_fd, O_NONBLOCK);
 
 	osrfLogInternal( OSRF_LOG_MARK, "%ld : Received data at %f\n", (long) getpid(), get_timestamp_millis());
@@ -717,7 +717,7 @@
 		if(mgr->data_received)
 			mgr->data_received(mgr->blob, mgr, sock_fd, buf, node->parent_id);
 
-		memset(buf, 0, RBUFSIZE);
+		osrf_clearbuf(buf, sizeof(buf));
 	}
     int local_errno = errno; /* capture errno as set by recv() */
 

Modified: branches/autotools/src/libopensrf/string_array.c
===================================================================
--- branches/autotools/src/libopensrf/string_array.c	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/libopensrf/string_array.c	2007-11-05 13:40:16 UTC (rev 1121)
@@ -8,18 +8,11 @@
 	if(size > STRING_ARRAY_MAX_SIZE)
 		osrfLogError( OSRF_LOG_MARK, "init_string_array size is too large");
 
-	/*
-	string_array* arr = 
-		(string_array*) safe_malloc(sizeof(string_array));
-		*/
 	string_array* arr;
 	OSRF_MALLOC( arr, sizeof(string_array));
-
-	//arr->array = (char**) safe_malloc(size * sizeof(char*));
-	OSRF_MALLOC(arr->array, size * sizeof(char*));
-
+    arr->list = osrfNewListSize(size);
+    osrfListSetDefaultFree(arr->list);
 	arr->size = 0;
-	arr->arr_size = size;
 	return arr;
 }
 
@@ -30,65 +23,39 @@
 
 void string_array_add(string_array* arr, char* str) {
 	if(arr == NULL || str == NULL ) return;
-	if( strlen(str) < 1 ) return;
-
-	arr->size++;
-
 	if( arr->size > STRING_ARRAY_MAX_SIZE ) 
 		osrfLogError( OSRF_LOG_MARK, "string_array_add size is too large");
-
-	/* if necessary, double capacity */
-	if(arr->size >= arr->arr_size) {
-		arr->arr_size *= 2;
-		//char** tmp = (char**) safe_malloc(arr->arr_size * sizeof(char*));
-		char** tmp;
-		OSRF_MALLOC( tmp, arr->arr_size * sizeof(char*));
-		int i;
-
-		/* copy the string pointers over */
-		for( i = 0; i!= arr->size; i++ ) 
-			tmp[i] = arr->array[i];
-
-		free(arr->array);
-		arr->array = tmp;
-	}
-
-	arr->array[arr->size - 1] = strdup(str);
+    osrfListPush(arr->list, strdup(str));
+    arr->size = arr->list->size;
 }
 
 char* osrfStringArrayGetString(osrfStringArray* arr, int index) {
-	return string_array_get_string(arr, index);
+    if(!arr) return NULL;
+    return OSRF_LIST_GET_INDEX(arr->list, index);
 }
 
 char* string_array_get_string(string_array* arr, int index) {
-	if(!arr || index < 0 || index >= arr->size ) return NULL;
-	return arr->array[index]; 
+    if(!arr) return NULL;
+    return OSRF_LIST_GET_INDEX(arr->list, index);
 }
 
 
 void osrfStringArrayFree(osrfStringArray* arr) {
-	string_array_destroy(arr);
+    OSRF_STRING_ARRAY_FREE(arr);
 }
 
 void string_array_destroy(string_array* arr) {
-	if(arr) {
-		int i = 0;
-		while( i < arr->size ) free(arr->array[i++]);
-		free(arr->array);
-		free(arr);
-	}
+    OSRF_STRING_ARRAY_FREE(arr);
 }
 
 
 int osrfStringArrayContains( osrfStringArray* arr, char* string ) {
 	if(!(arr && string)) return 0;
-	
 	int i;
-	for( i = 0; i != arr->size; i++ ) {
-		char* str = osrfStringArrayGetString(arr, i);
-		if(str) {
-			if(!strcmp(str, string)) return 1;
-		}
+	for( i = 0; i < arr->size; i++ ) {
+        char* str = OSRF_LIST_GET_INDEX(arr->list, i);
+		if(str && !strcmp(str, string)) 
+            return 1;
 	}
 
 	return 0;
@@ -97,19 +64,29 @@
 void osrfStringArrayRemove( osrfStringArray* arr, char* tstr) {
 	if(!(arr && tstr)) return;
 	int i;
-	for( i = 0; i != arr->size; i++ ) {
-		char* str = osrfStringArrayGetString(arr, i);
-		if(str) {
-			if(!strcmp(str, tstr)) {
-				free(arr->array[i]);
-				arr->array[i] = NULL;
-				break;
-			}
+    char* str;
+
+	for( i = 0; i < arr->size; i++ ) {
+        /* find and remove the string */
+        str = OSRF_LIST_GET_INDEX(arr->list, i);
+		if(str && !strcmp(str, tstr)) {
+            osrfListRemove(arr->list, i);
+			break;
 		}
 	}
-	for( ; i != arr->size; i++ ) 
-		arr->array[i] = arr->array[i+1];
 
+    /* disable automatic item freeing on delete and shift
+     * items up in the array to fill in the gap
+     */
+    arr->list->freeItem = NULL;
+	for( ; i < arr->size - 1; i++ ) 
+        osrfListSet(arr->list, OSRF_LIST_GET_INDEX(arr->list, i+1) , i);
+
+    /* remove the last item since it was shifted up */
+    osrfListRemove(arr->list, i);
+
+    /* re-enable automatic item freeing in delete */
+    osrfListSetDefaultFree(arr->list);
 	arr->size--;
 }
 

Modified: branches/autotools/src/libopensrf/transport_client.c
===================================================================
--- branches/autotools/src/libopensrf/transport_client.c	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/libopensrf/transport_client.c	2007-11-05 13:40:16 UTC (rev 1121)
@@ -23,7 +23,7 @@
 		if( recv->body ) {
 			int len = strlen(recv->body);
 			char buf[len + 20];
-			memset( buf, 0, len + 20); 
+			osrf_clearbuf( buf, 0, sizeof(buf)); 
 			sprintf( buf, "Echoing...%s", recv->body );
 			send = message_init( buf, "Echoing Stuff", "12345", recv->sender, "" );
 		} else {

Modified: branches/autotools/src/libopensrf/transport_message.c
===================================================================
--- branches/autotools/src/libopensrf/transport_message.c	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/libopensrf/transport_message.c	2007-11-05 13:40:16 UTC (rev 1121)
@@ -238,7 +238,7 @@
 		xmlAddChild( message_node, error_node );
 		xmlNewProp( error_node, BAD_CAST "type", BAD_CAST msg->error_type );
 		char code_buf[16];
-		memset( code_buf, 0, 16);
+		osrf_clearbuf( code_buf, sizeof(code_buf));
 		sprintf(code_buf, "%d", msg->error_code );
 		xmlNewProp( error_node, BAD_CAST "code", BAD_CAST code_buf  );
 	}
@@ -303,6 +303,7 @@
 		if( jid[i] == 64 ) { /*ascii @*/
 			if(i > size)  i = size;
 			strncpy( buf, jid, i );
+			buf[i] = '\0'; // strncpy doesn't provide the nul
 			return;
 		}
 	}
@@ -319,6 +320,7 @@
 			int rlen = len - (i+1);
 			if(rlen > size) rlen = size;
 			strncpy( buf, start, rlen );
+			buf[rlen] = '\0'; // strncpy doesn't provide the nul
 		}
 	}
 }
@@ -343,6 +345,7 @@
 		int dlen = index2 - index1;
 		if(dlen > size) dlen = size;
 		memcpy( buf, jid + index1, dlen );
+		buf[dlen] = '\0'; // memcpy doesn't provide the nul
 	}
 }
 

Modified: branches/autotools/src/libopensrf/transport_session.c
===================================================================
--- branches/autotools/src/libopensrf/transport_session.c	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/libopensrf/transport_session.c	2007-11-05 13:40:16 UTC (rev 1121)
@@ -183,8 +183,7 @@
 		char* our_hostname = getenv("HOSTNAME");
 		size1 = 150 + strlen( server );
 		char stanza1[ size1 ]; 
-		memset( stanza1, 0, size1 );
-		sprintf( stanza1, 
+		snprintf( stanza1, sizeof(stanza1),
 				"<stream:stream version='1.0' xmlns:stream='http://etherx.jabber.org/streams' "
 				"xmlns='jabber:component:accept' to='%s' from='%s' xml:lang='en'>",
 				username, our_hostname );
@@ -207,14 +206,12 @@
 	
 			int ss = session->session_id->n_used + strlen(password) + 5;
 			char hashstuff[ss];
-			memset(hashstuff,0,ss);
-			sprintf( hashstuff, "%s%s", session->session_id->buf, password );
+			snprintf( hashstuff, sizeof(hashstuff), "%s%s", session->session_id->buf, password );
 
 			char* hash = shahash( hashstuff );
 			size2 = 100 + strlen( hash );
 			char stanza2[ size2 ];
-			memset( stanza2, 0, size2 );
-			sprintf( stanza2, "<handshake>%s</handshake>", hash );
+			snprintf( stanza2, sizeof(stanza2), "<handshake>%s</handshake>", hash );
 	
 			//if( ! tcp_send( session->sock_obj, stanza2 )  ) {
 			if( socket_send( session->sock_id, stanza2 )  ) {
@@ -228,8 +225,7 @@
 		/* the first Jabber connect stanza */
 		size1 = 100 + strlen( server );
 		char stanza1[ size1 ]; 
-		memset( stanza1, 0, size1 );
-		sprintf( stanza1, 
+		snprintf( stanza1, sizeof(stanza1), 
 				"<stream:stream to='%s' xmlns='jabber:client' "
 				"xmlns:stream='http://etherx.jabber.org/streams'>",
 			server );
@@ -253,9 +249,7 @@
 			/* the second jabber connect stanza including login info*/
 			size2 = 150 + strlen( username ) + strlen(password) + strlen(resource);
 			char stanza2[ size2 ];
-			memset( stanza2, 0, size2 );
-		
-			sprintf( stanza2, 
+			snprintf( stanza2, sizeof(stanza2), 
 					"<iq id='123456789' type='set'><query xmlns='jabber:iq:auth'>"
 					"<username>%s</username><password>%s</password><resource>%s</resource></query></iq>",
 					username, password, resource );
@@ -273,17 +267,14 @@
 
 			int ss = session->session_id->n_used + strlen(password) + 5;
 			char hashstuff[ss];
-			memset(hashstuff,0,ss);
-			sprintf( hashstuff, "%s%s", session->session_id->buf, password );
+			snprintf( hashstuff, sizeof(hashstuff), "%s%s", session->session_id->buf, password );
 
 			char* hash = shahash( hashstuff );
 
 			/* the second jabber connect stanza including login info*/
 			size2 = 150 + strlen( hash ) + strlen(password) + strlen(resource);
 			char stanza2[ size2 ];
-			memset( stanza2, 0, size2 );
-		
-			sprintf( stanza2, 
+			snprintf( stanza2, sizeof(stanza2), 
 					"<iq id='123456789' type='set'><query xmlns='jabber:iq:auth'>"
 					"<username>%s</username><digest>%s</digest><resource>%s</resource></query></iq>",
 					username, hash, resource );
@@ -566,7 +557,6 @@
 		void *session, const xmlChar *ch, int len) {
 
 	char data[len+1];
-	memset( data, 0, len+1 );
 	strncpy( data, (char*) ch, len );
 	data[len] = 0;
 
@@ -597,7 +587,7 @@
 
 	if( ses->state_machine->in_error ) {
 		/* for now... */
-		osrfLogWarning( OSRF_LOG_MARK,  "ERROR Xml fragment: %s\n", ch );
+		osrfLogWarning( OSRF_LOG_MARK,  "ERROR XML fragment: %s\n", ch );
 	}
 
 }

Modified: branches/autotools/src/libopensrf/utils.c
===================================================================
--- branches/autotools/src/libopensrf/utils.c	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/libopensrf/utils.c	2007-11-05 13:40:16 UTC (rev 1121)
@@ -22,6 +22,16 @@
 		osrfLogError( OSRF_LOG_MARK, "Out of Memory" );
 		exit(99);
 	}
+	memset( ptr, 0, size ); // remove this after safe_calloc transition
+	return ptr;
+}
+
+inline void* safe_calloc( int size ) {
+	void* ptr = (void*) malloc( size );
+	if( ptr == NULL ) {
+		osrfLogError( OSRF_LOG_MARK, "Out of Memory" );
+		exit(99);
+	}
 	memset( ptr, 0, size );
 	return ptr;
 }
@@ -45,8 +55,9 @@
 	int i = 0;
 	while( i < argc ) {
 		int len = strlen( global_argv[i]);
-		bzero( global_argv[i++], len );
+		osrf_clearbuf( global_argv[i], len );
 		global_argv_size += len;
+		i++;
 	}
 
 	global_argv_size -= 2;
@@ -55,7 +66,7 @@
 
 int set_proc_title( char* format, ... ) {
 	VA_LIST_TO_STRING(format);
-	bzero( *(global_argv), global_argv_size );
+	osrf_clearbuf( *(global_argv), global_argv_size);
 	return snprintf( *(global_argv), global_argv_size, VA_BUF );
 }
 
@@ -121,7 +132,7 @@
 	len = va_list_size(format, args);
 
 	char buf[len];
-	memset(buf, 0, len);
+	osrf_clearbuf(buf, sizeof(buf));
 
 	va_start(a_copy, format);
 	vsnprintf(buf, len - 1, format, a_copy);
@@ -164,7 +175,7 @@
 	len = va_list_size(format, args);
 
 	char buf[len];
-	memset(buf, 0, len);
+	osrf_clearbuf(buf, sizeof(buf));
 
 	va_start(a_copy, format);
 	vsnprintf(buf, len - 1, format, a_copy);
@@ -212,7 +223,7 @@
 int buffer_reset( growing_buffer *gb){
 	if( gb == NULL ) { return 0; }
 	if( gb->buf == NULL ) { return 0; }
-	memset( gb->buf, 0, gb->size );
+	osrf_clearbuf( gb->buf, sizeof(gb->buf) );
 	gb->n_used = 0;
 	return 1;
 }
@@ -416,7 +427,7 @@
 
 	int len = 1024;
 	char buf[len];
-	bzero(buf, len);
+	osrf_clearbuf(buf, sizeof(buf));
 	growing_buffer* gb = buffer_init(len);
 
 	FILE* file = fopen(filename, "r");
@@ -425,9 +436,9 @@
 		return NULL;
 	}
 
-	while(fgets(buf, len - 1, file)) {
+	while(fgets(buf, sizeof(buf), file)) {
 		buffer_add(gb, buf);
-		bzero(buf, len);
+		osrf_clearbuf(buf, sizeof(buf));
 	}
 
 	fclose(file);
@@ -454,13 +465,11 @@
 	MD5_stop (&ctx, digest);
 
 	char buf[16];
-	memset(buf,0,16);
-
 	char final[256];
-	memset(final,0,256);
+	osrf_clearbuf(final, sizeof(final));
 
 	for ( i=0 ; i<16 ; i++ ) {
-		sprintf(buf, "%02x", digest[i]);
+		snprintf(buf, sizeof(buf), "%02x", digest[i]);
 		strcat( final, buf );
 	}
 

Modified: branches/autotools/src/objson/json_parser.c
===================================================================
--- branches/autotools/src/objson/json_parser.c	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/objson/json_parser.c	2007-11-05 13:40:16 UTC (rev 1121)
@@ -482,7 +482,7 @@
 							"json_parse_json_string(): truncated escaped unicode"); }
 
 					char buff[5];
-					memset(buff,0,5);
+					memset(buff, 0, sizeof(buff));
 					memcpy(buff, string + (*index), 4);
 
 
@@ -491,7 +491,7 @@
 					/* The following chunk was borrowed with permission from 
 						json-c http://oss.metaparadigm.com/json-c/ */
 					unsigned char utf_out[4];
-					memset(utf_out,0,4);
+					memset(utf_out, 0, sizeof(utf_out));
 
 					#define hexdigit(x) ( ((x) <= '9') ? (x) - '0' : ((x) & 7) + 9)
 
@@ -695,7 +695,7 @@
 int json_handle_error(char* string, unsigned long* index, char* err_msg) {
 
 	char buf[60];
-	memset(buf, 0, 60);
+	memset(buf, 0, sizeof(buf));
 
 	if(*index > 30)
 		strncpy( buf, string + (*index - 30), 59 );

Modified: branches/autotools/src/objson/objson_test.c
===================================================================
--- branches/autotools/src/objson/objson_test.c	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/objson/objson_test.c	2007-11-05 13:40:16 UTC (rev 1121)
@@ -183,11 +183,11 @@
 
 	char buf[10240];
 	char smallbuf[512];
-	bzero(buf, 10240);
-	bzero(smallbuf, 512);
+	memset(buf, 0, sizeof(buf));
+	memset(smallbuf, 0, sizeof(smallbuf));
 
-	while(fgets(smallbuf, 512, F)) 
-		strcat(buf, smallbuf);
+	while(fgets(smallbuf, sizeof(smallbuf), F)) 
+		strncat(buf, smallbuf, sizeof(buf) - 1);
 
 	/* dig our way into the JSON object we parsed, see test.json to get
 	   an idea of the object structure */

Modified: branches/autotools/src/perlmods/OpenSRF/AppSession.pm
===================================================================
--- branches/autotools/src/perlmods/OpenSRF/AppSession.pm	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/perlmods/OpenSRF/AppSession.pm	2007-11-05 13:40:16 UTC (rev 1121)
@@ -156,6 +156,14 @@
 	return $self->{'last_sent_payload'};
 }
 
+sub session_locale {
+	my( $self, $type ) = @_;
+	if( $type ) {
+		return $self->{'session_locale'} = $type;
+	}
+	return $self->{'session_locale'};
+}
+
 sub last_sent_type {
 	my( $self, $type ) = @_;
 	if( $type ) {
@@ -192,9 +200,6 @@
 }
 
 # When we're a client and we want to connect to a remote service
-# create( $app, username => $user, secret => $passwd );
-#    OR
-# create( $app, sysname => $user, secret => $shared_secret );
 sub create {
 	my $class = shift;
 	$class = ref($class) || $class;
@@ -202,6 +207,7 @@
 	my $app = shift;
         my $api_level = shift;
 	my $quiet = shift;
+	my $locale = shift;
 
 	$api_level = 1 if (!defined($api_level));
 			        
@@ -237,6 +243,7 @@
 			   session_id  => $sess_id,
 			   remote_id   => $r_id,
 			   raise_error   => $quiet ? 0 : 1,
+			   session_locale   => $locale,
 			   api_level   => $api_level,
 			   orig_remote_id   => $r_id,
 				peer_handle => $peer_handle,
@@ -494,6 +501,7 @@
 	
 		$msg->api_level($self->api_level);
 		$msg->payload($payload) if $payload;
+		$msg->sender_locale($self->session_locale) if $self->session_locale;
 	
 		push @doc, $msg;
 
@@ -742,7 +750,7 @@
 	$logger->debug( "Number of matched responses: " . @list, DEBUG );
 	$self->queue_wait(0); # check for statuses
 	
-	return $list[0] unless (wantarray);
+	return $list[0] if (!wantarray);
 	return @list;
 }
 

Modified: branches/autotools/src/perlmods/OpenSRF/Application.pm
===================================================================
--- branches/autotools/src/perlmods/OpenSRF/Application.pm	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/perlmods/OpenSRF/Application.pm	2007-11-05 13:40:16 UTC (rev 1121)
@@ -1,4 +1,5 @@
 package OpenSRF::Application;
+# vim:noet:ts=4
 use vars qw/$_app $log @_METHODS $thunk $server_class/;
 
 use base qw/OpenSRF/;
@@ -98,7 +99,7 @@
         my @p = $app_msg->params;
 		my $method_name = $app_msg->method;
 		my $method_proto = $session->last_message_api_level;
-        $logger->info("CALL: $method_name [".join(', ', at p)."]");
+		$log->info("CALL: $method_name [". (@p ? join(', ', at p) : '') ."]");
 
 		my $coderef = $app->method_lookup( $method_name, $method_proto, 1, 1 );
 

Modified: branches/autotools/src/perlmods/OpenSRF/DomainObject/oilsMessage.pm
===================================================================
--- branches/autotools/src/perlmods/OpenSRF/DomainObject/oilsMessage.pm	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/perlmods/OpenSRF/DomainObject/oilsMessage.pm	2007-11-05 13:40:16 UTC (rev 1121)
@@ -86,6 +86,24 @@
 	return $self->{api_level};
 }
 
+=head2 OpenSRF::DomainObject::oilsMessage->sender_locale( [$locale] );
+
+=over 4
+
+Sets or gets the current message locale hint.  Useful for telling the
+server how you see the world.
+
+=back
+
+=cut
+
+sub sender_locale {
+	my $self = shift;
+	my $val = shift;
+	$self->{sender_locale} = $val if (defined $val);
+	return $self->{sender_locale};
+}
+
 =head2 OpenSRF::DomainObject::oilsMessage->threadTrace( [$new_threadTrace] );
 
 =over 4
@@ -163,12 +181,14 @@
 	my $session = shift;
 
 	my $mtype = $self->type;
+	my $locale = $self->sender_locale;
 	my $api_level = $self->api_level || 1;;
 	my $tT = $self->threadTrace;
 
 	$session->last_message_type($mtype);
 	$session->last_message_api_level($api_level);
 	$session->last_threadTrace($tT);
+	$session->session_locale($locale);
 
 	$log->debug(" Received api_level => [$api_level], MType => [$mtype], ".
 			"from [".$session->remote_id."], threadTrace[".$self->threadTrace."]");

Modified: branches/autotools/src/perlmods/OpenSRF/DomainObject/oilsResponse.pm
===================================================================
--- branches/autotools/src/perlmods/OpenSRF/DomainObject/oilsResponse.pm	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/perlmods/OpenSRF/DomainObject/oilsResponse.pm	2007-11-05 13:40:16 UTC (rev 1121)
@@ -201,7 +201,7 @@
 =head1 ABSTRACT
 
 Implements the STATUS_CONTINUE message, informing the client that it should
-continue to wait for a response to it's request.
+continue to wait for a response to its request.
 
 =head1 SEE ALSO
 
@@ -316,11 +316,11 @@
 
 The base class for Exception messages sent between client and server.  This
 is implemented on top of the C<OpenSRF::DomainObject::oilsResponse> class, and 
-sets the default B<status> to C<Exception occured> and B<statusCode> to C<STATUS_BADREQUEST>.
+sets the default B<status> to C<Exception occurred> and B<statusCode> to C<STATUS_BADREQUEST>.
 
 =cut
 
-$status = 'Exception occured';
+$status = 'Exception occurred';
 $statusCode = STATUS_INTERNALSERVERERROR;
 
 #-------------------------------------------------------------------------------
@@ -372,7 +372,7 @@
 
 =head1 NAME
 
-OpenSRF::DomainObject::oilsMehtodException
+OpenSRF::DomainObject::oilsMethodException
 
 =head1 SYNOPSIS
 
@@ -387,7 +387,7 @@
 
 =head1 ABSTRACT
 
-The class for Exceptions that occur durring the B<CONNECT> phase of a session.  This
+The class for Exceptions that occur during the B<CONNECT> phase of a session.  This
 is implemented on top of the C<OpenSRF::DomainObject::oilsException> class, and 
 sets the default B<status> to C<Connect Request Failed> and B<statusCode> to C<STATUS_NOTFOUND>.
 
@@ -398,7 +398,7 @@
 =cut
 
 
-$status = 'A server error occured during method execution';
+$status = 'A server error occurred during method execution';
 $statusCode = STATUS_INTERNALSERVERERROR;
 
 # -------------------------------------------

Modified: branches/autotools/src/perlmods/OpenSRF/Transport.pm
===================================================================
--- branches/autotools/src/perlmods/OpenSRF/Transport.pm	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/perlmods/OpenSRF/Transport.pm	2007-11-05 13:40:16 UTC (rev 1121)
@@ -90,7 +90,7 @@
 	my $body	= $helper->get_body();
 	my $type	= $helper->get_msg_type();
 
-   $logger->set_osrf_xid($helper->get_osrf_xid);
+	$logger->set_osrf_xid($helper->get_osrf_xid);
 
 	if (defined($type) and $type eq 'error') {
 		throw OpenSRF::EX::Session ("$remote_id IS NOT CONNECTED TO THE NETWORK!!!");

Modified: branches/autotools/src/perlmods/OpenSRF/UnixServer.pm
===================================================================
--- branches/autotools/src/perlmods/OpenSRF/UnixServer.pm	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/perlmods/OpenSRF/UnixServer.pm	2007-11-05 13:40:16 UTC (rev 1121)
@@ -146,7 +146,7 @@
 		$logger->debug( "Looping on zombies " . $x++ , DEBUG);
 	}
 
-	$logger->debug( "Timed out, disconnected, or auth failed" );
+	$logger->debug( "Timed out, disconnected, or authentication failed" );
 	$app_session->kill_me if ($app_session);
 
 	$0 = $orig;
@@ -203,7 +203,7 @@
 	# boot a client
 	OpenSRF::System->bootstrap_client( client_name => "system_client" );
 
-	$logger->debug( "Setting application implementaion for $app", DEBUG );
+	$logger->debug( "Setting application implementation for $app", DEBUG );
 	my $client = OpenSRF::Utils::SettingsClient->new();
 	my $imp = $client->config_value("apps", $app, "implementation");
 	OpenSRF::Application::server_class($app);

Modified: branches/autotools/src/perlmods/OpenSRF/Utils/JSON.pm
===================================================================
--- branches/autotools/src/perlmods/OpenSRF/Utils/JSON.pm	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/perlmods/OpenSRF/Utils/JSON.pm	2007-11-05 13:40:16 UTC (rev 1121)
@@ -85,8 +85,80 @@
 	return $hint;
 }
 
+
+my $JSON_CLASS_KEY = '__c';
+my $JSON_PAYLOAD_KEY = '__p';
+
 sub JSON2perl {
+	my( $class, $string ) = @_;
+	my $perl = $class->rawJSON2perl($string);
+	return $class->JSONObject2Perl($perl);
+}
+
+sub perl2JSON {
+	my( $class, $obj ) = @_;
+	my $json = $class->perl2JSONObject($obj);
+	return $class->rawPerl2JSON($json);
+}
+
+sub JSONObject2Perl {
 	my $class = shift;
+	my $obj = shift;
+	my $ref = ref($obj);
+	if( $ref eq 'HASH' ) {
+		if( defined($obj->{$JSON_CLASS_KEY})) {
+			my $cls = $obj->{$JSON_CLASS_KEY};
+            $cls =~ s/^\s+//o;
+            $cls =~ s/\s+$//o;
+			if( $obj = $class->JSONObject2Perl($obj->{$JSON_PAYLOAD_KEY}) ) {
+				$cls = $class->lookup_class($cls) || $cls;
+				return bless(\$obj, $cls) unless ref($obj); 
+				return bless($obj, $cls);
+			}
+			return undef;
+		}
+		$obj->{$_} = $class->JSONObject2Perl($obj->{$_}) for (keys %$obj);
+	} elsif( $ref eq 'ARRAY' ) {
+		$obj->[$_] = $class->JSONObject2Perl($obj->[$_]) for(0..scalar(@$obj) - 1);
+	}
+	return $obj;
+}
+
+sub perl2JSONObject {
+	my $class = shift;
+	my $obj = shift;
+	my $ref = ref($obj);
+
+	return $obj unless $ref;
+	my $newobj;
+
+	if( $ref eq 'HASH' ) {
+		$newobj = {};
+		$newobj->{$_} = $class->perl2JSONObject( $obj->{$_} ) for (keys %$obj);
+	} elsif( $ref eq 'ARRAY' ) {
+		$newobj = [];
+		$newobj->[$_] = $class->perl2JSONObject( $obj->[$_] ) for(0..scalar(@$obj) - 1 );
+	} elsif( $ref ) {
+		if(UNIVERSAL::isa($obj, 'HASH')) {
+			$newobj = {};
+			$newobj->{$_} = $class->perl2JSONObject( $obj->{$_} ) for (keys %$obj);
+			bless( $newobj, ref($obj) );
+			#bless($obj, 'HASH'); # so our parser won't add the hints
+		} elsif(UNIVERSAL::isa($obj, 'ARRAY')) {
+			$newobj = [];
+			$newobj->[$_] = $class->perl2JSONObject( $obj->[$_] ) for(0..scalar(@$obj) - 1);
+			bless( $newobj, ref($obj) );
+			#bless($obj, 'ARRAY'); # so our parser won't add the hints
+		}
+		$ref = $class->lookup_hint($ref) || $ref;
+		$newobj = { $JSON_CLASS_KEY => $ref, $JSON_PAYLOAD_KEY => $newobj };
+	} 
+	return $newobj;	
+}
+
+
+sub rawJSON2perl {
+	my $class = shift;
 	local $_ = shift;
 
 	s/(?<!\\)\$/\\\$/gmo; # fixup $ for later
@@ -97,8 +169,8 @@
 	s/\\u([0-9a-fA-F]{4})/chr(hex($1))/esog;
 
 	# handle class blessings
-	s/\/\*--\s*S\w*?\s+\S+\s*--\*\// bless(/sog;
-	s/(\]|\}|")\s*\/\*--\s*E\w*?\s+(\S+)\s*--\*\//$1 => _json_hint_to_class("$1", "$2")) /sog;
+#	s/\/\*--\s*S\w*?\s+\S+\s*--\*\// bless(/sog;
+#	s/(\]|\}|")\s*\/\*--\s*E\w*?\s+(\S+)\s*--\*\//$1 => _json_hint_to_class("$1", "$2")) /sog;
 
 	my $re = qr/((?<!\\)"(?>(?<=\\)"|[^"])*(?<!\\)")/;
 	# Grab strings...
@@ -112,17 +184,18 @@
 	s/:/ => /sog;
 
 	# Do numbers...
-	#s/\b(-?\d+\.?\d*)\b/ OpenSRF::Utils::JSON::number::new($1) /sog;
+	#s/\b(-?\d+\.?\d*)\b/ JSON::number::new($1) /sog;
 
 	# Change javascript stuff to perl...
 	s/null/ undef /sog;
-	s/true/ bless( {}, "OpenSRF::Utils::JSON::bool::true") /sog;
-	s/false/ bless( {}, "OpenSRF::Utils::JSON::bool::false") /sog;
+	s/true/ bless( {}, "JSON::bool::true") /sog;
+	s/false/ bless( {}, "JSON::bool::false") /sog;
 
 	my $ret;
 	return eval '$ret = '.$_;
 }
 
+
 my $_json_index;
 sub ___JSON2perl {
 	my $class = shift;
@@ -638,7 +711,7 @@
 		} elsif ($element =~ /^\/\*/) {
 			next;
 		} elsif ($element =~ /^\d/) {
-			$output .= "do { OpenSRF::Utils::JSON::number::new($element) }";
+			$output .= "do { JSON::number::new($element) }";
 			next;
 		} elsif ($element eq '{' or $element eq '[') {
 			$casting_depth++;
@@ -654,10 +727,10 @@
 			$output .= ' => ';
 			next;
 		} elsif ($element eq 'true') {
-			$output .= 'bless( {}, "OpenSRF::Utils::JSON::bool::true")';
+			$output .= 'bless( {}, "JSON::bool::true")';
 			next;
 		} elsif ($element eq 'false') {
-			$output .= 'bless( {}, "OpenSRF::Utils::JSON::bool::false")';
+			$output .= 'bless( {}, "JSON::bool::false")';
 			next;
 		}
 		
@@ -667,26 +740,28 @@
 	return eval $output;
 }
 
-sub perl2JSON {
+
+sub rawPerl2JSON {
 	my ($class, $perl, $strict) = @_;
 
 	my $output = '';
 	if (!defined($perl)) {
 		$output = '' if $strict;
 		$output = 'null' unless $strict;
-	} elsif (ref($perl) and ref($perl) =~ /^OpenSRF::Utils::JSON/) {
+	} elsif (ref($perl) and ref($perl) =~ /^JSON/) {
 		$output .= $perl;
-	} elsif ( ref($perl) && exists($_class_map{classes}{ref($perl)}) ) {
-		$output .= '/*--S '.$_class_map{classes}{ref($perl)}{hint}.'--*/';
-		if (lc($_class_map{classes}{ref($perl)}{type}) eq 'hash') {
-			my %hash =  %$perl;
-			$output .= perl2JSON(undef,\%hash, $strict);
-		} elsif (lc($_class_map{classes}{ref($perl)}{type}) eq 'array') {
-			my @array =  @$perl;
-			$output .= perl2JSON(undef,\@array, $strict);
-		}
-		$output .= '/*--E '.$_class_map{classes}{ref($perl)}{hint}.'--*/';
-	} elsif (ref($perl) and ref($perl) =~ /HASH/) {
+#	} elsif ( ref($perl) && exists($_class_map{classes}{ref($perl)}) ) {
+#		$output .= '/*--S '.$_class_map{classes}{ref($perl)}{hint}.'--*/';
+#		if (lc($_class_map{classes}{ref($perl)}{type}) eq 'hash') {
+#			my %hash =  %$perl;
+#			$output .= rawPerl2JSON(undef,\%hash, $strict);
+#		} elsif (lc($_class_map{classes}{ref($perl)}{type}) eq 'array') {
+#			my @array =  @$perl;
+#			$output .= rawPerl2JSON(undef,\@array, $strict);
+#		}
+#		$output .= '/*--E '.$_class_map{classes}{ref($perl)}{hint}.'--*/';
+#	} elsif (ref($perl) and ref($perl) =~ /HASH/) {
+	} elsif (UNIVERSAL::isa($perl, 'HASH')) {
 		$output .= '{';
 		my $c = 0;
 		for my $key (sort keys %$perl) {
@@ -701,27 +776,28 @@
 			$outkey =~ s/\n/\\n/sgo;
 			$outkey =~ s/([\x{0080}-\x{fffd}])/sprintf('\u%0.4x',ord($1))/sgoe;
 
-			$output .= '"'.$outkey.'":'. perl2JSON(undef,$$perl{$key}, $strict);
+			$output .= '"'.$outkey.'":'. rawPerl2JSON(undef,$$perl{$key}, $strict);
 			$c++;
 		}
 		$output .= '}';
-	} elsif (ref($perl) and ref($perl) =~ /ARRAY/) {
+#	} elsif (ref($perl) and ref($perl) =~ /ARRAY/) {
+	} elsif (UNIVERSAL::isa($perl, 'ARRAY')) {
 		$output .= '[';
 		my $c = 0;
 		for my $part (@$perl) {
 			$output .= ',' if ($c); 
 			
-			$output .= perl2JSON(undef,$part, $strict);
+			$output .= rawPerl2JSON(undef,$part, $strict);
 			$c++;
 		}
 		$output .= ']';
 	} elsif (ref($perl) and ref($perl) =~ /CODE/) {
-		$output .= perl2JSON(undef,$perl->(), $strict);
+		$output .= rawPerl2JSON(undef,$perl->(), $strict);
 	} elsif (ref($perl) and ("$perl" =~ /^([^=]+)=(\w+)/o)) {
 		my $type = $2;
 		my $name = $1;
 		OpenSRF::Utils::JSON->register_class_hint(name => $name, hint => $name, type => lc($type));
-		$output .= perl2JSON(undef,$perl, $strict);
+		$output .= rawPerl2JSON(undef,$perl, $strict);
 	} else {
 		$perl = NFC($perl);
 		$perl =~ s{\\}{\\\\}sgo;
@@ -750,7 +826,7 @@
 	if (!defined($perl)) {
 		$output = "   "x$depth unless($nospace);
 		$output .= 'null';
-	} elsif (ref($perl) and ref($perl) =~ /^OpenSRF::Utils::JSON/) {
+	} elsif (ref($perl) and ref($perl) =~ /^JSON/) {
 		$output = "   "x$depth unless($nospace);
 		$output .= $perl;
 	} elsif ( ref($perl) && exists($_class_map{classes}{ref($perl)}) ) {

Modified: branches/autotools/src/perlmods/OpenSRF/Utils/Logger.pm
===================================================================
--- branches/autotools/src/perlmods/OpenSRF/Utils/Logger.pm	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/perlmods/OpenSRF/Utils/Logger.pm	2007-11-05 13:40:16 UTC (rev 1121)
@@ -1,4 +1,5 @@
 package OpenSRF::Utils::Logger;
+# vim:ts=4:noet:
 use strict;
 use vars qw($AUTOLOAD @EXPORT_OK %EXPORT_TAGS);
 use Exporter;
@@ -29,7 +30,7 @@
 %EXPORT_TAGS = ( level => [ qw/ NONE ERROR WARN INFO DEBUG INTERNAL / ], logger => [ '$logger' ] );
 
 my $config;							# config handle
-my $loglevel;						# global log level
+my $loglevel = INFO();				# global log level
 my $logfile;						# log file
 my $facility;						# syslog facility
 my $actfac;							# activity log syslog facility
@@ -101,8 +102,12 @@
         $actfile = $config->bootstrap->actlog || $config->bootstrap->logfile;
     }
 
-
-	$isclient = (OpenSRF::Utils::Config->current->bootstrap->client =~ /^true$/iog) ?  1 : 0;
+	my $client = OpenSRF::Utils::Config->current->bootstrap->client();
+	if (!$client) {
+		$isclient = 0;
+		return;
+	}
+	$isclient = ($client =~ /^true$/iog) ?  1 : 0;
 }
 
 sub _fac_to_const {

Modified: branches/autotools/src/python/osrf/gateway.py
===================================================================
--- branches/autotools/src/python/osrf/gateway.py	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/python/osrf/gateway.py	2007-11-05 13:40:16 UTC (rev 1121)
@@ -2,17 +2,21 @@
 from xml.sax import handler, make_parser, saxutils
 from json import *
 from net_obj import *
+from log import *
 import urllib, urllib2, sys, re
 
 defaultHost = None
-#paramRegex = re.compile('\%27')
 
 class GatewayRequest:
     def __init__(self, service, method, params=[]):
         self.service = service
         self.method = method
         self.params = params
+        self.path = 'gateway'
 
+    def setPath(self, path):
+        self.path = path
+
     def send(self):
         params = self.buildPOSTParams()
         request = urllib2.Request(self.buildURL(), data=params)
@@ -45,9 +49,34 @@
     setDefaultHost = staticmethod(setDefaultHost)
 
     def buildURL(self):
-        return 'http://%s/gateway' % defaultHost
+        return 'http://%s/%s' % (defaultHost, self.path)
 
+class JSONGatewayRequest(GatewayRequest):
+    def __init__(self, service, method, *params):
+        GatewayRequest.__init__(self, service, method, list(params))
 
+    def getFormat(self):
+        return 'json'
+
+    def getInputFormat(self):
+        return self.getFormat()
+
+    def handleResponse(self, response):
+        s = response.read()
+        obj = osrfJSONToObject(s)
+        if obj['status'] != 200:
+            sys.stderr.write('JSON gateway returned status %d:\n%s\n' % (obj['status'], s))
+            return None
+
+        # the gateway wraps responses in an array to handle streaming data
+        # if there is only one item in the array, it (probably) wasn't a streaming request
+        p = obj['payload']
+        if len(p) > 1: return p
+        return p[0]
+
+    def encodeParam(self, param):
+        return osrfObjectToJSON(param)
+
 class XMLGatewayRequest(GatewayRequest):
 
     def __init__(self, service, method, *params):
@@ -63,7 +92,12 @@
         handler = XMLGatewayParser()
         parser = make_parser()
         parser.setContentHandler(handler)
-        parser.parse(response)
+        try:
+            parser.parse(response)
+        except Exception, e:
+            osrfLogErr('Error parsing gateway XML: %s' % str(e))
+            return None
+
         return handler.getResult()
 
     def encodeParam(self, param):

Modified: branches/autotools/src/python/osrf/json.py
===================================================================
--- branches/autotools/src/python/osrf/json.py	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/python/osrf/json.py	2007-11-05 13:40:16 UTC (rev 1121)
@@ -4,10 +4,21 @@
 
 class osrfJSONNetworkEncoder(simplejson.JSONEncoder):
     def default(self, obj):
+
         if isinstance(obj, osrfNetworkObject):
+            reg = obj.getRegistry()
+            data = obj.getData()
+
+            # re-encode the object as an array if necessary
+            if reg.wireProtocol == 'array':
+                d = []
+                for k in reg.keys:
+                    d.append(data.get(k)) 
+                data = d
+
             return { 
-                OSRF_JSON_CLASS_KEY: obj.getRegistry().hint,
-                OSRF_JSON_PAYLOAD_KEY: self.default(obj.getData())
+                OSRF_JSON_CLASS_KEY: reg.hint,
+                OSRF_JSON_PAYLOAD_KEY: self.default(data)
             }   
         return obj
 
@@ -77,9 +88,15 @@
     instring = False
     inescape = False
     done = False
+    eatws = False
 
     for c in json:
 
+        if eatws: # simpljson adds a pesky space after array and object items
+            if c == ' ': 
+                continue
+
+        eatws = False
         done = False
         if (c == '{' or c == '[') and not instring:
             t += 1
@@ -94,7 +111,11 @@
         if c == ',' and not instring:
             r += c + '\n' + __tabs(t)
             done = True
+            eatws = True
 
+        if c == ':' and not instring:
+            eatws = True
+
         if c == '"' and not inescape:
             instring = not instring
 

Modified: branches/autotools/src/python/osrf/log.py
===================================================================
--- branches/autotools/src/python/osrf/log.py	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/python/osrf/log.py	2007-11-05 13:40:16 UTC (rev 1121)
@@ -13,7 +13,7 @@
 # GNU General Public License for more details.
 # -----------------------------------------------------------------------
 
-import traceback, sys, os, re
+import traceback, sys, os, re, threading
 from osrf.const import *
 
 loglevel = 4
@@ -50,6 +50,8 @@
     try:
         import syslog
     except:
+        if level == OSRF_LOG_ERR:
+            sys.stderr.write('ERR ' + msg)
         return
         
     global loglevel
@@ -66,8 +68,11 @@
     if level == OSRF_LOG_WARN: lvl = 'WARN'; slvl=syslog.LOG_WARNING
     if level == OSRF_LOG_ERR:  lvl = 'ERR '; slvl=syslog.LOG_ERR
 
+
+    # XXX when file logging is implemented, wrap io in a semaphore for thread safety
+
     file = frgx.sub('',tb[0])
-    msg = '[%s:%d:%s:%s] %s' % (lvl, os.getpid(), file, tb[1], msg)
+    msg = '[%s:%d:%s:%s:%s] %s' % (lvl, os.getpid(), file, tb[1], threading.currentThread().getName(), msg)
     syslog.syslog(slvl, msg)
 
     if level == OSRF_LOG_ERR:

Modified: branches/autotools/src/python/osrf/net.py
===================================================================
--- branches/autotools/src/python/osrf/net.py	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/python/osrf/net.py	2007-11-05 13:40:16 UTC (rev 1121)
@@ -19,129 +19,133 @@
 from pyxmpp.jid import JID
 from socket import gethostname
 from osrf.log import *
-import os, time
+import os, time, threading
 import logging
 
+threadSessions = {}
+
 # - log jabber activity (for future reference)
 #logger=logging.getLogger()
 #logger.addHandler(logging.StreamHandler())
 #logger.addHandler(logging.FileHandler('j.log'))
 #logger.setLevel(logging.DEBUG)
 
-__network = None
 def osrfSetNetworkHandle(handle):
-	"""Sets the global network connection handle."""
-	global __network
-	__network = handle
+    """ Sets the thread-specific network handle"""
+    threadSessions[threading.currentThread().getName()] = handle
 
 def osrfGetNetworkHandle():
-	"""Returns the global network connection handle."""
-	global __network
-	return __network
+    """ Returns the thread-specific network connection handle."""
+    return threadSessions.get(threading.currentThread().getName())
 
 
 class osrfNetworkMessage(object):
-	"""Network message
+    """Network message
 
-	attributes:
+    attributes:
 
-	sender - message sender
-	to - message recipient
-	body - the body of the message
-	thread - the message thread
-	"""
+    sender - message sender
+    to - message recipient
+    body - the body of the message
+    thread - the message thread
+    """
 
-	def __init__(self, message=None, **args):
-		if message:
-			self.body = message.get_body()
-			self.thread = message.get_thread()
-			self.to = message.get_to()
-			if message.xmlnode.hasProp('router_from') and message.xmlnode.prop('router_from') != '':
-				self.sender = message.xmlnode.prop('router_from')
-			else: self.sender = message.get_from().as_utf8()
-		else:
-			if args.has_key('sender'): self.sender = args['sender']
-			if args.has_key('to'): self.to = args['to']
-			if args.has_key('body'): self.body = args['body']
-			if args.has_key('thread'): self.thread = args['thread']
+    def __init__(self, message=None, **args):
+        if message:
+            self.body = message.get_body()
+            self.thread = message.get_thread()
+            self.to = message.get_to()
+            if message.xmlnode.hasProp('router_from') and message.xmlnode.prop('router_from') != '':
+                self.sender = message.xmlnode.prop('router_from')
+            else: self.sender = message.get_from().as_utf8()
+        else:
+            if args.has_key('sender'): self.sender = args['sender']
+            if args.has_key('to'): self.to = args['to']
+            if args.has_key('body'): self.body = args['body']
+            if args.has_key('thread'): self.thread = args['thread']
 
 
 class osrfNetwork(JabberClient):
-	def __init__(self, **args):
-		self.isconnected = False
+    def __init__(self, **args):
+        self.isconnected = False
 
-		# Create a unique jabber resource
-		resource = 'osrf_client'
-		if args.has_key('resource'):
-			resource = args['resource']
-		resource += '_' + gethostname()+':'+ str(os.getpid()) 
-		self.jid = JID(args['username'], args['host'], resource)
+        # Create a unique jabber resource
+        resource = 'python'
+        if args.has_key('resource'):
+            resource = args['resource']
+        resource += '_' + gethostname()+':'+ str(os.getpid()) + '_'+ threading.currentThread().getName().lower()
+        self.jid = JID(args['username'], args['host'], resource)
 
-		osrfLogDebug("initializing network with JID %s and host=%s, port=%s, username=%s" % 
-			(self.jid.as_utf8(), args['host'], args['port'], args['username']))
+        osrfLogDebug("initializing network with JID %s and host=%s, port=%s, username=%s" % 
+            (self.jid.as_utf8(), args['host'], args['port'], args['username']))
 
-		#initialize the superclass
-		JabberClient.__init__(self, self.jid, args['password'], args['host'])
-		self.queue = []
+        #initialize the superclass
+        JabberClient.__init__(self, self.jid, args['password'], args['host'])
+        self.queue = []
 
-	def connect(self):
-		JabberClient.connect(self)
-		while not self.isconnected:
-			stream = self.get_stream()
-			act = stream.loop_iter(10)
-			if not act: self.idle()
+        self.recvCallback = None
 
-	def setRecvCallback(self, func):
-		"""The callback provided is called when a message is received.
-		
-			The only argument to the function is the received message. """
-		self.recvCallback = func
+    def connect(self):
+        JabberClient.connect(self)
+        while not self.isconnected:
+            stream = self.get_stream()
+            act = stream.loop_iter(10)
+            if not act: self.idle()
 
-	def session_started(self):
-		osrfLogInfo("Successfully connected to the opensrf network")
-		self.authenticated()
-		self.stream.set_message_handler("normal",self.message_received)
-		self.isconnected = True
+    def setRecvCallback(self, func):
+        """The callback provided is called when a message is received.
+        
+            The only argument to the function is the received message. """
+        self.recvCallback = func
 
-	def send(self, message):
-		"""Sends the provided network message."""
-		osrfLogInternal("jabber sending to %s: %s" % (message.to, message.body))
-		msg = Message(None, None, message.to, None, None, None, message.body, message.thread)
-		self.stream.send(msg)
-	
-	def message_received(self, stanza):
-		"""Handler for received messages."""
-		osrfLogInternal("jabber received a message of type %s" % stanza.get_type())
-		if stanza.get_type()=="headline":
-			return True
-		# check for errors
-		osrfLogInternal("jabber received message from %s : %s" 
-			% (stanza.get_from().as_utf8(), stanza.get_body()))
-		self.queue.append(osrfNetworkMessage(stanza))
-		return True
+    def session_started(self):
+        osrfLogInfo("Successfully connected to the opensrf network")
+        self.authenticated()
+        self.stream.set_message_handler("normal",self.message_received)
+        self.isconnected = True
 
-	def recv(self, timeout=120):
-		"""Attempts to receive a message from the network.
+    def send(self, message):
+        """Sends the provided network message."""
+        osrfLogInternal("jabber sending to %s: %s" % (message.to, message.body))
+        msg = Message(None, None, message.to, None, None, None, message.body, message.thread)
+        self.stream.send(msg)
+    
+    def message_received(self, stanza):
+        """Handler for received messages."""
+        osrfLogInternal("jabber received a message of type %s" % stanza.get_type())
+        if stanza.get_type()=="headline":
+            return True
+        # check for errors
+        osrfLogInternal("jabber received message from %s : %s" 
+            % (stanza.get_from().as_utf8(), stanza.get_body()))
+        self.queue.append(osrfNetworkMessage(stanza))
+        return True
 
-		timeout - max number of seconds to wait for a message.  
-		If no message is received in 'timeout' seconds, None is returned. """
+    def recv(self, timeout=120):
+        """Attempts to receive a message from the network.
 
-		msg = None
-		if len(self.queue) == 0:
-			while timeout >= 0 and len(self.queue) == 0:
-				starttime = time.time()
-				osrfLogInternal("going into stream loop at " + str(starttime))
-				act = self.get_stream().loop_iter(timeout)
-				endtime = time.time() - starttime
-				timeout -= endtime
-				osrfLogInternal("exiting stream loop after %s seconds" % str(endtime))
-				osrfLogInternal("act = %s : queue length = %d" % (act, len(self.queue)) )
-				if not act: self.idle()
+        timeout - max number of seconds to wait for a message.  
+        If a message is received in 'timeout' seconds, the message is passed to 
+        the recvCallback is called and True is returned.  Otherwise, false is returned."""
 
-		# if we've acquired a message, handle it
-		if len(self.queue) > 0:
-			self.recvCallback(self.queue.pop(0))
-		return None
+        msg = None
+        if len(self.queue) == 0:
+            while timeout >= 0 and len(self.queue) == 0:
+                starttime = time.time()
+                osrfLogInternal("going into stream loop at " + str(starttime))
+                act = self.get_stream().loop_iter(timeout)
+                endtime = time.time() - starttime
+                timeout -= endtime
+                osrfLogInternal("exiting stream loop after %s seconds" % str(endtime))
+                osrfLogInternal("act = %s : queue length = %d" % (act, len(self.queue)) )
+                if not act: self.idle()
 
+        # if we've acquired a message, handle it
+        if len(self.queue) > 0:
+            self.recvCallback(self.queue.pop(0))
+            return True
 
+        return False
 
+
+

Modified: branches/autotools/src/python/osrf/net_obj.py
===================================================================
--- branches/autotools/src/python/osrf/net_obj.py	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/python/osrf/net_obj.py	2007-11-05 13:40:16 UTC (rev 1121)
@@ -2,20 +2,11 @@
 from xml.sax import saxutils
 
 
-class osrfNetworkObject(object):
-    ''' Base class for all network serializable objects '''
-    pass
+# -----------------------------------------------------------
+# Define the global network-class registry
+# -----------------------------------------------------------
 
-def osrfNewObjectFromHint(hint):
-    try:
-        obj = None
-        exec('obj = osrfNetworkObject.%s()' % hint)
-        return obj
-    except AttributeError:
-        return osrfNetworkObject.__unknown()
-
-
-''' Global object registry '''
+# Global object registry 
 objectRegistry = {}
 
 class osrfNetworkRegistry(object):
@@ -37,56 +28,79 @@
     getRegistry = staticmethod(getRegistry)
 
 
-def __makeNetworkAccessor(cls, key):
-    '''  Creates and accessor/mutator method for the given class.  
+# -----------------------------------------------------------
+# Define the base class for all network-serializable objects
+# -----------------------------------------------------------
 
-        'key' is the name the method will have and represents
-        the field on the object whose data we are accessing
-        ''' 
-    def accessor(self, *args):
-        if len(args) != 0:
-            self.__data[key] = args[0]
-        return self.__data.get(key)
-    setattr(cls, key, accessor)
+class osrfNetworkObject(object):
+    ''' Base class for all network serializable objects '''
 
+    # link to our registry object for this registered class
+    registry = None
 
+    def __init__(self, data=None):
+        ''' If this is an array, we pull data out of the data array
+            (if there is any) and translate that into a hash internally '''
 
-def __makeGetRegistry(cls, registry):
-    ''' Wraps the registry for this class inside an accessor method '''
-    def get(self):
-        return registry
-    setattr(cls, 'getRegistry', get)
+        self._data = data
+        if not data: self._data = {}
+        if isinstance(data, list):
+            self.importArrayData(list)
 
-def __makeGetData(cls):
-    ''' Wraps the stored data in an accessor method '''
-    def get(self):
-        return self.__data
-    setattr(cls, 'getData', get)
+    def importArrayData(self, data):
+        ''' If an array-based object is created with an array
+            of data, cycle through and load the data '''
 
-def __makeSetField(cls):
-    ''' Creates a generic mutator for fields by fieldname '''
-    def set(self, field, value):
-        self.__data[field] = value
-    setattr(cls, 'setField', set)
-        
+        self._data = {}
+        if len(data) == 0: return
 
-def __osrfNetworkObjectInit(self, data={}):
-    ''' __init__ method for osrNetworkObjects.
-        If this is an array, we pull data out of the data array
-        (if there is any) and translate that into a hash internally
-        '''
-    self.__data = data
-    if isinstance(data, list) and len(data) > 0:
         reg = self.getRegistry()
         if reg.wireProtocol == 'array':
-            self.__data = {}
             for i in range(len(reg.keys)):
-                try:
-                    self.__data[reg.keys[i]] = data[i]
-                except:
-                    self.__data[reg.keys[i]] = None
+                if len(data) > i: break
+                self.setField(reg.keys[i], data[i])
 
+    def getData(self):
+        ''' Returns the full dataset for this object as a dict '''
+        return self._data
 
+    def setField(self, field, value):
+        self._data[field] = value
+
+    def getField(self, field):
+        return self._data.get(field)
+
+    def getRegistry(cls):
+        ''' Returns the registry object for this registered class '''
+        return cls.registry
+    getRegistry = classmethod(getRegistry)
+
+
+def osrfNewObjectFromHint(hint):
+    ''' Given a hint, this will create a new object of that 
+        type and return it.  If this hint is not registered,
+        an object of type osrfNetworkObject.__unknown is returned'''
+    try:
+        obj = None
+        exec('obj = osrfNetworkObject.%s()' % hint)
+        return obj
+    except AttributeError:
+        return osrfNetworkObject.__unknown()
+
+
+
+
+def __makeNetworkAccessor(cls, key):
+    ''' Creates and accessor/mutator method for the given class.  
+        'key' is the name the method will have and represents
+        the field on the object whose data we are accessing ''' 
+    def accessor(self, *args):
+        if len(args) != 0:
+            self.setField(key, args[0])
+        return self.getField(key)
+    setattr(cls, key, accessor)
+
+
 def osrfNetworkRegisterHint(hint, keys, type='hash'):
     ''' Registers a new network-serializable object class.
 
@@ -111,16 +125,10 @@
     for k in keys:
         __makeNetworkAccessor(cls, k)
 
-    # assign our custom init function
-    setattr(cls, '__init__', __osrfNetworkObjectInit)
-    __makeGetRegistry(cls, registry)
-    __makeGetData(cls)
-    __makeSetField(cls)
-
-
     # attach our new class to the osrfNetworkObject 
     # class so others can access it
     setattr(osrfNetworkObject, hint , cls)
+    cls.registry = registry
 
 
 

Modified: branches/autotools/src/python/osrf/ses.py
===================================================================
--- branches/autotools/src/python/osrf/ses.py	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/python/osrf/ses.py	2007-11-05 13:40:16 UTC (rev 1121)
@@ -19,7 +19,7 @@
 from osrf.net import osrfNetworkMessage, osrfGetNetworkHandle
 from osrf.log import *
 from osrf.const import *
-import random, sys, os, time
+import random, sys, os, time, threading
 
 
 # -----------------------------------------------------------------------
@@ -35,10 +35,16 @@
 class osrfSession(object):
     """Abstract session superclass."""
 
+    ''' Global cache of in-service sessions '''
+    sessionCache = {}
+
     def __init__(self):
         # by default, we're connected to no one
         self.state = OSRF_APP_SESSION_DISCONNECTED
 
+    def findSession(threadTrace):
+        return osrfSession.sessionCache.get(threadTrace)
+    findSession = staticmethod(findSession)
 
     def wait(self, timeout=120):
         """Wait up to <timeout> seconds for data to arrive on the network"""
@@ -58,7 +64,7 @@
 
     def cleanup(self):
         """Removes the session from the global session cache."""
-        del osrfClientSession.sessionCache[self.thread]
+        del osrfSession.sessionCache[self.thread]
 
 class osrfClientSession(osrfSession):
     """Client session object.  Use this to make server requests."""
@@ -78,7 +84,8 @@
         self.origRemoteId = self.remoteId
 
         # generate a random message thread
-        self.thread = "%s%s%s" % (os.getpid(), str(random.randint(100,100000)), str(time.time()))
+        self.thread = "%s%s%s%s" % (os.getpid(), 
+            str(random.randint(100,100000)), str(time.time()),threading.currentThread().getName().lower())
 
         # how many requests this session has taken part in
         self.nextId = 0 
@@ -87,7 +94,7 @@
         self.requests = {}
 
         # cache this session in the global session cache
-        osrfClientSession.sessionCache[self.thread] = self
+        osrfSession.sessionCache[self.thread] = self
 
     def resetRequestTimeout(self, rid):
         req = self.findRequest(rid)
@@ -190,13 +197,6 @@
 
 
 
-osrfSession.sessionCache = {}
-def osrfFindSession(thread):
-    """Finds a session in the global cache."""
-    try:
-        return osrfClientSession.sessionCache[thread]
-    except: return None
-
 class osrfRequest(object):
     """Represents a single OpenSRF request.
         A request is made and any resulting respones are 

Modified: branches/autotools/src/python/osrf/stack.py
===================================================================
--- branches/autotools/src/python/osrf/stack.py	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/python/osrf/stack.py	2007-11-05 13:40:16 UTC (rev 1121)
@@ -16,13 +16,13 @@
 from osrf.json import *
 from osrf.log import *
 from osrf.ex import *
-from osrf.ses import osrfFindSession, osrfClientSession, osrfServerSession
+from osrf.ses import osrfSession, osrfClientSession, osrfServerSession
 from osrf.const import *
 from time import time
 
 
 def osrfPushStack(netMessage):
-   ses = osrfFindSession(netMessage.thread)
+   ses = osrfSession.findSession(netMessage.thread)
 
    if not ses:
       # This is an incoming request from a client, create a new server session

Modified: branches/autotools/src/python/osrf/system.py
===================================================================
--- branches/autotools/src/python/osrf/system.py	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/python/osrf/system.py	2007-11-05 13:40:16 UTC (rev 1121)
@@ -14,7 +14,7 @@
 # -----------------------------------------------------------------------
 
 from osrf.conf import osrfConfig, osrfConfigValue, osrfConfigValueNoEx
-from osrf.net import osrfNetwork, osrfSetNetworkHandle
+from osrf.net import osrfNetwork, osrfSetNetworkHandle, osrfGetNetworkHandle
 from osrf.stack import osrfPushStack
 from osrf.log import *
 from osrf.set import osrfLoadSettings
@@ -24,6 +24,10 @@
 def osrfConnect(configFile, configContext):
     """ Connects to the opensrf network """
 
+    if osrfGetNetworkHandle():
+        ''' This thread already has a handle '''
+        return
+
     # parse the config file
     configParser = osrfConfig(configFile, configContext)
     configParser.parseConfig()
@@ -49,3 +53,5 @@
 
 
 
+
+

Modified: branches/autotools/src/python/srfsh.py
===================================================================
--- branches/autotools/src/python/srfsh.py	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/python/srfsh.py	2007-11-05 13:40:16 UTC (rev 1121)
@@ -11,73 +11,73 @@
 # main listen loop
 # -------------------------------------------------------------------
 def do_loop():
-	while True:
+    while True:
 
-		try:
-			#line = raw_input("srfsh% ")
-			line = raw_input("\033[01;32msrfsh\033[01;34m% \033[00m")
-			if not len(line): 
-				continue
-			if lower(line) == 'exit' or lower(line) == 'quit': 
-				break
-			parts = split(line)
+        try:
+            #line = raw_input("srfsh% ")
+            line = raw_input("\033[01;32msrfsh\033[01;34m% \033[00m")
+            if not len(line): 
+                continue
+            if lower(line) == 'exit' or lower(line) == 'quit': 
+                break
+            parts = split(line)
 
-			command = parts[0]
-		
-			if command == 'request':
-				parts.pop(0)
-				handle_request(parts)
-				continue
+            command = parts[0]
+        
+            if command == 'request':
+                parts.pop(0)
+                handle_request(parts)
+                continue
 
-			if command == 'math_bench':
-				parts.pop(0)
-				handle_math_bench(parts)
-				continue
+            if command == 'math_bench':
+                parts.pop(0)
+                handle_math_bench(parts)
+                continue
 
-			if command == 'help':
-				handle_help()
-				continue
+            if command == 'help':
+                handle_help()
+                continue
 
-			if command == 'set':
-				parts.pop(0)
-				handle_set(parts)
+            if command == 'set':
+                parts.pop(0)
+                handle_set(parts)
 
-			if command == 'get':
-				parts.pop(0)
-				handle_get(parts)
+            if command == 'get':
+                parts.pop(0)
+                handle_get(parts)
 
 
 
-		except KeyboardInterrupt:
-			print ""
+        except KeyboardInterrupt:
+            print ""
 
-		except EOFError:
-			print "exiting..."
-			sys.exit(0)
+        except EOFError:
+            print "exiting..."
+            sys.exit(0)
 
 
 # -------------------------------------------------------------------
 # Set env variables to control behavior
 # -------------------------------------------------------------------
 def handle_set(parts):
-	m = re.compile('(.*)=(.*)').match(parts[0])
-	key = m.group(1)
-	val = m.group(2)
-	set_var(key, val)
-	print "%s = %s" % (key, val)
+    m = re.compile('(.*)=(.*)').match(parts[0])
+    key = m.group(1)
+    val = m.group(2)
+    set_var(key, val)
+    print "%s = %s" % (key, val)
 
 def handle_get(parts):
-	try:
-		print get_var(parts[0])
-	except:
-		print ""
+    try:
+        print get_var(parts[0])
+    except:
+        print ""
 
 
 # -------------------------------------------------------------------
 # Prints help info
 # -------------------------------------------------------------------
 def handle_help():
-	print """
+    print """
   help
     - show this menu
 
@@ -93,88 +93,88 @@
   Environment variables:
     SRFSH_OUTPUT = pretty - print pretty JSON and key/value pairs for network objects
                  = raw - print formatted JSON 
-	"""
+    """
 
-		
+        
 
 
 # -------------------------------------------------------------------
 # performs an opesnrf request
 # -------------------------------------------------------------------
 def handle_request(parts):
-	service = parts.pop(0)
-	method = parts.pop(0)
-	jstr = '[%s]' % join(parts)
-	params = None
+    service = parts.pop(0)
+    method = parts.pop(0)
+    jstr = '[%s]' % join(parts)
+    params = None
 
-	try:
-		params = osrfJSONToObject(jstr)
-	except:
-		print "Error parsing JSON: %s" % jstr
-		return
+    try:
+        params = osrfJSONToObject(jstr)
+    except:
+        print "Error parsing JSON: %s" % jstr
+        return
 
-	ses = osrfClientSession(service)
+    ses = osrfClientSession(service)
 
-	end = None
-	start = time.time()
+    end = None
+    start = time.time()
 
-	req = ses.request2(method, tuple(params))
+    req = ses.request2(method, tuple(params))
 
 
-	while True:
-		resp = req.recv(timeout=120)
-		if not end:
-			total = time.time() - start
-		if not resp: break
+    while True:
+        resp = req.recv(timeout=120)
+        if not end:
+            total = time.time() - start
+        if not resp: break
 
-		otp = get_var('SRFSH_OUTPUT')
-		if otp == 'pretty':
-			print osrfDebugNetworkObject(resp.content())
-		else:
-			print osrfFormatJSON(osrfObjectToJSON(resp.content()))
+        otp = get_var('SRFSH_OUTPUT')
+        if otp == 'pretty':
+            print "\n" + osrfDebugNetworkObject(resp.content())
+        else:
+            print osrfFormatJSON(osrfObjectToJSON(resp.content()))
 
-	req.cleanup()
-	ses.cleanup()
+    req.cleanup()
+    ses.cleanup()
 
-	print '-'*60
-	print "Total request time: %f" % total
-	print '-'*60
+    print '-'*60
+    print "Total request time: %f" % total
+    print '-'*60
 
 
 def handle_math_bench(parts):
 
-	count = int(parts.pop(0))
-	ses = osrfClientSession('opensrf.math')
-	times = []
+    count = int(parts.pop(0))
+    ses = osrfClientSession('opensrf.math')
+    times = []
 
-	for i in range(100):
-		if i % 10: sys.stdout.write('.')
-		else: sys.stdout.write( str( i / 10 ) )
-	print "";
+    for i in range(100):
+        if i % 10: sys.stdout.write('.')
+        else: sys.stdout.write( str( i / 10 ) )
+    print "";
 
 
-	for i in range(count):
-	
-		starttime = time.time()
-		req = ses.request('add', 1, 2)
-		resp = req.recv(timeout=2)
-		endtime = time.time()
-	
-		if resp.content() == 3:
-			sys.stdout.write("+")
-			sys.stdout.flush()
-			times.append( endtime - starttime )
-		else:
-			print "What happened? %s" % str(resp.content())
-	
-		req.cleanup()
-		if not ( (i+1) % 100):
-			print ' [%d]' % (i+1)
-	
-	ses.cleanup()
-	total = 0
-	for i in times: total += i
-	print "\naverage time %f" % (total / len(times))
+    for i in range(count):
+    
+        starttime = time.time()
+        req = ses.request('add', 1, 2)
+        resp = req.recv(timeout=2)
+        endtime = time.time()
+    
+        if resp.content() == 3:
+            sys.stdout.write("+")
+            sys.stdout.flush()
+            times.append( endtime - starttime )
+        else:
+            print "What happened? %s" % str(resp.content())
+    
+        req.cleanup()
+        if not ( (i+1) % 100):
+            print ' [%d]' % (i+1)
+    
+    ses.cleanup()
+    total = 0
+    for i in times: total += i
+    print "\naverage time %f" % (total / len(times))
 
 
 
@@ -183,87 +183,87 @@
 # Defines the tab-completion handling and sets up the readline history 
 # -------------------------------------------------------------------
 def setup_readline():
-	class SrfshCompleter(object):
-		def __init__(self, words):
-			self.words = words
-			self.prefix = None
-	
-		def complete(self, prefix, index):
-			if prefix != self.prefix:
-				# find all words that start with this prefix
-				self.matching_words = [
-					w for w in self.words if w.startswith(prefix)
-				]
-				self.prefix = prefix
-				try:
-					return self.matching_words[index]
-				except IndexError:
-					return None
-	
-	words = 'request', 'help', 'exit', 'quit', 'opensrf.settings', 'opensrf.math', 'set'
-	completer = SrfshCompleter(words)
-	readline.parse_and_bind("tab: complete")
-	readline.set_completer(completer.complete)
+    class SrfshCompleter(object):
+        def __init__(self, words):
+            self.words = words
+            self.prefix = None
+    
+        def complete(self, prefix, index):
+            if prefix != self.prefix:
+                # find all words that start with this prefix
+                self.matching_words = [
+                    w for w in self.words if w.startswith(prefix)
+                ]
+                self.prefix = prefix
+                try:
+                    return self.matching_words[index]
+                except IndexError:
+                    return None
+    
+    words = 'request', 'help', 'exit', 'quit', 'opensrf.settings', 'opensrf.math', 'set'
+    completer = SrfshCompleter(words)
+    readline.parse_and_bind("tab: complete")
+    readline.set_completer(completer.complete)
 
-	histfile = os.path.join(get_var('HOME'), ".srfsh_history")
-	try:
-	    readline.read_history_file(histfile)
-	except IOError:
-		pass
-	atexit.register(readline.write_history_file, histfile)
+    histfile = os.path.join(get_var('HOME'), ".srfsh_history")
+    try:
+        readline.read_history_file(histfile)
+    except IOError:
+        pass
+    atexit.register(readline.write_history_file, histfile)
 
 def do_connect():
-	file = os.path.join(get_var('HOME'), ".srfsh.xml")
-	print_green("Connecting to opensrf...")
-	osrfConnect(file, 'srfsh')
-	print_red('OK\n')
+    file = os.path.join(get_var('HOME'), ".srfsh.xml")
+    print_green("Connecting to opensrf...")
+    osrfConnect(file, 'srfsh')
+    print_red('OK\n')
 
 def load_plugins():
-	# Load the user defined external plugins
-	# XXX Make this a real module interface, with tab-complete words, commands, etc.
-	plugins = osrfConfigValue('plugins')
-	plugins = osrfConfigValue('plugins.plugin')
-	if not isinstance(plugins, list):
-		plugins = [plugins]
+    # Load the user defined external plugins
+    # XXX Make this a real module interface, with tab-complete words, commands, etc.
+    plugins = osrfConfigValue('plugins')
+    plugins = osrfConfigValue('plugins.plugin')
+    if not isinstance(plugins, list):
+        plugins = [plugins]
 
-	for module in plugins:
-		name = module['module']
-		init = module['init']
-		print_green("Loading module %s..." % name)
+    for module in plugins:
+        name = module['module']
+        init = module['init']
+        print_green("Loading module %s..." % name)
 
-		try:
-			str = 'from %s import %s\n%s()' % (name, init, init)
-			exec(str)
-			print_red('OK\n')
+        try:
+            str = 'from %s import %s\n%s()' % (name, init, init)
+            exec(str)
+            print_red('OK\n')
 
-		except Exception, e:
-			sys.stderr.write("\nError importing plugin %s, with init symbol %s: \n%s\n" % (name, init, e))
+        except Exception, e:
+            sys.stderr.write("\nError importing plugin %s, with init symbol %s: \n%s\n" % (name, init, e))
 
 def set_vars():
-	if not get_var('SRFSH_OUTPUT'):
-		set_var('SRFSH_OUTPUT', 'pretty')
+    if not get_var('SRFSH_OUTPUT'):
+        set_var('SRFSH_OUTPUT', 'pretty')
 
 
 def set_var(key, val):
-	os.environ[key] = val
+    os.environ[key] = val
 
 
 def get_var(key):
-	try: return os.environ[key]
-	except: return ''
-	
-	
+    try: return os.environ[key]
+    except: return ''
+    
+    
 def print_green(str):
-	sys.stdout.write("\033[01;32m")
-	sys.stdout.write(str)
-	sys.stdout.write("\033[00m")
-	sys.stdout.flush()
+    sys.stdout.write("\033[01;32m")
+    sys.stdout.write(str)
+    sys.stdout.write("\033[00m")
+    sys.stdout.flush()
 
 def print_red(str):
-	sys.stdout.write("\033[01;31m")
-	sys.stdout.write(str)
-	sys.stdout.write("\033[00m")
-	sys.stdout.flush()
+    sys.stdout.write("\033[01;31m")
+    sys.stdout.write(str)
+    sys.stdout.write("\033[00m")
+    sys.stdout.flush()
 
 
 

Modified: branches/autotools/src/router/Makefile
===================================================================
--- branches/autotools/src/router/Makefile	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/router/Makefile	2007-11-05 13:40:16 UTC (rev 1121)
@@ -1,6 +1,6 @@
 #MALLOC_CHECK_=1 # XXX debug only
 
-LDLIBS	+= -lxml2 -lopensrf -lobjson
+LDLIBS	+= -lxml2 -lopensrf 
 CFLAGS	+= -D_ROUTER
 
 all: opensrf_router 

Modified: branches/autotools/src/router/osrf_router.c
===================================================================
--- branches/autotools/src/router/osrf_router.c	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/router/osrf_router.c	2007-11-05 13:40:16 UTC (rev 1121)
@@ -119,7 +119,7 @@
 			/* if the sender is not a trusted server, drop the message */
 			int len = strlen(msg->sender) + 1;
 			char domain[len];
-			bzero(domain, len);
+			memset(domain, 0, sizeof(domain));
 			jid_get_domain( msg->sender, domain, len - 1 );
 
 			if(osrfStringArrayContains( router->trustedServers, domain)) 
@@ -150,7 +150,7 @@
 			/* if the client is not from a trusted domain, drop the message */
 			int len = strlen(msg->sender) + 1;
 			char domain[len];
-			bzero(domain, len);
+			memset(domain, 0, sizeof(domain));
 			jid_get_domain( msg->sender, domain, len - 1 );
 
 			if(osrfStringArrayContains( router->trustedClients, domain)) {
@@ -486,7 +486,7 @@
 
 	int T = 32;
 	osrfMessage* arr[T];
-	memset(arr, 0, T );
+	memset(arr, 0, sizeof(arr));
 
 	int num_msgs = osrf_message_deserialize( msg->body, arr, T );
 	osrfMessage* omsg = NULL;
@@ -520,7 +520,7 @@
 
 	osrfMessage* success = osrf_message_init( STATUS, omsg->thread_trace, omsg->protocol );
 
-	osrfLogDebug( OSRF_LOG_MARK, "router recevied a CONNECT message from %s", msg->sender );
+	osrfLogDebug( OSRF_LOG_MARK, "router received a CONNECT message from %s", msg->sender );
 
 	osrf_message_set_status_info( 
 		success, "osrfConnectStatus", "Connection Successful", OSRF_STATUS_OK );

Modified: branches/autotools/src/srfsh/Makefile
===================================================================
--- branches/autotools/src/srfsh/Makefile	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/srfsh/Makefile	2007-11-05 13:40:16 UTC (rev 1121)
@@ -1,6 +1,6 @@
 # if EXEC_DEFAULT is defined, then srfsh will send all unknown commands to the shell for execution
 
-LDLIBS	+= -lobjson -lreadline -lxml2 -lopensrf -lncurses 
+LDLIBS	+= -lreadline -lxml2 -lopensrf -lncurses 
 LDFLAGS	+= -DEXEC_DEFAULT
 
 all: srfsh

Modified: branches/autotools/src/srfsh/srfsh.c
===================================================================
--- branches/autotools/src/srfsh/srfsh.c	2007-11-04 11:38:50 UTC (rev 1120)
+++ branches/autotools/src/srfsh/srfsh.c	2007-11-05 13:40:16 UTC (rev 1121)
@@ -47,7 +47,7 @@
 static int handle_router( char* words[] );
 
 /* utility method for print time data */
-/* static int handle_time( char* words[] ); */
+static int handle_time( char* words[] ); 
 
 /* handles app level requests */
 static int handle_request( char* words[], int relay );
@@ -80,8 +80,7 @@
 	char* home = getenv("HOME");
 	int l = strlen(home) + 36;
 	char fbuf[l];
-	memset(fbuf, 0, l);
-	sprintf(fbuf,"%s/.srfsh.xml",home);
+	snprintf(fbuf, sizeof(fbuf), "%s/.srfsh.xml", home);
 	
 	if(!access(fbuf, R_OK)) {
 		if( ! osrf_system_bootstrap_client(fbuf, "srfsh") ) {
@@ -182,33 +181,18 @@
 		write_history(history_file);
 
 	free(request);
+	free(login_session);
 
 	osrf_system_shutdown();
 	return 0;
 }
 
-/*
-static void sig_child_handler( int s ) {
-	child_dead = 1;
-}
-*/
-
-/*
-void sig_int_handler( int s ) {
-	printf("\n");
-	caught_sigint = 1;
-	signal(SIGINT,sig_int_handler);
-}
-*/
-
 static int load_history( void ) {
 
 	char* home = getenv("HOME");
 	int l = strlen(home) + 24;
 	char fbuf[l];
-
-	memset(fbuf, 0, l);
-	sprintf(fbuf,"%s/.srfsh_history",home);
+	snprintf(fbuf, sizeof(fbuf), "%s/.srfsh_history", home);
 	history_file = strdup(fbuf);
 
 	if(!access(history_file, W_OK | R_OK )) {
@@ -279,10 +263,8 @@
 	if( !strcmp(words[0],"router") ) 
 		ret_val = handle_router( words );
 
-	/*
 	else if( !strcmp(words[0],"time") ) 
 		ret_val = handle_time( words );
-		*/
 
 	else if (!strcmp(words[0],"request"))
 		ret_val = handle_request( words, 0 );
@@ -337,14 +319,14 @@
 		static const char text[] = "request %s opensrf.system.method %s";
 		len = sizeof( text ) + strlen( words[1] ) + strlen( words[2] );
 		char buf[len];
-		sprintf( buf, text, words[1], words[2] );
+		snprintf( buf, sizeof(buf), text, words[1], words[2] );
 		return parse_request( buf );
 
 	} else {
 		static const char text[] = "request %s opensrf.system.method.all";
 		len = sizeof( text ) + strlen( words[1] );
 		char buf[len];
-		sprintf( buf, text, words[1] );
+		snprintf( buf, sizeof(buf), text, words[1] );
 		return parse_request( buf );
 
 	}
@@ -363,17 +345,14 @@
 		int orgloci = (orgloc) ? atoi(orgloc) : 0;
 		if(!type) type = "opac";
 
-		char buf[256];
-		memset(buf,0,256);
+		char login_text[] = "request open-ils.auth open-ils.auth.authenticate.init \"%s\"";
+		size_t len = sizeof( login_text ) + strlen(username) + 1;
 
-		char buf2[256];
-		memset(buf2,0,256);
+		char buf[len];
+		snprintf( buf, sizeof(buf), login_text, username );
+		parse_request(buf);
 
-		sprintf( buf, 
-				"request open-ils.auth open-ils.auth.authenticate.init \"%s\"", username );
-		parse_request(buf); 
-
-		char* hash;
+		const char* hash;
 		if(last_result && last_result->_result_content) {
 			jsonObject* r = last_result->_result_content;
 			hash = jsonObjectGetString(r);
@@ -382,19 +361,12 @@
 
 		char* pass_buf = md5sum(password);
 
-		char both_buf[256];
-		memset(both_buf,0,256);
-		sprintf(both_buf,"%s%s",hash, pass_buf);
+		size_t both_len = strlen( hash ) + strlen( pass_buf ) + 1;
+		char both_buf[both_len];
+		snprintf(both_buf, sizeof(both_buf), "%s%s", hash, pass_buf);
 
 		char* mess_buf = md5sum(both_buf);
 
-		/*
-		sprintf( buf2, "request open-ils.auth open-ils.auth.authenticate.complete "
-				"{ \"username\" : \"%s\", \"password\" : \"%s\", "
-				"\"type\" : \"%s\", \"org\" : %d, \"workstation\": \"%s\"}", 
-				username, mess_buf, type, orgloci, workstation );
-				*/
-
 		growing_buffer* argbuf = buffer_init(64);
 		buffer_fadd(argbuf, 
 				"request open-ils.auth open-ils.auth.authenticate.complete "
@@ -411,19 +383,26 @@
 		parse_request( argbuf->buf );
 		buffer_free(argbuf);
 
-		jsonObject* x = last_result->_result_content;
+		if( login_session != NULL )
+			free( login_session );
+
+		const jsonObject* x = last_result->_result_content;
 		double authtime = 0;
 		if(x) {
-			char* authtoken = jsonObjectGetString(
-					jsonObjectGetKey(jsonObjectGetKey(x,"payload"), "authtoken"));
+			const char* authtoken = jsonObjectGetString(
+					jsonObjectGetKeyConst(jsonObjectGetKeyConst(x,"payload"), "authtoken"));
 			authtime  = jsonObjectGetNumber(
-					jsonObjectGetKey(jsonObjectGetKey(x,"payload"), "authtime"));
-			if(authtoken) login_session = strdup(authtoken);
-			else login_session = NULL;
+					jsonObjectGetKeyConst(jsonObjectGetKeyConst(x,"payload"), "authtime"));
+
+			if(authtoken)
+				login_session = strdup(authtoken);
+			else
+				login_session = NULL;
 		}
 		else login_session = NULL;
 
-		printf("Login Session: %s.  Session timeout: %f\n", login_session, authtime );
+		printf("Login Session: %s.  Session timeout: %f\n",
+			   (login_session ? login_session : "(none)"), authtime );
 		
 		return 1;
 
@@ -487,8 +466,19 @@
 			}
 		}
 
+		if(!strcmp(variable,"raw_print")) {
+			if(raw_print) {
+				printf("raw_print = true\n");
+				return 1;
+			} else {
+				printf("raw_print = false\n");
+				return 1;
+			}
+		}
+
 		if(!strcmp(variable,"login")) {
-			printf("login session = %s\n", login_session );
+			printf("login session = %s\n",
+				   login_session ? login_session : "(none)" );
 			return 1;
 		}
 
@@ -558,7 +548,7 @@
 	jsonObject* params = NULL;
 	if( !relay ) {
 		if( buffer != NULL && buffer->n_used > 0 ) 
-			params = json_parse_string(buffer->buf);
+			params = jsonParseString(buffer->buf);
 	} else {
 		if(!last_result || ! last_result->_result_content) { 
 			printf("We're not going to call 'relay' with no result params\n");
@@ -616,22 +606,25 @@
 	
 				char* content;
 	
-				if( pretty_print && omsg->_result_content ) {
+				if( pretty_print ) {
 					char* j = jsonObjectToJSON(omsg->_result_content);
 					//content = json_printer(j); 
 					content = jsonFormatString(j);
 					free(j);
-				} else
-					content = jsonObjectGetString(omsg->_result_content);
-	
+				} else {
+					const char * temp_content = jsonObjectGetString(omsg->_result_content);
+					if( ! temp_content )
+						temp_content = "[null]";
+					content = strdup( temp_content );
+				}
+				
 				printf( "\nReceived Data: %s\n", content ); 
 				free(content);
 	
 			} else {
 
 				char code[16];
-				memset(code, 0, 16);
-				sprintf( code, "%d", omsg->status_code );
+				snprintf( code, sizeof(code), "%d", omsg->status_code );
 				buffer_add( resp_buffer, code );
 
 				printf( "\nReceived Exception:\nName: %s\nStatus: %s\nStatus: %s\n", 
@@ -654,9 +647,14 @@
 					//content = json_printer(j); 
 					content = jsonFormatString(j);
 					free(j);
-				} else
-					content = jsonObjectGetString(omsg->_result_content);
-	
+				} else {
+					const char * temp_content = jsonObjectGetString(omsg->_result_content);
+					if( temp_content )
+						content = strdup( temp_content );
+					else
+						content = NULL;
+				}
+
 				buffer_add( resp_buffer, "\nReceived Data: " ); 
 				buffer_add( resp_buffer, content );
 				buffer_add( resp_buffer, "\n" );
@@ -670,8 +668,7 @@
 				buffer_add( resp_buffer, omsg->status_text );
 				buffer_add( resp_buffer, "\nStatus: " );
 				char code[16];
-				memset(code, 0, 16);
-				sprintf( code, "%d", omsg->status_code );
+				snprintf( code, sizeof(code), "%d", omsg->status_code );
 				buffer_add( resp_buffer, code );
 			}
 		}
@@ -705,30 +702,15 @@
 
 }
 
-/*
 static int handle_time( char* words[] ) {
-
-	if( ! words[1] ) {
-
-		char buf[36];
-		memset(buf,0,36);
-		get_timestamp(buf);
-		printf( "%s\n", buf );
-		return 1;
-	}
-
-	if( words[1] ) {
-		time_t epoch = (time_t)atoi( words[1] );
-		char* localtime = strdup( ctime( &epoch ) );
-		printf( "%s => %s", words[1], localtime );
-		free(localtime);
-		return 1;
-	}
-
-	return 0;
-
+	if(!words[1]) {
+		printf("%f\n", get_timestamp_millis());
+    } else {
+        time_t epoch = (time_t) atoi(words[1]);
+		printf("%s", ctime(&epoch));
+    }
+	return 1;
 }
-*/
 
 		
 
@@ -737,9 +719,10 @@
 	if( ! router_server || strlen(router_server) == 0 ) 
 		return 0;
 
-	char rbuf[256];
-	memset(rbuf,0,256);
-	sprintf(rbuf,"router@%s/router", router_server );
+	const static char router_text[] = "router@%s/router";
+	size_t len = sizeof( router_text ) + strlen( router_server ) + 1;
+	char rbuf[len];
+	snprintf(rbuf, sizeof(rbuf), router_text, router_server );
 		
 	transport_message* send = 
 		message_init( "servers", NULL, NULL, rbuf, NULL );
@@ -775,47 +758,47 @@
 			"---------------------------------------------------------------------------------\n"
 			"Commands:\n"
 			"---------------------------------------------------------------------------------\n"
-			"help			- Display this message\n"
-			"!<command> [args] - Forks and runs the given command in the shell\n"
+			"help                   - Display this message\n"
+			"!<command> [args]      - Forks and runs the given command in the shell\n"
 		/*
 			"time			- Prints the current time\n"
-			"time <timestamp>	- Formats seconds since epoch into readable format\n"	
+			"time <timestamp>	- Formats seconds since epoch into readable format\n"
 		*/
 			"set <variable> <value> - set a srfsh variable (e.g. set pretty_print true )\n"
-			"print <variable>		- Displays the value of a srfsh variable\n"
+			"print <variable>       - Displays the value of a srfsh variable\n"
 			"---------------------------------------------------------------------------------\n"
 
 			"router query servers <server1 [, server2, ...]>\n"
-			"	- Returns stats on connected services\n"
+			"       - Returns stats on connected services\n"
 			"\n"
 			"\n"
 			"request <service> <method> [ <json formatted string of params> ]\n"
-			"	- Anything passed in will be wrapped in a json array,\n"
-			"		so add commas if there is more than one param\n"
+			"       - Anything passed in will be wrapped in a json array,\n"
+			"               so add commas if there is more than one param\n"
 			"\n"
 			"\n"
 			"relay <service> <method>\n"
-			"	- Performs the requested query using the last received result as the param\n"
+			"       - Performs the requested query using the last received result as the param\n"
 			"\n"
 			"\n"
 			"math_bench <num_batches> [0|1|2]\n"
-			"	- 0 means don't reconnect, 1 means reconnect after each batch of 4, and\n"
-			"		 2 means reconnect after every request\n"
+			"       - 0 means don't reconnect, 1 means reconnect after each batch of 4, and\n"
+			"                2 means reconnect after every request\n"
 			"\n"
 			"introspect <service>\n"
-			"	- prints the API for the service\n"
+			"       - prints the API for the service\n"
 			"\n"
 			"\n"
 			"---------------------------------------------------------------------------------\n"
 			" Commands for Open-ILS\n"
 			"---------------------------------------------------------------------------------\n"
 			"login <username> <password>\n"
-			"	-	Logs into the 'server' and displays the session id\n"
-			"	- To view the session id later, enter: print login\n"
+			"       - Logs into the 'server' and displays the session id\n"
+			"       - To view the session id later, enter: print login\n"
 			"---------------------------------------------------------------------------------\n"
 			"\n"
 			"\n"
-			"Note: long output is piped through 'less'.  To search in 'less', type: /<search>\n"
+			"Note: long output is piped through 'less'. To search in 'less', type: /<search>\n"
 			"---------------------------------------------------------------------------------\n"
 			"\n"
 			);
@@ -850,7 +833,7 @@
 	osrf_app_session* session = osrf_app_client_session_init(  "opensrf.math" );
 	osrf_app_session_connect(session);
 
-	jsonObject* params = json_parse_string("[]");
+	jsonObject* params = jsonParseString("[]");
 	jsonObjectPush(params,jsonNewObject("1"));
 	jsonObjectPush(params,jsonNewObject("2"));
 
@@ -858,7 +841,7 @@
 	char* answers[] = { "3", "-1", "2", "0.500000" };
 
 	float times[ count * 4 ];
-	memset(times,0,count*4);
+	memset(times, 0, sizeof(times));
 
 	int k;
 	for(k=0;k!=100;k++) {



More information about the opensrf-commits mailing list