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