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