示例#1
0
static void
skypeweb_close(PurpleConnection *pc)
{
	SkypeWebAccount *sa;
	
	g_return_if_fail(pc != NULL);
	
	sa = purple_connection_get_protocol_data(pc);
	g_return_if_fail(sa != NULL);
	
	purple_timeout_remove(sa->authcheck_timeout);
	purple_timeout_remove(sa->poll_timeout);
	purple_timeout_remove(sa->watchdog_timeout);

	skypeweb_logout(sa);
	purple_signal_disconnect(purple_conversations_get_handle(), "conversation-updated", pc, PURPLE_CALLBACK(skypeweb_mark_conv_seen));
	purple_debug_info("skypeweb", "destroying %d waiting connections\n",
					  g_queue_get_length(sa->waiting_conns));
	
	while (!g_queue_is_empty(sa->waiting_conns))
		skypeweb_connection_destroy(g_queue_pop_tail(sa->waiting_conns));
	g_queue_free(sa->waiting_conns);
	
	purple_debug_info("skypeweb", "destroying %d incomplete connections\n",
			g_slist_length(sa->conns));

	while (sa->conns != NULL)
		skypeweb_connection_destroy(sa->conns->data);
		
	while (sa->dns_queries != NULL) {
		PurpleDnsQueryData *dns_query = sa->dns_queries->data;
		purple_debug_info("skypeweb", "canceling dns query for %s\n",
					purple_dnsquery_get_host(dns_query));
		sa->dns_queries = g_slist_remove(sa->dns_queries, dns_query);
		purple_dnsquery_destroy(dns_query);
	}
	
	g_hash_table_destroy(sa->sent_messages_hash);
	g_hash_table_destroy(sa->cookie_table);
	g_hash_table_destroy(sa->hostname_ip_cache);
	
	g_free(sa->messages_host);
	g_free(sa->skype_token);
	g_free(sa->registration_token);
	g_free(sa->endpoint);
	g_free(sa->username);
	g_free(sa);
}
static void skypeweb_fatal_connection_cb(SkypeWebConnection *skypewebcon)
{
	PurpleConnection *pc = skypewebcon->sa->pc;

	purple_debug_error("skypeweb", "fatal connection error\n");

	skypeweb_connection_destroy(skypewebcon);

	/* We died.  Do not pass Go.  Do not collect $200 */
	/* In all seriousness, don't attempt to call the normal callback here.
	 * That may lead to the wrong error message being displayed */
	purple_connection_error(pc,
				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
				_("Server closed the connection."));

}
static void skypeweb_ssl_connection_error(PurpleSslConnection *ssl,
		PurpleSslErrorType errortype, gpointer data)
{
	SkypeWebConnection *skypewebcon = data;
	SkypeWebAccount *sa = skypewebcon->sa;
	PurpleConnection *pc = sa->pc;
	
	skypewebcon->ssl_conn = NULL;
	
	/* Try resend the request */
	skypewebcon->retry_count++;
	if (skypewebcon->retry_count < 3) {
		skypeweb_connection_close(skypewebcon);
		skypewebcon->request_time = time(NULL);
		
		g_queue_push_head(sa->waiting_conns, skypewebcon);
		skypeweb_next_connection(sa);
	} else {
		skypeweb_connection_destroy(skypewebcon);
		purple_connection_ssl_error(pc, errortype);
	}
}
static void skypeweb_post_or_get_readdata_cb(gpointer data, gint source,
		PurpleInputCondition cond)
{
	SkypeWebConnection *skypewebcon;
	SkypeWebAccount *sa;
	gchar buf[4096];
	gssize len;

	skypewebcon = data;
	sa = skypewebcon->sa;

	if (skypewebcon->method & SKYPEWEB_METHOD_SSL) {
		len = purple_ssl_read(skypewebcon->ssl_conn,
				buf, sizeof(buf) - 1);
	} else {
		len = recv(skypewebcon->fd, buf, sizeof(buf) - 1, 0);
	}

	if (len < 0)
	{
		if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
			/* Try again later */
			return;
		}

		if (skypewebcon->method & SKYPEWEB_METHOD_SSL && skypewebcon->rx_len > 0) {
			/*
			 * This is a slightly hacky workaround for a bug in either
			 * GNU TLS or in the SSL implementation on skypeweb's web
			 * servers.  The sequence of events is:
			 * 1. We attempt to read the first time and successfully read
			 *    the server's response.
			 * 2. We attempt to read a second time and libpurple's call
			 *    to gnutls_record_recv() returns the error
			 *    GNUTLS_E_UNEXPECTED_PACKET_LENGTH, or
			 *    "A TLS packet with unexpected length was received."
			 *
			 * Normally the server would have closed the connection
			 * cleanly and this second read() request would have returned
			 * 0.  Or maybe it's normal for SSL connections to be severed
			 * in this manner?  In any case, this differs from the behavior
			 * of the standard recv() system call.
			 */
			purple_debug_warning("skypeweb",
				"ssl error, but data received.  attempting to continue\n");
		} else {
			/* Try resend the request */
			skypewebcon->retry_count++;
			if (skypewebcon->retry_count < 3) {
				skypeweb_connection_close(skypewebcon);
				skypewebcon->request_time = time(NULL);
				
				g_queue_push_head(sa->waiting_conns, skypewebcon);
				skypeweb_next_connection(sa);
			} else {
				skypeweb_fatal_connection_cb(skypewebcon);
			}
			return;
		}
	}

	if (len > 0)
	{
		buf[len] = '\0';

		skypewebcon->rx_buf = g_realloc(skypewebcon->rx_buf,
				skypewebcon->rx_len + len + 1);
		memcpy(skypewebcon->rx_buf + skypewebcon->rx_len, buf, len + 1);
		skypewebcon->rx_len += len;

		/* Wait for more data before processing */
		return;
	}

	/* The server closed the connection, let's parse the data */
	skypeweb_connection_process_data(skypewebcon);

	skypeweb_connection_destroy(skypewebcon);
	
	skypeweb_next_connection(sa);
}