static void fb_ssl_connection_error(PurpleSslConnection *ssl, PurpleSslErrorType errortype, gpointer data) { FacebookConnection *fbconn = data; PurpleConnection *pc = fbconn->fba->pc; fbconn->ssl_conn = NULL; fb_connection_destroy(fbconn); purple_connection_ssl_error(pc, errortype); }
static void fb_fatal_connection_cb(FacebookConnection *fbconn) { PurpleConnection *pc = fbconn->fba->pc; purple_debug_error("facebook", "fatal connection error\n"); fb_connection_destroy(fbconn); /* 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_reason(pc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, _("Server closed the connection.")); }
static void fb_close(PurpleConnection *pc) { FacebookAccount *fba; gchar *postdata; GSList *buddies; purple_debug_info("facebook", "disconnecting account\n"); g_return_if_fail(pc != NULL); g_return_if_fail(pc->proto_data != NULL); fba = pc->proto_data; if ( fba == NULL ) //VOXOX - JRT - 2009.10.12 - Prevent crash when network is lost or resuming from hibernation. return; purple_debug_info("facebook", "unloading plugin\n"); /* destroy blist subsystem */ fb_blist_destroy(fba); /* destroy conversation subsystem */ fb_conversation_destroy(fba); buddies = purple_find_buddies(fba->account, NULL); while(buddies) { PurpleBuddy *b = buddies->data; fb_buddy_free(b); buddies = g_slist_delete_link(buddies, buddies); } /* Tell Facebook that we've logged out. */ /* * TODO * This doesn't actually work because the request is non-blocking * and we're in the process of logging out. So we start making a * connection but then libpurple immediately cancels the attempt * and frees everything. * * There are two ways to fix this: * 1. We could make this request, but not pass in fba or reference * any other data. The request could complete normally even * after this account has logged out, since it really doesn't * need access to the PurpleConnection or the FacebookAccount. * * 2. The close prpl callback could be changed in libpurple so that * protocol plugins can have a chance to make network requests * and do other long cleanup operations. So the call to * prpl->close() would become asynchronous. It tells the * protocol plugin to begin the shutdown sequence, and the * protocol plugin tells the core when it's finished. */ if (fba->post_form_id) postdata = g_strdup_printf( "visibility=false&post_form_id=%s&" "fb_dtsg=%s&post_form_id_source=AsyncRequest&" "__a=1", fba->post_form_id, fba->dtsg); else postdata = g_strdup("visibility=false"); fb_post_or_get(fba, FB_METHOD_POST, NULL, "/ajax/chat/settings.php", postdata, NULL, NULL, FALSE); g_free(postdata); if (fba->friend_request_timer) { purple_timeout_remove(fba->friend_request_timer); } if (fba->notifications_timer) { purple_timeout_remove(fba->notifications_timer); } if (fba->new_messages_check_timer) { purple_timeout_remove(fba->new_messages_check_timer); } if (fba->perpetual_messages_timer) { purple_timeout_remove(fba->perpetual_messages_timer); } purple_debug_info("facebook", "destroying %d incomplete connections\n", g_slist_length(fba->conns)); while (fba->conns != NULL) fb_connection_destroy(fba->conns->data); while (fba->dns_queries != NULL) { PurpleDnsQueryData *dns_query = fba->dns_queries->data; purple_debug_info("facebook", "canceling dns query for %s\n", purple_dnsquery_get_host(dns_query)); fba->dns_queries = g_slist_remove(fba->dns_queries, dns_query); purple_dnsquery_destroy(dns_query); } if (fba->resending_messages != NULL) { fb_cancel_resending_messages(fba); } //VOXOX - JRT - 2009.10.13 - I know we are deleting fba anyway, but since other threads may also be accessing this, // it helps reduce crashes due to freed memory ptrs. (There is no thread syncing to control this better). g_hash_table_destroy(fba->cookie_table); g_hash_table_destroy(fba->hostname_ip_cache); g_hash_table_destroy(fba->auth_buddies); g_free(fba->post_form_id); g_free(fba->dtsg); g_free(fba->channel_number); g_free(fba->last_status_message); g_free(fba->extra_challenge); g_free(fba->captcha_session); g_free(fba->persist_data); g_free(fba); }
static void fb_post_or_get_readdata_cb(gpointer data, gint source, PurpleInputCondition cond) { FacebookConnection *fbconn; gchar buf[4096]; ssize_t len; fbconn = data; if (fbconn->method & FB_METHOD_SSL) { len = purple_ssl_read(fbconn->ssl_conn, buf, sizeof(buf) - 1); } else { len = recv(fbconn->fd, buf, sizeof(buf) - 1, 0); } if (len < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) { /* Try again later */ return; } if (fbconn->method & FB_METHOD_SSL && fbconn->rx_len > 0) { /* * This is a slightly hacky workaround for a bug in either * GNU TLS or in the SSL implementation on Facebook'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("facebook", "ssl error, but data received. attempting to continue\n"); } else { /* TODO: Is this a regular occurrence? If so then maybe resend the request? */ fb_fatal_connection_cb(fbconn); return; } } if (len > 0) { buf[len] = '\0'; fbconn->rx_buf = g_realloc(fbconn->rx_buf, fbconn->rx_len + len + 1); memcpy(fbconn->rx_buf + fbconn->rx_len, buf, len + 1); fbconn->rx_len += len; /* Wait for more data before processing */ return; } /* The server closed the connection, let's parse the data */ fb_connection_process_data(fbconn); fb_connection_destroy(fbconn); }