]> git.evergreen-ils.org Git - OpenSRF.git/blob - src/libopensrf/transport_session.c
Fix a bug whereby, if there was only one <service> entry for the
[OpenSRF.git] / src / libopensrf / transport_session.c
1 #include <opensrf/transport_session.h>
2
3 // ---------------------------------------------------------------------------------
4 // Callback for handling the startElement event.  Much of the jabber logic occurs
5 // in this and the characterHandler callbacks.
6 // Here we check for the various top level jabber elements: body, iq, etc.
7 // ---------------------------------------------------------------------------------
8 static void startElementHandler( 
9                 void *session, const xmlChar *name, const xmlChar **atts);
10
11 // ---------------------------------------------------------------------------------
12 // Callback for handling the endElement event.  Updates the Jabber state machine
13 // to let us know the element is over.
14 // ---------------------------------------------------------------------------------
15 static void endElementHandler( void *session, const xmlChar *name);
16
17 // ---------------------------------------------------------------------------------
18 // This is where we extract XML text content.  In particular, this is useful for
19 // extracting Jabber message bodies.
20 // ---------------------------------------------------------------------------------
21 static void characterHandler(
22                 void *session, const xmlChar *ch, int len);
23
24 static void parseWarningHandler( void *session, const char* msg, ... );
25 static void parseErrorHandler( void *session, const char* msg, ... );
26
27 // ---------------------------------------------------------------------------------
28 // Tells the SAX parser which functions will be used as event callbacks
29 // ---------------------------------------------------------------------------------
30 static xmlSAXHandler SAXHandlerStruct = {
31    NULL,                                                        /* internalSubset */
32    NULL,                                                        /* isStandalone */
33    NULL,                                                        /* hasInternalSubset */
34    NULL,                                                        /* hasExternalSubset */
35    NULL,                                                        /* resolveEntity */
36    NULL,                                                        /* getEntity */
37    NULL,                                                        /* entityDecl */
38    NULL,                                                        /* notationDecl */
39    NULL,                                                        /* attributeDecl */
40    NULL,                                                        /* elementDecl */
41    NULL,                                                        /* unparsedEntityDecl */
42    NULL,                                                        /* setDocumentLocator */
43    NULL,                                                        /* startDocument */
44    NULL,                                                        /* endDocument */
45    startElementHandler,         /* startElement */
46    endElementHandler,           /* endElement */
47    NULL,                                                        /* reference */
48    characterHandler,                    /* characters */
49    NULL,                                                        /* ignorableWhitespace */
50    NULL,                                                        /* processingInstruction */
51    NULL,                                                        /* comment */
52    parseWarningHandler,         /* xmlParserWarning */
53    parseErrorHandler,           /* xmlParserError */
54    NULL,                                                        /* xmlParserFatalError : unused */
55    NULL,                                                        /* getParameterEntity */
56    NULL,                                                        /* cdataBlock; */
57    NULL,                                                        /* externalSubset; */
58    1,
59    NULL,
60    NULL,                                                        /* startElementNs */
61    NULL,                                                        /* endElementNs */
62    NULL                                                 /* xmlStructuredErrorFunc */
63 };
64
65 // ---------------------------------------------------------------------------------
66 // Our SAX handler pointer.
67 // ---------------------------------------------------------------------------------
68 static const xmlSAXHandlerPtr SAXHandler = &SAXHandlerStruct;
69
70 #ifndef HOST_NAME_MAX
71 #define HOST_NAME_MAX 256
72 #endif
73
74 static void grab_incoming(void* blob, socket_manager* mgr, int sockid, char* data, int parent);
75 static int reset_session_buffers( transport_session* session );
76 static char* get_xml_attr( const xmlChar** atts, const char* attr_name );
77
78 // ---------------------------------------------------------------------------------
79 // returns a built and allocated transport_session object.
80 // This codes does no network activity, only memory initilization
81 // ---------------------------------------------------------------------------------
82 transport_session* init_transport(  const char* server, 
83         int port, const char* unix_path, void* user_data, int component ) {
84
85         /* create the session struct */
86         transport_session* session = 
87                 (transport_session*) safe_malloc( sizeof(transport_session) );
88
89         session->user_data = user_data;
90
91         session->component = component;
92
93         /* initialize the data buffers */
94         session->body_buffer                    = buffer_init( JABBER_BODY_BUFSIZE );
95         session->subject_buffer         = buffer_init( JABBER_SUBJECT_BUFSIZE );
96         session->thread_buffer          = buffer_init( JABBER_THREAD_BUFSIZE );
97         session->from_buffer                    = buffer_init( JABBER_JID_BUFSIZE );
98         session->status_buffer          = buffer_init( JABBER_STATUS_BUFSIZE );
99         session->recipient_buffer       = buffer_init( JABBER_JID_BUFSIZE );
100         session->message_error_type = buffer_init( JABBER_JID_BUFSIZE );
101         session->session_id                     = buffer_init( 64 );
102
103         session->message_error_code = 0;
104
105         /* for OpenSRF extensions */
106         session->router_to_buffer               = buffer_init( JABBER_JID_BUFSIZE );
107         session->router_from_buffer     = buffer_init( JABBER_JID_BUFSIZE );
108         session->osrf_xid_buffer        = buffer_init( JABBER_JID_BUFSIZE );
109         session->router_class_buffer    = buffer_init( JABBER_JID_BUFSIZE );
110         session->router_command_buffer  = buffer_init( JABBER_JID_BUFSIZE );
111
112         session->router_broadcast   = 0;
113
114         /* initialize the jabber state machine */
115         session->state_machine = (jabber_machine*) safe_malloc( sizeof(jabber_machine) );
116         session->state_machine->connected        = 0;
117         session->state_machine->connecting       = 0;
118         session->state_machine->in_message       = 0;
119         session->state_machine->in_message_body  = 0;
120         session->state_machine->in_thread        = 0;
121         session->state_machine->in_subject       = 0;
122         session->state_machine->in_error         = 0;
123         session->state_machine->in_message_error = 0;
124         session->state_machine->in_iq            = 0;
125         session->state_machine->in_presence      = 0;
126         session->state_machine->in_status        = 0;
127
128         /* initialize the sax push parser */
129         session->parser_ctxt = xmlCreatePushParserCtxt(SAXHandler, session, "", 0, NULL);
130
131         /* initialize the transport_socket structure */
132         session->sock_mgr = (socket_manager*) safe_malloc( sizeof(socket_manager) );
133
134         session->sock_mgr->data_received = &grab_incoming;
135         session->sock_mgr->on_socket_closed = NULL;
136         session->sock_mgr->socket = NULL;
137         session->sock_mgr->blob = session;
138         
139         session->port = port;
140         session->server = strdup(server);
141         if(unix_path)   
142                 session->unix_path = strdup(unix_path);
143         else session->unix_path = NULL;
144
145         session->sock_id = 0;
146         session->message_callback = NULL;
147
148         return session;
149 }
150
151
152
153 /* XXX FREE THE BUFFERS */
154 int session_free( transport_session* session ) {
155         if( ! session ) { return 0; }
156
157         if(session->sock_mgr)
158                 socket_manager_free(session->sock_mgr);
159
160         if( session->state_machine ) free( session->state_machine );
161         if( session->parser_ctxt) {
162                 xmlFreeDoc( session->parser_ctxt->myDoc );
163                 xmlFreeParserCtxt(session->parser_ctxt);
164         }
165
166         xmlCleanupCharEncodingHandlers();
167         xmlDictCleanup();
168         xmlCleanupParser();
169
170         buffer_free(session->body_buffer);
171         buffer_free(session->subject_buffer);
172         buffer_free(session->thread_buffer);
173         buffer_free(session->from_buffer);
174         buffer_free(session->recipient_buffer);
175         buffer_free(session->status_buffer);
176         buffer_free(session->message_error_type);
177         buffer_free(session->router_to_buffer);
178         buffer_free(session->router_from_buffer);
179         buffer_free(session->osrf_xid_buffer);
180         buffer_free(session->router_class_buffer);
181         buffer_free(session->router_command_buffer);
182         buffer_free(session->session_id);
183
184         free(session->server);
185         free(session->unix_path);
186
187         free( session );
188         return 1;
189 }
190
191
192 int session_wait( transport_session* session, int timeout ) {
193         if( ! session || ! session->sock_mgr ) {
194                 return 0;
195         }
196
197         int ret =  socket_wait( session->sock_mgr, timeout, session->sock_id );
198
199         if( ret ) {
200                 osrfLogDebug(OSRF_LOG_MARK, "socket_wait returned error code %d", ret);
201                 session->state_machine->connected = 0;
202         }
203         return ret;
204 }
205
206 int session_send_msg( 
207                 transport_session* session, transport_message* msg ) {
208
209         if( ! session ) { return -1; }
210
211         if( ! session->state_machine->connected ) {
212                 osrfLogWarning(OSRF_LOG_MARK, "State machine is not connected in send_msg()");
213                 return -1;
214         }
215
216         message_prepare_xml( msg );
217         return socket_send( session->sock_id, msg->msg_xml );
218
219 }
220
221
222 /* connects to server and connects to jabber */
223 int session_connect( transport_session* session, 
224                 const char* username, const char* password, 
225                 const char* resource, int connect_timeout, enum TRANSPORT_AUTH_TYPE auth_type ) {
226
227         int size1 = 0;
228         int size2 = 0;
229
230         if( ! session ) { 
231                 osrfLogWarning(OSRF_LOG_MARK,  "session is null in connect" );
232                 return 0; 
233         }
234
235
236         char* server = session->server;
237
238         if( ! session->sock_id ) {
239
240                 if(session->port > 0) {
241                         if( (session->sock_id = socket_open_tcp_client(
242                                 session->sock_mgr, session->port, session->server)) <= 0 ) 
243                         return 0;
244
245                 } else if(session->unix_path != NULL) {
246                         if( (session->sock_id = socket_open_unix_client(
247                                 session->sock_mgr, session->unix_path)) <= 0 ) 
248                         return 0;
249                 }
250                 else {
251                         osrfLogWarning( OSRF_LOG_MARK, "Can't open session: no port or unix path" );
252                         return 0;
253                 }
254         }
255
256         if( session->component ) {
257
258                 /* the first Jabber connect stanza */
259                 char our_hostname[HOST_NAME_MAX + 1] = "";
260                 gethostname(our_hostname, sizeof(our_hostname) );
261                 our_hostname[HOST_NAME_MAX] = '\0';
262                 size1 = 150 + strlen( server );
263                 char stanza1[ size1 ]; 
264                 snprintf( stanza1, sizeof(stanza1),
265                                 "<stream:stream version='1.0' xmlns:stream='http://etherx.jabber.org/streams' "
266                                 "xmlns='jabber:component:accept' to='%s' from='%s' xml:lang='en'>",
267                                 username, our_hostname );
268
269                 /* send the first stanze */
270                 session->state_machine->connecting = CONNECTING_1;
271
272                 if( socket_send( session->sock_id, stanza1 ) ) {
273                         osrfLogWarning(OSRF_LOG_MARK, "error sending");
274                         return 0;
275                 }
276         
277                 /* wait for reply */
278                 socket_wait(session->sock_mgr, connect_timeout, session->sock_id);
279         
280                 /* server acknowledges our existence, now see if we can login */
281                 if( session->state_machine->connecting == CONNECTING_2 ) {
282         
283                         int ss = session->session_id->n_used + strlen(password) + 5;
284                         char hashstuff[ss];
285                         snprintf( hashstuff, sizeof(hashstuff), "%s%s", session->session_id->buf, password );
286
287                         char* hash = shahash( hashstuff );
288                         size2 = 100 + strlen( hash );
289                         char stanza2[ size2 ];
290                         snprintf( stanza2, sizeof(stanza2), "<handshake>%s</handshake>", hash );
291         
292                         if( socket_send( session->sock_id, stanza2 )  ) {
293                                 osrfLogWarning(OSRF_LOG_MARK, "error sending");
294                                 return 0;
295                         }
296                 }
297
298         } else { /* we're not a component */
299
300                 /* the first Jabber connect stanza */
301                 size1 = 100 + strlen( server );
302                 char stanza1[ size1 ]; 
303                 snprintf( stanza1, sizeof(stanza1), 
304                                 "<stream:stream to='%s' xmlns='jabber:client' "
305                                 "xmlns:stream='http://etherx.jabber.org/streams'>",
306                         server );
307         
308
309                 /* send the first stanze */
310                 session->state_machine->connecting = CONNECTING_1;
311                 if( socket_send( session->sock_id, stanza1 ) ) {
312                         osrfLogWarning(OSRF_LOG_MARK, "error sending");
313                         return 0;
314                 }
315
316
317                 /* wait for reply */
318                 socket_wait( session->sock_mgr, connect_timeout, session->sock_id ); /* make the timeout smarter XXX */
319
320                 if( auth_type == AUTH_PLAIN ) {
321
322                         /* the second jabber connect stanza including login info*/
323                         size2 = 150 + strlen( username ) + strlen(password) + strlen(resource);
324                         char stanza2[ size2 ];
325                         snprintf( stanza2, sizeof(stanza2), 
326                                         "<iq id='123456789' type='set'><query xmlns='jabber:iq:auth'>"
327                                         "<username>%s</username><password>%s</password><resource>%s</resource></query></iq>",
328                                         username, password, resource );
329         
330                         /* server acknowledges our existence, now see if we can login */
331                         if( session->state_machine->connecting == CONNECTING_2 ) {
332                                 if( socket_send( session->sock_id, stanza2 )  ) {
333                                         osrfLogWarning(OSRF_LOG_MARK, "error sending");
334                                         return 0;
335                                 }
336                         }
337
338                 } else if( auth_type == AUTH_DIGEST ) {
339
340                         int ss = session->session_id->n_used + strlen(password) + 5;
341                         char hashstuff[ss];
342                         snprintf( hashstuff, sizeof(hashstuff), "%s%s", session->session_id->buf, password );
343
344                         char* hash = shahash( hashstuff );
345
346                         /* the second jabber connect stanza including login info*/
347                         size2 = 150 + strlen( hash ) + strlen(password) + strlen(resource);
348                         char stanza2[ size2 ];
349                         snprintf( stanza2, sizeof(stanza2), 
350                                         "<iq id='123456789' type='set'><query xmlns='jabber:iq:auth'>"
351                                         "<username>%s</username><digest>%s</digest><resource>%s</resource></query></iq>",
352                                         username, hash, resource );
353         
354                         /* server acknowledges our existence, now see if we can login */
355                         if( session->state_machine->connecting == CONNECTING_2 ) {
356                                 if( socket_send( session->sock_id, stanza2 )  ) {
357                                         osrfLogWarning(OSRF_LOG_MARK, "error sending");
358                                         return 0;
359                                 }
360                         }
361
362                 }
363
364         } // not component
365
366
367         /* wait for reply */
368         socket_wait( session->sock_mgr, connect_timeout, session->sock_id );
369
370         if( session->state_machine->connected ) {
371                 /* yar! */
372                 return 1;
373         }
374
375         return 0;
376 }
377
378 // ---------------------------------------------------------------------------------
379 // TCP data callback.  Takes data from the socket handler and pushes it directly
380 // into the push parser
381 // ---------------------------------------------------------------------------------
382 static void grab_incoming(void* blob, socket_manager* mgr, int sockid, char* data, int parent) {
383         transport_session* ses = (transport_session*) blob;
384         if( ! ses ) { return; }
385         xmlParseChunk(ses->parser_ctxt, data, strlen(data), 0);
386 }
387
388
389 static void startElementHandler(
390         void *session, const xmlChar *name, const xmlChar **atts) {
391
392         transport_session* ses = (transport_session*) session;
393         if( ! ses ) { return; }
394
395         
396         if( strcmp( (char*) name, "message" ) == 0 ) {
397                 ses->state_machine->in_message = 1;
398                 buffer_add( ses->from_buffer, get_xml_attr( atts, "from" ) );
399                 buffer_add( ses->recipient_buffer, get_xml_attr( atts, "to" ) );
400                 buffer_add( ses->router_from_buffer, get_xml_attr( atts, "router_from" ) );
401                 buffer_add( ses->osrf_xid_buffer, get_xml_attr( atts, "osrf_xid" ) );
402                 buffer_add( ses->router_to_buffer, get_xml_attr( atts, "router_to" ) );
403                 buffer_add( ses->router_class_buffer, get_xml_attr( atts, "router_class" ) );
404                 buffer_add( ses->router_command_buffer, get_xml_attr( atts, "router_command" ) );
405                 char* broadcast = get_xml_attr( atts, "broadcast" );
406                 if( broadcast )
407                         ses->router_broadcast = atoi( broadcast );
408
409                 return;
410         }
411
412         if( ses->state_machine->in_message ) {
413
414                 if( strcmp( (char*) name, "body" ) == 0 ) {
415                         ses->state_machine->in_message_body = 1;
416                         return;
417                 }
418         
419                 if( strcmp( (char*) name, "subject" ) == 0 ) {
420                         ses->state_machine->in_subject = 1;
421                         return;
422                 }
423         
424                 if( strcmp( (char*) name, "thread" ) == 0 ) {
425                         ses->state_machine->in_thread = 1;
426                         return;
427                 }
428
429         }
430
431         if( strcmp( (char*) name, "presence" ) == 0 ) {
432                 ses->state_machine->in_presence = 1;
433                 buffer_add( ses->from_buffer, get_xml_attr( atts, "from" ) );
434                 buffer_add( ses->recipient_buffer, get_xml_attr( atts, "to" ) );
435                 return;
436         }
437
438         if( strcmp( (char*) name, "status" ) == 0 ) {
439                 ses->state_machine->in_status = 1;
440                 return;
441         }
442
443
444         if( strcmp( (char*) name, "stream:error" ) == 0 ) {
445                 ses->state_machine->in_error = 1;
446                 ses->state_machine->connected = 0;
447                 osrfLogWarning(  OSRF_LOG_MARK, "Received <stream:error> message from Jabber server" );
448                 return;
449         }
450
451
452         /* first server response from a connect attempt */
453         if( strcmp( (char*) name, "stream:stream" ) == 0 ) {
454                 if( ses->state_machine->connecting == CONNECTING_1 ) {
455                         ses->state_machine->connecting = CONNECTING_2;
456                         buffer_add( ses->session_id, get_xml_attr(atts, "id") );
457                 }
458         }
459
460         if( strcmp( (char*) name, "handshake" ) == 0 ) {
461                 ses->state_machine->connected = 1;
462                 ses->state_machine->connecting = 0;
463                 return;
464         }
465
466
467         if( strcmp( (char*) name, "error" ) == 0 ) {
468                 ses->state_machine->in_message_error = 1;
469                 buffer_add( ses->message_error_type, get_xml_attr( atts, "type" ) );
470                 ses->message_error_code = atoi( get_xml_attr( atts, "code" ) );
471                 osrfLogInfo( OSRF_LOG_MARK,  "Received <error> message with type %s and code %s", 
472                         get_xml_attr( atts, "type"), get_xml_attr( atts, "code") );
473                 return;
474         }
475
476         if( strcmp( (char*) name, "iq" ) == 0 ) {
477                 ses->state_machine->in_iq = 1;
478
479                 if( strcmp( get_xml_attr(atts, "type"), "result") == 0 
480                                 && ses->state_machine->connecting == CONNECTING_2 ) {
481                         ses->state_machine->connected = 1;
482                         ses->state_machine->connecting = 0;
483                         return;
484                 }
485
486                 if( strcmp( get_xml_attr(atts, "type"), "error") == 0 ) {
487                         osrfLogWarning( OSRF_LOG_MARK,  "Error connecting to jabber" );
488                         return;
489                 }
490         }
491 }
492
493 // ------------------------------------------------------------------
494 // Returns the value of the given XML attribute
495 // The xmlChar** construct is commonly returned from SAX event
496 // handlers.  Pass that in with the name of the attribute you want
497 // to retrieve.
498 // ------------------------------------------------------------------
499 static char* get_xml_attr( const xmlChar** atts, const char* attr_name ) {
500         int i;
501         if (atts != NULL) {
502                 for(i = 0;(atts[i] != NULL);i++) {
503                         if( strcmp( (char*) atts[i++], attr_name ) == 0 ) {
504                                 if( atts[i] != NULL ) {
505                                         return (char*) atts[i];
506                                 }
507                         }
508                 }
509         }
510         return NULL;
511 }
512
513
514 // ------------------------------------------------------------------
515 // See which tags are ending
516 // ------------------------------------------------------------------
517 static void endElementHandler( void *session, const xmlChar *name) {
518         transport_session* ses = (transport_session*) session;
519         if( ! ses ) { return; }
520
521         if( strcmp( (char*) name, "message" ) == 0 ) {
522
523
524                 /* pass off the message info the callback */
525                 if( ses->message_callback ) {
526
527                         /* here it's ok to pass in the raw buffers because
528                                 message_init allocates new space for the chars 
529                                 passed in */
530                         transport_message* msg =  message_init( 
531                                 ses->body_buffer->buf, 
532                                 ses->subject_buffer->buf,
533                                 ses->thread_buffer->buf, 
534                                 ses->recipient_buffer->buf, 
535                                 ses->from_buffer->buf );
536
537                         message_set_router_info( msg, 
538                                 ses->router_from_buffer->buf, 
539                                 ses->router_to_buffer->buf, 
540                                 ses->router_class_buffer->buf,
541                                 ses->router_command_buffer->buf,
542                                 ses->router_broadcast );
543
544          message_set_osrf_xid( msg, ses->osrf_xid_buffer->buf );
545
546                         if( ses->message_error_type->n_used > 0 ) {
547                                 set_msg_error( msg, ses->message_error_type->buf, ses->message_error_code );
548                         }
549
550                         if( msg == NULL ) { return; }
551                         ses->message_callback( ses->user_data, msg );
552                 }
553
554                 ses->state_machine->in_message = 0;
555                 reset_session_buffers( session );
556                 return;
557         }
558         
559         if( strcmp( (const char*) name, "body" ) == 0 ) {
560                 ses->state_machine->in_message_body = 0;
561                 return;
562         }
563
564         if( strcmp( (const char*) name, "subject" ) == 0 ) {
565                 ses->state_machine->in_subject = 0;
566                 return;
567         }
568
569         if( strcmp( (const char*) name, "thread" ) == 0 ) {
570                 ses->state_machine->in_thread = 0;
571                 return;
572         }
573         
574         if( strcmp( (const char*) name, "iq" ) == 0 ) {
575                 ses->state_machine->in_iq = 0;
576                 if( ses->message_error_code > 0 ) {
577                         osrfLogWarning( OSRF_LOG_MARK,  "Error in IQ packet: code %d",  ses->message_error_code );
578                         osrfLogWarning( OSRF_LOG_MARK,  "Error 401 means not authorized" );
579                 }
580                 reset_session_buffers( session );
581                 return;
582         }
583
584         if( strcmp( (const char*) name, "presence" ) == 0 ) {
585                 ses->state_machine->in_presence = 0;
586                 /*
587                 if( ses->presence_callback ) {
588                         // call the callback with the status, etc.
589                 }
590                 */
591                 reset_session_buffers( session );
592                 return;
593         }
594
595         if( strcmp( (const char*) name, "status" ) == 0 ) {
596                 ses->state_machine->in_status = 0;
597                 return;
598         }
599
600         if( strcmp( (const char*) name, "error" ) == 0 ) {
601                 ses->state_machine->in_message_error = 0;
602                 return;
603         }
604
605         if( strcmp( (const char*) name, "error:error" ) == 0 ) {
606                 ses->state_machine->in_error = 0;
607                 return;
608         }
609 }
610
611 static int reset_session_buffers( transport_session* ses ) {
612         buffer_reset( ses->body_buffer );
613         buffer_reset( ses->subject_buffer );
614         buffer_reset( ses->thread_buffer );
615         buffer_reset( ses->from_buffer );
616         buffer_reset( ses->recipient_buffer );
617         buffer_reset( ses->router_from_buffer );
618         buffer_reset( ses->osrf_xid_buffer );
619         buffer_reset( ses->router_to_buffer );
620         buffer_reset( ses->router_class_buffer );
621         buffer_reset( ses->router_command_buffer );
622         buffer_reset( ses->message_error_type );
623         buffer_reset( ses->session_id );
624
625         return 1;
626 }
627
628 // ------------------------------------------------------------------
629 // takes data out of the body of the message and pushes it into
630 // the appropriate buffer
631 // ------------------------------------------------------------------
632 static void characterHandler(
633                 void *session, const xmlChar *ch, int len) {
634
635         const char* p = (const char*) ch;
636
637         transport_session* ses = (transport_session*) session;
638         if( ! ses ) { return; }
639
640         /* set the various message parts */
641         if( ses->state_machine->in_message ) {
642
643                 if( ses->state_machine->in_message_body ) {
644                         buffer_add_n( ses->body_buffer, p, len );
645                 }
646
647                 if( ses->state_machine->in_subject ) {
648                         buffer_add_n( ses->subject_buffer, p, len );
649                 }
650
651                 if( ses->state_machine->in_thread ) {
652                         buffer_add_n( ses->thread_buffer, p, len );
653                 }
654         }
655
656         /* set the presence status */
657         if( ses->state_machine->in_presence && ses->state_machine->in_status ) {
658                 buffer_add_n( ses->status_buffer, p, len );
659         }
660
661         if( ses->state_machine->in_error ) {
662                 /* for now... */
663                 osrfLogWarning( OSRF_LOG_MARK,  "ERROR XML fragment: %s\n", ch );
664         }
665
666 }
667
668 /* XXX change to warning handlers */
669 static void  parseWarningHandler( void *session, const char* msg, ... ) {
670
671         va_list args;
672         va_start(args, msg);
673         fprintf(stdout, "transport_session XML WARNING");
674         vfprintf(stdout, msg, args);
675         va_end(args);
676         fprintf(stderr, "XML WARNING: %s\n", msg ); 
677 }
678
679 static void  parseErrorHandler( void *session, const char* msg, ... ){
680
681         va_list args;
682         va_start(args, msg);
683         fprintf(stdout, "transport_session XML ERROR");
684         vfprintf(stdout, msg, args);
685         va_end(args);
686         fprintf(stderr, "XML ERROR: %s\n", msg ); 
687
688 }
689
690 int session_disconnect( transport_session* session ) {
691         if( session == NULL ) { return 0; }
692         socket_send(session->sock_id, "</stream:stream>");
693         socket_disconnect(session->sock_mgr, session->sock_id);
694         return 0;
695 }
696