explicitly removing pre-existing connections when two overlap
[OpenSRF.git] / src / jserver / osrf_chat.c
1 /*
2 Copyright (C) 2005  Georgia Public Library Service 
3 Bill Erickson <billserickson@gmail.com>
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14 */
15
16 #include "osrf_chat.h"
17 #include <string.h>
18 #include <stdio.h>
19
20 int __osrfChatXMLErrorOcurred = 0;
21 int __osrfChatClientSentDisconnect = 0;
22
23 /* shorter version of strcmp */
24 static int eq(const char* a, const char* b) { return (a && b && !strcmp(a,b)); }
25
26 /* gnarly debug function */
27 static void chatdbg( osrfChatServer* server ) {
28
29         if(!server) return;
30         return; /* heavy logging, should only be used in heavy debug mode */
31
32         growing_buffer* buf = buffer_init(256);
33
34         buffer_add(buf, "---------------------------------------------------------------------\n");
35
36         buffer_fadd(buf, 
37                 "ChopChop Debug:\n"
38                 "Connections:           %lu\n"
39                 "Named nodes in hash:   %lu\n"
40                 "Domain:                %s\n"
41                 "Port:                  %d\n"
42                 "S2S Port:              %d\n"
43                 "-------------------------------------------------------\n",
44                 osrfListGetCount(server->nodeList), osrfHashGetCount(server->nodeHash),
45                 server->domain, server->port, server->s2sport );
46
47         osrfListIterator* itr = osrfNewListIterator(server->nodeList);
48         osrfChatNode* node;
49
50         while( (node = osrfListIteratorNext(itr)) ) {
51
52                 buffer_fadd( buf, 
53                         "sockid:    %d\n"
54                         "Remote:    %s\n"
55                         "State:     %d\n"
56                         "XMLState:  %d\n"
57                         "In Parse:  %d\n"
58                         "to:        %s\n"
59                         "Resource:  %s\n"
60                         "Username:  %s\n"
61                         "Domain:    %s\n"
62                         "Authkey:   %s\n"
63                         "type:          %d\n"
64                         "-------------------------------------------------------\n",
65                         node->sockid, node->remote, node->state, node->xmlstate, node->inparse,
66                         node->to, node->resource, node->username, node->domain, node->authkey, node->type );
67         }
68
69         debug_handler("DEBUG:\n%s", buf->buf );
70         buffer_free(buf);
71         osrfListIteratorFree(itr);
72 }
73
74 osrfChatServer* osrfNewChatServer( char* domain, char* secret, int s2sport ) {
75         if(!(domain && secret)) return NULL;
76
77         osrfChatServer* server = safe_malloc(sizeof(osrfChatServer));
78
79         server->nodeHash = osrfNewHash();
80         server->nodeList = osrfNewList();
81         server->deadNodes = osrfNewList();
82         server->nodeList->freeItem = &osrfChatNodeFree;
83         server->domain = strdup(domain);
84         server->s2sport = s2sport;
85
86         server->mgr = safe_malloc(sizeof(socket_manager));
87         server->mgr->data_received = &osrfChatHandleData;
88         server->mgr->blob = server;
89         server->mgr->on_socket_closed = &osrfChatSocketClosed;
90
91         if(secret) server->secret = strdup(secret);
92         return server;
93 }
94
95 void osrfChatCleanupClients( osrfChatServer* server ) {
96         if(server) {
97                 osrfListFree(server->deadNodes);
98                 server->deadNodes = osrfNewList();
99         }
100 }
101
102
103
104 osrfChatNode* osrfNewChatNode( int sockid, char* domain ) {
105         if(sockid < 1 || !domain) return NULL;
106         osrfChatNode* node      = safe_malloc(sizeof(osrfChatNode));
107         node->state                             = OSRF_CHAT_STATE_NONE;
108         node->msgs                              = NULL; /* only s2s nodes cache messages */
109         node->parserCtx         = xmlCreatePushParserCtxt(osrfChatSaxHandler, node, "", 0, NULL);
110         node->msgDoc                    = xmlNewDoc(BAD_CAST "1.0");
111         node->domain = strdup(domain);
112         xmlKeepBlanksDefault(0);
113         node->authkey                   = NULL;
114         node->username                  = NULL;
115         node->resource                  = NULL;
116         node->to                                        = NULL;
117         node->type = 0;
118         return node;
119 }
120
121
122 osrfChatNode* osrfNewChatS2SNode( char* domain, char* remote ) {
123         if(!(domain && remote)) return NULL;
124         osrfChatNode* n = osrfNewChatNode( 1, domain );
125         n->state                = OSRF_CHAT_STATE_S2S_CHALLENGE;
126         n->sockid       = -1;
127         n->remote       = strdup(remote);
128         n->msgs         = osrfNewList();
129         n->msgs->freeItem = &osrfChatS2SMessageFree;
130         n->type = 1;
131         return n;
132 }
133
134 void osrfChatS2SMessageFree(void* n) { free(n); }
135
136 void osrfChatNodeFree( void* node ) {
137         if(!node) return;
138         osrfChatNode* n = (osrfChatNode*) node;
139
140         /* we can't free messages that are mid-parse because the
141                 we can't free the parser context */
142         if(n->inparse) {
143                 n->inparse = 0;
144                 osrfListPush(n->parent->deadNodes, n);
145                 return;
146         }
147
148         free(n->remote);
149         free(n->to);
150         free(n->username);
151         free(n->resource);
152         free(n->domain);
153         free(n->authkey);
154
155         osrfListFree(n->msgs);
156
157         if(n->parserCtx) {
158                 xmlFreeDoc(n->parserCtx->myDoc);
159                 xmlFreeParserCtxt(n->parserCtx);
160         }
161
162         xmlFreeDoc(n->msgDoc);
163         free(n);
164 }
165
166
167
168 int osrfChatServerConnect( osrfChatServer* cs,  int port, int s2sport, char* listenAddr ) {
169         if(!(cs && port && listenAddr)) return -1;
170         cs->port = port;
171         cs->s2sport = s2sport;
172         if( socket_open_tcp_server(cs->mgr, port, listenAddr ) < 0 )
173                 return -1;
174         if( socket_open_tcp_server(cs->mgr, s2sport, listenAddr ) < 0 )
175                 return -1;
176         return 0;
177 }
178
179
180 int osrfChatServerWait( osrfChatServer* server ) {
181         if(!server) return -1;
182         while(1) {
183                 if(socket_wait_all(server->mgr, -1) < 0)
184                         warning_handler( "jserver_wait(): socket_wait_all() returned error");
185         }
186         return -1;
187 }
188
189
190 void osrfChatServerFree(osrfChatServer* server ) {
191         if(!server) return;
192         osrfHashFree(server->nodeHash);
193         osrfListFree(server->nodeList);
194         free(server->mgr);
195         free(server->secret);
196 }
197
198
199 void osrfChatHandleData( void* cs, 
200         socket_manager* mgr, int sockid, char* data, int parent_id ) {
201
202         if(!(cs && mgr && sockid && data)) return;
203
204         osrfChatServer* server = (osrfChatServer*) cs;
205
206         osrfChatNode* node = osrfListGetIndex( server->nodeList, sockid );
207
208         if(node)
209                 debug_handler("Found node for sockid %d with state %d", sockid, node->state);
210
211         if(!node) {
212                 debug_handler("Adding new connection for sockid %d", sockid );
213                 node = osrfChatAddNode( server, sockid );
214         }
215
216         if(node) {
217                 if( (osrfChatPushData( server, node, data ) == -1) ) {
218                         warning_handler("Node at socket %d received bad XML, disconnecting...", sockid );
219                         osrfChatSendRaw(  node, OSRF_CHAT_PARSE_ERROR );
220                         osrfChatRemoveNode( server, node );
221                 }
222         }
223
224         osrfChatCleanupClients(server); /* clean up old dead clients */
225 }
226
227
228 void osrfChatSocketClosed( void* blob, int sockid ) {
229         if(!blob) return;
230         osrfChatServer* server = (osrfChatServer*) blob;
231         osrfChatNode* node = osrfListGetIndex(server->nodeList, sockid);
232         osrfChatRemoveNode( server, node );
233 }
234
235 osrfChatNode* osrfChatAddNode( osrfChatServer* server, int sockid ) {
236         if(!(server && sockid)) return NULL;
237         osrfChatNode* node = osrfNewChatNode(sockid, server->domain);
238         node->parent = server;
239         node->sockid = sockid;
240         osrfListSet( server->nodeList, node, sockid );
241         return node;
242 }
243
244 void osrfChatRemoveNode( osrfChatServer* server, osrfChatNode* node ) {
245         if(!(server && node)) return;
246         socket_disconnect(server->mgr, node->sockid);
247         if(node->remote) 
248                 osrfHashRemove( server->nodeHash, node->remote );
249         osrfListRemove( server->nodeList, node->sockid ); /* this will free it */
250 }
251
252 int osrfChatSendRaw( osrfChatNode* node, char* msgXML ) {
253         if(!(node && msgXML)) return -1;
254         return socket_send( node->sockid, msgXML );
255 }
256
257
258
259
260 void osrfChatNodeFinish( osrfChatServer* server, osrfChatNode* node ) {
261         if(!(server && node)) return;
262         osrfChatSendRaw( node, "</stream:stream>");
263         osrfChatRemoveNode( server, node );
264 }
265
266
267 int osrfChatSend( osrfChatServer* cs, osrfChatNode* node, char* toAddr, char* fromAddr, char* msgXML ) {
268         if(!(cs && node && toAddr && msgXML)) return -1;
269
270         int l = strlen(toAddr);
271         char dombuf[l];
272         bzero(dombuf, l);
273         jid_get_domain( toAddr, dombuf, l );    
274
275         if( eq( dombuf, cs->domain ) ) { /* this is to a user we host */
276
277                 info_handler("Sending message on local connection\nfrom: %s\nto: %s", fromAddr, toAddr );
278                 osrfChatNode* tonode = osrfHashGet(cs->nodeHash, toAddr);
279                 if(tonode) {
280                         osrfChatSendRaw( tonode, msgXML );
281
282                 } else {
283
284                         /* send an error message saying we don't have this connection */
285                         warning_handler("We have no connection for %s", toAddr);
286                         char* xml = va_list_to_string( OSRF_CHAT_NO_RECIPIENT, toAddr, fromAddr );
287                         osrfChatSendRaw( node, xml );
288                         free(xml);
289                 }
290
291         } else {
292
293                 osrfChatNode* tonode = osrfHashGet(cs->nodeHash, dombuf);
294                 if(tonode) {
295                         if( tonode->state == OSRF_CHAT_STATE_CONNECTED ) {
296                                 debug_handler("Routing message to server %s", dombuf);
297                                 osrfChatSendRaw( tonode, msgXML );
298
299                         } else {
300                                 info_handler("Received s2s message and we're still trying to connect...caching");
301                                 osrfListPush( tonode->msgs, strdup(msgXML) );
302                         }
303
304                 } else {
305
306                         if( osrfChatInitS2S( cs, dombuf, toAddr, msgXML ) != 0 ) {
307                                 warning_handler("We are unable to connect to remote server %s for recipient %s", dombuf, toAddr);
308                                 char* xml = va_list_to_string( OSRF_CHAT_NO_RECIPIENT, toAddr, fromAddr );
309                                 osrfChatSendRaw( node, xml );
310                                 free(xml);
311                         }
312                 }
313         }
314
315         return 0;
316 }
317
318
319 /*
320 void osrfChatCacheS2SMessage( char* toAddr, char* msgXML, osrfChatNode* snode ) {
321         if(!(toAddr && msgXML)) return;
322         osrfChatS2SMessage* msg = safe_malloc(sizeof(osrfChatS2SMessage));
323         msg->toAddr = strdup(toAddr);
324         msg->msgXML = strdup(msgXML);
325         info_handler("Pushing client message onto s2s queue waiting for connect... ");
326         osrfListPush( snode->msgs, msgXML );
327 }
328 */
329
330
331 int osrfChatInitS2S( osrfChatServer* cs, char* remote, char* toAddr, char* msgXML ) {
332         if(!(cs && remote && toAddr && msgXML)) return -1;
333
334         info_handler("Initing server2server connection to domain %s", remote );
335         osrfChatNode* snode = osrfNewChatS2SNode( cs->domain, remote );
336         snode->parent = cs;
337
338         /* try to connect to the remote site */
339         snode->sockid = socket_open_tcp_client(cs->mgr, cs->s2sport, remote);
340         if(snode->sockid < 1) {
341                 warning_handler("Unable to connect to remote server at %s", remote );
342                 return -1;
343         }
344
345         /* store the message we were supposed to deliver until we're fully connected */
346         //osrfChatCacheS2SMessage( toAddr, msgXML, snode );
347         osrfListPush( snode->msgs, strdup(msgXML) );
348         osrfHashSet(cs->nodeHash, snode, remote );
349         osrfListSet(cs->nodeList, snode, snode->sockid );
350
351         /* send the initial s2s request */
352         osrfChatSendRaw( snode, OSRF_CHAT_S2S_INIT );
353
354         debug_handler("Added new s2s node...");
355         chatdbg(cs);
356
357         return 0;
358 }
359
360
361 /* commence SAX handling code */
362
363 int osrfChatPushData( osrfChatServer* server, osrfChatNode* node, char* data ) {
364         if(!(node && data)) return -1;
365
366         chatdbg(server);
367
368         debug_handler("pushing data into xml parser for node %d with state %d:\n%s", 
369                                                  node->sockid, node->state, data);
370         node->inparse = 1;
371         xmlParseChunk(node->parserCtx, data, strlen(data), 0);
372         node->inparse = 0;
373
374         if(__osrfChatXMLErrorOcurred) {
375                 __osrfChatXMLErrorOcurred = 0;
376                 return -1;
377         }
378
379         /* we can't do cleanup of the XML handlers while in the middle of a 
380                 data push, so set flags in the data push and doe the cleanup here */
381         /*
382         if(__osrfChatClientSentDisconnect) {
383                 __osrfChatClientSentDisconnect  = 0;
384                 osrfChatNodeFinish( server, node );
385         }
386         */
387
388         return 0;
389 }
390
391
392 void osrfChatStartStream( void* blob ) {
393         debug_handler("Starting new client stream...");
394 }
395
396
397 void osrfChatStartElement( void* blob, const xmlChar *name, const xmlChar **atts ) {
398         if(!(blob && name)) return;
399         osrfChatNode* node = (osrfChatNode*) blob;
400
401         int status = -1;
402         char* nm = (char*) name;
403
404         debug_handler("Starting element %s with namespace %s and node state %d", 
405                                                  nm, xmlSaxAttr(atts, "xmlns"), node->state );
406
407         switch( node->state ) {
408
409                 case OSRF_CHAT_STATE_NONE:
410                         status = osrfChatHandleNewConnection( node, nm, atts );
411                         debug_handler("After NewConnection we have state %d", node->state);
412                         break;
413
414                 case OSRF_CHAT_STATE_CONNECTING:
415                         status = osrfChatHandleConnecting( node, nm, atts );
416                         break;
417
418                 case OSRF_CHAT_STATE_CONNECTED:
419                         status = osrfChatHandleConnected( node, nm, atts );
420                         break;
421
422                 case OSRF_CHAT_STATE_S2S_CHALLENGE:      
423                         status = osrfChatHandleS2SChallenge( node, nm, atts );
424                         break;
425
426                 case OSRF_CHAT_STATE_S2S_RESPONSE: /* server waiting for client response to challenge */
427                         if(eq(nm, "db:result")) {
428                                 char* remote = xmlSaxAttr(atts, "from");
429                                 if(remote) node->remote = strdup(remote); /* copy off the client's id */
430                                 status = 0;
431                                 node->xmlstate |= OSRF_CHAT_STATE_INS2SRESULT;
432                         } else status = -1; 
433                         break;
434
435                 case OSRF_CHAT_STATE_S2S_VERIFY:        /* client : waiting for server verify message */
436                         if(eq(nm, "db:verify")) {
437                                 char* id = xmlSaxAttr( atts, "id" );
438                                 if(id) {
439                                         char* xml = va_list_to_string( OSRF_CHAT_S2S_VERIFY_RESPONSE, 
440                                                         node->remote, node->domain, id );
441                                         osrfChatSendRaw( node, xml );
442                                         free(xml);
443                                         node->state = OSRF_CHAT_STATE_S2S_VERIFY_FINAL;
444                                         status = 0;
445                                 }
446                         }
447                         break;
448
449                 case OSRF_CHAT_STATE_S2S_VERIFY_RESPONSE:       /* server waiting for client verify response */
450                 case OSRF_CHAT_STATE_S2S_VERIFY_FINAL: /* client waitig for final verify */
451                         status = osrfChatHandleS2SConnected( node, nm, atts );
452                         break;
453
454         }
455
456         if(status != 0) 
457                 osrfChatParseError( node, "We don't know how to handle the XML data received" );
458 }
459
460 #define CHAT_CHECK_VARS(x,y,z) if(!(x && y)) return -1; if(z) debug_handler(z);
461
462
463
464 int osrfChatHandleS2SConnected( osrfChatNode* node, const char* name, const xmlChar**atts ) {
465         CHAT_CHECK_VARS(node, name, "osrfChatHandleS2SConnected" );
466
467         int status = -1;
468
469         if(eq(name,"db:verify")) { /* server receives verify from client */
470                 char* xml = va_list_to_string(OSRF_CHAT_S2S_VERIFY_FINAL, node->domain, node->remote ); 
471                 osrfChatSendRaw(node, xml );
472                 free(xml);
473                 status = 0;
474         }
475
476         if(eq(name, "db:result")) {
477                 /* send all the messages that we have queued for this server */
478                 node->state = OSRF_CHAT_STATE_CONNECTED;
479                 osrfListIterator* itr = osrfNewListIterator(node->msgs);
480
481                 char* xml;
482                 while( (xml = (char*) osrfListIteratorNext(itr)) ) {
483                         xmlDocPtr doc = xmlParseMemory(xml, strlen(xml));
484                         if(doc) {
485                                 char* from = (char*) xmlGetProp(xmlDocGetRootElement(doc), BAD_CAST "from");
486                                 char* to = (char*) xmlGetProp(xmlDocGetRootElement(doc), BAD_CAST "to");
487                                 osrfChatSend( node->parent, node, to, from, xml );
488                                 debug_handler("Sending cached message from %s to %s", from, to);
489                                 xmlFree(to); xmlFree(from);
490                                 xmlFreeDoc(doc);
491                         }
492                 }
493
494                 osrfListIteratorFree(itr);
495                 osrfListFree(node->msgs);
496                 node->msgs = NULL;
497                 status = 0;
498         }
499
500         if(status == 0) {
501                 info_handler("Successfully made S2S connection to %s", node->remote );
502                 node->state = OSRF_CHAT_STATE_CONNECTED;
503                 node->xmlstate = 0;
504         }
505
506         return status;
507 }
508
509
510 /** check the namespace of the stream message to see if it's a server or client connection */
511 int osrfChatHandleNewConnection( osrfChatNode* node, const char* name, const xmlChar** atts ) {
512         CHAT_CHECK_VARS(node, name, "osrfChatHandleNewConnection()");
513
514         if(!eq(name, "stream:stream")) return -1;
515
516         node->authkey = osrfChatMkAuthKey();
517         char* ns = xmlSaxAttr(atts, "xmlns");
518         if(!ns) return -1;
519
520         if(eq(ns, "jabber:client")) { /* client connection */
521
522                 char* domain = xmlSaxAttr( atts, "to" );
523                 if(!domain) return -1; 
524         
525                 if(!eq(domain, node->domain)) {
526                         warning_handler("Client attempting to connect to invalid domain");
527                         return -1;
528                 }
529         
530                 char* buf = va_list_to_string( OSRF_CHAT_START_STREAM, domain, node->authkey );
531                 node->state = OSRF_CHAT_STATE_CONNECTING;
532
533                 debug_handler("Server node %d setting state to OSRF_CHAT_STATE_CONNECTING[%d]",
534                                                          node->sockid, node->state );
535         
536                 debug_handler("Server responding to connect message with\n%s\n", buf );
537                 osrfChatSendRaw( node, buf );
538                 free(buf);
539                 return 0;
540         }
541
542         /* server to server init */
543         if(eq(ns, "jabber:server")) { /* client connection */
544                 info_handler("We received a new server 2 server connection, generating auth key...");
545                 char* xml = va_list_to_string( OSRF_CHAT_S2S_CHALLENGE, node->authkey );
546                 osrfChatSendRaw( node, xml );
547                 free(xml);
548                 node->state = OSRF_CHAT_STATE_S2S_RESPONSE; /* the next message should be the response */
549                 node->type = 1;
550                 return 0;
551         }
552
553         return -1;
554 }
555
556
557
558 char* osrfChatMkAuthKey() {
559         char keybuf[112];
560         bzero(keybuf, 112);
561         snprintf(keybuf, 111, "%d%d%s", (int) time(NULL), getpid(), getenv("HOSTNAME"));
562         return strdup(shahash(keybuf));
563 }
564
565 int osrfChatHandleConnecting( osrfChatNode* node, const char* name, const xmlChar** atts ) {
566         CHAT_CHECK_VARS(node, name, "osrfChatHandleConnecting()");
567         debug_handler("Handling connect node %s", name );
568
569         if(eq(name, "iq")) node->xmlstate |= OSRF_CHAT_STATE_INIQ;
570         else if(eq(name,"username")) node->xmlstate |= OSRF_CHAT_STATE_INUSERNAME;
571         else if(eq(name,"resource")) node->xmlstate |= OSRF_CHAT_STATE_INRESOURCE;
572         return 0;
573 }
574
575 int osrfChatHandleConnected( osrfChatNode* node, const char* name, const xmlChar** atts ) {
576         CHAT_CHECK_VARS(node, name, "osrfChatHandleConnected()");
577
578         if(eq(name,"message")) {
579
580                 /* drop the old message and start with a new one */
581                 xmlNodePtr root = xmlNewNode(NULL, name);
582                 xmlAddAttrs(root, atts);
583                 xmlNodePtr oldRoot = xmlDocSetRootElement(node->msgDoc, root);
584                 free(node->to);
585
586                 char* to = xmlSaxAttr(atts, "to");
587                 if(!to) to = "";
588
589                 node->to = strdup(to);
590                 if(oldRoot) xmlFreeNode(oldRoot);
591                 node->xmlstate = OSRF_CHAT_STATE_INMESSAGE;
592
593         } else {
594
595                 /* all non "message" nodes are simply added to the message */
596                 xmlNodePtr nodep = xmlNewNode(NULL, name);
597                 xmlAddAttrs(nodep, atts);
598                 xmlAddChild(xmlDocGetRootElement(node->msgDoc), nodep);
599         }
600
601         return 0;
602 }
603
604 /* takes s2s secret, hashdomain, and the s2s auth token */
605 static char* osrfChatGenerateS2SKey( char* secret, char* hashdomain, char* authtoken ) {
606         if(!(secret && hashdomain && authtoken)) return NULL;
607         info_handler("Generating s2s key with auth token: %s", authtoken );
608         char* a = shahash(secret);
609         debug_handler("S2S secret hash: %s", a);
610         char* b = va_list_to_string("%s%s", a, hashdomain);
611         char* c = shahash(b);
612         debug_handler("S2S intermediate hash: %s", c);
613         char* d = va_list_to_string("%s%s", c, authtoken);
614         char* e = strdup(shahash(d));
615         free(b); free(d); 
616         return e;
617 }
618
619 int osrfChatHandleS2SChallenge( osrfChatNode* node, const char* name, const xmlChar** atts ) {
620         CHAT_CHECK_VARS(node, name, "osrfChatHandleS2SChallenge()");
621
622 /* here we respond to the stream challenge */
623         if(eq(name, "stream:stream")) {
624                 char* id = xmlSaxAttr(atts, "id");
625                 if(id) {
626                         /* we use our domain in the s2s challenge hash */
627                         char* d = osrfChatGenerateS2SKey(node->parent->secret, node->domain, id );
628                         char* e = va_list_to_string(OSRF_CHAT_S2S_RESPONSE, node->remote, node->domain, d );
629                         info_handler("Answering s2s challenge with key:  %s", e );
630                         osrfChatSendRaw( node, e );
631                         free(d); free(e);
632                         node->state = OSRF_CHAT_STATE_S2S_VERIFY;
633                         return 0;
634                 }
635         }
636
637         return -1;
638 }
639
640 /*
641 int osrfChatHandleS2SResponse( osrfChatNode* node, const char* name, const xmlChar** atts ) {
642         CHAT_CHECK_VARS(node, name, "osrfChatHandleS2SResponse()");
643
644         if(eq(name, "db:result")) {
645                 node->xmlstate |= OSRF_CHAT_STATE_INS2SRESULT;
646                 return 0;
647         }
648
649         return -1;
650 }
651 */
652
653
654
655 void osrfChatEndElement( void* blob, const xmlChar* name ) {
656         if(!(blob && name)) return;
657         osrfChatNode* node = (osrfChatNode*) blob;
658
659         char* nm = (char*) name;
660
661         if(eq(nm,"stream:stream")) {
662                 osrfChatNodeFinish( node->parent, node );
663                 return;
664         }
665
666         if( node->state == OSRF_CHAT_STATE_CONNECTED ) {
667                 if(eq(nm, "message")) {
668
669                         xmlNodePtr msg = xmlDocGetRootElement(node->msgDoc);
670                         if(msg && node->type == 0)
671                                 xmlSetProp(msg, BAD_CAST "from", BAD_CAST node->remote );
672                         char* string = xmlDocToString(node->msgDoc, 0 );
673
674                         char* from = (char*) xmlGetProp(msg, BAD_CAST "from");
675                         debug_handler( "Routing message to %s\n%s\n", node->to, from, string );
676                         osrfChatSend( node->parent, node, node->to, from, string ); 
677                         xmlFree(from);
678                         free(string);
679                 }
680         }
681
682         if( node->state == OSRF_CHAT_STATE_CONNECTING ) {
683                 if( node->xmlstate & OSRF_CHAT_STATE_INIQ ) {
684
685                         if(eq(nm, "iq")) {
686                                 node->xmlstate &= ~OSRF_CHAT_STATE_INIQ;
687                                 node->remote = va_list_to_string( 
688                                                 "%s@%s/%s", node->username, node->domain, node->resource );
689
690                                 info_handler("%s successfully logged in", node->remote );
691
692                                 debug_handler("Setting remote address to %s", node->remote );
693                                 osrfChatSendRaw( node, OSRF_CHAT_LOGIN_OK );
694                                 if(osrfHashGet( node->parent->nodeHash, node->remote ) ) {
695                                         warning_handler("New node replaces existing node for remote id %s", node->remote);
696                                         osrfHashRemove(node->parent->nodeHash, node->remote);
697                                 }
698                                 osrfHashSet( node->parent->nodeHash, node, node->remote );
699                                 node->state = OSRF_CHAT_STATE_CONNECTED;
700                         }
701                 }
702         }
703 }
704
705
706 void osrfChatHandleCharacter( void* blob, const xmlChar *ch, int len) {
707         if(!(blob && ch && len)) return;
708         osrfChatNode* node = (osrfChatNode*) blob;
709
710         /*
711         debug_handler("Char Handler: state %d, xmlstate %d, chardata %s", 
712                         node->state, node->xmlstate, (char*) ch );
713                         */
714
715         if( node->state == OSRF_CHAT_STATE_CONNECTING ) {
716                 if( node->xmlstate & OSRF_CHAT_STATE_INIQ ) {
717
718                         if( node->xmlstate & OSRF_CHAT_STATE_INUSERNAME ) {
719                                 free(node->username);
720                                 node->username = strndup((char*) ch, len);
721                                 node->xmlstate &= ~OSRF_CHAT_STATE_INUSERNAME;
722                         }
723
724                         if( node->xmlstate & OSRF_CHAT_STATE_INRESOURCE ) {
725                                 free(node->resource);
726                                 node->resource = strndup((char*) ch, len);
727                                 node->xmlstate &= ~OSRF_CHAT_STATE_INRESOURCE;
728                         }
729                 }
730
731                 return;
732         } 
733         
734         if( node->state == OSRF_CHAT_STATE_CONNECTED ) {
735                 xmlNodePtr last = xmlGetLastChild(xmlDocGetRootElement(node->msgDoc));
736                 xmlNodePtr txt = xmlNewTextLen(ch, len);
737                 xmlAddChild(last, txt);
738                 return;
739         }
740
741         if( node->state == OSRF_CHAT_STATE_S2S_RESPONSE &&
742                         (node->xmlstate & OSRF_CHAT_STATE_INS2SRESULT) ) {
743
744                 char* key = strndup((char*) ch, len);
745                 debug_handler("Got s2s key from %s : %s", node->remote, key );
746                 char* e = osrfChatGenerateS2SKey(node->parent->secret, node->remote, node->authkey );
747                 info_handler("\nReceived s2s key from server: %s\nKey should be: %s", key, e );
748
749                 if(eq(key, e)) {
750                         char* msg = va_list_to_string(OSRF_CHAT_S2S_VERIFY_REQUEST,  
751                                         node->authkey, node->domain, node->remote, e );
752                         osrfChatSendRaw(node, msg );
753                         free(msg);
754                         node->state = OSRF_CHAT_STATE_S2S_VERIFY_RESPONSE;
755                         node->xmlstate = 0;
756
757                 } else {
758                         warning_handler("Server2Server keys do not match!");
759                 }
760
761                 /* do the hash dance again */
762         }
763
764 }
765
766
767 void osrfChatParseError( void* blob, const char* msg, ... ) {
768
769         __osrfChatXMLErrorOcurred = 1;
770 }
771
772
773
774