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