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