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); }