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