gutted chopchop
authorerickson <erickson@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Mon, 10 Oct 2005 20:22:30 +0000 (20:22 +0000)
committererickson <erickson@dcc99617-32d9-48b4-a31d-7c20da2025e4>
Mon, 10 Oct 2005 20:22:30 +0000 (20:22 +0000)
moved to osrfList and osrfHash for faster lookups
added core server 2 server code

much testing required, more robust error messages required

git-svn-id: svn://svn.open-ils.org/ILS/trunk@1904 dcc99617-32d9-48b4-a31d-7c20da2025e4

OpenSRF/src/jserver/Makefile
OpenSRF/src/jserver/jserver-c.c [deleted file]
OpenSRF/src/jserver/jserver-c.h [deleted file]
OpenSRF/src/jserver/jserver-c_main.c [deleted file]
OpenSRF/src/jserver/jserver-c_session.c [deleted file]
OpenSRF/src/jserver/jserver-c_session.h [deleted file]
OpenSRF/src/jserver/jstrings.h [deleted file]
OpenSRF/src/jserver/osrf_chat.c [new file with mode: 0644]
OpenSRF/src/jserver/osrf_chat.h [new file with mode: 0644]
OpenSRF/src/jserver/osrf_chat_main.c [new file with mode: 0644]

index 085ced5..e21cfe1 100644 (file)
@@ -1,19 +1,17 @@
 LDLIBS += -lopensrf -lobjson -lxml2
-OBJECTS        = jserver-c.o jserver-c_main.o jserver-c_session.o
+CFLAGS += -D_GNU_SOURCE
 
-all: jserver-c 
+all: chopchop
 
-jserver-c: $(OBJECTS)
-#      $(CC) $(LD_OPTS) $(OBJECTS) -o $@
-
-jserver-c_main.o: jserver-c_main.c 
-jserver-c.o: jserver-c.c jserver-c.h
-jserver-c_session.o: jserver-c_session.c jserver-c_session.h
+chopchop: osrf_chat.o osrf_chat_main.o
+       $(CC) $(CFLAGS) $(LDFLAGS) $(LDLIBS) osrf_chat.o osrf_chat_main.o -o $@
 
+osrf_chat.o: osrf_chat.c osrf_chat.h
+osrf_chat_main.o: osrf_chat_main.c
 
 install: 
-       cp jserver-c $(BINDIR)
+       cp chopchop $(BINDIR)
 
 clean:
-       /bin/rm -f *.o jserver-c 
+       /bin/rm -f *.o chopchop
 
diff --git a/OpenSRF/src/jserver/jserver-c.c b/OpenSRF/src/jserver/jserver-c.c
deleted file mode 100644 (file)
index 9590708..0000000
+++ /dev/null
@@ -1,306 +0,0 @@
-#include "jserver-c.h"
-
-jserver* jserver_init() {
-       jserver* js                                     = safe_malloc(sizeof(jserver));
-       js->mgr                                         = safe_malloc(sizeof(socket_manager));
-       js->mgr->data_received  = &jserver_handle_request;
-       js->mgr->blob                           = js;
-       js->mgr->on_socket_closed       = &jserver_socket_closed;
-       js->client                                      = NULL;
-
-       return js;
-}
-
-void jserver_free(jserver* js) {
-       if(js == NULL) return;
-       jclient_node* node; 
-       while(js->client) {
-               node = js->client->next;
-               _jserver_remove_client_id(js, js->client->id);
-               js->client = node;
-       }
-       socket_manager_free(js->mgr);
-       free(js);
-}
-
-void jserver_socket_closed(void* blob, int sock_id) {
-       jserver* js = (jserver*) blob;
-       if(js == NULL) return;
-       info_handler("Removing client %d - site closed socket",sock_id);
-       _jserver_remove_client_id(js, sock_id);
-}
-
-/* opens the inet and unix sockets that we're listening on */
-int jserver_connect(jserver* js, int port, char* listen_ip, char* unix_path) {
-       if(js == NULL || js->mgr == NULL) return -1;
-       int status = 0;
-
-       if(port > 0) {
-               status = socket_open_tcp_server(js->mgr, port, listen_ip);
-               if(status == -1) return status;
-       }
-
-       if(unix_path != NULL) {
-               status = socket_open_unix_server(js->mgr, unix_path);
-               if(status == -1) return status;
-       }
-
-       return 0;
-}
-
-void _free_jclient_node(jclient_node* node) {
-       if(node == NULL) return;
-       free(node->addr);
-       jserver_session_free(node->session);
-       free(node);
-}
-
-/* allocates a new client node */
-jclient_node* _new_jclient_node(int id) {
-       jclient_node* node = safe_malloc(sizeof(jclient_node));
-       node->id = id;
-       node->addr = NULL;
-       node->session = jserver_session_init();
-       node->session->blob = node;
-       node->session->on_msg_complete = &jserver_client_handle_msg; 
-       node->session->on_from_discovered = &jserver_client_from_found;
-       node->session->on_login_init = &jserver_client_login_init;
-       node->session->on_login_ok = &jserver_client_login_ok;
-       node->session->on_client_finish = &jserver_client_finish;
-       return node;
-}
-
-/* client has sent the end of it's session doc, we may now disconnect */
-void jserver_client_finish(void* blob) {
-       jclient_node* node = (jclient_node*) blob;
-       if(node == NULL) return;
-       jserver_send_id(node->id, "</stream:stream>");
-       _jserver_remove_client(node->parent, node->addr);
-
-}
-
-void jserver_client_from_found(void* blob, char* from) {
-       jclient_node* node = (jclient_node*) blob;
-       if(node == NULL || from == NULL) return;
-
-       /* prevent duplicate login - kick off original */
-       _jserver_remove_client(node->parent, from);
-       info_handler("logged in: %s", from);
-       node->addr = strdup(from);
-}
-
-void jserver_client_login_init(void* blob, char* reply) {
-       debug_handler("here");
-       jclient_node* node = (jclient_node*) blob;
-       if(node == NULL || reply == NULL) return;
-       debug_handler("jserver handling login init");
-       jserver_send_id(node->id, reply);
-}
-
-void jserver_client_login_ok(void* blob) {
-       jclient_node* node = (jclient_node*) blob;
-       if(node == NULL) return;
-       info_handler("Client logging in ok => %d", node->id);
-       //jserver_send_id(node->id, xml_login_ok);
-       jserver_send_id(node->id, JSTRING_LOGIN_OK);
-}
-
-void jserver_client_handle_msg( 
-       void* blob, char* xml, char* from, char* to ) {
-
-       jclient_node* node = (jclient_node*) blob;
-       if(node == NULL || xml == NULL || to == NULL) return;
-       int from_id = 0;
-
-       jclient_node* from_node = jserver_find_client(node->parent, from);
-       if(from_node)
-               from_id = from_node->id;
-
-
-       debug_handler("Client %d received from %s message : %s", 
-                       node->id, from, xml );
-
-       jserver_send(node->parent, from_id, to, xml);
-}
-
-/* allocates a new client node and adds it to the set */
-jclient_node* _jserver_add_client(jserver* js, int id) {
-       if(js == NULL) return NULL;
-       jclient_node* node = _new_jclient_node(id);
-       node->next = js->client;
-       js->client = node;
-       node->parent = js;
-       return node;
-}
-
-
-/* removes and frees a client node */
-void _jserver_remove_client(jserver* js, char* addr) {
-       if(js == NULL || js->client == NULL || addr == NULL) return;
-
-       jclient_node* node = js->client;
-
-       if(node->addr && !strcmp(node->addr,addr)) {
-               js->client = node->next;
-               debug_handler("Removing the first jserver client");
-               socket_disconnect(js->mgr, node->id);
-               _free_jclient_node(node);
-               return;
-       }
-
-       debug_handler("Searching for jclient to remove");
-       jclient_node* tail_node = node;
-       node = node->next;
-
-       while(node) {
-               if(node->addr && !strcmp(node->addr,addr)) {
-                       tail_node->next = node->next;
-                       debug_handler("Removing a jserver client");
-                       socket_disconnect(js->mgr, node->id);
-                       _free_jclient_node(node);
-                       return;
-               }
-               tail_node = node;
-               node = node->next;
-       }
-}
-
-
-/* removes and frees a client node */
-void _jserver_remove_client_id(jserver* js, int id) {
-       if(js == NULL || js->client == NULL) return;
-
-       jclient_node* node = js->client;
-
-       debug_handler("Searching for jclient to remove with id %d", id);
-       debug_handler("First node in list has id %d", node->id );
-
-       if(node->id == id) {
-               js->client = node->next;
-               debug_handler("Removing the first jserver client");
-               socket_disconnect(js->mgr, node->id);
-               _free_jclient_node(node);
-               return;
-       }
-
-       jclient_node* tail_node = node;
-       node = node->next;
-
-       while(node) {
-               debug_handler("Checking node %d to remove", node->id);
-               if(node->id == id) {
-                       tail_node->next = node->next;
-                       debug_handler("Removing a jserver client");
-                       socket_disconnect(js->mgr, node->id);
-                       _free_jclient_node(node);
-                       return;
-               }
-               tail_node = node;
-               node = node->next;
-       }
-}
-
-/* finds a client node by addr */
-jclient_node* jserver_find_client(jserver* js, char* addr) {
-       if(js == NULL || addr == NULL) return NULL;
-       jclient_node* node = js->client;
-       while(node) {
-               if(node->addr && !strcmp(node->addr, addr)) 
-                       return node;
-               node = node->next;
-       }
-       return NULL;
-}
-
-jclient_node* jserver_find_client_id(jserver* js, int id) {
-       if(js == NULL) return NULL;
-       jclient_node* node = js->client;
-       while(node) {
-               if(node->id == id) 
-                       return node;
-               node = node->next;
-       }
-       return NULL;
-}
-
-/* sends msg to client at 'to_addr' */
-int jserver_send(jserver* js, int from_id, char* to_addr, const char* msg_xml) {
-       debug_handler("sending message to %s : %s", to_addr, msg_xml);
-       if(to_addr == NULL || msg_xml == NULL) return -1;
-
-       jclient_node* node = jserver_find_client(js, to_addr);
-
-       if(node == NULL) {
-               info_handler("message to non-existent client %s", to_addr);
-               if(from_id > 0) {
-                       jclient_node* from = jserver_find_client_id(js, from_id);
-
-                       if(from) {
-                               info_handler("replying with error...");
-                               char buf[2048];
-                               memset(buf, 0, 2048);
-                               /*
-                               snprintf(buf, 2047, "<message xmlns='jabber:client' type='error' from='%s' "
-                                       "to='%s'><error type='cancel' code='404'><item-not-found "
-                                       "xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/></error>"
-                                       "<body>NOT ADDING BODY</body></message>", to_addr, from->addr );
-                                       */
-                               snprintf(buf, 2047, JSTRING_NO_RECIPIENT, to_addr, from->addr );
-                               jserver_send_id(from_id, buf);
-                       }
-               }
-               return -1;
-       }
-
-       return jserver_send_id(node->id, msg_xml);
-}
-
-int jserver_send_id(int client_id, const char* msg_xml) {
-       if(msg_xml == NULL || client_id < 1) return -1;
-       return socket_send(client_id, msg_xml );
-}
-
-/* waits for any incoming data */
-int jserver_wait(jserver* js) {
-       if(js == NULL) return -1;
-       while(1) {
-               if(socket_wait_all(js->mgr, -1) < 0)
-                       warning_handler(
-                               "jserver_wait(): socket_wait_all() returned error");
-
-       }
-}
-
-
-int _jserver_push_client_data(jclient_node* node, char* data) {
-       if(node == NULL || data == NULL) return -1;
-       return jserver_session_push_data( node->session, data);
-}
-
-void jserver_handle_request(void* js_blob, 
-       socket_manager* mgr, int sock_id, char* data, int parent_id ) {
-
-       jserver* js = (jserver*) js_blob;
-
-       debug_handler("jsever received data from socket %d (parent %d)", sock_id, parent_id );
-
-       jclient_node* node = jserver_find_client_id(js, sock_id);
-       if(!node) {
-               debug_handler("We have a new client connection, adding to list");
-               node = _jserver_add_client(js, sock_id);
-       }
-
-       if(_jserver_push_client_data(node, data) == -1) {
-               warning_handler("Client sent bad data, disconnecting...");
-               //jserver_send_id(node->id, xml_parse_error);
-               jserver_send_id(node->id, JSTRING_PARSE_ERROR);
-               _jserver_remove_client(js, node->addr);         
-
-       } else {
-               debug_handler("Client data successfully parsed");
-       }
-
-}
-
-
-
diff --git a/OpenSRF/src/jserver/jserver-c.h b/OpenSRF/src/jserver/jserver-c.h
deleted file mode 100644 (file)
index 498df0a..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-#include "opensrf/utils.h"
-#include "opensrf/logging.h"
-#include "opensrf/socket_bundle.h"
-#include "jserver-c_session.h"
-#include "jstrings.h"
-
-
-
-struct jclient_node_struct {
-       int id;
-       char* addr;
-       struct jclient_node_struct* next;
-       jserver_session* session;
-       struct jserver_struct* parent;
-};
-typedef struct jclient_node_struct jclient_node;
-
-struct jserver_struct {
-       jclient_node* client;
-       socket_manager* mgr;
-};
-typedef struct jserver_struct jserver;
-
-/* allocats and sets up a new jserver */
-jserver* jserver_init();
-
-void jserver_socket_closed(void* blob, int sock_id);
-
-/* disconnects all client, deallocates the server and all clients */
-void jserver_free();
-
-/* opens the inet and unix sockets that we're listening on 
-       listen_ip is the IP address the server should listen on.
-       if listen_ip is NULL, jserver will bind to all local IP's. 
-       if(port < 1) no inet socket is opened
-       if unix_path == NULL no unix socket is opened
-       returns -1 on error */
-int jserver_connect(jserver* js, int port, char* listen_ip, char* unix_path);
-
-/* allocates a new client node */
-jclient_node* _new_jclient_node(int id);
-
-void _free_jclient_node(jclient_node* node);
-
-int _jserver_push_client_data(jclient_node* node, char* data);
-
-void jclient_on_parse_error(void* blob, jserver_session* session);
-
-/* called when a newly connected client reveals its address */
-void jserver_client_from_found(void* blob, char* from);
-void jserver_client_login_init(void* blob, char* reply);
-void jserver_client_login_ok(void* blob);
-void jserver_client_finish(void* blob);
-
-/* allocates a new client node and adds it to the set */
-jclient_node* _jserver_add_client(jserver* js, int id);
-
-/* removes and frees a client node */
-void _jserver_remove_client(jserver* js, char* addr);
-
-void _jserver_remove_client_id(jserver* js, int id);
-
-/* finds a client node by addr */
-jclient_node* jserver_find_client(jserver* js, char* addr);
-
-jclient_node* jserver_find_client_id(jserver* js, int id);
-
-/* sends msg to client at 'to_addr'. from_id is the id
-       of the sending client (if from_id > 0). used for error replies */
-int jserver_send(jserver* js, int from_id, char* to_addr, const char* msg_xml);
-
-/* send the data to the client with client_id */
-int jserver_send_id(int client_id, const char* msg_xml);
-
-/* waits for any incoming data */
-int jserver_wait(jserver* js);
-
-/* handles all incoming socket data */
-void jserver_handle_request(void* js, 
-       socket_manager* mgr, int sock_id, char* data, int parent_id ); 
-
-
-/* called by the jserver_session when any client has a 
-       complete message parsed and ready to forward on */
-void jserver_client_handle_msg( 
-               void* blob, char* xml, char* from, char* to );
diff --git a/OpenSRF/src/jserver/jserver-c_main.c b/OpenSRF/src/jserver/jserver-c_main.c
deleted file mode 100644 (file)
index 53a69ad..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-#include "jserver-c.h"
-#include <signal.h>
-#include <fcntl.h>
-
-/* config vars */
-jserver* js                                    = NULL;
-int            port                            = -1;
-char*          unix_sock_file = NULL;
-int            log_level               = -1;
-char*          log_file                        = NULL;
-char*  listen_ip               = NULL;
-
-/* starts the logging and server processes */
-void launch_server();
-
-
-/* shut down, clean up, and restart */
-void sig_hup_handler( int a ) { 
-       warning_handler(" +++ Re-launching server for SIGHUP");
-
-       jserver_free(js);
-       log_free();
-       unlink(unix_sock_file);
-
-       launch_server();
-       return; 
-}
-
-/* die gracefully */
-void sig_int_handler( int a ) { 
-       warning_handler(" +++ Shutting down because of user signal");
-       jserver_free(js);
-       log_free();
-       unlink(unix_sock_file);
-       exit(0); 
-}
-
-
-
-/* loads the command line settings and launches the server */
-int main(int argc, char* argv[]) {
-
-       char* prog                      = argv[0];
-       char* sport                     = argv[1];      
-       listen_ip                       = argv[2];
-       unix_sock_file          = argv[3];      
-       char* slog_level        = argv[4];
-       log_file                                = argv[5];
-
-       if(!sport || !unix_sock_file || !slog_level) {
-               fprintf(stderr, 
-                       "usage: %s <port> <listen_ip> <path_to_unix_sock_file> <log_level [1-4]"
-                       "(4 is the highest)> [log_file (optional, goes to stderr otherwise)]\n"
-                       "e.g: %s 5222 10.0.0.100 /tmp/server.sock 1 /tmp/server.log\n"
-                       "if listen_ip is '*', then we will listen on all addresses",
-                       prog, prog);
-               return 99;
-       }
-
-       port                    = atoi(sport);
-       log_level       = atoi(slog_level);
-
-       if(port < 1) {
-               warning_handler("invalid port (%d), falling back to 5222");
-               port = 5222;
-       }
-
-       if(log_level < 1 || log_level > 4) {
-               warning_handler("log level (%d) is not recognized, falling back to WARN", log_level);
-               log_level = 2;
-       }
-
-       fprintf(stderr, "Launching with port %d, unix sock %s, log level %d, log file %s\n",
-                       port, unix_sock_file, log_level, log_file );
-
-       if (daemonize() == -1) {
-               fprintf(stderr, "!!! Error forking the daemon!  Going away now... :(\n");
-               exit(2);
-       }
-
-       signal(SIGHUP, &sig_hup_handler);
-       signal(SIGINT, &sig_int_handler);
-       signal(SIGTERM, &sig_int_handler);
-
-       //init_proc_title( argc, argv );
-       //set_proc_title( "opensrf jabber" );
-
-       launch_server();
-       return 0;
-}
-
-void launch_server() {
-
-       log_init(log_level, log_file);
-       info_handler("Booting jserver-c on port %d and "
-                       "sock file %s", port, unix_sock_file);
-
-       if(!strcmp(listen_ip,"*")) listen_ip = NULL;
-
-       js = jserver_init();
-       unlink(unix_sock_file);
-       if(jserver_connect(js, port, listen_ip, unix_sock_file) < 0)
-               fatal_handler("Could not connect...");
-
-       jserver_wait(js);
-}
-
-
-
-
-
diff --git a/OpenSRF/src/jserver/jserver-c_session.c b/OpenSRF/src/jserver/jserver-c_session.c
deleted file mode 100644 (file)
index 7c69c1c..0000000
+++ /dev/null
@@ -1,281 +0,0 @@
-#include "jserver-c_session.h"
-
-static int xml_error_occured = 0;
-static int client_sent_disconnect = 0;
-
-jserver_session* jserver_session_init() {
-
-       jserver_session* session = safe_malloc(sizeof(jserver_session));
-       session->parser_ctxt = xmlCreatePushParserCtxt(sax_handler, session, "", 0, NULL);
-       session->current_msg = xmlNewDoc(BAD_CAST "1.0");
-       session->current_to = strdup("");
-       session->current_from = strdup("");
-       session->state = 0;
-       xmlKeepBlanksDefault(0);
-       return session;
-}
-
-void jserver_session_free(jserver_session* session) {
-       if(session == NULL) return;
-
-       if( session->parser_ctxt) {
-               xmlFreeDoc(session->parser_ctxt->myDoc);
-               xmlFreeParserCtxt(session->parser_ctxt);
-       }
-
-       free(session->current_username);
-       free(session->current_resource);
-       free(session->current_domain);
-
-       xmlCleanupCharEncodingHandlers();
-       xmlFreeDoc(session->current_msg);
-       xmlCleanupParser();
-
-       free(session);
-}
-
-
-int jserver_session_push_data(jserver_session* session, char* data) {
-       if(session == NULL || data == NULL) return -1;  
-       debug_handler("pushing data into xml parser: %s", data);
-       xmlParseChunk(session->parser_ctxt, data, strlen(data), 0);
-       if(xml_error_occured) {
-               xml_error_occured = 0;
-               return -1;
-       }
-
-       if(client_sent_disconnect) {
-               client_sent_disconnect = 0;
-               if(session->on_client_finish)
-                       session->on_client_finish(session->blob);
-       }
-
-       return 0;
-}
-
-void sax_start_doc(void* blob) {
-       debug_handler("Starting new session doc");
-}
-
-// ---------------------------------------------------------------------------------
-// Our SAX handlers 
-// ---------------------------------------------------------------------------------
-void sax_start_element( 
-               void* blob, const xmlChar *name, const xmlChar **atts) {
-
-       jserver_session* session = (jserver_session*) blob;
-       if(!session) return;
-
-       debug_handler("jserver-c_session received opening XML node %s", name);
-
-       if(!strcmp(name, "stream:stream")) {
-
-               /* opening a new session */     
-               free(session->current_domain);
-               session->current_domain = strdup(sax_xml_attr(atts, "to"));
-               char* from_domain = sax_xml_attr(atts, "from");
-               if(!from_domain) from_domain = "";
-
-               if(session->current_domain == NULL) {
-                       sax_warning(session->blob, "No 'to' specified in stream opener");
-
-               }       else {
-                       debug_handler("jserver-c_session received opening stream from client on domain %s", 
-                               session->current_domain);
-
-                       char buf[1024];
-                       memset(buf,0,1024);
-                       snprintf(buf, 1023, JSTRING_START_STREAM, session->current_domain, from_domain);
-
-                       debug_handler("Session Sending: %s", buf);
-
-                       session->state = JABBER_STATE_CONNECTING;
-                       if(session->on_login_init)
-                               session->on_login_init(session->blob, buf);
-               }
-               return;
-       }
-
-       if(session->state & JABBER_STATE_CONNECTING) {
-               /* during the connect shuffle, we have to store off the
-                       username and resource to determine the routing address */
-               if(!strcmp(name,"iq"))
-                       session->in_iq = 1;
-               if(!strcmp(name,"username"))
-                       session->in_uname = 1;
-               if(!strcmp(name,"resource"))
-                       session->in_resource = 1;
-       }
-
-       if(session->state & JABBER_STATE_CONNECTED) {
-
-               if(!strcmp(name, "message")) {
-                       /* opening of a new message, build a new doc */
-                       xmlNodePtr root = xmlNewNode(NULL, name);
-                       dom_add_attrs(root, atts);
-                       xmlNodePtr old_root = xmlDocSetRootElement(session->current_msg, root);
-
-
-                       free(session->current_to);
-
-                       char* from = sax_xml_attr(atts, "from");
-                       if(from == NULL) from = "";
-                       char* to = sax_xml_attr(atts, "to");
-                       if(to == NULL) to = "";
-
-                       session->current_to = strdup(to);
-
-                       /* free the old message tree */
-                       if(old_root) xmlFreeNode(old_root);
-
-               } else {
-                       xmlNodePtr node = xmlNewNode(NULL, name);
-                       dom_add_attrs(node, atts);
-                       xmlAddChild(xmlDocGetRootElement(session->current_msg), node);
-               }
-       }
-}
-
-void sax_end_element( void* blob, const xmlChar *name) {
-       jserver_session* session = (jserver_session*) blob;
-       if(!session) return;
-
-       if(session->state & JABBER_STATE_CONNECTED) {
-               if(!strcmp(name, "message")) {
-                       if(session->on_msg_complete) {
-
-                               debug_handler("Message is complete, finishing DOC");
-
-                               /* we have to make sure the 'from' address is set.. */
-                               xmlNodePtr msg = xmlDocGetRootElement(session->current_msg);
-                               if(msg) xmlSetProp(msg, BAD_CAST "from", BAD_CAST session->current_from );
-                               char* string = _xml_to_string(session->current_msg);
-
-                               session->on_msg_complete(session->blob, string, 
-                                       session->current_from, session->current_to );
-                               free(string);
-                       }
-               }
-       }
-
-       if(session->state & JABBER_STATE_CONNECTING) {
-               if(session->in_iq) {
-                       if(!strcmp(name, "iq")) {
-                               session->in_iq = 0;
-
-                               char buf[1024];
-                               memset(buf, 0, 1024);
-                               snprintf(buf, 1023, "%s@%s/%s", session->current_username,
-                                               session->current_domain, session->current_resource );
-                               if(session->on_from_discovered) 
-                                       session->on_from_discovered(session->blob, buf);
-
-                               free(session->current_from);
-                               session->current_from = strdup(buf);
-                               debug_handler("Set from address to %s", session->current_from);
-                               session->state = JABBER_STATE_CONNECTED;
-                               if(session->on_login_ok) 
-                                       session->on_login_ok(session->blob);
-
-                       }
-               }
-       }
-
-       if(!strcmp(name,"stream:stream")) {
-               debug_handler("receive end of client session doc");
-               client_sent_disconnect = 1;
-       }
-}
-
-void sax_character( void* blob, const xmlChar *ch, int len) {
-       jserver_session* session = (jserver_session*) blob;
-       if(!session) return;
-
-       if(session->state & JABBER_STATE_CONNECTED) {
-               xmlNodePtr last = xmlGetLastChild(
-                       xmlDocGetRootElement(session->current_msg));
-       
-               xmlNodePtr txt = xmlNewTextLen(ch, len);
-               xmlAddChild(last, txt);
-               return;
-       } 
-
-       if(session->state & JABBER_STATE_CONNECTING) {
-               if(session->in_iq) {
-                       if(session->in_uname) {
-                               free(session->current_username);
-                               session->current_username = strndup((char*) ch, len);
-                               session->in_uname = 0;
-                       }
-       
-                       if(session->in_resource) {
-                               free(session->current_resource);
-                               session->current_resource = strndup((char*) ch, len);
-                               session->in_resource = 0;
-                       }
-               }
-               
-       }
-}
-
-void  sax_warning( void* blob, const char* msg, ... ) {
-
-       jserver_session* session = (jserver_session*) blob;
-       if(!session) return;
-
-       char buf[1024];
-       memset(buf, 0,  1024);
-
-       va_list args;
-       va_start(args, msg);
-       vsnprintf(buf, 1023, msg, args);
-       va_end(args);
-       warning_handler("XML Warning : %s", buf);
-       xml_error_occured = 1;
-}
-
-
-void dom_add_attrs(xmlNodePtr node, const xmlChar** atts) {
-       int i;
-       if (node != NULL && atts != NULL) {
-               for(i = 0; (atts[i] != NULL); i++) {
-                       if(atts[i+1]) {
-                               xmlNewProp(node, atts[i], atts[i+1]);
-                               i++;
-                       }
-               }
-       }
-}
-
-char* sax_xml_attr( const xmlChar** atts, char* attr_name ) {
-       int i;
-       if(attr_name == NULL) return NULL;
-
-       if (atts != NULL) {
-               for(i = 0;(atts[i] != NULL);i++) {
-                       if(!strcmp(atts[i], attr_name)) 
-                               if(atts[++i])
-                                       return (char*) atts[i];
-               }
-       }
-       return NULL;
-}
-
-
-
-char* _xml_to_string( xmlDocPtr doc ) {
-       
-       xmlBufferPtr xmlbuf = xmlBufferCreate();
-       xmlNodeDump( xmlbuf, doc, xmlDocGetRootElement(doc), 0, 0);
-
-       char* xml = strdup( (char*) (xmlBufferContent(xmlbuf)));
-       xmlBufferFree(xmlbuf);
-
-       int l = strlen(xml)-1;
-       if( xml[l] == 10 || xml[l] == 13 )
-               xml[l] = '\0';
-
-       return xml;
-
-}
-
diff --git a/OpenSRF/src/jserver/jserver-c_session.h b/OpenSRF/src/jserver/jserver-c_session.h
deleted file mode 100644 (file)
index d8e7229..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-#define _GNU_SOURCE
-
-#include "opensrf/utils.h"
-#include "opensrf/logging.h"
-
-#include "jstrings.h"
-
-#include <stdio.h>
-#include <string.h>
-
-#include <libxml/globals.h>
-#include <libxml/xmlerror.h>
-#include <libxml/parser.h>
-#include <libxml/parserInternals.h> /* only for xmlNewInputFromFile() */
-#include <libxml/tree.h>
-#include <libxml/debugXML.h>
-#include <libxml/xmlmemory.h>
-
-
-/* session states */
-#define JABBER_STATE_CONNECTED                 2
-#define JABBER_STATE_CONNECTING                        4 
-#define JABBER_STATE_IN_MESSAGE                        8       
-
-
-struct jserver_session_struct {
-
-       /* our connection state */
-       unsigned int state;
-
-       /* incoming XML is parsed with the SAX parser */
-       xmlParserCtxtPtr parser_ctxt;
-
-       /* incoming message are shoved into this DOM doc after they are parsed */
-       xmlDocPtr current_msg;
-
-       /* we have to grab off the from and to for routing */
-       char* current_to;
-       char* current_from;
-
-       char* current_domain;
-       char* current_resource;
-       char* current_username;
-
-       int in_iq;
-       int in_uname;
-       int in_resource;
-
-       void* blob; /* callback blob - can be anything that needs passing around */
-       void (*on_msg_complete) (void* blob, char* msg_xml, char* from, char* to );
-
-       /* happens after someone logs in and we've pieced together the from address */
-       void (*on_from_discovered) (void* blob, char* from );
-       void (*on_login_init) (void* blob, char* reply );
-       void (*on_login_ok) (void* blob);
-       void (*on_client_finish) (void* blob);
-
-};
-typedef struct jserver_session_struct jserver_session;
-
-
-jserver_session* jserver_session_init();
-void jserver_session_free(jserver_session* session);
-char* sax_xml_attr( const xmlChar** atts, char* attr_name );
-int jserver_session_push_data(jserver_session* session, char* data);
-
-void dom_add_attrs(xmlNodePtr node, const xmlChar** atts);
-char* _xml_to_string( xmlDocPtr doc ); 
-
-
-// ---------------------------------------------------------------------------------
-// Our SAX handlers 
-// ---------------------------------------------------------------------------------
-void sax_start_element( 
-               void *session, const xmlChar *name, const xmlChar **atts);
-
-void sax_end_element( void* blob, const xmlChar *name);
-
-void sax_start_doc(void* blob);
-//void sax_end_doc(void* blob);
-
-void sax_character( void* blob, const xmlChar *ch, int len);
-
-void  sax_warning( void* blob, const char* msg, ... );
-
-static xmlSAXHandler sax_handler_struct = {
-   NULL,                                               /* internalSubset */
-   NULL,                                               /* isStandalone */
-   NULL,                                               /* hasInternalSubset */
-   NULL,                                               /* hasExternalSubset */
-   NULL,                                               /* resolveEntity */
-   NULL,                                               /* getEntity */
-   NULL,                                               /* entityDecl */
-   NULL,                                               /* notationDecl */
-   NULL,                                               /* attributeDecl */
-   NULL,                                               /* elementDecl */
-   NULL,                                               /* unparsedEntityDecl */
-   NULL,                                               /* setDocumentLocator */
-   sax_start_doc,                      /* startDocument */
-   NULL,                                               /* endDocument */
-       sax_start_element,      /* startElement */
-       sax_end_element,                /* endElement */
-   NULL,                                               /* reference */
-       sax_character,                  /* characters */
-   NULL,                                               /* ignorableWhitespace */
-   NULL,                                               /* processingInstruction */
-   NULL,                                               /* comment */
-   sax_warning,                        /* xmlParserWarning */
-   sax_warning,                        /* xmlParserError */
-   NULL,                                               /* xmlParserFatalError : unused */
-   NULL,                                               /* getParameterEntity */
-   NULL,                                               /* cdataBlock; */
-   NULL,                                               /* externalSubset; */
-   1,
-   NULL,
-   NULL,                                               /* startElementNs */
-   NULL,                                               /* endElementNs */
-       NULL                                            /* xmlStructuredErrorFunc */
-};
-
-static const xmlSAXHandlerPtr sax_handler = &sax_handler_struct;
diff --git a/OpenSRF/src/jserver/jstrings.h b/OpenSRF/src/jserver/jstrings.h
deleted file mode 100644 (file)
index bc9878c..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/* ------------------------------------------------
-       some pre-packaged Jabber XML
-       ------------------------------------------------ */
-
-#ifndef _JSTRINGS_H_
-#define _JSTRINGS_H_
-
-#define JSTRING_START_STREAM "<?xml version='1.0'?><stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:client' from='%s' to='%s' version='1.0' id='d253et09iw1fv8a2noqc38f28sb0y5fc7kfmegvx'>" /* this will need to by dynamic when we add login handling */
-
-
-#define JSTRING_PARSE_ERROR "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' version='1.0'><stream:error xmlns:stream='http://etherx.jabber.org/streams'><xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><text xmlns='urn:ietf:params:xml:ns:xmpp-streams'>syntax error</text></stream:error></stream:stream>" 
-
-#define JSTRING_LOGIN_OK "<iq xmlns='jabber:client' id='0123456789' type='result'/>"
-
-#define JSTRING_NO_RECIPIENT "<message xmlns='jabber:client' type='error' from='%s' to='%s'><error type='cancel' code='404'><item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/></error><body>NOT ADDING BODY</body></message>"
-
-#endif
diff --git a/OpenSRF/src/jserver/osrf_chat.c b/OpenSRF/src/jserver/osrf_chat.c
new file mode 100644 (file)
index 0000000..98a100d
--- /dev/null
@@ -0,0 +1,757 @@
+/*
+Copyright (C) 2005  Georgia Public Library Service 
+Bill Erickson <billserickson@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 "osrf_chat.h"
+#include <string.h>
+#include <stdio.h>
+
+int __osrfChatXMLErrorOcurred = 0;
+int __osrfChatClientSentDisconnect = 0;
+
+/* shorter version of strcmp */
+static int eq(const char* a, const char* b) { return (a && b && !strcmp(a,b)); }
+
+/* gnarly debug function */
+static void chatdbg( osrfChatServer* server ) {
+
+       if(!server) return;
+
+       growing_buffer* buf = buffer_init(256);
+
+       buffer_add(buf, "---------------------------------------------------------------------\n");
+
+       buffer_fadd(buf, 
+               "ChopChop Debug:\n"
+               "Connections:           %lu\n"
+               "Named nodes in hash:   %lu\n"
+               "Domain:                %s\n"
+               "Port:                  %d\n"
+               "S2S Port:              %d\n"
+               "-------------------------------------------------------\n",
+               osrfListGetCount(server->nodeList), osrfHashGetCount(server->nodeHash),
+               server->domain, server->port, server->s2sport );
+
+       osrfListIterator* itr = osrfNewListIterator(server->nodeList);
+       osrfChatNode* node;
+
+       while( (node = osrfListIteratorNext(itr)) ) {
+
+               buffer_fadd( buf, 
+                       "sockid:    %d\n"
+                       "Remote:    %s\n"
+                       "State:     %d\n"
+                       "XMLState:  %d\n"
+                       "In Parse:  %d\n"
+                       "to:        %s\n"
+                       "Resource:  %s\n"
+                       "Username:  %s\n"
+                       "Domain:    %s\n"
+                       "Authkey:   %s\n"
+                       "type:          %d\n"
+                       "-------------------------------------------------------\n",
+                       node->sockid, node->remote, node->state, node->xmlstate, node->inparse,
+                       node->to, node->resource, node->username, node->domain, node->authkey, node->type );
+       }
+
+       debug_handler("DEBUG:\n%s", buf->buf );
+       buffer_free(buf);
+       osrfListIteratorFree(itr);
+}
+
+osrfChatServer* osrfNewChatServer( char* domain, char* secret, int s2sport ) {
+       if(!(domain && secret)) return NULL;
+
+       osrfChatServer* server = safe_malloc(sizeof(osrfChatServer));
+
+       server->nodeHash = osrfNewHash();
+       server->nodeList = osrfNewList();
+       server->deadNodes = osrfNewList();
+       server->nodeList->freeItem = &osrfChatNodeFree;
+       server->domain = strdup(domain);
+       server->s2sport = s2sport;
+
+       server->mgr = safe_malloc(sizeof(socket_manager));
+       server->mgr->data_received = &osrfChatHandleData;
+       server->mgr->blob = server;
+       server->mgr->on_socket_closed = &osrfChatSocketClosed;
+
+       if(secret) server->secret = strdup(secret);
+       return server;
+}
+
+void osrfChatCleanupClients( osrfChatServer* server ) {
+       if(server) {
+               osrfListFree(server->deadNodes);
+               server->deadNodes = osrfNewList();
+       }
+}
+
+
+
+osrfChatNode* osrfNewChatNode( int sockid, char* domain ) {
+       if(sockid < 1 || !domain) return NULL;
+       osrfChatNode* node      = safe_malloc(sizeof(osrfChatNode));
+       node->state                             = OSRF_CHAT_STATE_NONE;
+       node->msgs                              = NULL; /* only s2s nodes cache messages */
+       node->parserCtx         = xmlCreatePushParserCtxt(osrfChatSaxHandler, node, "", 0, NULL);
+       node->msgDoc                    = xmlNewDoc(BAD_CAST "1.0");
+       node->domain = strdup(domain);
+       xmlKeepBlanksDefault(0);
+       node->authkey                   = NULL;
+       node->username                  = NULL;
+       node->resource                  = NULL;
+       node->to                                        = NULL;
+       node->type = 0;
+       return node;
+}
+
+
+osrfChatNode* osrfNewChatS2SNode( char* domain, char* remote ) {
+       if(!(domain && remote)) return NULL;
+       osrfChatNode* n = osrfNewChatNode( 1, domain );
+       n->state                = OSRF_CHAT_STATE_S2S_CHALLENGE;
+       n->sockid       = -1;
+       n->remote       = strdup(remote);
+       n->msgs         = osrfNewList();
+       n->msgs->freeItem = &osrfChatS2SMessageFree;
+       n->type = 1;
+       return n;
+}
+
+void osrfChatS2SMessageFree(void* n) { free(n); }
+
+void osrfChatNodeFree( void* node ) {
+       if(!node) return;
+       osrfChatNode* n = (osrfChatNode*) node;
+
+       /* we can't free messages that are mid-parse because the
+               we can't free the parser context */
+       if(n->inparse) {
+               n->inparse = 0;
+               osrfListPush(n->parent->deadNodes, n);
+               return;
+       }
+
+       free(n->remote);
+       free(n->to);
+       free(n->username);
+       free(n->resource);
+       free(n->domain);
+       free(n->authkey);
+
+       osrfListFree(n->msgs);
+
+       if(n->parserCtx) {
+               xmlFreeDoc(n->parserCtx->myDoc);
+               xmlFreeParserCtxt(n->parserCtx);
+       }
+
+       xmlFreeDoc(n->msgDoc);
+       free(n);
+}
+
+
+
+int osrfChatServerConnect( osrfChatServer* cs,  int port, int s2sport, char* listenAddr ) {
+       if(!(cs && port && listenAddr)) return -1;
+       cs->port = port;
+       cs->s2sport = s2sport;
+       if( socket_open_tcp_server(cs->mgr, port, listenAddr ) < 0 )
+               return -1;
+       if( socket_open_tcp_server(cs->mgr, s2sport, listenAddr ) < 0 )
+               return -1;
+       return 0;
+}
+
+
+int osrfChatServerWait( osrfChatServer* server ) {
+       if(!server) return -1;
+       while(1) {
+               if(socket_wait_all(server->mgr, -1) < 0)
+                       warning_handler( "jserver_wait(): socket_wait_all() returned error");
+       }
+       return -1;
+}
+
+
+void osrfChatServerFree(osrfChatServer* server ) {
+       if(!server) return;
+       osrfHashFree(server->nodeHash);
+       osrfListFree(server->nodeList);
+       free(server->mgr);
+       free(server->secret);
+}
+
+
+void osrfChatHandleData( void* cs, 
+       socket_manager* mgr, int sockid, char* data, int parent_id ) {
+
+       if(!(cs && mgr && sockid && data)) return;
+
+       osrfChatServer* server = (osrfChatServer*) cs;
+
+       osrfChatNode* node = osrfListGetIndex( server->nodeList, sockid );
+
+       if(!node) {
+               debug_handler("Adding new connection for sockid %d", sockid );
+               node = osrfChatAddNode( server, sockid );
+       }
+
+       if(node) {
+               if( (osrfChatPushData( server, node, data ) == -1) ) {
+                       warning_handler("Node at socket %d received bad XML, disconnecting...", sockid );
+                       osrfChatSendRaw(  node, OSRF_CHAT_PARSE_ERROR );
+                       osrfChatRemoveNode( server, node );
+               }
+       }
+
+       osrfChatCleanupClients(server); /* clean up old dead clients */
+}
+
+
+void osrfChatSocketClosed( void* blob, int sockid ) {
+       if(!blob) return;
+       osrfChatServer* server = (osrfChatServer*) blob;
+       osrfChatNode* node = osrfListGetIndex(server->nodeList, sockid);
+       osrfChatRemoveNode( server, node );
+}
+
+osrfChatNode* osrfChatAddNode( osrfChatServer* server, int sockid ) {
+       if(!(server && sockid)) return NULL;
+       osrfChatNode* node = osrfNewChatNode(sockid, server->domain);
+       node->parent = server;
+       node->sockid = sockid;
+       osrfListSet( server->nodeList, node, sockid );
+       return node;
+}
+
+void osrfChatRemoveNode( osrfChatServer* server, osrfChatNode* node ) {
+       if(!(server && node)) return;
+       socket_disconnect(server->mgr, node->sockid);
+       if(node->remote) 
+               osrfHashRemove( server->nodeHash, node->remote );
+       osrfListRemove( server->nodeList, node->sockid ); /* this will free it */
+}
+
+int osrfChatSendRaw( osrfChatNode* node, char* msgXML ) {
+       if(!(node && msgXML)) return -1;
+       return socket_send( node->sockid, msgXML );
+}
+
+
+
+
+void osrfChatNodeFinish( osrfChatServer* server, osrfChatNode* node ) {
+       if(!(server && node)) return;
+       osrfChatSendRaw( node, "</stream:stream>");
+       osrfChatRemoveNode( server, node );
+}
+
+
+int osrfChatSend( osrfChatServer* cs, osrfChatNode* node, char* toAddr, char* fromAddr, char* msgXML ) {
+       if(!(cs && node && toAddr && msgXML)) return -1;
+
+       int l = strlen(toAddr);
+       char dombuf[l];
+       bzero(dombuf, l);
+       jid_get_domain( toAddr, dombuf );       
+
+       if( eq( dombuf, cs->domain ) ) { /* this is to a user we host */
+
+               osrfChatNode* tonode = osrfHashGet(cs->nodeHash, toAddr);
+               if(tonode) {
+                       osrfChatSendRaw( tonode, msgXML );
+
+               } else {
+
+                       /* send an error message saying we don't have this connection */
+                       warning_handler("We have no connection for %s", toAddr);
+                       char* xml = va_list_to_string( OSRF_CHAT_NO_RECIPIENT, toAddr, fromAddr );
+                       osrfChatSendRaw( node, xml );
+                       free(xml);
+               }
+
+       } else {
+
+               osrfChatNode* tonode = osrfHashGet(cs->nodeHash, dombuf);
+               if(tonode) {
+                       if( tonode->state == OSRF_CHAT_STATE_CONNECTED ) {
+                               debug_handler("Routing message to server %s", dombuf);
+                               osrfChatSendRaw( tonode, msgXML );
+
+                       } else {
+                               info_handler("Received s2s message and we're still trying to connect...caching");
+                               osrfListPush( tonode->msgs, strdup(msgXML) );
+                       }
+
+               } else {
+
+                       if( osrfChatInitS2S( cs, dombuf, toAddr, msgXML ) != 0 ) {
+                               warning_handler("We are unable to connect to remote server %s for recipient %s", dombuf, toAddr);
+                               char* xml = va_list_to_string( OSRF_CHAT_NO_RECIPIENT, toAddr, fromAddr );
+                               osrfChatSendRaw( node, xml );
+                               free(xml);
+                       }
+               }
+       }
+
+       return 0;
+}
+
+
+/*
+void osrfChatCacheS2SMessage( char* toAddr, char* msgXML, osrfChatNode* snode ) {
+       if(!(toAddr && msgXML)) return;
+       osrfChatS2SMessage* msg = safe_malloc(sizeof(osrfChatS2SMessage));
+       msg->toAddr = strdup(toAddr);
+       msg->msgXML = strdup(msgXML);
+       info_handler("Pushing client message onto s2s queue waiting for connect... ");
+       osrfListPush( snode->msgs, msgXML );
+}
+*/
+
+
+int osrfChatInitS2S( osrfChatServer* cs, char* remote, char* toAddr, char* msgXML ) {
+       if(!(cs && remote && toAddr && msgXML)) return -1;
+
+       info_handler("Initing server2server connection to domain %s", remote );
+       osrfChatNode* snode = osrfNewChatS2SNode( cs->domain, remote );
+       snode->parent = cs;
+
+       /* try to connect to the remote site */
+       snode->sockid = socket_open_tcp_client(cs->mgr, cs->s2sport, remote);
+       if(snode->sockid < 1) {
+               warning_handler("Unable to connect to remote server at %s", remote );
+               return -1;
+       }
+
+       /* store the message we were supposed to deliver until we're fully connected */
+       //osrfChatCacheS2SMessage( toAddr, msgXML, snode );
+       osrfListPush( snode->msgs, strdup(msgXML) );
+       osrfHashSet(cs->nodeHash, snode, remote );
+       osrfListSet(cs->nodeList, snode, snode->sockid );
+
+       /* send the initial s2s request */
+       osrfChatSendRaw( snode, OSRF_CHAT_S2S_INIT );
+
+       debug_handler("Added new s2s node...");
+       chatdbg(cs);
+
+       return 0;
+}
+
+
+/* commence SAX handling code */
+
+int osrfChatPushData( osrfChatServer* server, osrfChatNode* node, char* data ) {
+       if(!(node && data)) return -1;
+
+       chatdbg(server);
+
+       debug_handler("pushing data into xml parser for node %d:\n%s", node->sockid, data);
+       node->inparse = 1;
+       xmlParseChunk(node->parserCtx, data, strlen(data), 0);
+       node->inparse = 0;
+
+       if(__osrfChatXMLErrorOcurred) {
+               __osrfChatXMLErrorOcurred = 0;
+               return -1;
+       }
+
+       /* we can't do cleanup of the XML handlers while in the middle of a 
+               data push, so set flags in the data push and doe the cleanup here */
+       /*
+       if(__osrfChatClientSentDisconnect) {
+               __osrfChatClientSentDisconnect  = 0;
+               osrfChatNodeFinish( server, node );
+       }
+       */
+
+       return 0;
+}
+
+
+void osrfChatStartStream( void* blob ) {
+       debug_handler("Starting new client stream...");
+}
+
+
+void osrfChatStartElement( void* blob, const xmlChar *name, const xmlChar **atts ) {
+       if(!(blob && name)) return;
+       osrfChatNode* node = (osrfChatNode*) blob;
+
+       int status = -1;
+       char* nm = (char*) name;
+
+       debug_handler("Starting element %s with namespace %s", nm, xmlSaxAttr(atts, "xmlns") );
+
+       switch( node->state ) {
+
+               case OSRF_CHAT_STATE_NONE:
+                       status = osrfChatHandleNewConnection( node, nm, atts );
+                       break;
+
+               case OSRF_CHAT_STATE_CONNECTING:
+                       status = osrfChatHandleConnecting( node, nm, atts );
+                       break;
+
+               case OSRF_CHAT_STATE_CONNECTED:
+                       status = osrfChatHandleConnected( node, nm, atts );
+                       break;
+
+               case OSRF_CHAT_STATE_S2S_CHALLENGE:      
+                       status = osrfChatHandleS2SChallenge( node, nm, atts );
+                       break;
+
+               case OSRF_CHAT_STATE_S2S_RESPONSE: /* server waiting for client response to challenge */
+                       if(eq(nm, "db:result")) {
+                               char* remote = xmlSaxAttr(atts, "from");
+                               if(remote) node->remote = strdup(remote); /* copy off the client's id */
+                               status = 0;
+                               node->xmlstate |= OSRF_CHAT_STATE_INS2SRESULT;
+                       } else status = -1; 
+                       break;
+
+               case OSRF_CHAT_STATE_S2S_VERIFY:        /* client : waiting for server verify message */
+                       if(eq(nm, "db:verify")) {
+                               char* id = xmlSaxAttr( atts, "id" );
+                               if(id) {
+                                       char* xml = va_list_to_string( OSRF_CHAT_S2S_VERIFY_RESPONSE, 
+                                                       node->remote, node->domain, id );
+                                       osrfChatSendRaw( node, xml );
+                                       free(xml);
+                                       node->state = OSRF_CHAT_STATE_S2S_VERIFY_FINAL;
+                                       status = 0;
+                               }
+                       }
+                       break;
+
+               case OSRF_CHAT_STATE_S2S_VERIFY_RESPONSE:       /* server waiting for client verify response */
+               case OSRF_CHAT_STATE_S2S_VERIFY_FINAL: /* client waitig for final verify */
+                       status = osrfChatHandleS2SConnected( node, nm, atts );
+                       break;
+
+       }
+
+       if(status != 0) 
+               osrfChatParseError( node, "We don't know how to handle the XML data received" );
+}
+
+#define CHAT_CHECK_VARS(x,y,z) if(!(x && y)) return -1; if(z) debug_handler(z);
+
+
+
+int osrfChatHandleS2SConnected( osrfChatNode* node, const char* name, const xmlChar**atts ) {
+       CHAT_CHECK_VARS(node, name, "osrfChatHandleS2SConnected" );
+
+       int status = -1;
+
+       if(eq(name,"db:verify")) { /* server receives verify from client */
+               char* xml = va_list_to_string(OSRF_CHAT_S2S_VERIFY_FINAL, node->domain, node->remote ); 
+               osrfChatSendRaw(node, xml );
+               free(xml);
+               status = 0;
+       }
+
+       if(eq(name, "db:result")) {
+               /* send all the messages that we have queued for this server */
+               node->state = OSRF_CHAT_STATE_CONNECTED;
+               osrfListIterator* itr = osrfNewListIterator(node->msgs);
+
+               char* xml;
+               while( (xml = (char*) osrfListIteratorNext(itr)) ) {
+                       xmlDocPtr doc = xmlParseMemory(xml, strlen(xml));
+                       if(doc) {
+                               char* from = (char*) xmlGetProp(xmlDocGetRootElement(doc), BAD_CAST "from");
+                               char* to = (char*) xmlGetProp(xmlDocGetRootElement(doc), BAD_CAST "to");
+                               osrfChatSend( node->parent, node, to, from, xml );
+                               debug_handler("Sending cached message from %s to %s", from, to);
+                               xmlFree(to); xmlFree(from);
+                               xmlFreeDoc(doc);
+                       }
+               }
+
+               osrfListIteratorFree(itr);
+               osrfListFree(node->msgs);
+               node->msgs = NULL;
+               status = 0;
+       }
+
+       if(status == 0) {
+               info_handler("Successfully made S2S connection to %s", node->remote );
+               node->state = OSRF_CHAT_STATE_CONNECTED;
+               node->xmlstate = 0;
+       }
+
+       return status;
+}
+
+
+/** check the namespace of the stream message to see if it's a server or client connection */
+int osrfChatHandleNewConnection( osrfChatNode* node, const char* name, const xmlChar** atts ) {
+       CHAT_CHECK_VARS(node, name, "osrfChatHandleNewConnection()");
+
+       if(!eq(name, "stream:stream")) return -1;
+
+       node->authkey = osrfChatMkAuthKey();
+       char* ns = xmlSaxAttr(atts, "xmlns");
+       if(!ns) return -1;
+
+       if(eq(ns, "jabber:client")) { /* client connection */
+
+               char* domain = xmlSaxAttr( atts, "to" );
+               if(!domain) return -1; 
+       
+               if(!eq(domain, node->domain)) {
+                       warning_handler("Client attempting to connect to invalid domain");
+                       return -1;
+               }
+       
+               char* buf = va_list_to_string( OSRF_CHAT_START_STREAM, domain, node->authkey );
+               node->state = OSRF_CHAT_STATE_CONNECTING;
+       
+               debug_handler("Server responding to connect message with\n%s\n", buf );
+               osrfChatSendRaw( node, buf );
+               free(buf);
+               return 0;
+       }
+
+       /* server to server init */
+       if(eq(ns, "jabber:server")) { /* client connection */
+               info_handler("We received a new server 2 server connection, generating auth key...");
+               char* xml = va_list_to_string( OSRF_CHAT_S2S_CHALLENGE, node->authkey );
+               osrfChatSendRaw( node, xml );
+               free(xml);
+               node->state = OSRF_CHAT_STATE_S2S_RESPONSE; /* the next message should be the response */
+               node->type = 1;
+               return 0;
+       }
+
+       return -1;
+}
+
+
+
+char* osrfChatMkAuthKey() {
+       char keybuf[112];
+       bzero(keybuf, 112);
+       snprintf(keybuf, 111, "%d%d%s", (int) time(NULL), getpid(), getenv("HOSTNAME"));
+       return strdup(shahash(keybuf));
+}
+
+int osrfChatHandleConnecting( osrfChatNode* node, const char* name, const xmlChar** atts ) {
+       CHAT_CHECK_VARS(node, name, "osrfChatHandleConnecting()");
+       debug_handler("Handling connect node %s", name );
+
+       if(eq(name, "iq")) node->xmlstate |= OSRF_CHAT_STATE_INIQ;
+       else if(eq(name,"username")) node->xmlstate |= OSRF_CHAT_STATE_INUSERNAME;
+       else if(eq(name,"resource")) node->xmlstate |= OSRF_CHAT_STATE_INRESOURCE;
+       return 0;
+}
+
+int osrfChatHandleConnected( osrfChatNode* node, const char* name, const xmlChar** atts ) {
+       CHAT_CHECK_VARS(node, name, "osrfChatHandleConnected()");
+
+       if(eq(name,"message")) {
+
+               /* drop the old message and start with a new one */
+               xmlNodePtr root = xmlNewNode(NULL, name);
+               xmlAddAttrs(root, atts);
+               xmlNodePtr oldRoot = xmlDocSetRootElement(node->msgDoc, root);
+               free(node->to);
+
+               char* to = xmlSaxAttr(atts, "to");
+               if(!to) to = "";
+
+               node->to = strdup(to);
+               if(oldRoot) xmlFreeNode(oldRoot);
+               node->xmlstate = OSRF_CHAT_STATE_INMESSAGE;
+
+       } else {
+
+               /* all non "message" nodes are simply added to the message */
+               xmlNodePtr nodep = xmlNewNode(NULL, name);
+               xmlAddAttrs(nodep, atts);
+               xmlAddChild(xmlDocGetRootElement(node->msgDoc), nodep);
+       }
+
+       return 0;
+}
+
+/* takes s2s secret, hashdomain, and the s2s auth token */
+static char* osrfChatGenerateS2SKey( char* secret, char* hashdomain, char* authtoken ) {
+       if(!(secret && hashdomain && authtoken)) return NULL;
+       info_handler("Generating s2s key with auth token: %s", authtoken );
+       char* a = shahash(secret);
+       debug_handler("S2S secret hash: %s", a);
+       char* b = va_list_to_string("%s%s", a, hashdomain);
+       char* c = shahash(b);
+       debug_handler("S2S intermediate hash: %s", c);
+       char* d = va_list_to_string("%s%s", c, authtoken);
+       char* e = strdup(shahash(d));
+       free(b); free(d); 
+       return e;
+}
+
+int osrfChatHandleS2SChallenge( osrfChatNode* node, const char* name, const xmlChar** atts ) {
+       CHAT_CHECK_VARS(node, name, "osrfChatHandleS2SChallenge()");
+
+/* here we respond to the stream challenge */
+       if(eq(name, "stream:stream")) {
+               char* id = xmlSaxAttr(atts, "id");
+               if(id) {
+                       /* we use our domain in the s2s challenge hash */
+                       char* d = osrfChatGenerateS2SKey(node->parent->secret, node->domain, id );
+                       char* e = va_list_to_string(OSRF_CHAT_S2S_RESPONSE, node->remote, node->domain, d );
+                       info_handler("Answering s2s challenge with key:  %s", e );
+                       osrfChatSendRaw( node, e );
+                       free(d); free(e);
+                       node->state = OSRF_CHAT_STATE_S2S_VERIFY;
+                       return 0;
+               }
+       }
+
+       return -1;
+}
+
+/*
+int osrfChatHandleS2SResponse( osrfChatNode* node, const char* name, const xmlChar** atts ) {
+       CHAT_CHECK_VARS(node, name, "osrfChatHandleS2SResponse()");
+
+       if(eq(name, "db:result")) {
+               node->xmlstate |= OSRF_CHAT_STATE_INS2SRESULT;
+               return 0;
+       }
+
+       return -1;
+}
+*/
+
+
+
+void osrfChatEndElement( void* blob, const xmlChar* name ) {
+       if(!(blob && name)) return;
+       osrfChatNode* node = (osrfChatNode*) blob;
+
+       char* nm = (char*) name;
+
+       if(eq(nm,"stream:stream")) {
+               osrfChatNodeFinish( node->parent, node );
+               return;
+       }
+
+       if( node->state == OSRF_CHAT_STATE_CONNECTED ) {
+               if(eq(nm, "message")) {
+
+                       xmlNodePtr msg = xmlDocGetRootElement(node->msgDoc);
+                       if(msg && node->type == 0)
+                               xmlSetProp(msg, BAD_CAST "from", BAD_CAST node->remote );
+                       char* string = xmlDocToString(node->msgDoc, 0 );
+
+                       char* from = (char*) xmlGetProp(msg, BAD_CAST "from");
+                       debug_handler( "Routing message to %s\n%s\n", node->to, from, string );
+                       osrfChatSend( node->parent, node, node->to, from, string ); 
+                       xmlFree(from);
+                       free(string);
+               }
+       }
+
+       if( node->state == OSRF_CHAT_STATE_CONNECTING ) {
+               if( node->xmlstate & OSRF_CHAT_STATE_INIQ ) {
+
+                       if(eq(nm, "iq")) {
+                               node->xmlstate &= ~OSRF_CHAT_STATE_INIQ;
+                               node->remote = va_list_to_string( 
+                                               "%s@%s/%s", node->username, node->domain, node->resource );
+
+                               debug_handler("Setting remote address to %s", node->remote );
+                               osrfChatSendRaw( node, OSRF_CHAT_LOGIN_OK );
+                               osrfHashSet( node->parent->nodeHash, node, node->remote );
+                               node->state = OSRF_CHAT_STATE_CONNECTED;
+                       }
+               }
+       }
+}
+
+
+void osrfChatHandleCharacter( void* blob, const xmlChar *ch, int len) {
+       if(!(blob && ch && len)) return;
+       osrfChatNode* node = (osrfChatNode*) blob;
+
+       /*
+       debug_handler("Char Handler: state %d, xmlstate %d, chardata %s", 
+                       node->state, node->xmlstate, (char*) ch );
+                       */
+
+       if( node->state == OSRF_CHAT_STATE_CONNECTING ) {
+               if( node->xmlstate & OSRF_CHAT_STATE_INIQ ) {
+
+                       if( node->xmlstate & OSRF_CHAT_STATE_INUSERNAME ) {
+                               free(node->username);
+                               node->username = strndup((char*) ch, len);
+                               node->xmlstate &= ~OSRF_CHAT_STATE_INUSERNAME;
+                       }
+
+                       if( node->xmlstate & OSRF_CHAT_STATE_INRESOURCE ) {
+                               free(node->resource);
+                               node->resource = strndup((char*) ch, len);
+                               node->xmlstate &= ~OSRF_CHAT_STATE_INRESOURCE;
+                       }
+               }
+
+               return;
+       } 
+       
+       if( node->state == OSRF_CHAT_STATE_CONNECTED ) {
+               xmlNodePtr last = xmlGetLastChild(xmlDocGetRootElement(node->msgDoc));
+               xmlNodePtr txt = xmlNewTextLen(ch, len);
+               xmlAddChild(last, txt);
+               return;
+       }
+
+       if( node->state == OSRF_CHAT_STATE_S2S_RESPONSE &&
+                       (node->xmlstate & OSRF_CHAT_STATE_INS2SRESULT) ) {
+
+               char* key = strndup((char*) ch, len);
+               debug_handler("Got s2s key from %s : %s", node->remote, key );
+               char* e = osrfChatGenerateS2SKey(node->parent->secret, node->remote, node->authkey );
+               info_handler("\nReceived s2s key from server: %s\nKey should be: %s", key, e );
+
+               if(eq(key, e)) {
+                       char* msg = va_list_to_string(OSRF_CHAT_S2S_VERIFY_REQUEST,  
+                                       node->authkey, node->domain, node->remote, e );
+                       osrfChatSendRaw(node, msg );
+                       free(msg);
+                       node->state = OSRF_CHAT_STATE_S2S_VERIFY_RESPONSE;
+                       node->xmlstate = 0;
+
+               } else {
+                       warning_handler("Server2Server keys do not match!");
+               }
+
+               /* do the hash dance again */
+       }
+
+}
+
+
+void osrfChatParseError( void* blob, const char* msg, ... ) {
+
+       __osrfChatXMLErrorOcurred = 1;
+}
+
+
+
+
diff --git a/OpenSRF/src/jserver/osrf_chat.h b/OpenSRF/src/jserver/osrf_chat.h
new file mode 100644 (file)
index 0000000..3e5446c
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+Copyright (C) 2005  Georgia Public Library Service 
+Bill Erickson <billserickson@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.
+*/
+
+#ifndef OSRF_CHAT_H
+#define OSRF_CHAT_H
+
+
+/* opensrf headers */
+#include "opensrf/utils.h"
+#include "opensrf/osrf_hash.h"
+#include "opensrf/osrf_list.h"
+#include "opensrf/logging.h"
+#include "opensrf/xml_utils.h"
+#include "opensrf/socket_bundle.h"
+#include "opensrf/sha.h"
+#include "opensrf/transport_message.h"
+
+/* libxml2 headers */
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include <libxml/globals.h>
+#include <libxml/xmlerror.h>
+
+/* client to server XML */
+#define OSRF_CHAT_START_STREAM "<?xml version='1.0'?><stream:stream "\
+       "xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:client' "\
+       "from='%s' version='1.0' id='%s'>" 
+
+#define OSRF_CHAT_PARSE_ERROR "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' "\
+       "version='1.0'><stream:error xmlns:stream='http://etherx.jabber.org/streams'>"\
+       "<xml-not-well-formed xmlns='urn:ietf:params:xml:ns:xmpp-streams'/>"    \
+       "<text xmlns='urn:ietf:params:xml:ns:xmpp-streams'>syntax error</text></stream:error></stream:stream>" 
+
+#define OSRF_CHAT_LOGIN_OK "<iq xmlns='jabber:client' id='0123456789' type='result'/>"
+
+#define OSRF_CHAT_NO_RECIPIENT "<message xmlns='jabber:client' type='error' from='%s' to='%s'>"\
+       "<error type='cancel' code='404'><item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>"\
+       "</error><body>NOT ADDING BODY</body></message>"
+
+/* ---------------------------------------------------------------------------------- */
+/* server to server XML */
+
+// client to server init
+#define OSRF_CHAT_S2S_INIT "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' "\
+       "xmlns='jabber:server' xmlns:db='jabber:server:dialback'>"
+
+// server to client challenge 
+#define OSRF_CHAT_S2S_CHALLENGE "<stream:stream xmlns:stream='http://etherx.jabber.org/streams' "\
+       "xmlns='jabber:server' id='%s' xmlns:db='jabber:server:dialback'>"
+
+// client to server challenge response
+#define OSRF_CHAT_S2S_RESPONSE "<db:result xmlns:db='jabber:server:dialback' to='%s' from='%s'>%s</db:result>"
+
+// server to client verify
+#define OSRF_CHAT_S2S_VERIFY_REQUEST "<db:verify xmlns:db='jabber:server:dialback' id='%s' from='%s' to='%s'>%s</db:verify>"
+
+// client to server verify response
+#define OSRF_CHAT_S2S_VERIFY_RESPONSE "<db:verify xmlns:db='jabber:server:dialback' type='valid' to='%s' from='%s' id='%s'/>"
+
+//server to client final verification
+#define OSRF_CHAT_S2S_VERIFY_FINAL "<db:result xmlns:db='jabber:server:dialback' type='valid' from='%s' to ='%s'/>"
+
+
+/* c2s states */
+#define OSRF_CHAT_STATE_NONE                                           0               /* blank node */
+#define OSRF_CHAT_STATE_CONNECTING                             1               /* we have received the opening stream */
+#define OSRF_CHAT_STATE_CONNECTED                              2               /* we have sent the OK/result message */
+
+/* s2s states */
+#define OSRF_CHAT_STATE_S2S_CHALLENGE                  4               /* client : waiting for the challenge */
+#define OSRF_CHAT_STATE_S2S_RESPONSE                   5               /* server : waiting for the challenge response */
+#define OSRF_CHAT_STATE_S2S_VERIFY                             6               /* client : waiting for verify message */
+#define OSRF_CHAT_STATE_S2S_VERIFY_RESPONSE    7               /* server : waiting for verify response */
+#define OSRF_CHAT_STATE_S2S_VERIFY_FINAL               8               /* client : waiting for final verify response */
+
+/* xml parser states */
+#define OSRF_CHAT_STATE_INMESSAGE              1
+#define OSRF_CHAT_STATE_INIQ                           2
+#define OSRF_CHAT_STATE_INUSERNAME             4
+#define OSRF_CHAT_STATE_INRESOURCE             8
+#define OSRF_CHAT_STATE_INS2SRESULT            8
+#define OSRF_CHAT_STATE_INS2SVERIFY            8
+
+
+struct __osrfChatNodeStruct {
+
+       int sockid;                     /* our socket id */
+
+       int type;                       /* 0 for client, 1 for server */
+
+       /* for clients this is the full JID of the client that connected to this server.
+               for servers it's the domain (network id) of the server we're connected to */
+       char* remote;           
+
+
+       int state;                      /* for the various stages of connectivity and parsing */
+       int xmlstate;           /* what part of the message are we currently parsing */
+       int inparse;            /* true if we are currently parsing a chunk of XML.  If so, we can't 
+                                                                       free the node.  we have to cache it and free it later */
+
+       char* to;                       /* The JID where the current message is being routed */
+
+       char* domain;           /* the domain, resource, and username of our connecting entity. */ 
+       char* resource; /* for s2s nodes, resource and username will be empty . */
+       char* username;
+
+       char* authkey;          /* when doing any auth negotiation, this is the auth seed hash */
+
+       osrfList* msgs; /* if we're a server node we may have a pool of messages waiting to be delivered */
+
+       xmlParserCtxtPtr parserCtx; 
+       xmlDocPtr msgDoc;
+       struct __osrfChatServerStruct* parent;
+
+};
+typedef struct __osrfChatNodeStruct osrfChatNode;
+
+struct __osrfChatS2SMessageStruct {
+       char* toAddr;
+       char* msgXML;
+};
+typedef struct __osrfChatS2SMessageStruct osrfChatS2SMessage;
+
+struct __osrfChatServerStruct {
+       osrfHash* nodeHash; /* sometimes we need hash (remote id) lookup, sometimes we need socket id lookup */
+       osrfList* nodeList;
+       osrfList* deadNodes; /* collection of nodes to free when we get a chance */
+       socket_manager* mgr;
+       char* secret;                   /* shared S2S secret */
+       char* domain;                   /* the domain this server hosts */
+       int s2sport;
+       int port;
+};
+
+typedef struct __osrfChatServerStruct osrfChatServer;
+
+
+void osrfChatCacheS2SMessage( char* toAddr, char* msgXML, osrfChatNode* snode );
+
+osrfChatNode* osrfNewChatS2SNode( char* domain, char* remote );
+osrfChatNode* osrfNewChatNode( int sockid, char* domain );
+void osrfChatNodeFree( void* node );
+
+/* @param s2sSecret The Server to server secret.  OK to leave NULL if no 
+       server to server communication is expected
+       */
+osrfChatServer* osrfNewChatServer( char* domain, char* s2sSecret, int s2sport );
+
+int osrfChatServerConnect( osrfChatServer* cs,  int port, int s2sport, char* listenAddr );
+
+int osrfChatServerWait( osrfChatServer* server );
+void osrfChatServerFree(osrfChatServer* cs);
+
+void osrfChatHandleData( void* cs, 
+       socket_manager* mgr, int sockid, char* data, int parent_id );
+
+
+/* removes dead nodes that have been cached due to mid-parse removals */
+void osrfChatCleanupClients( osrfChatServer* server );
+
+
+osrfChatNode* osrfChatAddNode( osrfChatServer* server, int sockid );
+
+
+void osrfChatRemoveNode( osrfChatServer* server, osrfChatNode* node );
+
+/** pushes new data into the nodes parser */
+int osrfChatPushData( osrfChatServer* server, osrfChatNode* node, char* data );
+
+
+void osrfChatSocketClosed( void* blob, int sockid );
+
+/**
+  Sends msgXML to the client with remote 'toAddr'.  if we have no connection
+  to 'toAddr' and the domain for 'toAddr' is different than our hosted domain
+  we attempt to send the message to the domain found in 'toAddr'.
+  */
+int osrfChatSend( osrfChatServer* cs, osrfChatNode* node, char* toAddr, char* fromAddr, char* msgXML );
+
+int osrfChatSendRaw( osrfChatNode* node, char* xml );
+
+
+void osrfChatNodeFinish( osrfChatServer* server, osrfChatNode* node );
+
+/* initializes the negotiation of a server to server connection */
+int osrfChatInitS2S( osrfChatServer* cs, char* remote, char* toAddr, char* msgXML );
+
+
+void osrfChatStartStream( void* blob );
+void osrfChatStartElement( void* blob, const xmlChar *name, const xmlChar **atts );
+void osrfChatEndElement( void* blob, const xmlChar* name );
+void osrfChatHandleCharacter(void* blob, const xmlChar *ch, int len);
+void osrfChatParseError( void* blob, const char* msg, ... );
+
+int osrfChatHandleNewConnection( osrfChatNode* node, const char* name, const xmlChar** atts );
+int osrfChatHandleConnecting( osrfChatNode* node, const char* name, const xmlChar** atts );
+int osrfChatHandleConnected( osrfChatNode* node, const char* name, const xmlChar** atts );
+int osrfChatHandleS2SInit( osrfChatNode* node, const char* name, const xmlChar** atts );
+int osrfChatHandleS2SChallenge( osrfChatNode* node, const char* name, const xmlChar** atts );
+int osrfChatHandleS2SResponse( osrfChatNode* node, const char* name, const xmlChar** atts );
+
+int osrfChatHandleS2SConnected( osrfChatNode* node, const char* nm, const xmlChar**atts );
+
+void osrfChatS2SMessageFree(void* n);
+
+
+
+/* generates a random sha1 hex key */
+char* osrfChatMkAuthKey();
+
+static xmlSAXHandler osrfChatSaxHandlerStruct = {
+   NULL,                                                               /* internalSubset */
+   NULL,                                                               /* isStandalone */
+   NULL,                                                               /* hasInternalSubset */
+   NULL,                                                               /* hasExternalSubset */
+   NULL,                                                               /* resolveEntity */
+   NULL,                                                               /* getEntity */
+   NULL,                                                               /* entityDecl */
+   NULL,                                                               /* notationDecl */
+   NULL,                                                               /* attributeDecl */
+   NULL,                                                               /* elementDecl */
+   NULL,                                                               /* unparsedEntityDecl */
+   NULL,                                                               /* setDocumentLocator */
+   osrfChatStartStream,                        /* startDocument */
+   NULL,                                                               /* endDocument */
+       osrfChatStartElement,           /* startElement */
+       osrfChatEndElement,                     /* endElement */
+   NULL,                                                               /* reference */
+       osrfChatHandleCharacter,        /* characters */
+   NULL,                                                               /* ignorableWhitespace */
+   NULL,                                                               /* processingInstruction */
+   NULL,                                                               /* comment */
+   osrfChatParseError,                 /* xmlParserWarning */
+   osrfChatParseError,                 /* xmlParserError */
+   NULL,                                                               /* xmlParserFatalError : unused */
+   NULL,                                                               /* getParameterEntity */
+   NULL,                                                               /* cdataBlock; */
+   NULL,                                                               /* externalSubset; */
+   1,
+   NULL,
+   NULL,                                                               /* startElementNs */
+   NULL,                                                               /* endElementNs */
+       NULL                                                            /* xmlStructuredErrorFunc */
+};
+
+static const xmlSAXHandlerPtr osrfChatSaxHandler = &osrfChatSaxHandlerStruct;
+
+
+#endif
+
+
diff --git a/OpenSRF/src/jserver/osrf_chat_main.c b/OpenSRF/src/jserver/osrf_chat_main.c
new file mode 100644 (file)
index 0000000..64ae958
--- /dev/null
@@ -0,0 +1,56 @@
+#include "osrf_chat.h"
+#include "opensrf/osrfConfig.h"
+#include <stdio.h>
+#include "opensrf/logging.h"
+
+
+int main( int argc, char* argv[] ) {
+
+       if( argc < 3 ) {
+               fprintf( stderr, "Usage: %s <config_file> <config_context>\n", argv[0] );
+               exit(0);
+       }
+
+       osrfConfig* cfg = osrfConfigInit( argv[1], argv[2] );
+
+       init_proc_title( argc, argv );
+       set_proc_title( "ChopChop" );
+
+       char* domain            = osrfConfigGetValue(cfg, "/domain");
+       char* secret            = osrfConfigGetValue(cfg, "/secret");
+       char* sport                     = osrfConfigGetValue(cfg, "/port");
+       char* s2sport           = osrfConfigGetValue(cfg, "/s2sport");
+       char* listenaddr        = osrfConfigGetValue(cfg, "/listen_address");
+       char* llevel            = osrfConfigGetValue(cfg, "/loglevel");
+       char* lfile                     = osrfConfigGetValue(cfg, "/logfile");
+
+       if(!(domain && secret && sport && listenaddr && llevel && lfile && s2sport)) {
+               fprintf(stderr, "Configuration error for ChopChop - missing key ingredient\n");
+               return -1;
+       }
+
+       int port = atoi(sport);
+       int s2port = atoi(s2sport);
+       int level = atoi(llevel);
+       log_init(level, lfile);
+
+       fprintf(stderr, "Attempting to launch ChopChop with:\n"
+                       "domain: %s\nport: %s\nlisten address: %s\nlog level: %s\nlog file: %s\n",
+                       domain, sport, listenaddr, llevel, lfile );
+
+       osrfChatServer* server = osrfNewChatServer(domain, secret, s2port);
+
+       if( osrfChatServerConnect( server, port, s2port, listenaddr ) != 0 ) 
+               return fatal_handler("ChopChop unable to bind to port %d on %s", port, listenaddr);
+
+       daemonize();
+       osrfChatServerWait( server );
+
+       osrfChatServerFree( server );
+       log_free();
+       osrfConfigFree(cfg);
+
+       return 0;
+
+}
+