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