2 Copyright (C) 2005 Georgia Public Library Service
3 Bill Erickson <billserickson@gmail.com>
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.
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.
16 #include "osrf_chat.h"
21 static void osrfChatStartStream( void* blob );
22 static void osrfChatStartElement( void* blob, const xmlChar *name, const xmlChar **atts );
23 static void osrfChatEndElement( void* blob, const xmlChar* name );
24 static void osrfChatHandleCharacter(void* blob, const xmlChar *ch, int len);
25 static void osrfChatParseError( void* blob, const char* msg, ... );
27 static xmlSAXHandler osrfChatSaxHandlerStruct = {
28 NULL, /* internalSubset */
29 NULL, /* isStandalone */
30 NULL, /* hasInternalSubset */
31 NULL, /* hasExternalSubset */
32 NULL, /* resolveEntity */
34 NULL, /* entityDecl */
35 NULL, /* notationDecl */
36 NULL, /* attributeDecl */
37 NULL, /* elementDecl */
38 NULL, /* unparsedEntityDecl */
39 NULL, /* setDocumentLocator */
40 osrfChatStartStream, /* startDocument */
41 NULL, /* endDocument */
42 osrfChatStartElement, /* startElement */
43 osrfChatEndElement, /* endElement */
45 osrfChatHandleCharacter, /* characters */
46 NULL, /* ignorableWhitespace */
47 NULL, /* processingInstruction */
49 osrfChatParseError, /* xmlParserWarning */
50 osrfChatParseError, /* xmlParserError */
51 NULL, /* xmlParserFatalError : unused */
52 NULL, /* getParameterEntity */
53 NULL, /* cdataBlock; */
54 NULL, /* externalSubset; */
57 NULL, /* startElementNs */
58 NULL, /* endElementNs */
59 NULL /* xmlStructuredErrorFunc */
62 static const xmlSAXHandlerPtr osrfChatSaxHandler = &osrfChatSaxHandlerStruct;
65 #define HOST_NAME_MAX 256
68 static int osrfChatXMLErrorOcurred = 0;
70 /* This is used by code in osrfChatPushData, but that code is
71 currently commented out. Uncomment the next line if needed. */
72 //static int osrfChatClientSentDisconnect = 0;
74 /* shorter version of strcmp */
75 static int eq(const char* a, const char* b) { return (a && b && !strcmp(a,b)); }
76 //#define eq(a,b) ((a && b && !strcmp(a,b)) ? 1 : 0)
78 /* gnarly debug function */
79 static void chatdbg( osrfChatServer* server ) {
82 return; /* heavy logging, should only be used in heavy debug mode */
84 growing_buffer* buf = buffer_init(256);
86 buffer_add(buf, "---------------------------------------------------------------------\n");
91 "Named nodes in hash: %lu\n"
95 "-------------------------------------------------------\n",
96 osrfListGetCount(server->nodeList), osrfHashGetCount(server->nodeHash),
97 server->domain, server->port, server->s2sport );
99 osrfListIterator* itr = osrfNewListIterator(server->nodeList);
102 while( (node = osrfListIteratorNext(itr)) ) {
116 "-------------------------------------------------------\n",
117 node->sockid, node->remote, node->state, node->xmlstate, node->inparse,
118 node->to, node->resource, node->username, node->domain, node->authkey, node->type );
121 osrfLogDebug( OSRF_LOG_MARK, "DEBUG:\n%s", buf->buf );
123 osrfListIteratorFree(itr);
126 osrfChatServer* osrfNewChatServer( char* domain, char* secret, int s2sport ) {
127 if(!(domain && secret)) return NULL;
129 osrfChatServer* server = safe_malloc(sizeof(osrfChatServer));
131 server->nodeHash = osrfNewHash();
132 server->nodeList = osrfNewList();
133 server->deadNodes = osrfNewList();
134 server->nodeList->freeItem = &osrfChatNodeFree;
135 server->domain = strdup(domain);
136 server->secret = strdup(secret);
137 server->s2sport = s2sport;
140 // Build socket manager
141 server->mgr = safe_malloc(sizeof(socket_manager));
142 server->mgr->data_received = &osrfChatHandleData;
143 server->mgr->socket = NULL;
144 server->mgr->blob = server;
145 server->mgr->on_socket_closed = &osrfChatSocketClosed;
150 void osrfChatCleanupClients( osrfChatServer* server ) {
152 osrfListFree(server->deadNodes);
153 server->deadNodes = osrfNewList();
158 osrfChatNode* osrfNewChatNode( int sockid, char* domain ) {
159 if(sockid < 1 || !domain) return NULL;
160 osrfChatNode* node = safe_malloc(sizeof(osrfChatNode));
163 node->state = OSRF_CHAT_STATE_NONE;
166 node->msgs = NULL; /* only s2s nodes cache messages */
167 node->parserCtx = xmlCreatePushParserCtxt(osrfChatSaxHandler, node, "", 0, NULL);
168 node->msgDoc = xmlNewDoc(BAD_CAST "1.0");
169 node->domain = strdup(domain);
170 xmlKeepBlanksDefault(0);
171 node->authkey = NULL;
172 node->username = NULL;
173 node->resource = NULL;
181 osrfChatNode* osrfNewChatS2SNode( char* domain, char* remote ) {
182 if(!(domain && remote)) return NULL;
183 osrfChatNode* n = osrfNewChatNode( 1, domain );
184 n->state = OSRF_CHAT_STATE_S2S_CHALLENGE;
186 n->remote = strdup(remote);
187 n->msgs = osrfNewList();
188 n->msgs->freeItem = &osrfChatS2SMessageFree;
193 void osrfChatS2SMessageFree(void* n) { free(n); }
195 void osrfChatNodeFree( void* node ) {
197 osrfChatNode* n = (osrfChatNode*) node;
199 /* we can't free messages that are mid-parse because the
200 we can't free the parser context */
203 osrfListPush(n->parent->deadNodes, n);
214 osrfListFree(n->msgs);
217 xmlFreeDoc(n->parserCtx->myDoc);
218 xmlFreeParserCtxt(n->parserCtx);
221 xmlFreeDoc(n->msgDoc);
227 int osrfChatServerConnect( osrfChatServer* cs, int port, int s2sport, char* listenAddr ) {
228 if(!(cs && port && listenAddr)) return -1;
230 cs->s2sport = s2sport;
231 if( socket_open_tcp_server(cs->mgr, port, listenAddr ) < 0 )
233 if( socket_open_tcp_server(cs->mgr, s2sport, listenAddr ) < 0 )
239 int osrfChatServerWait( osrfChatServer* server ) {
240 if(!server) return -1;
242 if(socket_wait_all(server->mgr, -1) < 0)
243 osrfLogWarning( OSRF_LOG_MARK, "jserver_wait(): socket_wait_all() returned error");
249 void osrfChatServerFree(osrfChatServer* server ) {
251 osrfHashFree(server->nodeHash);
252 osrfListFree(server->nodeList);
253 osrfListFree(server->deadNodes);
254 socket_manager_free(server->mgr);
255 free(server->domain);
256 free(server->secret);
262 void osrfChatHandleData( void* cs,
263 socket_manager* mgr, int sockid, char* data, int parent_id ) {
265 if(!(cs && mgr && sockid && data)) return;
267 osrfChatServer* server = (osrfChatServer*) cs;
269 osrfChatNode* node = osrfListGetIndex( server->nodeList, sockid );
272 osrfLogDebug( OSRF_LOG_MARK, "Found node for sockid %d with state %d", sockid, node->state);
275 osrfLogDebug( OSRF_LOG_MARK, "Adding new connection for sockid %d", sockid );
276 node = osrfChatAddNode( server, sockid );
280 if( (osrfChatPushData( server, node, data ) == -1) ) {
281 osrfLogError( OSRF_LOG_MARK,
282 "Node at socket %d with remote address %s and destination %s, "
283 "received bad XML [%s], disconnecting...", sockid, node->remote, node->to, data );
284 osrfChatSendRaw( node, OSRF_CHAT_PARSE_ERROR );
285 osrfChatRemoveNode( server, node );
289 osrfChatCleanupClients(server); /* clean up old dead clients */
293 void osrfChatSocketClosed( void* blob, int sockid ) {
295 osrfChatServer* server = (osrfChatServer*) blob;
296 osrfChatNode* node = osrfListGetIndex(server->nodeList, sockid);
297 osrfChatRemoveNode( server, node );
300 osrfChatNode* osrfChatAddNode( osrfChatServer* server, int sockid ) {
301 if(!(server && sockid)) return NULL;
302 osrfChatNode* node = osrfNewChatNode(sockid, server->domain);
303 node->parent = server;
304 node->sockid = sockid;
305 osrfListSet( server->nodeList, node, sockid );
309 void osrfChatRemoveNode( osrfChatServer* server, osrfChatNode* node ) {
310 if(!(server && node)) return;
311 socket_disconnect(server->mgr, node->sockid);
313 osrfHashRemove( server->nodeHash, node->remote );
314 osrfListRemove( server->nodeList, node->sockid ); /* this will free it */
317 int osrfChatSendRaw( osrfChatNode* node, char* msgXML ) {
318 if(!(node && msgXML)) return -1;
319 /* wait at most 3 second for this client to take our data */
320 return socket_send_timeout( node->sockid, msgXML, 3000000 );
323 void osrfChatNodeFinish( osrfChatServer* server, osrfChatNode* node ) {
324 if(!(server && node)) return;
325 osrfChatSendRaw( node, "</stream:stream>");
326 osrfChatRemoveNode( server, node );
330 int osrfChatSend( osrfChatServer* cs, osrfChatNode* node, char* toAddr, char* fromAddr, char* msgXML ) {
331 if(!(cs && node && toAddr && msgXML)) return -1;
333 int l = strlen(toAddr);
335 memset(dombuf, 0, sizeof(dombuf));
336 jid_get_domain( toAddr, dombuf, l );
338 if( eq( dombuf, cs->domain ) ) { /* this is to a user we host */
340 osrfLogInfo( OSRF_LOG_MARK, "Sending message on local connection\nfrom: %s\nto: %s", fromAddr, toAddr );
341 osrfChatNode* tonode = osrfHashGet(cs->nodeHash, toAddr);
344 /* if we can't send to the recipient (recipient is gone or too busy,
345 * we drop the recipient and inform the sender that the recipient
347 if( osrfChatSendRaw( tonode, msgXML ) < 0 ) {
349 osrfChatRemoveNode( cs, tonode );
350 char* xml = va_list_to_string( OSRF_CHAT_NO_RECIPIENT, toAddr, fromAddr );
352 osrfLogError( OSRF_LOG_MARK, "Node failed to function. "
353 "Responding to caller with error: %s", toAddr);
356 if( osrfChatSendRaw( node, xml ) < 0 ) {
357 osrfLogError(OSRF_LOG_MARK, "Sending node is now gone..removing");
358 osrfChatRemoveNode( cs, node );
365 /* send an error message saying we don't have this connection */
366 osrfLogInfo( OSRF_LOG_MARK, "We have no connection for %s", toAddr);
367 char* xml = va_list_to_string( OSRF_CHAT_NO_RECIPIENT, toAddr, fromAddr );
368 if( osrfChatSendRaw( node, xml ) < 0 )
369 osrfChatRemoveNode( cs, node );
375 osrfChatNode* tonode = osrfHashGet(cs->nodeHash, dombuf);
377 if( tonode->state == OSRF_CHAT_STATE_CONNECTED ) {
378 osrfLogDebug( OSRF_LOG_MARK, "Routing message to server %s", dombuf);
380 if( osrfChatSendRaw( tonode, msgXML ) < 0 ) {
381 osrfLogError( OSRF_LOG_MARK, "Node failed to function: %s", toAddr);
382 char* xml = va_list_to_string( OSRF_CHAT_NO_RECIPIENT, toAddr, fromAddr );
383 if( osrfChatSendRaw( node, xml ) < 0 )
384 osrfChatRemoveNode( cs, node );
386 osrfChatRemoveNode( cs, tonode );
390 osrfLogInfo( OSRF_LOG_MARK, "Received s2s message and we're still trying to connect...caching");
391 osrfListPush( tonode->msgs, strdup(msgXML) );
396 if( osrfChatInitS2S( cs, dombuf, toAddr, msgXML ) != 0 ) {
397 osrfLogWarning( OSRF_LOG_MARK, "We are unable to connect to remote server %s for recipient %s", dombuf, toAddr);
398 char* xml = va_list_to_string( OSRF_CHAT_NO_RECIPIENT, toAddr, fromAddr );
399 osrfChatSendRaw( node, xml );
410 void osrfChatCacheS2SMessage( char* toAddr, char* msgXML, osrfChatNode* snode ) {
411 if(!(toAddr && msgXML)) return;
412 osrfChatS2SMessage* msg = safe_malloc(sizeof(osrfChatS2SMessage));
413 msg->toAddr = strdup(toAddr);
414 msg->msgXML = strdup(msgXML);
415 osrfLogInfo( OSRF_LOG_MARK, "Pushing client message onto s2s queue waiting for connect... ");
416 osrfListPush( snode->msgs, msgXML );
421 int osrfChatInitS2S( osrfChatServer* cs, char* remote, char* toAddr, char* msgXML ) {
422 if(!(cs && remote && toAddr && msgXML)) return -1;
424 osrfLogInfo( OSRF_LOG_MARK, "Initing server2server connection to domain %s", remote );
425 osrfChatNode* snode = osrfNewChatS2SNode( cs->domain, remote );
428 /* try to connect to the remote site */
429 snode->sockid = socket_open_tcp_client(cs->mgr, cs->s2sport, remote);
430 if(snode->sockid < 1) {
431 osrfLogWarning( OSRF_LOG_MARK, "Unable to connect to remote server at %s", remote );
432 osrfChatNodeFree( snode );
436 /* store the message we were supposed to deliver until we're fully connected */
437 //osrfChatCacheS2SMessage( toAddr, msgXML, snode );
438 osrfListPush( snode->msgs, strdup(msgXML) );
439 osrfHashSet(cs->nodeHash, snode, remote );
440 osrfListSet(cs->nodeList, snode, snode->sockid );
442 /* send the initial s2s request */
443 osrfChatSendRaw( snode, OSRF_CHAT_S2S_INIT );
445 osrfLogDebug( OSRF_LOG_MARK, "Added new s2s node...");
452 /* commence SAX handling code */
454 int osrfChatPushData( osrfChatServer* server, osrfChatNode* node, char* data ) {
455 if(!(node && data)) return -1;
459 osrfLogDebug( OSRF_LOG_MARK, "pushing data into xml parser for node %d with state %d:\n%s",
460 node->sockid, node->state, data);
462 xmlParseChunk(node->parserCtx, data, strlen(data), 0);
465 if(osrfChatXMLErrorOcurred) {
466 osrfChatXMLErrorOcurred = 0;
470 /* we can't do cleanup of the XML handlers while in the middle of a
471 data push, so set flags in the data push and doe the cleanup here */
473 if(osrfChatClientSentDisconnect) {
474 osrfChatClientSentDisconnect = 0;
475 osrfChatNodeFinish( server, node );
483 static void osrfChatStartStream( void* blob ) {
484 osrfLogDebug( OSRF_LOG_MARK, "Starting new client stream...");
488 static void osrfChatStartElement( void* blob, const xmlChar *name, const xmlChar **atts ) {
489 if(!(blob && name)) return;
490 osrfChatNode* node = (osrfChatNode*) blob;
493 char* nm = (char*) name;
495 osrfLogDebug( OSRF_LOG_MARK, "Starting element %s with namespace %s and node state %d",
496 nm, xmlSaxAttr(atts, "xmlns"), node->state );
498 switch( node->state ) {
500 case OSRF_CHAT_STATE_NONE:
501 status = osrfChatHandleNewConnection( node, nm, atts );
502 osrfLogDebug( OSRF_LOG_MARK, "After NewConnection we have state %d", node->state);
505 case OSRF_CHAT_STATE_CONNECTING:
506 status = osrfChatHandleConnecting( node, nm, atts );
509 case OSRF_CHAT_STATE_CONNECTED:
510 status = osrfChatHandleConnected( node, nm, atts );
513 case OSRF_CHAT_STATE_S2S_CHALLENGE:
514 status = osrfChatHandleS2SChallenge( node, nm, atts );
517 case OSRF_CHAT_STATE_S2S_RESPONSE: /* server waiting for client response to challenge */
518 if(eq(nm, "db:result")) {
519 char* remote = xmlSaxAttr(atts, "from");
521 if( node->remote) free( node->remote );
522 node->remote = strdup(remote); /* copy off the client's id */
525 node->xmlstate |= OSRF_CHAT_STATE_INS2SRESULT;
529 case OSRF_CHAT_STATE_S2S_VERIFY: /* client : waiting for server verify message */
530 if(eq(nm, "db:verify")) {
531 char* id = xmlSaxAttr( atts, "id" );
533 char* xml = va_list_to_string( OSRF_CHAT_S2S_VERIFY_RESPONSE,
534 node->remote, node->domain, id );
535 osrfChatSendRaw( node, xml );
537 node->state = OSRF_CHAT_STATE_S2S_VERIFY_FINAL;
543 case OSRF_CHAT_STATE_S2S_VERIFY_RESPONSE: /* server waiting for client verify response */
544 case OSRF_CHAT_STATE_S2S_VERIFY_FINAL: /* client waitig for final verify */
545 status = osrfChatHandleS2SConnected( node, nm, atts );
551 osrfChatParseError( node, "We don't know how to handle the XML data received" );
554 #define CHAT_CHECK_VARS(x,y,z) if(!(x && y)) return -1; if(z) osrfLogDebug( OSRF_LOG_MARK, z);
558 int osrfChatHandleS2SConnected( osrfChatNode* node, const char* name, const xmlChar**atts ) {
559 CHAT_CHECK_VARS(node, name, "osrfChatHandleS2SConnected" );
563 if(eq(name,"db:verify")) { /* server receives verify from client */
564 char* xml = va_list_to_string(OSRF_CHAT_S2S_VERIFY_FINAL, node->domain, node->remote );
565 osrfChatSendRaw(node, xml );
570 if(eq(name, "db:result")) {
571 /* send all the messages that we have queued for this server */
572 node->state = OSRF_CHAT_STATE_CONNECTED;
573 osrfListIterator* itr = osrfNewListIterator(node->msgs);
576 while( (xml = (char*) osrfListIteratorNext(itr)) ) {
577 xmlDocPtr doc = xmlParseMemory(xml, strlen(xml));
579 char* from = (char*) xmlGetProp(xmlDocGetRootElement(doc), BAD_CAST "from");
580 char* to = (char*) xmlGetProp(xmlDocGetRootElement(doc), BAD_CAST "to");
581 osrfChatSend( node->parent, node, to, from, xml );
582 osrfLogDebug( OSRF_LOG_MARK, "Sending cached message from %s to %s", from, to);
583 xmlFree(to); xmlFree(from);
588 osrfListIteratorFree(itr);
589 osrfListFree(node->msgs);
595 osrfLogInfo( OSRF_LOG_MARK, "Successfully made S2S connection to %s", node->remote );
596 node->state = OSRF_CHAT_STATE_CONNECTED;
604 /** check the namespace of the stream message to see if it's a server or client connection */
605 int osrfChatHandleNewConnection( osrfChatNode* node, const char* name, const xmlChar** atts ) {
606 CHAT_CHECK_VARS(node, name, "osrfChatHandleNewConnection()");
608 if(!eq(name, "stream:stream")) return -1;
610 if( node->authkey ) free( node->authkey );
611 node->authkey = osrfChatMkAuthKey();
612 char* ns = xmlSaxAttr(atts, "xmlns");
615 if(eq(ns, "jabber:client")) { /* client connection */
617 char* domain = xmlSaxAttr( atts, "to" );
618 if(!domain) return -1;
620 if(!eq(domain, node->domain)) {
621 osrfLogWarning( OSRF_LOG_MARK,
622 "Client attempting to connect to invalid domain %s. Our domain is %s", domain, node->domain);
626 char* buf = va_list_to_string( OSRF_CHAT_START_STREAM, domain, node->authkey );
627 node->state = OSRF_CHAT_STATE_CONNECTING;
629 osrfLogDebug( OSRF_LOG_MARK, "Server node %d setting state to OSRF_CHAT_STATE_CONNECTING[%d]",
630 node->sockid, node->state );
632 osrfLogDebug( OSRF_LOG_MARK, "Server responding to connect message with\n%s\n", buf );
633 osrfChatSendRaw( node, buf );
638 /* server to server init */
639 if(eq(ns, "jabber:server")) { /* client connection */
640 osrfLogInfo( OSRF_LOG_MARK, "We received a new server 2 server connection, generating auth key...");
641 char* xml = va_list_to_string( OSRF_CHAT_S2S_CHALLENGE, node->authkey );
642 osrfChatSendRaw( node, xml );
644 node->state = OSRF_CHAT_STATE_S2S_RESPONSE; /* the next message should be the response */
654 char* osrfChatMkAuthKey() {
655 char hostname[HOST_NAME_MAX + 1] = "";
656 gethostname(hostname, sizeof(hostname) );
657 hostname[HOST_NAME_MAX] = '\0';
659 snprintf(keybuf, sizeof(keybuf), "%d%ld%s", (int) time(NULL), (long) getpid(), hostname);
660 return strdup(shahash(keybuf));
663 int osrfChatHandleConnecting( osrfChatNode* node, const char* name, const xmlChar** atts ) {
664 CHAT_CHECK_VARS(node, name, "osrfChatHandleConnecting()");
665 osrfLogDebug( OSRF_LOG_MARK, "Handling connect node %s", name );
667 if(eq(name, "iq")) node->xmlstate |= OSRF_CHAT_STATE_INIQ;
668 else if(eq(name,"username")) node->xmlstate |= OSRF_CHAT_STATE_INUSERNAME;
669 else if(eq(name,"resource")) node->xmlstate |= OSRF_CHAT_STATE_INRESOURCE;
673 int osrfChatHandleConnected( osrfChatNode* node, const char* name, const xmlChar** atts ) {
674 CHAT_CHECK_VARS(node, name, "osrfChatHandleConnected()");
676 if(eq(name,"message")) {
678 /* drop the old message and start with a new one */
679 xmlNodePtr root = xmlNewNode(NULL, BAD_CAST name);
680 xmlAddAttrs(root, atts);
681 xmlNodePtr oldRoot = xmlDocSetRootElement(node->msgDoc, root);
684 char* to = xmlSaxAttr(atts, "to");
687 node->to = strdup(to);
688 if(oldRoot) xmlFreeNode(oldRoot);
689 node->xmlstate = OSRF_CHAT_STATE_INMESSAGE;
693 /* all non "message" nodes are simply added to the message */
694 xmlNodePtr nodep = xmlNewNode(NULL, BAD_CAST name);
695 xmlAddAttrs(nodep, atts);
696 xmlAddChild(xmlDocGetRootElement(node->msgDoc), nodep);
702 /* takes s2s secret, hashdomain, and the s2s auth token */
703 static char* osrfChatGenerateS2SKey( char* secret, char* hashdomain, char* authtoken ) {
704 if(!(secret && hashdomain && authtoken)) return NULL;
705 osrfLogInfo( OSRF_LOG_MARK, "Generating s2s key with auth token: %s", authtoken );
706 char* a = shahash(secret);
707 osrfLogDebug( OSRF_LOG_MARK, "S2S secret hash: %s", a);
708 char* b = va_list_to_string("%s%s", a, hashdomain);
709 char* c = shahash(b);
710 osrfLogDebug( OSRF_LOG_MARK, "S2S intermediate hash: %s", c);
711 char* d = va_list_to_string("%s%s", c, authtoken);
712 char* e = strdup(shahash(d));
717 int osrfChatHandleS2SChallenge( osrfChatNode* node, const char* name, const xmlChar** atts ) {
718 CHAT_CHECK_VARS(node, name, "osrfChatHandleS2SChallenge()");
720 /* here we respond to the stream challenge */
721 if(eq(name, "stream:stream")) {
722 char* id = xmlSaxAttr(atts, "id");
724 /* we use our domain in the s2s challenge hash */
725 char* d = osrfChatGenerateS2SKey(node->parent->secret, node->domain, id );
726 char* e = va_list_to_string(OSRF_CHAT_S2S_RESPONSE, node->remote, node->domain, d );
727 osrfLogInfo( OSRF_LOG_MARK, "Answering s2s challenge with key: %s", e );
728 osrfChatSendRaw( node, e );
730 node->state = OSRF_CHAT_STATE_S2S_VERIFY;
739 int osrfChatHandleS2SResponse( osrfChatNode* node, const char* name, const xmlChar** atts ) {
740 CHAT_CHECK_VARS(node, name, "osrfChatHandleS2SResponse()");
742 if(eq(name, "db:result")) {
743 node->xmlstate |= OSRF_CHAT_STATE_INS2SRESULT;
753 static void osrfChatEndElement( void* blob, const xmlChar* name ) {
754 if(!(blob && name)) return;
755 osrfChatNode* node = (osrfChatNode*) blob;
757 char* nm = (char*) name;
759 if(eq(nm,"stream:stream")) {
760 osrfChatNodeFinish( node->parent, node );
764 if( node->state == OSRF_CHAT_STATE_CONNECTED ) {
765 if(eq(nm, "message")) {
767 xmlNodePtr msg = xmlDocGetRootElement(node->msgDoc);
768 if(msg && node->type == 0)
769 xmlSetProp(msg, BAD_CAST "from", BAD_CAST node->remote );
770 char* string = xmlDocToString(node->msgDoc, 0 );
772 char* from = (char*) xmlGetProp(msg, BAD_CAST "from");
773 osrfLogDebug( OSRF_LOG_MARK, "Routing message to %s\n%s\n", node->to, from, string );
774 osrfChatSend( node->parent, node, node->to, from, string );
780 if( node->state == OSRF_CHAT_STATE_CONNECTING ) {
781 if( node->xmlstate & OSRF_CHAT_STATE_INIQ ) {
784 node->xmlstate &= ~OSRF_CHAT_STATE_INIQ;
785 if( node->remote ) free( node->remote );
786 node->remote = va_list_to_string(
787 "%s@%s/%s", node->username, node->domain, node->resource );
789 osrfLogInfo( OSRF_LOG_MARK, "%s successfully logged in", node->remote );
791 osrfLogDebug( OSRF_LOG_MARK, "Setting remote address to %s", node->remote );
792 osrfChatSendRaw( node, OSRF_CHAT_LOGIN_OK );
793 if(osrfHashGet( node->parent->nodeHash, node->remote ) ) {
794 osrfLogWarning( OSRF_LOG_MARK, "New node replaces existing node for remote id %s", node->remote);
795 osrfHashRemove(node->parent->nodeHash, node->remote);
797 osrfHashSet( node->parent->nodeHash, node, node->remote );
798 node->state = OSRF_CHAT_STATE_CONNECTED;
805 static void osrfChatHandleCharacter( void* blob, const xmlChar *ch, int len) {
806 if(!(blob && ch && len)) return;
807 osrfChatNode* node = (osrfChatNode*) blob;
810 osrfLogDebug( OSRF_LOG_MARK, "Char Handler: state %d, xmlstate %d, chardata %s",
811 node->state, node->xmlstate, (char*) ch );
814 if( node->state == OSRF_CHAT_STATE_CONNECTING ) {
815 if( node->xmlstate & OSRF_CHAT_STATE_INIQ ) {
817 if( node->xmlstate & OSRF_CHAT_STATE_INUSERNAME ) {
818 free(node->username);
819 node->username = strndup((char*) ch, len);
820 node->xmlstate &= ~OSRF_CHAT_STATE_INUSERNAME;
823 if( node->xmlstate & OSRF_CHAT_STATE_INRESOURCE ) {
824 free(node->resource);
825 node->resource = strndup((char*) ch, len);
826 node->xmlstate &= ~OSRF_CHAT_STATE_INRESOURCE;
833 if( node->state == OSRF_CHAT_STATE_CONNECTED ) {
834 xmlNodePtr last = xmlGetLastChild(xmlDocGetRootElement(node->msgDoc));
835 xmlNodePtr txt = xmlNewTextLen(ch, len);
836 xmlAddChild(last, txt);
840 if( node->state == OSRF_CHAT_STATE_S2S_RESPONSE &&
841 (node->xmlstate & OSRF_CHAT_STATE_INS2SRESULT) ) {
843 char* key = strndup((char*) ch, len);
844 osrfLogDebug( OSRF_LOG_MARK, "Got s2s key from %s : %s", node->remote, key );
845 char* e = osrfChatGenerateS2SKey(node->parent->secret, node->remote, node->authkey );
846 osrfLogInfo( OSRF_LOG_MARK, "\nReceived s2s key from server: %s\nKey should be: %s", key, e );
849 char* msg = va_list_to_string(OSRF_CHAT_S2S_VERIFY_REQUEST,
850 node->authkey, node->domain, node->remote, e );
851 osrfChatSendRaw(node, msg );
853 node->state = OSRF_CHAT_STATE_S2S_VERIFY_RESPONSE;
857 osrfLogWarning( OSRF_LOG_MARK, "Server2Server keys do not match!");
863 /* do the hash dance again */
868 static void osrfChatParseError( void* blob, const char* msg, ... ) {
870 osrfChatXMLErrorOcurred = 1;