loudmouth/src/lm-connection.c
changeset 10 59927b2d3b75
parent 0 d0f3a028347a
equal deleted inserted replaced
0:d0f3a028347a 10:59927b2d3b75
     1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
       
     2 /*
       
     3  * Copyright (C) 2003-2007 Imendio AB
       
     4  *  and/or its subsidiary/subsidiaries. All rights reserved.
       
     5  * Copyright (C) 2007 Collabora Ltd.
       
     6  *
       
     7  * This program is free software; you can redistribute it and/or
       
     8  * modify it under the terms of the GNU Lesser General Public License as
       
     9  * published by the Free Software Foundation; either version 2 of the
       
    10  * License, or (at your option) any later version.
       
    11  *
       
    12  * This program is distributed in the hope that it will be useful,
       
    13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    15  * Lesser General Public License for more details.
       
    16  *
       
    17  * You should have received a copy of the GNU Lesser General Public
       
    18  * License along with this program; if not, write to the
       
    19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
       
    20  * Boston, MA 02111-1307, USA.
       
    21  */
       
    22 
       
    23 #include <config.h>
       
    24 
       
    25 #include <string.h>
       
    26 #include <sys/stat.h> 
       
    27 #include <sys/types.h>
       
    28 #include <fcntl.h>
       
    29 
       
    30 /* Needed on Mac OS X */
       
    31 #if HAVE_NETINET_IN_H
       
    32 #include <netinet/in.h>
       
    33 #endif
       
    34 
       
    35 #include <arpa/nameser.h>
       
    36 //#include <resolv.h>
       
    37 
       
    38 #include <glib.h>
       
    39 #include <gdebug.h>
       
    40 
       
    41 #include "lm-sock.h"
       
    42 #include "lm-debug.h"
       
    43 #include "lm-error.h"
       
    44 #include "lm-internals.h"
       
    45 #include "lm-message-queue.h"
       
    46 #include "lm-misc.h"
       
    47 #include "lm-ssl-internals.h"
       
    48 #include "lm-parser.h"
       
    49 #include "lm-sha.h"
       
    50 #include "lm-connection.h"
       
    51 #include "lm-utils.h"
       
    52 #include "lm-socket.h"
       
    53 #include "lm-sasl.h"
       
    54 
       
    55 #define IN_BUFFER_SIZE 1024
       
    56 //#define SRV_LEN 8192
       
    57 #define SRV_LEN 2048 // check the actual value needed here! - MeCo
       
    58 
       
    59 typedef struct {
       
    60 	LmHandlerPriority  priority;
       
    61 	LmMessageHandler  *handler;
       
    62 } HandlerData;
       
    63 
       
    64 struct _LmConnection {
       
    65 	/* Parameters */
       
    66 	GMainContext *context;
       
    67 	gchar        *server;
       
    68 	gchar        *jid;
       
    69 	gchar        *effective_jid;
       
    70 	guint         port;
       
    71 	gboolean      use_srv;
       
    72 
       
    73 	LmSocket     *socket;
       
    74 	LmSSL        *ssl;
       
    75 	LmProxy      *proxy;
       
    76 	LmParser     *parser;
       
    77 
       
    78 	gchar        *stream_id;
       
    79 
       
    80 	GHashTable   *id_handlers;
       
    81 	GSList       *handlers[LM_MESSAGE_TYPE_UNKNOWN];
       
    82 
       
    83 	/* XMPP1.0 stuff (SASL, resource binding, StartTLS) */
       
    84 	gboolean      use_sasl;
       
    85 	LmSASL       *sasl;
       
    86 	gchar        *resource;
       
    87 	LmMessageHandler *features_cb;
       
    88 	LmMessageHandler *starttls_cb;
       
    89 	gboolean      tls_started;
       
    90 
       
    91 	/* Communication */
       
    92 	guint         open_id;
       
    93 	LmCallback   *open_cb;
       
    94 
       
    95  	gboolean      async_connect_waiting;
       
    96 	gboolean      blocking;
       
    97 
       
    98 	gboolean      cancel_open;
       
    99 	LmCallback   *auth_cb;
       
   100 
       
   101 	LmCallback   *disconnect_cb;
       
   102 
       
   103 	LmMessageQueue *queue;
       
   104 
       
   105 	LmConnectionState state;
       
   106 
       
   107 	guint         keep_alive_rate;
       
   108 	GSource      *keep_alive_source;
       
   109 
       
   110 	gint          ref_count;
       
   111 };
       
   112 
       
   113 typedef enum {
       
   114 	AUTH_TYPE_PLAIN  = 1,
       
   115 	AUTH_TYPE_DIGEST = 2,
       
   116 	AUTH_TYPE_0K     = 4
       
   117 } AuthType;
       
   118 
       
   119 #define XMPP_NS_BIND "urn:ietf:params:xml:ns:xmpp-bind"
       
   120 #define XMPP_NS_SESSION "urn:ietf:params:xml:ns:xmpp-session"
       
   121 #define XMPP_NS_STARTTLS "urn:ietf:params:xml:ns:xmpp-tls"
       
   122 
       
   123 static void     connection_free (LmConnection *connection);
       
   124 
       
   125 
       
   126 static void     connection_handle_message    (LmConnection         *connection,
       
   127 					      LmMessage            *message);
       
   128 
       
   129 static void     connection_new_message_cb    (LmParser             *parser,
       
   130 					      LmMessage            *message,
       
   131 					      LmConnection         *connection);
       
   132 static gboolean connection_do_open           (LmConnection         *connection,
       
   133 					      GError              **error);
       
   134 void            connection_do_close          (LmConnection         *connection);
       
   135 
       
   136 
       
   137 static LmMessage *     connection_create_auth_req_msg (const gchar *username);
       
   138 static LmMessage *     connection_create_auth_msg     (LmConnection *connection,
       
   139 						       const gchar  *username,
       
   140 						       const gchar  *password,
       
   141 						       const gchar  *resource,
       
   142 						       gint          auth_type);
       
   143 static LmHandlerResult connection_auth_req_reply (LmMessageHandler *handler,
       
   144 						  LmConnection     *connection,
       
   145 						  LmMessage        *m,
       
   146 						  gpointer          user_data);
       
   147 static int connection_check_auth_type            (LmMessage      *auth_req_rpl);
       
   148 					      
       
   149 static LmHandlerResult
       
   150 connection_auth_reply                            (LmMessageHandler *handler,
       
   151 						  LmConnection     *connection,
       
   152 						  LmMessage        *m,
       
   153 						  gpointer          user_data);
       
   154 
       
   155 static void      connection_stream_received      (LmConnection    *connection, 
       
   156 						  LmMessage       *m);
       
   157 static void      connection_stream_error         (LmConnection    *connection, 
       
   158 						  LmMessage       *m);
       
   159 
       
   160 static gint      connection_handler_compare_func (HandlerData     *a,
       
   161 						  HandlerData     *b);
       
   162 static gboolean  connection_send_keep_alive      (LmConnection    *connection);
       
   163 static void      connection_start_keep_alive     (LmConnection    *connection);
       
   164 static void      connection_stop_keep_alive      (LmConnection    *connection);
       
   165 static gboolean  connection_send                 (LmConnection    *connection, 
       
   166 						  const gchar     *str, 
       
   167 						  gint             len, 
       
   168 						  GError         **error);
       
   169 static void      connection_message_queue_cb     (LmMessageQueue  *queue,
       
   170 						  LmConnection    *connection);
       
   171 static void      connection_signal_disconnect    (LmConnection       *connection,
       
   172 						  LmDisconnectReason  reason);
       
   173 static void      connection_incoming_data        (LmSocket        *socket, 
       
   174 						  const gchar     *buf,
       
   175 						  LmConnection    *connection);
       
   176 static void      connection_socket_closed_cb     (LmSocket        *socket,
       
   177 						  LmDisconnectReason reason,
       
   178 						  LmConnection       *connection);
       
   179 static void      connection_socket_connect_cb    (LmSocket           *socket,
       
   180 						  gboolean            result,
       
   181 						  LmConnection       *connection);
       
   182 
       
   183 static gboolean  connection_get_server_from_jid  (const gchar     *jid,
       
   184 						  gchar          **server);
       
   185 static void      connection_send_stream_header   (LmConnection    *connection);
       
   186 static LmHandlerResult connection_features_cb (LmMessageHandler *handler,
       
   187 					       LmConnection     *connection,
       
   188 					       LmMessage        *message,
       
   189 					       gpointer          user_data);
       
   190 
       
   191 static void
       
   192 connection_free (LmConnection *connection)
       
   193 {
       
   194 	int        i;
       
   195 
       
   196 	g_free (connection->server);
       
   197 	g_free (connection->jid);
       
   198 	g_free (connection->effective_jid);
       
   199 	g_free (connection->stream_id);
       
   200 	g_free (connection->resource);
       
   201 
       
   202 	if (connection->sasl) {
       
   203 		lm_sasl_free (connection->sasl);
       
   204 	}
       
   205 
       
   206 	if (connection->parser) {
       
   207 		lm_parser_free (connection->parser);
       
   208 	}
       
   209 
       
   210 	/* Unref handlers */
       
   211 	for (i = 0; i < LM_MESSAGE_TYPE_UNKNOWN; ++i) {
       
   212 		GSList *l;
       
   213 
       
   214 		for (l = connection->handlers[i]; l; l = l->next) {
       
   215 			HandlerData *hd = (HandlerData *) l->data;
       
   216 			
       
   217 			lm_message_handler_unref (hd->handler);
       
   218 			g_free (hd);
       
   219 		}
       
   220 
       
   221 		g_slist_free (connection->handlers[i]);
       
   222 	}
       
   223 
       
   224 	g_hash_table_destroy (connection->id_handlers);
       
   225 	if (connection->state >= LM_CONNECTION_STATE_OPENING) {
       
   226 		connection_do_close (connection);
       
   227 	}
       
   228 
       
   229 	if (connection->open_cb) {
       
   230 		_lm_utils_free_callback (connection->open_cb);
       
   231 	}
       
   232 	
       
   233 	if (connection->auth_cb) {
       
   234 		_lm_utils_free_callback (connection->auth_cb);
       
   235 	}
       
   236 
       
   237 	lm_connection_set_disconnect_function (connection, NULL, NULL, NULL);
       
   238 
       
   239 	if (connection->proxy) {
       
   240 		lm_proxy_unref (connection->proxy);
       
   241 	}
       
   242 
       
   243 	lm_message_queue_unref (connection->queue);
       
   244 
       
   245         if (connection->context) {
       
   246                 g_main_context_unref (connection->context);
       
   247         }
       
   248 
       
   249 	if (connection->socket) {
       
   250 		lm_socket_unref (connection->socket);
       
   251 	}
       
   252 
       
   253         g_free (connection);
       
   254 }
       
   255 
       
   256 static void
       
   257 connection_handle_message (LmConnection *connection, LmMessage *m)
       
   258 {
       
   259 	LmMessageHandler *handler;
       
   260 	GSList           *l;
       
   261 	const gchar      *id;
       
   262 	LmHandlerResult   result = LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
       
   263 
       
   264 	lm_connection_ref (connection);
       
   265 	lm_verbose("[connection_handle_message]: Inside\n");
       
   266 	lm_verbose("msg type:[%d]\n", lm_message_get_type (m));
       
   267 	id = lm_message_node_get_attribute (m->node, "id");
       
   268 	if(id)
       
   269 		{
       
   270 		lm_verbose("handlemsg node id: %s\n", id);
       
   271 		}
       
   272 	if (lm_message_get_type (m) == LM_MESSAGE_TYPE_STREAM) {
       
   273 		lm_verbose("[connection_handle_message]: Stream received\n");
       
   274 		lm_verbose("[connection_handle_message]: calling connection_stream_received \n");
       
   275 		connection_stream_received (connection, m);
       
   276 		lm_verbose("[connection_handle_message]: CALLED connection_stream_received \n");
       
   277 		goto out;
       
   278 	}
       
   279 
       
   280 	if ((lm_message_get_sub_type (m) == LM_MESSAGE_SUB_TYPE_ERROR) ||
       
   281 	    (lm_message_get_sub_type (m) == LM_MESSAGE_SUB_TYPE_RESULT)) {
       
   282 		id = lm_message_node_get_attribute (m->node, "id");
       
   283 
       
   284 		lm_verbose("[connection_handle_message]: type is error or result \n");
       
   285 		if (id) {
       
   286 			handler = g_hash_table_lookup (connection->id_handlers, id);
       
   287 			if (handler) {
       
   288 				lm_verbose("[connection_handle_message]: calling the right handler for error/result \n");
       
   289 				result = _lm_message_handler_handle_message (handler,
       
   290 									     connection,
       
   291 									     m);
       
   292 				lm_verbose("[connection_handle_message]: Called right handler for error/result \n");									     
       
   293 				g_hash_table_remove (connection->id_handlers,
       
   294 						    id);
       
   295 			}
       
   296 		}
       
   297 
       
   298 		if (result == LM_HANDLER_RESULT_REMOVE_MESSAGE) {
       
   299 			lm_verbose("return from connection_handle_message\n");
       
   300 			goto out;
       
   301 		}
       
   302 	}
       
   303 	lm_verbose("[connection_handle_message]:starting for loop for more handlers\n");
       
   304 	for (l = connection->handlers[lm_message_get_type (m)]; 
       
   305 	     l && result == LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS; 
       
   306 	     l = l->next) {
       
   307 		HandlerData *hd = (HandlerData *) l->data;
       
   308 		lm_verbose("[connection_handle_message]:inside for loop for more handlers with msg type: %d\n", lm_message_get_type (m));
       
   309 		lm_verbose("[connection_handle_message]:inside for loop with node name: %s\n",lm_message_get_node(m)->name);
       
   310 		result = _lm_message_handler_handle_message (hd->handler,
       
   311 							     connection,
       
   312 							     m);
       
   313 		lm_verbose("[connection_handle_message]:got result from _lm_message_handler_handle_message as :%d\n",result);
       
   314 	}
       
   315 	lm_verbose("[connection_handle_message]:Ended for loop for more handlers\n");
       
   316 	if (lm_message_get_type (m) == LM_MESSAGE_TYPE_STREAM_ERROR) {
       
   317 		lm_verbose("[connection_handle_message]:stream error\n");
       
   318 		connection_stream_error (connection, m);
       
   319 		goto out;
       
   320 	}
       
   321 	
       
   322 out:
       
   323 	lm_verbose("[connection_handle_message]:exiting connection_handle_message\n");
       
   324 	lm_connection_unref (connection);
       
   325 	lm_verbose("[connection_handle_message]:after unref of connection\n");
       
   326 	return;
       
   327 }
       
   328 
       
   329 static void
       
   330 connection_new_message_cb (LmParser     *parser,
       
   331 			   LmMessage    *m,
       
   332 			   LmConnection *connection)
       
   333 {
       
   334 	const gchar *from;
       
   335 	
       
   336 	lm_message_ref (m);
       
   337 
       
   338 	from = lm_message_node_get_attribute (m->node, "from");
       
   339 	if (!from) {
       
   340 		from = "unknown";
       
   341 	}
       
   342 	
       
   343 	lm_verbose ("New message with type=\"%s\" from: %s\n",
       
   344 		    _lm_message_type_to_string (lm_message_get_type (m)),
       
   345 		    from);
       
   346 
       
   347 	lm_message_queue_push_tail (connection->queue, m);
       
   348 	UNUSED_FORMAL_PARAM(parser);
       
   349 }
       
   350 
       
   351 static gboolean
       
   352 connection_send_keep_alive (LmConnection *connection)
       
   353 { 
       
   354     lm_verbose ("[connection_send_keep_alive]\n");
       
   355 	if (!connection_send (connection, " ", -1, NULL)) {
       
   356 		lm_verbose ("Error while sending keep alive package!\n");
       
   357 	}
       
   358 	return TRUE;
       
   359 }
       
   360 
       
   361 static void
       
   362 connection_start_keep_alive (LmConnection *connection)
       
   363 {
       
   364 	lm_verbose("[connection_start_keep_alive]:Inside ....");
       
   365 	/* try using TCP keepalives if possible */
       
   366 	if ((connection->keep_alive_rate > 0) &&
       
   367 		lm_socket_set_keepalive (connection->socket,
       
   368 			connection->keep_alive_rate)) {
       
   369 	lm_verbose("[connection_start_keep_alive]: timer already active\n");
       
   370 	connection->keep_alive_source =
       
   371          lm_misc_add_timeout (connection->context,
       
   372                       connection->keep_alive_rate * 1000,
       
   373                       (GSourceFunc) connection_send_keep_alive,
       
   374                       connection);
       
   375 		return;
       
   376 	}
       
   377 
       
   378 	if (connection->keep_alive_source) {
       
   379 		lm_verbose("[connection_start_keep_alive]:stopping keep alive timer");
       
   380 		connection_stop_keep_alive (connection);
       
   381 	}
       
   382 
       
   383 	if (connection->keep_alive_rate > 0) {
       
   384 		connection->keep_alive_source =
       
   385 			lm_misc_add_timeout (connection->context,
       
   386 					     connection->keep_alive_rate * 1000,
       
   387 					     (GSourceFunc) connection_send_keep_alive,
       
   388 					     connection);
       
   389 		lm_verbose("[connection_start_keep_alive]: added timer to gsource\n");
       
   390 	}
       
   391 lm_verbose("[connection_start_keep_alive]: ...Exiting connection_start_keep_alive....");	 
       
   392 }
       
   393 
       
   394 static void
       
   395 connection_stop_keep_alive (LmConnection *connection)
       
   396 {
       
   397 	lm_verbose("[connection_start_keep_alive]:Stopping Keep Alive\n");
       
   398 	if (connection->keep_alive_source) {
       
   399 		g_source_destroy (connection->keep_alive_source);
       
   400 	}
       
   401 
       
   402 	connection->keep_alive_source = NULL;
       
   403 }
       
   404 
       
   405 static gboolean
       
   406 connection_send (LmConnection  *connection, 
       
   407 		 const gchar   *str, 
       
   408 		 gint           len, 
       
   409 		 GError       **error)
       
   410 {
       
   411 	gint b_written;
       
   412 
       
   413 	if (connection->state < LM_CONNECTION_STATE_OPENING) {
       
   414 	/*	g_log (LM_LOG_DOMAIN,LM_LOG_LEVEL_NET,
       
   415 		       "Connection is not open.\n");
       
   416 
       
   417 		g_set_error (error,
       
   418 			     LM_ERROR,
       
   419 			     LM_ERROR_CONNECTION_NOT_OPEN,
       
   420 			     "Connection is not open, call lm_connection_open() first");*/
       
   421 		lm_verbose("[connection_send]: Connection is not open call lm_connection_open() first");	     
       
   422 		return FALSE;
       
   423 	}
       
   424 
       
   425 	if (len == -1) {
       
   426 		len = strlen (str);
       
   427 	}
       
   428 
       
   429 	//g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET, "\nSEND:\n");
       
   430 	//g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET, 
       
   431 	//       "-----------------------------------\n");
       
   432 	//g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET, "%s\n", str);
       
   433 	//g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET, 
       
   434 	//       "-----------------------------------\n");
       
   435 	lm_verbose (  "\n[connection_send]: SEND:\n");
       
   436 	lm_verbose (  "-----------------------------------\n");
       
   437 	lm_verbose (  "%s\n", str);
       
   438 	lm_verbose (  "-----------------------------------\n");
       
   439 
       
   440 	/* Check to see if there already is an output buffer, if so, add to the
       
   441 	   buffer and return */
       
   442 
       
   443 	if (lm_socket_output_is_buffered (connection->socket, str, len)) {
       
   444 		return TRUE;
       
   445 	}
       
   446 	
       
   447 	b_written = lm_socket_do_write (connection->socket, str, len);
       
   448 
       
   449 	lm_verbose("[connection_send]: number of bytes written using lm_socket_do_write is : %d\n",b_written);
       
   450 	if (b_written < 0) {
       
   451 		lm_verbose("[connection_send]: Since b_written<0 closing the connection\n");
       
   452 		connection_do_close (connection);
       
   453 		connection_signal_disconnect (connection, 
       
   454 		                     LM_DISCONNECT_REASON_ERROR);
       
   455 		g_set_error (error,
       
   456 			     LM_ERROR,
       
   457 			     LM_ERROR_CONNECTION_FAILED,
       
   458 			     "Server closed the connection");
       
   459 		return FALSE;
       
   460 	}
       
   461 
       
   462 	if (b_written < len) {
       
   463 		lm_socket_setup_output_buffer (connection->socket, 
       
   464 						str + b_written, 
       
   465 						len - b_written);
       
   466 	}
       
   467 
       
   468 	return TRUE;
       
   469 }
       
   470 
       
   471 static void
       
   472 connection_message_queue_cb (LmMessageQueue *queue, LmConnection *connection)
       
   473 {
       
   474 	LmMessage *m;
       
   475 
       
   476 	m = lm_message_queue_pop_nth (connection->queue, 0);
       
   477 
       
   478 	if (m) {
       
   479 	    lm_verbose("In connection_message_queue_cb\n");
       
   480 		connection_handle_message (connection, m);
       
   481 		lm_message_unref (m);
       
   482 		lm_verbose("After un refing the message\n");
       
   483 	}
       
   484 	UNUSED_FORMAL_PARAM(queue);
       
   485 }
       
   486 
       
   487 /* Returns directly */
       
   488 /* Setups all data needed to start the connection attempts */
       
   489 static gboolean
       
   490 connection_do_open (LmConnection *connection, GError **error) 
       
   491 {
       
   492 	gchar *domain = NULL;
       
   493 
       
   494 	if (lm_connection_is_open (connection)) {
       
   495 		g_set_error (error,
       
   496 			     LM_ERROR,
       
   497 			     LM_ERROR_CONNECTION_NOT_OPEN,
       
   498 			     "Connection is already open, call lm_connection_close() first");
       
   499 		return FALSE;
       
   500 	}
       
   501 
       
   502 	if (!connection_get_server_from_jid (connection->jid, &domain)) {
       
   503 		domain = g_strdup (connection->server);
       
   504 	}
       
   505 
       
   506 	lm_verbose ("[connection_do_open]: Connecting to: %s:%d\n", connection->server, connection->port);
       
   507 
       
   508 	connection->socket = lm_socket_create (connection->context,
       
   509 					       (IncomingDataFunc) connection_incoming_data,
       
   510 					       (SocketClosedFunc) connection_socket_closed_cb,
       
   511 					       (ConnectResultFunc) connection_socket_connect_cb,
       
   512 					       connection,
       
   513 					       connection,
       
   514 					       connection->blocking,
       
   515 					       connection->server,
       
   516 					       domain,
       
   517 					       connection->port,
       
   518 					       connection->ssl,
       
   519 					       connection->proxy,
       
   520 					       error);
       
   521 
       
   522 	g_free (domain);
       
   523     lm_verbose ("[connection_do_open]: after lm_socket_create call in connection_do_open");
       
   524     
       
   525 	if (!connection->socket) {
       
   526 		return FALSE;
       
   527 	}
       
   528 
       
   529 	lm_message_queue_attach (connection->queue, connection->context);
       
   530 	
       
   531 	connection->state = LM_CONNECTION_STATE_OPENING;
       
   532 	connection->async_connect_waiting = FALSE;
       
   533 
       
   534 	return TRUE;
       
   535 }
       
   536 					
       
   537 void
       
   538 connection_do_close (LmConnection *connection)
       
   539 {
       
   540 	connection_stop_keep_alive (connection);
       
   541 
       
   542 	if (connection->socket) {
       
   543 		lm_socket_close (connection->socket);
       
   544 	}
       
   545 
       
   546 	lm_message_queue_detach (connection->queue);
       
   547 	
       
   548 	if (!lm_connection_is_open (connection)) {
       
   549 		/* lm_connection_is_open is FALSE for state OPENING as well */
       
   550 		connection->state = LM_CONNECTION_STATE_CLOSED;
       
   551 		connection->async_connect_waiting = FALSE;
       
   552 		return;
       
   553 	}
       
   554 	
       
   555 	connection->state = LM_CONNECTION_STATE_CLOSED;
       
   556 	connection->async_connect_waiting = FALSE;
       
   557 	if (connection->ssl) {
       
   558 		_lm_ssl_close (connection->ssl);
       
   559 	}
       
   560 
       
   561 	if (connection->sasl) {
       
   562 		lm_sasl_free (connection->sasl);
       
   563 		connection->sasl = NULL;
       
   564 	}
       
   565 }
       
   566 
       
   567 typedef struct {
       
   568 	gchar        *username;
       
   569 	gchar        *password;
       
   570 	gchar        *resource;
       
   571 } AuthReqData;
       
   572 
       
   573 static void 
       
   574 auth_req_data_free (AuthReqData *data) 
       
   575 {
       
   576 	g_free (data->username);
       
   577 	g_free (data->password);
       
   578 	g_free (data->resource);
       
   579 	g_free (data);
       
   580 }
       
   581 
       
   582 static LmMessage *
       
   583 connection_create_auth_req_msg (const gchar *username)
       
   584 {
       
   585 	LmMessage     *m;
       
   586 	LmMessageNode *q_node;
       
   587 	
       
   588 	m = lm_message_new_with_sub_type (NULL, LM_MESSAGE_TYPE_IQ,
       
   589 					  LM_MESSAGE_SUB_TYPE_GET);
       
   590 	q_node = lm_message_node_add_child (m->node, "query", NULL);
       
   591 	lm_message_node_set_attributes (q_node,
       
   592 					"xmlns", "jabber:iq:auth",
       
   593 					NULL);
       
   594 	lm_message_node_add_child (q_node, "username", username);
       
   595 
       
   596 	return m;
       
   597 }
       
   598 
       
   599 static LmMessage *
       
   600 connection_create_auth_msg (LmConnection *connection,
       
   601 			    const gchar  *username,
       
   602 			    const gchar  *password,
       
   603 			    const gchar  *resource,
       
   604 			    gint          auth_type)
       
   605 {
       
   606 	LmMessage     *auth_msg;
       
   607 	LmMessageNode *q_node;
       
   608 
       
   609 	auth_msg = lm_message_new_with_sub_type (NULL, LM_MESSAGE_TYPE_IQ,
       
   610 						 LM_MESSAGE_SUB_TYPE_SET);
       
   611 	
       
   612 	q_node = lm_message_node_add_child (auth_msg->node, "query", NULL);
       
   613 	
       
   614 	lm_message_node_set_attributes (q_node,
       
   615 					"xmlns", "jabber:iq:auth", 
       
   616 					NULL);
       
   617 
       
   618 	lm_message_node_add_child (q_node, "username", username);
       
   619 	
       
   620 	if (auth_type & AUTH_TYPE_0K) {
       
   621 		lm_verbose ("Using 0k auth (not implemented yet)\n");
       
   622 		/* TODO: Should probably use this? */
       
   623 	}
       
   624 
       
   625 	if (auth_type & AUTH_TYPE_DIGEST) {
       
   626 		gchar       *str;
       
   627 		const gchar *digest;
       
   628 
       
   629 		lm_verbose ("Using digest\n");
       
   630 		str = g_strconcat (connection->stream_id, password, NULL);
       
   631 		digest = lm_sha_hash (str);
       
   632 		g_free (str);
       
   633 		lm_message_node_add_child (q_node, "digest", digest);
       
   634 	} 
       
   635 	else if (auth_type & AUTH_TYPE_PLAIN) {
       
   636 		lm_verbose ("Using plaintext auth\n");
       
   637 		lm_message_node_add_child (q_node, "password", password);
       
   638 	} else {
       
   639 		/* TODO: Report error somehow */
       
   640 	}
       
   641 	
       
   642 	lm_message_node_add_child (q_node, "resource", resource);
       
   643 
       
   644 	return auth_msg;
       
   645 }
       
   646 
       
   647 static LmHandlerResult
       
   648 connection_auth_req_reply (LmMessageHandler *handler,
       
   649 			   LmConnection     *connection,
       
   650 			   LmMessage        *m,
       
   651 			   gpointer          user_data)
       
   652 {
       
   653 	int               auth_type;
       
   654 	LmMessage        *auth_msg;
       
   655 	LmMessageHandler *auth_handler;
       
   656 	AuthReqData      *data = (AuthReqData *) user_data;      
       
   657 	gboolean          result;
       
   658 	
       
   659 	auth_type = connection_check_auth_type (m);
       
   660 
       
   661 	auth_msg = connection_create_auth_msg (connection, 
       
   662 					       data->username,
       
   663 					       data->password,
       
   664 					       data->resource,
       
   665 					       auth_type);
       
   666 
       
   667 	auth_handler = lm_message_handler_new (connection_auth_reply,
       
   668 					       NULL, NULL);
       
   669 	result = lm_connection_send_with_reply (connection, auth_msg, 
       
   670 						auth_handler, NULL);
       
   671 	lm_message_handler_unref (auth_handler);
       
   672 	lm_message_unref (auth_msg);
       
   673 	UNUSED_FORMAL_PARAM(handler);
       
   674 	UNUSED_FORMAL_PARAM(user_data);
       
   675 	return LM_HANDLER_RESULT_REMOVE_MESSAGE;
       
   676 }
       
   677 
       
   678 static int
       
   679 connection_check_auth_type (LmMessage *auth_req_rpl)
       
   680 {
       
   681 	LmMessageNode *q_node;
       
   682 	gint           ret_val = 0; 
       
   683 
       
   684 	q_node = lm_message_node_get_child (auth_req_rpl->node, "query");
       
   685 	
       
   686 	if (!q_node) {
       
   687 		return AUTH_TYPE_PLAIN;
       
   688 	}
       
   689 
       
   690 	if (lm_message_node_get_child (q_node, "password")) {
       
   691 		ret_val |= AUTH_TYPE_PLAIN;
       
   692 	}
       
   693 
       
   694 	if (lm_message_node_get_child (q_node, "digest")) {
       
   695 		ret_val |= AUTH_TYPE_DIGEST;
       
   696 	}
       
   697 
       
   698 	if (lm_message_node_get_child (q_node, "sequence") &&
       
   699 	    lm_message_node_get_child (q_node, "token")) {
       
   700 		ret_val |= AUTH_TYPE_0K;
       
   701 	}
       
   702 
       
   703 	return ret_val;
       
   704 }
       
   705 
       
   706 static LmHandlerResult 
       
   707 connection_auth_reply (LmMessageHandler *handler,
       
   708 		       LmConnection     *connection,
       
   709 		       LmMessage        *m,
       
   710 		       gpointer          user_data)
       
   711 {
       
   712 	const gchar *type;
       
   713 	gboolean     result = TRUE;
       
   714 	
       
   715 	g_return_val_if_fail (connection != NULL, 
       
   716 			      LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS);
       
   717 	
       
   718 
       
   719 	type = lm_message_node_get_attribute (m->node, "type");
       
   720 	if (strcmp (type, "result") == 0) {
       
   721 		result = TRUE;
       
   722 		connection->state = LM_CONNECTION_STATE_AUTHENTICATED;
       
   723 	} 
       
   724 	else if (strcmp (type, "error") == 0) {
       
   725 		result = FALSE;
       
   726 		connection->state = LM_CONNECTION_STATE_OPEN;
       
   727 	}
       
   728 	
       
   729 	lm_verbose ("AUTH reply: %d\n", result);
       
   730 	
       
   731 	if (connection->auth_cb) {
       
   732 	        LmCallback *cb = connection->auth_cb;
       
   733 
       
   734 		connection->auth_cb = NULL;
       
   735 
       
   736 		if (cb->func) {
       
   737 	    		(* ((LmResultFunction) cb->func)) (connection, 
       
   738 						           result, cb->user_data);
       
   739 		}
       
   740 
       
   741 		_lm_utils_free_callback (cb);
       
   742 	}
       
   743 	UNUSED_FORMAL_PARAM(handler);
       
   744 	UNUSED_FORMAL_PARAM(user_data);
       
   745 	return LM_HANDLER_RESULT_REMOVE_MESSAGE;
       
   746 }
       
   747 
       
   748 
       
   749 static LmHandlerResult
       
   750 _lm_connection_starttls_cb (LmMessageHandler *handler,
       
   751 			    LmConnection *connection,
       
   752 			    LmMessage *message,
       
   753 			    gpointer user_data)
       
   754 {
       
   755 	if (lm_socket_starttls (connection->socket)) {
       
   756 		connection->tls_started = TRUE;
       
   757 		connection_send_stream_header (connection);
       
   758 	} else {
       
   759 		connection_do_close (connection);
       
   760 		connection_signal_disconnect (connection, 
       
   761 					      LM_DISCONNECT_REASON_ERROR);
       
   762 	}
       
   763 	UNUSED_FORMAL_PARAM(message);
       
   764 	UNUSED_FORMAL_PARAM(handler);
       
   765 	UNUSED_FORMAL_PARAM(user_data);
       
   766 	return LM_HANDLER_RESULT_REMOVE_MESSAGE;
       
   767 }
       
   768 
       
   769 static void
       
   770 connection_stream_received (LmConnection *connection, LmMessage *m)
       
   771 {
       
   772 	gboolean result;
       
   773 	const char *xmpp_version;
       
   774 	
       
   775 	g_return_if_fail (connection != NULL);
       
   776 	g_return_if_fail (m != NULL);
       
   777 	
       
   778 	connection->stream_id = g_strdup (lm_message_node_get_attribute (m->node,
       
   779 									 "id"));;
       
   780 
       
   781 	xmpp_version = lm_message_node_get_attribute (m->node, "version");
       
   782 	if (xmpp_version && strcmp (xmpp_version, "1.0") == 0) {
       
   783 		lm_verbose ("[connection_stream_received]: XMPP 1.0 stream received: %s\n",
       
   784 			    connection->stream_id);
       
   785 
       
   786 		connection->use_sasl = TRUE;
       
   787 		
       
   788 		/* stream is started multiple times, but we only want
       
   789 		 * one sasl mechanism */
       
   790 		if (!connection->sasl)
       
   791 			connection->sasl = lm_sasl_new(connection);
       
   792 
       
   793 		/* if we'd like to use tls and we didn't already start
       
   794 		 * it, prepare for it now */
       
   795 		if (connection->ssl &&
       
   796 				lm_ssl_get_use_starttls (connection->ssl) &&
       
   797 				!connection->starttls_cb) {
       
   798 						lm_verbose("[connction_stream_received]: Starttls called");
       
   799 			connection->starttls_cb  =
       
   800 				lm_message_handler_new (_lm_connection_starttls_cb,
       
   801 					NULL, NULL);
       
   802 			lm_connection_register_message_handler (connection,
       
   803 				connection->starttls_cb,
       
   804 				LM_MESSAGE_TYPE_PROCEED,
       
   805 				LM_HANDLER_PRIORITY_FIRST);
       
   806 		}
       
   807 	} else {
       
   808 		lm_verbose ("Old Jabber stream received: %s\n", 
       
   809 			    connection->stream_id);
       
   810 	}
       
   811 	
       
   812 	if (connection->state < LM_CONNECTION_STATE_OPEN) {
       
   813 		connection->state = LM_CONNECTION_STATE_OPEN;
       
   814 	}
       
   815 	
       
   816 	/* Check to see if the stream is correctly set up */
       
   817 	result = TRUE;
       
   818 
       
   819 //	connection_start_keep_alive (connection); //prima
       
   820 
       
   821 	if (connection->open_cb) {
       
   822 		LmCallback *cb = connection->open_cb;
       
   823 
       
   824 		connection->open_cb = NULL;
       
   825 		
       
   826 		if (cb->func) {
       
   827 		        (* ((LmResultFunction) cb->func)) (connection, result,
       
   828 			        			   cb->user_data);
       
   829 		}
       
   830 		_lm_utils_free_callback (cb);
       
   831 	}
       
   832 }
       
   833 
       
   834 static void
       
   835 connection_stream_error (LmConnection *connection, LmMessage *m)
       
   836 {
       
   837 	LmMessageNode *node, *reason_node;
       
   838 	LmDisconnectReason reason;
       
   839 
       
   840 	g_return_if_fail (connection != NULL);
       
   841 	g_return_if_fail (m != NULL);
       
   842 
       
   843 	node = m->node;
       
   844 
       
   845 	/* Resource conflict */
       
   846 	reason_node = lm_message_node_get_child (node, "conflict");
       
   847 	if (reason_node) {
       
   848 		lm_verbose ("Stream error: Conflict (resource connected elsewhere)\n");
       
   849 		reason = LM_DISCONNECT_REASON_RESOURCE_CONFLICT;
       
   850 		return;
       
   851 	}
       
   852 
       
   853 	/* XML is crack */
       
   854 	reason_node = lm_message_node_get_child (node, "xml-not-well-formed");
       
   855 	if (reason_node) {
       
   856 		lm_verbose ("Stream error: XML not well formed\n");
       
   857 		reason = LM_DISCONNECT_REASON_INVALID_XML;
       
   858 		return;
       
   859 	}
       
   860 
       
   861 	lm_verbose ("Stream error: Unrecognised error\n");
       
   862 	reason = LM_DISCONNECT_REASON_ERROR;
       
   863 	connection->stream_id = g_strdup (lm_message_node_get_attribute (m->node,
       
   864 									 "id"));;
       
   865 	connection_do_close (connection);
       
   866 	connection_signal_disconnect (connection, reason);
       
   867 }
       
   868 
       
   869 static gint
       
   870 connection_handler_compare_func (HandlerData *a, HandlerData *b)
       
   871 {
       
   872 	return b->priority - a->priority;
       
   873 }
       
   874 
       
   875 static void
       
   876 connection_signal_disconnect (LmConnection       *connection,
       
   877 			      LmDisconnectReason  reason)
       
   878 {
       
   879     lm_verbose ("[connection_signal_disconnect]\n");      
       
   880 	if (connection->disconnect_cb && connection->disconnect_cb->func) {
       
   881 	    
       
   882 		LmCallback *cb = connection->disconnect_cb;
       
   883 		lm_verbose("[connection_signal_disconnect]: ...disconnecting\n");		
       
   884 		lm_connection_ref (connection);
       
   885 		(* ((LmDisconnectFunction) cb->func)) (connection,
       
   886 						       reason,
       
   887 						       cb->user_data);
       
   888 		lm_connection_unref (connection);
       
   889 		lm_verbose("[connection_signal_disconnect]: ...after unref\n"); 
       
   890 	}
       
   891 }
       
   892 
       
   893 static void
       
   894 connection_incoming_data (LmSocket     *socket, 
       
   895 			  const gchar  *buf, 
       
   896 			  LmConnection *connection)
       
   897 {
       
   898 	lm_parser_parse (connection->parser, buf);
       
   899 	UNUSED_FORMAL_PARAM(socket);
       
   900 }
       
   901 
       
   902 static void
       
   903 connection_socket_closed_cb (LmSocket        *socket,
       
   904 			     LmDisconnectReason reason,
       
   905 			     LmConnection       *connection)
       
   906 {
       
   907     lm_verbose("[connection_socket_closed_cb]: inside..\n");
       
   908     connection_do_close (connection);
       
   909 	connection_signal_disconnect (connection, reason);
       
   910 	lm_verbose("[connection_socket_closed_cb]: exiting..\n");
       
   911 	UNUSED_FORMAL_PARAM(socket);
       
   912 }
       
   913 
       
   914 static void
       
   915 connection_socket_connect_cb (LmSocket           *socket,
       
   916 			      gboolean            result,
       
   917 			      LmConnection       *connection)
       
   918 {
       
   919 	if (!result) {
       
   920 		connection_do_close (connection);
       
   921 	    lm_verbose ("[connection_socket_connect_cb]: result false ");
       
   922 		if (connection->open_cb) {
       
   923 			LmCallback *cb = connection->open_cb;
       
   924 		    lm_verbose ("[connection_socket_connect_cb]: connection->open_cb is defined "); 
       
   925 
       
   926 			connection->open_cb = NULL;
       
   927 			
       
   928 			(* ((LmResultFunction) cb->func)) (connection, FALSE,
       
   929 							   cb->user_data);
       
   930 			_lm_utils_free_callback (cb);
       
   931 		}
       
   932 	
       
   933 		UNUSED_FORMAL_PARAM(socket);
       
   934 		return;
       
   935 	}
       
   936 	
       
   937 	/* FIXME: Set up according to XMPP 1.0 specification */
       
   938 	/*        StartTLS and the like */
       
   939 	if (!connection_send (connection, 
       
   940 			      "<?xml version='1.0' encoding='UTF-8'?>", -1,
       
   941 			      NULL)) {
       
   942 		lm_verbose ("Failed to send xml version and encoding\n");
       
   943 		connection_do_close (connection);
       
   944 
       
   945 		return;
       
   946 	}
       
   947 
       
   948 	connection_send_stream_header (connection);
       
   949 	lm_verbose("\n[connection_socket_connect_cb]: exiting ");
       
   950 }
       
   951 
       
   952 static gboolean
       
   953 connection_get_server_from_jid (const gchar     *jid,
       
   954 				gchar          **server)
       
   955 {
       
   956 	gchar *ch;
       
   957 	gchar *ch_end;
       
   958 
       
   959 	if (jid != NULL && (ch = strchr (jid, '@')) != NULL) {
       
   960 		ch_end = strchr(ch + 1, '/');
       
   961 		if (ch_end != NULL) {
       
   962 			*server = g_strndup (ch + 1, ch_end - ch - 1);
       
   963 		} else {
       
   964 			*server = g_strdup (ch + 1);
       
   965 		}
       
   966 
       
   967 		return TRUE;
       
   968 	} 
       
   969 	
       
   970 	return FALSE;
       
   971 }
       
   972 
       
   973 static void
       
   974 connection_send_stream_header (LmConnection *connection)
       
   975 {
       
   976 	LmMessage *m;
       
   977 	gchar     *server_from_jid;
       
   978 
       
   979 	lm_verbose ("Sending stream header\n");
       
   980 
       
   981 	if (!connection_get_server_from_jid (connection->jid, &server_from_jid)) {
       
   982 		server_from_jid = g_strdup (connection->server);
       
   983 	}
       
   984 
       
   985 	m = lm_message_new (server_from_jid, LM_MESSAGE_TYPE_STREAM);
       
   986 	lm_message_node_set_attributes (m->node,
       
   987 					"xmlns:stream", 
       
   988 					"http://etherx.jabber.org/streams",
       
   989 					"xmlns", "jabber:client",
       
   990 					"version", "1.0",
       
   991 					NULL);
       
   992 	
       
   993 	g_free (server_from_jid);
       
   994 
       
   995 	if (!lm_connection_send (connection, m, NULL)) {
       
   996 		lm_verbose ("Failed to send stream information\n");
       
   997 		connection_do_close (connection);
       
   998 	}
       
   999 	connection_start_keep_alive (connection); //prima	
       
  1000 	lm_message_unref (m);
       
  1001 	lm_verbose("\n[connection_send_stream_header]: Exiting send stream header method");
       
  1002 }
       
  1003 
       
  1004 gboolean 
       
  1005 _lm_connection_async_connect_waiting (LmConnection *connection)
       
  1006 {
       
  1007 	return connection->async_connect_waiting;
       
  1008 }
       
  1009 
       
  1010 void
       
  1011 _lm_connection_set_async_connect_waiting (LmConnection *connection,
       
  1012 					  gboolean      waiting)
       
  1013 {
       
  1014 	connection->async_connect_waiting = waiting;
       
  1015 }
       
  1016 
       
  1017 static void
       
  1018 connection_call_auth_cb (LmConnection *connection, gboolean success)
       
  1019 {
       
  1020 	if (success) {
       
  1021 		lm_verbose("connection_call_auth_cb: authenticated\n");
       
  1022 		connection->state = LM_CONNECTION_STATE_AUTHENTICATED;
       
  1023 	} else {
       
  1024 		lm_verbose("connection_call_auth_cb: conn still open\n");
       
  1025 		connection->state = LM_CONNECTION_STATE_OPEN;
       
  1026 	}
       
  1027 
       
  1028 	if (connection->auth_cb) {
       
  1029 	        LmCallback *cb = connection->auth_cb;
       
  1030 
       
  1031 		connection->auth_cb = NULL;
       
  1032 
       
  1033 		if (cb->func) {
       
  1034 		lm_verbose("connection_call_auth_cb: calling the test code's registered cb method\n");
       
  1035 	    		(* ((LmResultFunction) cb->func)) (connection, 
       
  1036 						           success,
       
  1037 							   cb->user_data);
       
  1038 		}
       
  1039 
       
  1040 		_lm_utils_free_callback (cb);
       
  1041 	}
       
  1042 }
       
  1043 
       
  1044 static LmHandlerResult
       
  1045 connection_bind_reply (LmMessageHandler *handler,
       
  1046 			LmConnection    *connection,
       
  1047 			LmMessage       *message,
       
  1048 			gpointer         user_data)
       
  1049 {
       
  1050 	LmMessage        *m;
       
  1051 	LmMessageNode    *session_node;
       
  1052 	LmMessageNode    *jid_node;
       
  1053 	int               result;
       
  1054 	LmMessageSubType  type;
       
  1055 	lm_verbose("[connection_bind_reply]: inside connection_bind_reply\n");
       
  1056 	type = lm_message_get_sub_type (message);
       
  1057 	if (type == LM_MESSAGE_SUB_TYPE_ERROR) {
       
  1058 		/*g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SASL, 
       
  1059 		       "%s: error while binding to resource\n", G_STRFUNC);*/
       
  1060 		lm_verbose("[connection_bind_reply]: calling connection_call_auth_cb\n");
       
  1061 		connection_call_auth_cb (connection, FALSE);
       
  1062 		lm_verbose("[connection_bind_reply]: called connection_call_auth_cb\n");
       
  1063 		UNUSED_FORMAL_PARAM(user_data);
       
  1064 		UNUSED_FORMAL_PARAM(handler);
       
  1065 		return LM_HANDLER_RESULT_REMOVE_MESSAGE;
       
  1066 	}
       
  1067 
       
  1068 	/* use whatever server returns as our effective jid */
       
  1069 	jid_node = lm_message_node_find_child (message->node, "jid");
       
  1070 	if (jid_node) {
       
  1071 		g_free (connection->effective_jid);
       
  1072 		connection->effective_jid = g_strdup
       
  1073 			(lm_message_node_get_value (jid_node));
       
  1074 	}
       
  1075 
       
  1076 
       
  1077 	m = lm_message_new_with_sub_type (NULL,
       
  1078 					  LM_MESSAGE_TYPE_IQ, 
       
  1079 					  LM_MESSAGE_SUB_TYPE_SET);
       
  1080 
       
  1081 	lm_verbose("[connection_bind_reply]: Creation session child node\n");
       
  1082 	session_node = lm_message_node_add_child (m->node, "session", NULL);
       
  1083 	lm_message_node_set_attributes (session_node,
       
  1084 					"xmlns", XMPP_NS_SESSION,
       
  1085 					NULL);
       
  1086 	lm_verbose("[connection_bind_reply]: Sending session child node\n");
       
  1087 	result = lm_connection_send (connection, m, NULL);
       
  1088 	lm_message_unref (m);
       
  1089 	if (result < 0) {
       
  1090 		connection_do_close (connection);
       
  1091 	}
       
  1092 
       
  1093 	/* We may finally tell the client they're authorized */
       
  1094 	connection_call_auth_cb (connection, TRUE);
       
  1095 
       
  1096 	return LM_HANDLER_RESULT_REMOVE_MESSAGE;
       
  1097 }
       
  1098 
       
  1099 static LmHandlerResult
       
  1100 connection_features_cb (LmMessageHandler *handler,
       
  1101 			    LmConnection     *connection,
       
  1102 			    LmMessage        *message,
       
  1103 			    gpointer          user_data)
       
  1104 {
       
  1105 	LmMessageNode *bind_node;
       
  1106 	LmMessageNode    *starttls_node;
       
  1107 	LmMessageNode *old_auth;
       
  1108 	lm_verbose("[connection_features_cb] inside..\n");
       
  1109 	
       
  1110 	starttls_node = lm_message_node_find_child (message->node, "starttls");
       
  1111 	if (connection->ssl && lm_ssl_get_use_starttls (connection->ssl)) {
       
  1112 		if (starttls_node) {
       
  1113 			LmMessage        *msg;
       
  1114 
       
  1115 			msg = lm_message_new (NULL, LM_MESSAGE_TYPE_STARTTLS);
       
  1116 
       
  1117 			lm_message_node_set_attributes (
       
  1118 				msg->node,
       
  1119 				"xmlns", XMPP_NS_STARTTLS,
       
  1120 				NULL);
       
  1121 
       
  1122 			lm_connection_send (connection, msg, NULL);
       
  1123 			lm_message_unref (msg);
       
  1124 
       
  1125 			return LM_HANDLER_RESULT_REMOVE_MESSAGE;
       
  1126 		} else if (!connection->tls_started &&
       
  1127 				lm_ssl_get_require_starttls (connection->ssl)) {
       
  1128 			/* If there were no starttls features present and we require it, this is
       
  1129 			 * the place to scream. */
       
  1130 		lm_verbose("connection_features_cb: Required StartTLS feature not supported by server\n");
       
  1131 
       
  1132 			/*g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SASL, 
       
  1133 			       "%s: required StartTLS feature not supported by server\n", G_STRFUNC);*/
       
  1134 			connection_do_close (connection);
       
  1135 			connection_signal_disconnect (connection,
       
  1136 				LM_DISCONNECT_REASON_ERROR);
       
  1137 			UNUSED_FORMAL_PARAM(user_data);
       
  1138 			UNUSED_FORMAL_PARAM(handler);
       
  1139 			return LM_HANDLER_RESULT_REMOVE_MESSAGE;
       
  1140 		}
       
  1141 	}
       
  1142 
       
  1143 	bind_node = lm_message_node_find_child (message->node, "bind");
       
  1144 	if (bind_node) {
       
  1145 		LmMessageHandler *bind_handler;
       
  1146 		LmMessage        *bind_msg;
       
  1147 		const gchar      *ns;
       
  1148 		int               result;
       
  1149 
       
  1150 		lm_verbose("connection_features_cb: found bind node\n");
       
  1151 		ns = lm_message_node_get_attribute (bind_node, "xmlns");
       
  1152 		if (!ns || strcmp (ns, XMPP_NS_BIND) != 0) {
       
  1153 			return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
       
  1154 		}
       
  1155 
       
  1156 		bind_msg = lm_message_new_with_sub_type (NULL,
       
  1157 							 LM_MESSAGE_TYPE_IQ, 
       
  1158 							 LM_MESSAGE_SUB_TYPE_SET);
       
  1159 
       
  1160 		bind_node = lm_message_node_add_child (bind_msg->node, 
       
  1161 						       "bind", NULL);
       
  1162 		lm_message_node_set_attributes (bind_node,
       
  1163 						"xmlns", XMPP_NS_BIND,
       
  1164 						NULL);
       
  1165 
       
  1166 		lm_message_node_add_child (bind_node, "resource",
       
  1167 					   connection->resource);
       
  1168 
       
  1169 		lm_verbose("[connection_features_cb]:setting callback method for bind response\n");
       
  1170 		bind_handler = lm_message_handler_new (connection_bind_reply,
       
  1171 						       NULL, NULL);
       
  1172 		lm_verbose("[connection_features_cb]: calling lm_connection_send_with_reply for bind response\n");
       
  1173 		result = lm_connection_send_with_reply (connection, bind_msg, 
       
  1174 							bind_handler, NULL);
       
  1175 		lm_verbose("[connection_features_cb]:called lm_connection_send_with_reply for bind response with result: %d\n", result);
       
  1176 		lm_message_handler_unref (bind_handler);
       
  1177 		lm_message_unref (bind_msg);
       
  1178 
       
  1179 		if (result < 0) {
       
  1180 			/*g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SASL, 
       
  1181 			       "%s: can't send resource binding request\n", G_STRFUNC);*/
       
  1182 			connection_do_close (connection);
       
  1183 		}
       
  1184 	}
       
  1185 
       
  1186 	old_auth = lm_message_node_find_child (message->node, "auth");
       
  1187 	if (connection->use_sasl && old_auth) {
       
  1188 		g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_SASL, 
       
  1189 		       "Server uses XEP-0078 (jabber iq auth) instead of SASL\n");
       
  1190 		/* So the server is XMPP1.0, but doesn't support SASL and uses
       
  1191 		 * obsolete XEP-0078 instead. Let's cope. */
       
  1192 
       
  1193 		connection->use_sasl = FALSE;
       
  1194 
       
  1195 		if (connection->sasl) {
       
  1196 			const gchar *user, *pass;
       
  1197 
       
  1198 			lm_sasl_get_auth_params (connection->sasl, &user, &pass);
       
  1199 			if (user && pass) {
       
  1200 				GError *error = NULL;
       
  1201 				lm_verbose("[connection_features_cb]:calling _lm_connection_old_auth\n");
       
  1202 				_lm_connection_old_auth (connection, user, pass,
       
  1203 					connection->resource, &error);
       
  1204 
       
  1205 				if (error) {
       
  1206 					g_error_free (error);
       
  1207 				}
       
  1208 			}
       
  1209 
       
  1210 			lm_sasl_free (connection->sasl);
       
  1211 			connection->sasl = NULL;
       
  1212 		}
       
  1213 	}
       
  1214 
       
  1215 	return LM_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
       
  1216 }
       
  1217 
       
  1218 /**
       
  1219  * lm_connection_new:
       
  1220  * @server: The hostname to the server for the connection.
       
  1221  * 
       
  1222  * Creates a new closed connection. To open the connection call 
       
  1223  * lm_connection_open(). @server can be #NULL but must be set before calling lm_connection_open().
       
  1224  * 
       
  1225  * Return value: A newly created LmConnection, should be unreffed with lm_connection_unref().
       
  1226  **/
       
  1227 EXPORT_C LmConnection *
       
  1228 lm_connection_new (const gchar *server)
       
  1229 {
       
  1230 	LmConnection *connection = NULL;
       
  1231 	gint          i;
       
  1232 	
       
  1233 	lm_debug_init ();
       
  1234 	_lm_sock_library_init ();
       
  1235 
       
  1236 	connection = g_new0 (LmConnection, 1);
       
  1237 
       
  1238 	if (server) {
       
  1239 		connection->server  = _lm_utils_hostname_to_punycode (server);
       
  1240 		connection->use_srv = FALSE;
       
  1241 	} else {
       
  1242 		connection->server  = NULL;
       
  1243 		connection->use_srv = TRUE;
       
  1244 	}
       
  1245 
       
  1246 	connection->context           = NULL;
       
  1247 	connection->port              = LM_CONNECTION_DEFAULT_PORT;
       
  1248 	connection->jid               = NULL;
       
  1249 	connection->effective_jid     = NULL;
       
  1250 	connection->ssl               = NULL;
       
  1251 	connection->proxy             = NULL;
       
  1252 	connection->disconnect_cb     = NULL;
       
  1253 	connection->queue             = lm_message_queue_new ((LmMessageQueueCallback) connection_message_queue_cb, 
       
  1254 							      connection);
       
  1255 	connection->cancel_open       = FALSE;
       
  1256 	connection->state             = LM_CONNECTION_STATE_CLOSED;
       
  1257 	connection->keep_alive_source = NULL;
       
  1258 	connection->keep_alive_rate   = 0;
       
  1259 	connection->socket            = NULL;
       
  1260 	connection->use_sasl          = FALSE;
       
  1261 	connection->tls_started       = FALSE;
       
  1262 	
       
  1263 	connection->id_handlers = g_hash_table_new_full (g_str_hash, 
       
  1264 							 g_str_equal,
       
  1265 							 g_free, 
       
  1266 							 (GDestroyNotify) lm_message_handler_unref);
       
  1267 	connection->ref_count         = 1;
       
  1268 	
       
  1269 	for (i = 0; i < LM_MESSAGE_TYPE_UNKNOWN; ++i) {
       
  1270 		connection->handlers[i] = NULL;
       
  1271 	}
       
  1272 
       
  1273 	connection->parser = lm_parser_new 
       
  1274 		((LmParserMessageFunction) connection_new_message_cb, 
       
  1275 		 connection, NULL);
       
  1276 
       
  1277 	return connection;
       
  1278 }
       
  1279 
       
  1280 /**
       
  1281  * lm_connection_new_with_context:
       
  1282  * @server: The hostname to the server for the connection.
       
  1283  * @context: The context this connection should be running in.
       
  1284  * 
       
  1285  * Creates a new closed connection running in a certain context. To open the 
       
  1286  * connection call #lm_connection_open. @server can be #NULL but must be set 
       
  1287  * before calling #lm_connection_open.
       
  1288  * 
       
  1289  * Return value: A newly created LmConnection, should be unreffed with lm_connection_unref().
       
  1290  **/
       
  1291 EXPORT_C LmConnection *
       
  1292 lm_connection_new_with_context (const gchar *server, GMainContext *context)
       
  1293 {
       
  1294 	LmConnection *connection;
       
  1295 
       
  1296 	connection = lm_connection_new (server);
       
  1297 	connection->context = context;
       
  1298 
       
  1299 	if (context) {
       
  1300         	g_main_context_ref (connection->context);
       
  1301 	}
       
  1302 
       
  1303 	return connection;
       
  1304 }
       
  1305 
       
  1306 /**
       
  1307  * lm_connection_open:
       
  1308  * @connection: #LmConnection to open
       
  1309  * @function: Callback function that will be called when the connection is open.
       
  1310  * @user_data: User data that will be passed to @function.
       
  1311  * @notify: Function for freeing that user_data, can be NULL.
       
  1312  * @error: location to store error, or %NULL
       
  1313  * 
       
  1314  * An async call to open @connection. When the connection is open @function will be called.
       
  1315  * 
       
  1316  * Return value: #TRUE if everything went fine, otherwise #FALSE.
       
  1317  **/
       
  1318 EXPORT_C gboolean
       
  1319 lm_connection_open (LmConnection      *connection, 
       
  1320 		    LmResultFunction   function,
       
  1321 		    gpointer           user_data,
       
  1322 		    GDestroyNotify     notify,
       
  1323 		    GError           **error)
       
  1324 {
       
  1325 	lm_verbose("[lm_connection_open]: open...");
       
  1326 	g_return_val_if_fail (connection != NULL, FALSE);
       
  1327 	
       
  1328 	connection->open_cb = _lm_utils_new_callback ((gpointer)function, 
       
  1329 						      user_data, notify);
       
  1330 	connection->blocking = FALSE;
       
  1331 	lm_verbose("[lm_connection_open]: calling connection_do_open...");
       
  1332 	return connection_do_open (connection, error);
       
  1333 }
       
  1334 
       
  1335 /**
       
  1336  * lm_connection_open_and_block:
       
  1337  * @connection: an #LmConnection to open
       
  1338  * @error: location to store error, or %NULL
       
  1339  * 
       
  1340  * Opens @connection and waits until the stream is setup. 
       
  1341  * 
       
  1342  * Return value: #TRUE if no errors where encountered during opening and stream setup successfully, #FALSE otherwise.
       
  1343  **/
       
  1344 EXPORT_C gboolean
       
  1345 lm_connection_open_and_block (LmConnection *connection, GError **error)
       
  1346 {
       
  1347 	gboolean          result;
       
  1348 	LmConnectionState state;
       
  1349 	
       
  1350 	g_return_val_if_fail (connection != NULL, FALSE);
       
  1351 
       
  1352 	connection->open_cb = NULL;
       
  1353 	connection->blocking = TRUE;
       
  1354 
       
  1355 	result = connection_do_open (connection, error);
       
  1356 	
       
  1357 	if (result == FALSE) {
       
  1358 		return FALSE;
       
  1359 	}
       
  1360 		
       
  1361 	while ((state = lm_connection_get_state (connection)) == LM_CONNECTION_STATE_OPENING) {
       
  1362 		if (g_main_context_pending (connection->context)) {
       
  1363 			g_main_context_iteration (connection->context, TRUE);
       
  1364 		} else {
       
  1365 			/* Sleep for 1 millisecond */
       
  1366 			g_usleep (1000);
       
  1367 		}
       
  1368 	}
       
  1369 
       
  1370 	if (lm_connection_is_open (connection)) {
       
  1371 		connection_start_keep_alive (connection);
       
  1372 		return TRUE;
       
  1373 	}
       
  1374 
       
  1375 	/* Need to set the error here: LM-15 */
       
  1376 	g_set_error (error,
       
  1377 		     LM_ERROR,
       
  1378 		     LM_ERROR_CONNECTION_FAILED,
       
  1379 		     "Opening the connection failed");
       
  1380 
       
  1381 	return FALSE;
       
  1382 }
       
  1383 
       
  1384 /**
       
  1385  * lm_connection_cancel_open:
       
  1386  * @connection: an #LmConnection to cancel opening on
       
  1387  *
       
  1388  * Cancels the open operation of a connection. The connection should be in the state #LM_CONNECTION_STATE_OPENING.
       
  1389  **/
       
  1390 EXPORT_C void
       
  1391 lm_connection_cancel_open (LmConnection *connection)
       
  1392 {
       
  1393 	g_return_if_fail (connection != NULL);
       
  1394 
       
  1395 	lm_verbose("[lm_connection_cancel_open]: inside..");
       
  1396 	if (connection->open_cb) {
       
  1397 		_lm_utils_free_callback (connection->open_cb);
       
  1398 		connection->open_cb = NULL;
       
  1399 	}
       
  1400 
       
  1401 	connection->cancel_open = TRUE;
       
  1402 
       
  1403 #ifdef HAVE_ASYNCNS
       
  1404 	lm_verbose("[lm_connection_cancel_open] called in HAVE_ASYNCNS");
       
  1405 	_asyncns_cancel(connection->socket);
       
  1406 #endif
       
  1407 }
       
  1408 
       
  1409 /**
       
  1410  * lm_connection_close:
       
  1411  * @connection: #LmConnection to close 
       
  1412  * @error: location to store error, or %NULL
       
  1413  * 
       
  1414  * A synchronous call to close the connection. When returning the connection is considered to be closed and can be opened again with lm_connection_open().
       
  1415  * 
       
  1416  * Return value: Returns #TRUE if no errors where detected, otherwise #FALSE.
       
  1417  **/
       
  1418 EXPORT_C gboolean
       
  1419 lm_connection_close (LmConnection      *connection, 
       
  1420 		     GError           **error)
       
  1421 {
       
  1422 	gboolean no_errors = TRUE;
       
  1423 	
       
  1424 	g_return_val_if_fail (connection != NULL, FALSE);
       
  1425 
       
  1426 #ifdef HAVE_ASYNCNS
       
  1427 	_asyncns_cancel (connection->socket);
       
  1428 #endif
       
  1429 
       
  1430 	if (connection->state == LM_CONNECTION_STATE_CLOSED) {
       
  1431 		g_set_error (error,
       
  1432 			     LM_ERROR,
       
  1433 			     LM_ERROR_CONNECTION_NOT_OPEN,
       
  1434 			     "Connection is not open, call lm_connection_open() first");
       
  1435 		return FALSE;
       
  1436 	}
       
  1437 
       
  1438 	lm_verbose ("Disconnecting from: %s:%d\n", 
       
  1439 		    connection->server, connection->port);
       
  1440 	
       
  1441 	if (lm_connection_is_open (connection)) {
       
  1442 		if (!connection_send (connection, "</stream:stream>", -1, error)) {
       
  1443 			no_errors = FALSE;
       
  1444 		}
       
  1445 
       
  1446 		lm_socket_flush (connection->socket);
       
  1447 	}
       
  1448 	
       
  1449 	connection_do_close (connection);
       
  1450 	connection_signal_disconnect (connection, LM_DISCONNECT_REASON_OK);
       
  1451 	
       
  1452 	return no_errors;
       
  1453 }
       
  1454 
       
  1455 static void
       
  1456 connection_sasl_auth_finished (LmSASL *sasl,
       
  1457 			       LmConnection *connection,
       
  1458 			       gboolean success,
       
  1459 			       const gchar *reason)
       
  1460 {
       
  1461 	if (!success) {
       
  1462 		lm_verbose ("SASL authentication failed, closing connection\n");
       
  1463 		connection_call_auth_cb (connection, FALSE);
       
  1464 		return;
       
  1465 	}
       
  1466 
       
  1467 	connection_send_stream_header (connection);
       
  1468 	UNUSED_FORMAL_PARAM(sasl);
       
  1469 	UNUSED_FORMAL_PARAM(reason);
       
  1470 	lm_verbose("\n exiting SASL auth finished method");
       
  1471 }
       
  1472 
       
  1473 /**
       
  1474  * lm_connection_authenticate:
       
  1475  * @connection: #LmConnection to authenticate.
       
  1476  * @username: Username used to authenticate.
       
  1477  * @password: Password corresponding to @username.
       
  1478  * @resource: Resource used for this connection.
       
  1479  * @function: Callback called when authentication is finished.
       
  1480  * @user_data: Userdata passed to @function when called.
       
  1481  * @notify: Destroy function to free the memory used by @user_data, can be NULL.
       
  1482  * @error: location to store error, or %NULL
       
  1483  * 
       
  1484  * Tries to authenticate a user against the server. The #LmResult in the result callback @function will say whether it succeeded or not. 
       
  1485  * 
       
  1486  * Return value: #TRUE if no errors where detected while sending the authentication message, #FALSE otherwise.
       
  1487  **/
       
  1488 EXPORT_C gboolean
       
  1489 lm_connection_authenticate (LmConnection      *connection,
       
  1490 			    const gchar       *username,
       
  1491 			    const gchar       *password,
       
  1492 			    const gchar       *resource,
       
  1493 			    LmResultFunction   function,
       
  1494 			    gpointer           user_data,
       
  1495 			    GDestroyNotify     notify,
       
  1496 			    GError           **error)
       
  1497 {
       
  1498 	g_return_val_if_fail (connection != NULL, FALSE);
       
  1499 	g_return_val_if_fail (username != NULL, FALSE);
       
  1500 	g_return_val_if_fail (password != NULL, FALSE);
       
  1501 	g_return_val_if_fail (resource != NULL, FALSE);
       
  1502 
       
  1503 	if (!lm_connection_is_open (connection)) {
       
  1504 		g_set_error (error,
       
  1505 			     LM_ERROR,
       
  1506 			     LM_ERROR_CONNECTION_NOT_OPEN,
       
  1507 			     "Connection is not open, call lm_connection_open() first");
       
  1508 		return FALSE;
       
  1509 	}
       
  1510 	lm_verbose("\n[lm_connection_authenticate] inside...\n");
       
  1511 	connection->state = LM_CONNECTION_STATE_AUTHENTICATING;
       
  1512 	
       
  1513 	connection->auth_cb = _lm_utils_new_callback ((gpointer)function, 
       
  1514 						      user_data, 
       
  1515 						      notify);
       
  1516 
       
  1517 	connection->resource = g_strdup (resource);
       
  1518 	connection->effective_jid = g_strdup_printf ("%s/%s", 
       
  1519 		connection->jid, connection->resource);
       
  1520 
       
  1521 	if (connection->use_sasl) {
       
  1522 		lm_verbose("[lm_connection_authenticate]: conn->use_sasl is true. calling lm_sasl_authenticate\n");
       
  1523 		lm_sasl_authenticate (connection->sasl,
       
  1524 				      username, password,
       
  1525 				      connection->server,
       
  1526 				      connection_sasl_auth_finished);
       
  1527 
       
  1528 		connection->features_cb  =
       
  1529 			lm_message_handler_new (connection_features_cb,
       
  1530 				NULL, NULL);
       
  1531 		lm_connection_register_message_handler (connection,
       
  1532 			connection->features_cb,
       
  1533 			LM_MESSAGE_TYPE_STREAM_FEATURES,
       
  1534 			LM_HANDLER_PRIORITY_FIRST);
       
  1535 
       
  1536 		lm_verbose("[lm_connection_authenticate]: connection->use_sasl is true. So NOT calling create_auth_req_msg\n");
       
  1537 		return TRUE;
       
  1538 	}
       
  1539 
       
  1540 	return _lm_connection_old_auth (connection, username, password,
       
  1541 		resource, error);
       
  1542 }
       
  1543 
       
  1544 gboolean
       
  1545 _lm_connection_old_auth (LmConnection *connection, const gchar *username,
       
  1546 	const gchar *password, const gchar *resource, GError **error)
       
  1547 {
       
  1548 	LmMessage        *m;
       
  1549 	AuthReqData      *data;
       
  1550 	LmMessageHandler *handler;
       
  1551 	gboolean          result;
       
  1552 	
       
  1553 
       
  1554 	m = connection_create_auth_req_msg (username);
       
  1555 		
       
  1556 	data = g_new0 (AuthReqData, 1);
       
  1557 	data->username = g_strdup (username);
       
  1558 	data->password = g_strdup (password);
       
  1559 	data->resource = g_strdup (resource);
       
  1560 	
       
  1561 	handler = lm_message_handler_new (connection_auth_req_reply, 
       
  1562 					  data, 
       
  1563 					  (GDestroyNotify) auth_req_data_free);
       
  1564 	result = lm_connection_send_with_reply (connection, m, handler, error);
       
  1565 	
       
  1566 	lm_message_handler_unref (handler);
       
  1567 	lm_message_unref (m);
       
  1568 
       
  1569 	return result;
       
  1570 }
       
  1571 
       
  1572 /**
       
  1573  * lm_connection_authenticate_and_block:
       
  1574  * @connection: an #LmConnection
       
  1575  * @username: Username used to authenticate.
       
  1576  * @password: Password corresponding to @username.
       
  1577  * @resource: Resource used for this connection.
       
  1578  * @error: location to store error, or %NULL
       
  1579  * 
       
  1580  * Tries to authenticate a user against the server. This function blocks until a reply to the authentication attempt is returned and returns whether it was successful or not.
       
  1581  * 
       
  1582  * Return value: #TRUE if no errors where detected and authentication was successful. #FALSE otherwise.
       
  1583  **/
       
  1584 EXPORT_C gboolean
       
  1585 lm_connection_authenticate_and_block (LmConnection  *connection,
       
  1586 				      const gchar   *username,
       
  1587 				      const gchar   *password,
       
  1588 				      const gchar   *resource,
       
  1589 				      GError       **error)
       
  1590 {
       
  1591 	gboolean          result;
       
  1592 
       
  1593 	result = lm_connection_authenticate (connection, username, password,
       
  1594 		resource, NULL, NULL, NULL, error);
       
  1595 
       
  1596 	if (!result)
       
  1597 		return result;
       
  1598 
       
  1599 	while (lm_connection_get_state (connection) == LM_CONNECTION_STATE_AUTHENTICATING) {
       
  1600 		if (g_main_context_pending (connection->context)) {
       
  1601 			g_main_context_iteration (connection->context, TRUE);
       
  1602 		} else {
       
  1603 			/* Sleep for 1 millisecond */
       
  1604 			g_usleep (1000);
       
  1605 		}
       
  1606 	}
       
  1607 
       
  1608 	switch (lm_connection_get_state (connection)) {
       
  1609 	case LM_CONNECTION_STATE_AUTHENTICATED:
       
  1610 		return TRUE;
       
  1611 		//removing compilation error : not reachable statement
       
  1612 		//break;
       
  1613 	case LM_CONNECTION_STATE_OPEN:
       
  1614 		g_set_error (error,
       
  1615 			     LM_ERROR,
       
  1616 			     LM_ERROR_AUTH_FAILED,
       
  1617 			     "Authentication failed");
       
  1618 		return FALSE;
       
  1619 		//removing compilation error : not reachable statement
       
  1620 		//break;
       
  1621 	default:
       
  1622 		g_assert_not_reached ();
       
  1623 		break;
       
  1624 	} 
       
  1625 
       
  1626 	return FALSE;
       
  1627 }
       
  1628 
       
  1629 /**
       
  1630  * lm_connection_get_keep_alive_rate:
       
  1631  * @connection: an #LmConnection 
       
  1632  *
       
  1633  * Get the keep alive rate, in seconds. Zero is returned if no keep alive rate has been set.
       
  1634  *
       
  1635  * Since 1.3.5
       
  1636  **/
       
  1637 guint
       
  1638 lm_connection_get_keep_alive_rate (LmConnection *connection)
       
  1639 {
       
  1640 	g_return_val_if_fail (connection != NULL, 0);
       
  1641 
       
  1642 	return connection->keep_alive_rate;
       
  1643 }
       
  1644 
       
  1645 /**
       
  1646  * lm_connection_set_keep_alive_rate:
       
  1647  * @connection: an #LmConnection
       
  1648  * @rate: Number of seconds between keep alive packages are sent.
       
  1649  * 
       
  1650  * Set the keep alive rate, in seconds. Set to 0 to prevent keep alive messages to be sent.
       
  1651  * A keep alive message is a single space character.
       
  1652  **/
       
  1653 EXPORT_C void
       
  1654 lm_connection_set_keep_alive_rate (LmConnection *connection, guint rate)
       
  1655 {
       
  1656 	g_return_if_fail (connection != NULL);
       
  1657 	lm_verbose("Setting Keep Alive Rate");
       
  1658 	connection_stop_keep_alive (connection);
       
  1659 
       
  1660 	if (rate == 0) {
       
  1661 		connection->keep_alive_source = NULL;
       
  1662 		return;
       
  1663 	}
       
  1664 
       
  1665 	connection->keep_alive_rate = rate;
       
  1666 	
       
  1667 	if (lm_connection_is_open (connection)) {
       
  1668 		connection_start_keep_alive (connection);
       
  1669 	}
       
  1670 }
       
  1671 
       
  1672 /**
       
  1673  * lm_connection_is_open:
       
  1674  * @connection: #LmConnection to check if it is open.
       
  1675  * 
       
  1676  * Check if the @connection is currently open.
       
  1677  * 
       
  1678  * Return value: #TRUE if connection is open and #FALSE if it is closed.
       
  1679  **/
       
  1680 EXPORT_C gboolean
       
  1681 lm_connection_is_open (LmConnection *connection)
       
  1682 {
       
  1683 	g_return_val_if_fail (connection != NULL, FALSE);
       
  1684 	
       
  1685 	return connection->state >= LM_CONNECTION_STATE_OPEN;
       
  1686 }
       
  1687 
       
  1688 /**
       
  1689  * lm_connection_is_authenticated:
       
  1690  * @connection: #LmConnection to check if it is authenticated
       
  1691  * 
       
  1692  * Check if @connection is authenticated.
       
  1693  * 
       
  1694  * Return value: #TRUE if connection is authenticated, #FALSE otherwise.
       
  1695  **/
       
  1696 EXPORT_C gboolean 
       
  1697 lm_connection_is_authenticated (LmConnection *connection)
       
  1698 {
       
  1699 	g_return_val_if_fail (connection != NULL, FALSE);
       
  1700 
       
  1701 	return connection->state >= LM_CONNECTION_STATE_AUTHENTICATED;
       
  1702 }
       
  1703 
       
  1704 /**
       
  1705  * lm_connection_get_server:
       
  1706  * @connection: an #LmConnection
       
  1707  * 
       
  1708  * Fetches the server address that @connection is using. 
       
  1709  * 
       
  1710  * Return value: the server address
       
  1711  **/
       
  1712 EXPORT_C const gchar *
       
  1713 lm_connection_get_server (LmConnection *connection)
       
  1714 {
       
  1715 	g_return_val_if_fail (connection != NULL, NULL);
       
  1716 
       
  1717 	return connection->server;
       
  1718 }
       
  1719 
       
  1720 /**
       
  1721  * lm_connection_set_server:
       
  1722  * @connection: an #LmConnection
       
  1723  * @server: Address of the server
       
  1724  * 
       
  1725  * Sets the server address for @connection to @server. Notice that @connection
       
  1726  * can't be open while doing this. 
       
  1727  **/
       
  1728 EXPORT_C void
       
  1729 lm_connection_set_server (LmConnection *connection, const gchar *server)
       
  1730 {
       
  1731 	g_return_if_fail (connection != NULL);
       
  1732 	g_return_if_fail (server != NULL);
       
  1733 	
       
  1734 	if (lm_connection_is_open (connection)) {
       
  1735 		g_warning ("Can't change server address while connected");
       
  1736 		return;
       
  1737 	}
       
  1738 	
       
  1739 	g_free (connection->server);
       
  1740 	connection->server = _lm_utils_hostname_to_punycode (server);
       
  1741 	connection->use_srv = FALSE;
       
  1742 }
       
  1743 
       
  1744 /**
       
  1745  * lm_connection_get_jid:
       
  1746  * @connection: an #LmConnection
       
  1747  * 
       
  1748  * Fetches the jid set for @connection is using. 
       
  1749  * 
       
  1750  * Return value: the jid
       
  1751  **/
       
  1752 EXPORT_C const gchar *
       
  1753 lm_connection_get_jid (LmConnection *connection)
       
  1754 {
       
  1755 	g_return_val_if_fail (connection != NULL, NULL);
       
  1756 
       
  1757 	return connection->jid;
       
  1758 }
       
  1759 
       
  1760 /**
       
  1761  * lm_connection_get_full_jid:
       
  1762  * @connection: an #LmConnection
       
  1763  * 
       
  1764  * Returns the full jid that server set for us after
       
  1765  * resource binding, complete with the resource.
       
  1766  *
       
  1767  * Return value: the jid
       
  1768  **/
       
  1769 gchar *
       
  1770 lm_connection_get_full_jid (LmConnection *connection)
       
  1771 {
       
  1772 	g_return_val_if_fail (connection != NULL, NULL);
       
  1773 
       
  1774 	return connection->effective_jid;
       
  1775 }
       
  1776 
       
  1777 /**
       
  1778  * lm_connection_set_jid:
       
  1779  * @connection: an #LmConnection
       
  1780  * @jid: JID to be used for @connection
       
  1781  * 
       
  1782  * Sets the JID to be used for @connection.
       
  1783  **/
       
  1784 EXPORT_C void 
       
  1785 lm_connection_set_jid (LmConnection *connection, const gchar *jid)
       
  1786 {
       
  1787 	g_return_if_fail (connection != NULL);
       
  1788 
       
  1789 	if (lm_connection_is_open (connection)) {
       
  1790 		g_warning ("Can't change JID while connected");
       
  1791 		return;
       
  1792 	}
       
  1793 
       
  1794 	g_free (connection->jid);
       
  1795 	connection->jid = g_strdup (jid);
       
  1796 }
       
  1797 
       
  1798 /**
       
  1799  * lm_connection_get_port:
       
  1800  * @connection: an #LmConnection
       
  1801  * 
       
  1802  * Fetches the port that @connection is using.
       
  1803  * 
       
  1804  * Return value: 
       
  1805  **/
       
  1806 EXPORT_C guint
       
  1807 lm_connection_get_port (LmConnection *connection)
       
  1808 {
       
  1809 	g_return_val_if_fail (connection != NULL, 0);
       
  1810 
       
  1811 	return connection->port;
       
  1812 }
       
  1813 
       
  1814 /**
       
  1815  * lm_connection_set_port:
       
  1816  * @connection: an #LmConnection
       
  1817  * @port: server port
       
  1818  * 
       
  1819  * Sets the server port that @connection will be using.
       
  1820  **/
       
  1821 EXPORT_C void
       
  1822 lm_connection_set_port (LmConnection *connection, guint port)
       
  1823 {
       
  1824 	g_return_if_fail (connection != NULL);
       
  1825 	
       
  1826 	if (lm_connection_is_open (connection)) {
       
  1827 		g_warning ("Can't change server port while connected");
       
  1828 		return;
       
  1829 	}
       
  1830 	
       
  1831 	connection->port = port;
       
  1832 }
       
  1833 
       
  1834 /**
       
  1835  * lm_connection_get_ssl: 
       
  1836  * @connection: an #LmConnection
       
  1837  *
       
  1838  * Returns the SSL struct if the connection is using one.
       
  1839  * 
       
  1840  * Return value: The ssl struct or %NULL if no proxy is used.
       
  1841  **/
       
  1842 EXPORT_C LmSSL *
       
  1843 lm_connection_get_ssl (LmConnection *connection)
       
  1844 {
       
  1845 	g_return_val_if_fail (connection != NULL, NULL);
       
  1846 	
       
  1847 	return connection->ssl;
       
  1848 }
       
  1849 
       
  1850 /**
       
  1851  * lm_connection_set_ssl:
       
  1852  * @connection: An #LmConnection
       
  1853  * @ssl: An #LmSSL
       
  1854  *
       
  1855  * Sets SSL struct or unset if @ssl is %NULL. If set @connection will use SSL to for the connection.
       
  1856  */
       
  1857 EXPORT_C void
       
  1858 lm_connection_set_ssl (LmConnection *connection, LmSSL *ssl)
       
  1859 {
       
  1860 	lm_verbose("[lm_connection_set_ssl]: inside...");
       
  1861 	g_return_if_fail (connection != NULL);
       
  1862 	g_return_if_fail (lm_ssl_is_supported () == TRUE);
       
  1863 
       
  1864 	if (connection->ssl) {
       
  1865 		lm_ssl_unref (connection->ssl);
       
  1866 	}
       
  1867 
       
  1868 	if (ssl) {
       
  1869 		lm_verbose("[lm_connection_set_ssl]: setting of ssl success");
       
  1870 		connection->ssl = lm_ssl_ref (ssl);
       
  1871 	} else {
       
  1872 		lm_verbose("[lm_connection_set_ssl]: setting of ssl failed");
       
  1873 		connection->ssl = NULL;
       
  1874 	}
       
  1875 }
       
  1876 
       
  1877 /**
       
  1878  * lm_connection_get_proxy: 
       
  1879  * @connection: an #LmConnection
       
  1880  *
       
  1881  * Returns the proxy if the connection is using one.
       
  1882  * 
       
  1883  * Return value: The proxy or %NULL if no proxy is used.
       
  1884  **/
       
  1885 EXPORT_C LmProxy *
       
  1886 lm_connection_get_proxy (LmConnection *connection)
       
  1887 {
       
  1888 	g_return_val_if_fail (connection != NULL, NULL);
       
  1889 
       
  1890 	return connection->proxy;
       
  1891 } 
       
  1892 
       
  1893 /**
       
  1894  * lm_connection_set_proxy: 
       
  1895  * @connection: an #LmConnection
       
  1896  * @proxy: an #LmProxy
       
  1897  *
       
  1898  * Sets the proxy to use for this connection. To unset pass #NULL.
       
  1899  * 
       
  1900  **/
       
  1901 EXPORT_C void
       
  1902 lm_connection_set_proxy (LmConnection *connection, LmProxy *proxy)
       
  1903 {
       
  1904 	g_return_if_fail (connection != NULL);
       
  1905 
       
  1906 	if (lm_connection_is_open (connection)) {
       
  1907 		g_warning ("Can't change server proxy while connected");
       
  1908 		return;
       
  1909 	}
       
  1910 
       
  1911 	if (connection->proxy) {
       
  1912 		lm_proxy_unref (connection->proxy);
       
  1913 		connection->proxy = NULL;
       
  1914 	}
       
  1915 
       
  1916 	if (proxy && lm_proxy_get_type (proxy) != LM_PROXY_TYPE_NONE) {
       
  1917 		connection->proxy = lm_proxy_ref (proxy);
       
  1918 	}
       
  1919 }
       
  1920 
       
  1921 /**
       
  1922  * lm_connection_send: 
       
  1923  * @connection: #LmConnection to send message over.
       
  1924  * @message: #LmMessage to send.
       
  1925  * @error: location to store error, or %NULL
       
  1926  * 
       
  1927  * Asynchronous call to send a message.
       
  1928  * 
       
  1929  * Return value: Returns #TRUE if no errors where detected while sending, #FALSE otherwise.
       
  1930  **/
       
  1931 EXPORT_C gboolean
       
  1932 lm_connection_send (LmConnection  *connection, 
       
  1933 		    LmMessage     *message, 
       
  1934 		    GError       **error)
       
  1935 {
       
  1936 	gchar    *xml_str;
       
  1937 	gchar    *ch;
       
  1938 	gboolean  result;
       
  1939 	
       
  1940 	g_return_val_if_fail (connection != NULL, FALSE);
       
  1941 	g_return_val_if_fail (message != NULL, FALSE);
       
  1942 
       
  1943 	xml_str = lm_message_node_to_string (message->node);
       
  1944 	ch = strstr (xml_str, "</stream:stream>");
       
  1945 	if (ch) {
       
  1946 		*ch = '\0';
       
  1947 	}
       
  1948 	
       
  1949 	result = connection_send (connection, xml_str, -1, error);
       
  1950 	g_free (xml_str);
       
  1951 
       
  1952 	return result;
       
  1953 }
       
  1954 
       
  1955 /**
       
  1956  * lm_connection_send_with_reply:
       
  1957  * @connection: #LmConnection used to send message.
       
  1958  * @message: #LmMessage to send.
       
  1959  * @handler: #LmMessageHandler that will be used when a reply to @message arrives
       
  1960  * @error: location to store error, or %NULL
       
  1961  * 
       
  1962  * Send a #LmMessage which will result in a reply. 
       
  1963  * 
       
  1964  * Return value: Returns #TRUE if no errors where detected while sending, #FALSE otherwise.
       
  1965  **/
       
  1966 EXPORT_C gboolean 
       
  1967 lm_connection_send_with_reply (LmConnection      *connection,
       
  1968 			       LmMessage         *message,
       
  1969 			       LmMessageHandler  *handler,
       
  1970 			       GError           **error)
       
  1971 {
       
  1972 	gchar *id;
       
  1973 	
       
  1974 	g_return_val_if_fail (connection != NULL, FALSE);
       
  1975 	g_return_val_if_fail (message != NULL, FALSE);
       
  1976 	g_return_val_if_fail (handler != NULL, FALSE);
       
  1977 
       
  1978 	if (lm_message_node_get_attribute (message->node, "id")) {
       
  1979 		id = g_strdup (lm_message_node_get_attribute (message->node, 
       
  1980 							      "id"));
       
  1981 	} else {
       
  1982 		id = _lm_utils_generate_id ();
       
  1983 		lm_message_node_set_attributes (message->node, "id", id, NULL);
       
  1984 	}
       
  1985 	
       
  1986 	g_hash_table_insert (connection->id_handlers, 
       
  1987 			     id, lm_message_handler_ref (handler));
       
  1988 	lm_verbose("[lm_connection_send_with_reply]: inside..calling lm_connection_send\n");
       
  1989 	return lm_connection_send (connection, message, error);
       
  1990 }
       
  1991 
       
  1992 /**
       
  1993  * lm_connection_send_with_reply_and_block:
       
  1994  * @connection: an #LmConnection
       
  1995  * @message: an #LmMessage
       
  1996  * @error: Set if error was detected during sending.
       
  1997  * 
       
  1998  * Send @message and wait for return.
       
  1999  * 
       
  2000  * Return value: The reply
       
  2001  **/
       
  2002 EXPORT_C LmMessage *
       
  2003 lm_connection_send_with_reply_and_block (LmConnection  *connection,
       
  2004 					 LmMessage     *message,
       
  2005 					 GError       **error)
       
  2006 {
       
  2007 	gchar     *id;
       
  2008 	LmMessage *reply = NULL;
       
  2009 
       
  2010 	g_return_val_if_fail (connection != NULL, NULL);
       
  2011 	g_return_val_if_fail (message != NULL, NULL);
       
  2012 
       
  2013 	if (connection->state < LM_CONNECTION_STATE_OPENING) {
       
  2014 		g_set_error (error,
       
  2015 			     LM_ERROR,
       
  2016 			     LM_ERROR_CONNECTION_NOT_OPEN,
       
  2017 			     "Connection is not open, call lm_connection_open() first");
       
  2018 		return FALSE;
       
  2019 	}
       
  2020 
       
  2021 
       
  2022 	if (lm_message_node_get_attribute (message->node, "id")) {
       
  2023 		id = g_strdup (lm_message_node_get_attribute (message->node, 
       
  2024 							      "id"));
       
  2025 	} else {
       
  2026 		id = _lm_utils_generate_id ();
       
  2027 		lm_message_node_set_attributes (message->node, "id", id, NULL);
       
  2028 	}
       
  2029 
       
  2030 	lm_message_queue_detach (connection->queue);
       
  2031 
       
  2032 	lm_connection_send (connection, message, error);
       
  2033 
       
  2034 	while (!reply) {
       
  2035 		const gchar *m_id;
       
  2036 		guint        n;
       
  2037 
       
  2038 		g_main_context_iteration (connection->context, TRUE);
       
  2039 	
       
  2040 		if (lm_message_queue_is_empty (connection->queue)) {
       
  2041 			continue;
       
  2042 		}
       
  2043 
       
  2044 		for (n = 0; n < lm_message_queue_get_length (connection->queue); n++) {
       
  2045 			LmMessage *m;
       
  2046 
       
  2047 			m = (LmMessage *) lm_message_queue_peek_nth (connection->queue, n);
       
  2048 
       
  2049 			m_id = lm_message_node_get_attribute (m->node, "id");
       
  2050 			
       
  2051 			if (m_id && strcmp (m_id, id) == 0) {
       
  2052 				reply = m;
       
  2053 				lm_message_queue_pop_nth (connection->queue, n);
       
  2054 				break;
       
  2055 			}
       
  2056 		}
       
  2057 	}
       
  2058 
       
  2059 	g_free (id);
       
  2060 	lm_message_queue_attach (connection->queue, connection->context);
       
  2061 
       
  2062 	return reply;
       
  2063 }
       
  2064 
       
  2065 /**
       
  2066  * lm_connection_register_message_handler:
       
  2067  * @connection: Connection to register a handler for.
       
  2068  * @handler: Message handler to register.
       
  2069  * @type: Message type that @handler will handle.
       
  2070  * @priority: The priority in which to call @handler.
       
  2071  * 
       
  2072  * Registers a #LmMessageHandler to handle incoming messages of a certain type.
       
  2073  * To unregister the handler call lm_connection_unregister_message_handler().
       
  2074  **/
       
  2075 EXPORT_C void
       
  2076 lm_connection_register_message_handler  (LmConnection       *connection,
       
  2077 					 LmMessageHandler   *handler,
       
  2078 					 LmMessageType       type,
       
  2079 					 LmHandlerPriority   priority)
       
  2080 {
       
  2081 	HandlerData      *hd;
       
  2082 	
       
  2083 	g_return_if_fail (connection != NULL);
       
  2084 	g_return_if_fail (handler != NULL);
       
  2085 	g_return_if_fail (type != LM_MESSAGE_TYPE_UNKNOWN);
       
  2086 
       
  2087 	hd = g_new0 (HandlerData, 1);
       
  2088 	hd->priority = priority;
       
  2089 	hd->handler  = lm_message_handler_ref (handler);
       
  2090 
       
  2091 	connection->handlers[type] = g_slist_insert_sorted (connection->handlers[type],
       
  2092 							    hd, 
       
  2093 							    (GCompareFunc) connection_handler_compare_func);
       
  2094 }
       
  2095 
       
  2096 /**
       
  2097  * lm_connection_unregister_message_handler:
       
  2098  * @connection: Connection to unregister a handler for.
       
  2099  * @handler: The handler to unregister.
       
  2100  * @type: What type of messages to unregister this handler for.
       
  2101  * 
       
  2102  * Unregisters a handler for @connection. @handler will no longer be called 
       
  2103  * when incoming messages of @type arrive.
       
  2104  **/
       
  2105 EXPORT_C void
       
  2106 lm_connection_unregister_message_handler (LmConnection      *connection,
       
  2107 					  LmMessageHandler  *handler,
       
  2108 					  LmMessageType      type)
       
  2109 {
       
  2110 	GSList *l;
       
  2111 	
       
  2112 	g_return_if_fail (connection != NULL);
       
  2113 	g_return_if_fail (handler != NULL);
       
  2114 	g_return_if_fail (type != LM_MESSAGE_TYPE_UNKNOWN);
       
  2115 
       
  2116 	for (l = connection->handlers[type]; l; l = l->next) {
       
  2117 		HandlerData *hd = (HandlerData *) l->data;
       
  2118 		
       
  2119 		if (handler == hd->handler) {
       
  2120 			connection->handlers[type] = g_slist_remove_link (connection->handlers[type], l);
       
  2121 			g_slist_free (l);
       
  2122 			lm_message_handler_unref (hd->handler);
       
  2123 			g_free (hd);
       
  2124 			break;
       
  2125 		}
       
  2126 	}
       
  2127 }
       
  2128 
       
  2129 /**
       
  2130  * lm_connection_set_disconnect_function:
       
  2131  * @connection: Connection to register disconnect callback for.
       
  2132  * @function: Function to be called when @connection is closed.
       
  2133  * @user_data: User data passed to @function.
       
  2134  * @notify: Function that will be called with @user_data when @user_data needs to be freed. Pass #NULL if it shouldn't be freed.
       
  2135  * 
       
  2136  * Set the callback that will be called when a connection is closed. 
       
  2137  **/
       
  2138 EXPORT_C void
       
  2139 lm_connection_set_disconnect_function (LmConnection         *connection,
       
  2140 				       LmDisconnectFunction  function,
       
  2141 				       gpointer              user_data,
       
  2142 				       GDestroyNotify        notify)
       
  2143 {
       
  2144 	g_return_if_fail (connection != NULL);
       
  2145 
       
  2146 	if (connection->disconnect_cb) {
       
  2147 		_lm_utils_free_callback (connection->disconnect_cb);
       
  2148 	}
       
  2149 		
       
  2150 	if (function) {
       
  2151 		connection->disconnect_cb = _lm_utils_new_callback ((gpointer)function, 
       
  2152 	    					                    user_data,
       
  2153 							            notify);
       
  2154 	} else {
       
  2155 		connection->disconnect_cb = NULL;
       
  2156 	}
       
  2157 }
       
  2158 
       
  2159 /**
       
  2160  * lm_connection_send_raw:
       
  2161  * @connection: Connection used to send
       
  2162  * @str: The string to send, the entire string will be sent.
       
  2163  * @error: Set if error was detected during sending.
       
  2164  * 
       
  2165  * Asynchronous call to send a raw string. Useful for debugging and testing.
       
  2166  * 
       
  2167  * Return value: Returns #TRUE if no errors was detected during sending, 
       
  2168  * #FALSE otherwise.
       
  2169  **/
       
  2170 EXPORT_C gboolean 
       
  2171 lm_connection_send_raw (LmConnection  *connection, 
       
  2172 			const gchar   *str, 
       
  2173 			GError       **error)
       
  2174 {
       
  2175 	g_return_val_if_fail (connection != NULL, FALSE);
       
  2176 	g_return_val_if_fail (str != NULL, FALSE);
       
  2177 
       
  2178 	return connection_send (connection, str, -1, error);
       
  2179 }
       
  2180 /**
       
  2181  * lm_connection_get_state:
       
  2182  * @connection: Connection to get state on
       
  2183  *
       
  2184  * Returns the state of the connection.
       
  2185  *
       
  2186  * Return value: The state of the connection.
       
  2187  **/
       
  2188 EXPORT_C LmConnectionState 
       
  2189 lm_connection_get_state (LmConnection *connection)
       
  2190 {
       
  2191 	g_return_val_if_fail (connection != NULL, 
       
  2192 			      LM_CONNECTION_STATE_CLOSED);
       
  2193 
       
  2194 	return connection->state;
       
  2195 }
       
  2196 
       
  2197 /**
       
  2198  * lm_connection_get_client_host:
       
  2199  * @connection: An #LmConnection
       
  2200  *
       
  2201  * Returns the local host name of the connection.
       
  2202  *
       
  2203  * Return value: A newly allocated string representing the local host name.
       
  2204  **/
       
  2205 gchar *
       
  2206 lm_connection_get_local_host (LmConnection *connection)
       
  2207 {
       
  2208 	return lm_socket_get_local_host (connection->socket);
       
  2209 }
       
  2210 
       
  2211 /**
       
  2212  * lm_connection_ref:
       
  2213  * @connection: Connection to add a reference to.
       
  2214  * 
       
  2215  * Add a reference on @connection. To remove a reference call 
       
  2216  * lm_connection_unref().
       
  2217  * 
       
  2218  * Return value: Returns the same connection.
       
  2219  **/
       
  2220 EXPORT_C LmConnection*
       
  2221 lm_connection_ref (LmConnection *connection)
       
  2222 {
       
  2223 	g_return_val_if_fail (connection != NULL, NULL);
       
  2224 	
       
  2225 	connection->ref_count++;
       
  2226 	
       
  2227 	return connection;
       
  2228 }
       
  2229 
       
  2230 /**
       
  2231  * lm_connection_unref:
       
  2232  * @connection: Connection to remove reference from.
       
  2233  * 
       
  2234  * Removes a reference on @connection. If there are no references to
       
  2235  * @connection it will be freed and shouldn't be used again.
       
  2236  **/
       
  2237 EXPORT_C void
       
  2238 lm_connection_unref (LmConnection *connection)
       
  2239 {
       
  2240 	//g_return_if_fail (connection != NULL);
       
  2241 	if(!connection)
       
  2242 		return;
       
  2243 	connection->ref_count--;
       
  2244 	
       
  2245 	if (connection->ref_count == 0) {
       
  2246 		connection_free (connection);
       
  2247 	}
       
  2248 }