diff --git a/README.md b/README.md index 938cca1..35a5674 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ email - which is to say, SMTP+IMAP. Delta has: -* A mature [core library](https://github.com/deltachat/deltachat-core) +* A mature [core library](https://github.com/deltachat/deltachat-core-rust) * A mature [Android application](https://github.com/deltachat/deltachat-android) * An experimental [iOS application](https://github.com/deltachat/deltachat-ios) * An electron [desktop application](https://github.com/deltachat/deltachat-desktop) @@ -22,22 +22,21 @@ Current status is probably best described as "skunkworks", although connecting to an account and sending / receiving text messages should work reliably. You can view specific progress on [the issue board](https://gitlab.com/lupine/purple-plugin-delta/boards). +We currrently build against deltachat v1.50.0. You'll need to build and install +deltachat-ffi separately and ensure that it's available via `pkg-config` for +deltachat to install. + ## Build There are some licensing issues at present, so you shouldn't build this plugin. -`deltachat-core` vendors openssl, unconditionally links it, and is MPL-licensed. +`deltachat-core-rust` uses a vendored openssl 1, unconditionally links it, and +is MPL-licensed. `purple-plugin-delta` is GPLv3 without the [OpenSSL exemption](https://people.gnome.org/~markmc/openssl-and-the-gpl.html) `libpurple` itself is GPLv2 without the OpenSSL exemption. -`deltachat-core-rust` may make OpenSSL optional, so linking against that version -would be fine. - -Linking against a patched / changed `deltachat-core` that disregards vendored -OpenSSL and uses GnuTLS instead would also be fine. - There's no point to `purple-plugin-delta` adding the OpenSSL exemption because `libpurple` lacks it, and in any event, it will be unnecessary with the next major version of OpenSSL. So, time should resolve this for us one way or another. diff --git a/delta-connection.c b/delta-connection.c index d976488..7f33f5b 100644 --- a/delta-connection.c +++ b/delta-connection.c @@ -14,38 +14,6 @@ void delta_recv_im(DeltaConnectionData *conn, uint32_t msg_id); -void *imap_thread_func(void *delta_connection_data) -{ - DeltaConnectionData *conn = (DeltaConnectionData *)delta_connection_data; - g_assert(conn != NULL); - - dc_context_t *mailbox = conn->mailbox; - g_assert(mailbox != NULL); - - while (conn->runthreads) { - dc_perform_imap_jobs(mailbox); - dc_perform_imap_fetch(mailbox); - dc_perform_imap_idle(mailbox); - } - - return NULL; -} -void *smtp_thread_func(void *delta_connection_data) -{ - DeltaConnectionData *conn = (DeltaConnectionData *)delta_connection_data; - g_assert(conn != NULL); - - dc_context_t *mailbox = conn->mailbox; - g_assert(mailbox != NULL); - - while (conn->runthreads) { - dc_perform_smtp_jobs(mailbox); - dc_perform_smtp_idle(mailbox); - } - - return NULL; -} - void _transpose_config(dc_context_t *mailbox, PurpleAccount *acct) { @@ -84,11 +52,6 @@ typedef struct { // Used by delta_process_connection_state int connection_state; - - // Used by delta_process_http_get - char *http_url; - char *http_response; - pthread_cond_t *http_wait; } ProcessRequest; gboolean @@ -151,56 +114,6 @@ delta_process_fresh_messages(void *data) return FALSE; } -void -delta_process_http_get_cb( - PurpleUtilFetchUrlData *url_data, - gpointer user_data, - const gchar *url_text, - gsize len, - const gchar *error_message -) -{ - UNUSED(url_data); - - ProcessRequest *pr = (ProcessRequest *)user_data; - g_assert(pr != NULL); - g_assert(pr->http_wait != NULL); - - if (len == 0) { - purple_debug_info("Failed to GET %s: %s\n", pr->http_url, error_message); - pr->http_response = NULL; - goto out; - } - - pr->http_response = g_malloc(len); - g_assert(pr->http_response != NULL); - - strncpy(pr->http_response, url_text, len); - -out: - pthread_cond_broadcast(pr->http_wait); - return; -} - -gboolean -delta_process_http_get(void *data) -{ - ProcessRequest *pr = (ProcessRequest *)data; - g_assert(pr != NULL); - g_assert(pr->http_url != NULL); - - purple_util_fetch_url( - pr->http_url, - TRUE, - NULL, - TRUE, - delta_process_http_get_cb, - data - ); - - return FALSE; -} - ProcessRequest * delta_build_process_request(DeltaConnectionData *conn) { @@ -217,101 +130,100 @@ delta_build_process_request(DeltaConnectionData *conn) // Do not call any libpurple or delta functions in here, as it is not // thread-safe and events may be dispatched from any delta thread. Use // purple_timeout_add(0, callback, data) to run on the main thread instead -uintptr_t -my_delta_handler(dc_context_t* mailbox, int event, uintptr_t data1, uintptr_t data2) +void * +delta_event_handler(void *context) { - DeltaConnectionData *conn = (DeltaConnectionData *)dc_get_userdata(mailbox); + DeltaConnectionData *conn = (DeltaConnectionData *)context; + g_assert(conn != NULL); - ProcessRequest *pr = NULL; - uintptr_t out = 0; - pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; - pthread_cond_t cond = PTHREAD_COND_INITIALIZER; + dc_context_t *mailbox = conn->mailbox; + dc_event_emitter_t* emitter = dc_get_event_emitter(mailbox); + dc_event_t* event; - purple_debug_info(PLUGIN_ID, "Event %d received from Delta. Args: %" PRIuPTR ", %" PRIuPTR "\n", event, data1, data2); - switch (event) { - case DC_EVENT_SMTP_MESSAGE_SENT: - case DC_EVENT_IMAP_CONNECTED: - case DC_EVENT_SMTP_CONNECTED: - case DC_EVENT_INFO: - purple_debug_info(PLUGIN_ID, "INFO from Delta: %s\n", (char *)data2); - break; - case DC_EVENT_WARNING: - purple_debug_info(PLUGIN_ID, "WARNING from Delta: %s\n", (char *)data2); - break; - case DC_EVENT_ERROR: - case DC_EVENT_ERROR_NETWORK: - purple_debug_info(PLUGIN_ID, "ERROR from Delta: %d: %s\n", (int)data1, (char *)data2); - break; - case DC_EVENT_MSGS_CHANGED: - pr = delta_build_process_request(conn); - purple_timeout_add(0, delta_process_fresh_messages, pr); - break; + // FIXME: do we still need runthreads? + while (conn->runthreads && (event = dc_get_next_event(emitter)) != NULL) { + ProcessRequest *pr = NULL; + int event_id = dc_event_get_id(event); - case DC_EVENT_INCOMING_MSG: - // data1 is chat_id, which we don't seem to need yet. - // TODO: It may be needed for group chats - pr = delta_build_process_request(conn); - pr->msg_id = (uint32_t)data2; - purple_timeout_add(0, delta_process_incoming_message, pr); - break; + purple_debug_info(PLUGIN_ID, "Event %d received from Delta.\n", event_id); - // These are all to do with sending & receiving messages. The real meat of - // the event loop - case DC_EVENT_MSG_DELIVERED: - case DC_EVENT_MSG_READ: - case DC_EVENT_CHAT_MODIFIED: - case DC_EVENT_CONTACTS_CHANGED: - purple_debug_info(PLUGIN_ID, "Event %d is TODO\n", event); - break; - - case DC_EVENT_CONFIGURE_PROGRESS: - pr = delta_build_process_request(conn); - pr->connection_state = (int)data1; - purple_timeout_add(0, delta_process_connection_state, pr); - break; - - case DC_EVENT_HTTP_GET: - purple_debug_info(PLUGIN_ID, "HTTP GET requested: %s\n", (char *)data1); - - pthread_mutex_lock(&mutex); - - pr = delta_build_process_request(conn); - g_assert(pr != NULL); - - pr->http_url = (char *)data1; - pr->http_wait = &cond; - - purple_timeout_add(0, delta_process_http_get, pr); - - // Wait patiently for the HTTP GET to complete - pthread_cond_wait(pr->http_wait, &mutex); - out = (uintptr_t)pr->http_response; - - pthread_mutex_unlock(&mutex); - - pthread_cond_destroy(&cond); - pthread_mutex_destroy(&mutex); - g_free(pr); - - break; - case DC_EVENT_IS_OFFLINE: - if ( conn->pc == NULL || !PURPLE_CONNECTION_IS_CONNECTED(conn->pc) ) { - purple_debug_info(PLUGIN_ID, "Telling Delta we are offline\n"); - out = 1; - } else { - purple_debug_info(PLUGIN_ID, "Telling Delta we are online\n"); + switch (event_id) { + case DC_EVENT_SMTP_MESSAGE_SENT: + case DC_EVENT_IMAP_CONNECTED: + case DC_EVENT_SMTP_CONNECTED: + case DC_EVENT_IMAP_MESSAGE_DELETED: + case DC_EVENT_IMAP_MESSAGE_MOVED: + case DC_EVENT_INFO: { + char *info = dc_event_get_data2_str(event); + purple_debug_info(PLUGIN_ID, "INFO from Delta: %s\n", info); + dc_str_unref(info); + break; + } + case DC_EVENT_WARNING: { + char *warn = dc_event_get_data2_str(event); + purple_debug_info(PLUGIN_ID, "WARNING from Delta: %s\n", warn); + dc_str_unref(warn); + break; + } + case DC_EVENT_ERROR: + case DC_EVENT_ERROR_NETWORK: { + int errcode = dc_event_get_data1_int(event); + char *err = dc_event_get_data2_str(event); + purple_debug_info(PLUGIN_ID, "ERROR from Delta: %d: %s\n", errcode, err); + dc_str_unref(err); + break; } - break; - case DC_EVENT_GET_STRING: - break; - default: - purple_debug_info(PLUGIN_ID, "Unknown Delta event: %d\n", event); - } - return out; + case DC_EVENT_MSGS_CHANGED: + pr = delta_build_process_request(conn); + purple_timeout_add(0, delta_process_fresh_messages, pr); + break; + + case DC_EVENT_INCOMING_MSG: + // data1 is chat_id, which we don't seem to need yet. + // TODO: It may be needed for group chats + pr = delta_build_process_request(conn); + pr->msg_id = (uint32_t)dc_event_get_data2_int(event); + purple_timeout_add(0, delta_process_incoming_message, pr); + break; + + // Things left to do + case DC_EVENT_CHAT_EPHEMERAL_TIMER_MODIFIED: + case DC_EVENT_NEW_BLOB_FILE: + case DC_EVENT_DELETED_BLOB_FILE: + case DC_EVENT_MSG_DELIVERED: + case DC_EVENT_MSG_READ: + case DC_EVENT_MSG_FAILED: + case DC_EVENT_CHAT_MODIFIED: + case DC_EVENT_CONTACTS_CHANGED: + case DC_EVENT_ERROR_SELF_NOT_IN_GROUP: + case DC_EVENT_IMEX_FILE_WRITTEN: + case DC_EVENT_IMEX_PROGRESS: + case DC_EVENT_LOCATION_CHANGED: + case DC_EVENT_MSGS_NOTICED: + case DC_EVENT_SECUREJOIN_INVITER_PROGRESS: + case DC_EVENT_SECUREJOIN_JOINER_PROGRESS: + purple_debug_info(PLUGIN_ID, "Event %d is TODO\n", event_id); + break; + + case DC_EVENT_CONFIGURE_PROGRESS: + pr = delta_build_process_request(conn); + pr->connection_state = dc_event_get_data1_int(event); + purple_timeout_add(0, delta_process_connection_state, pr); + break; + + default: + purple_debug_info(PLUGIN_ID, "Unknown Delta event: %d\n", event_id); + } + + dc_event_unref(event); + } + dc_event_emitter_unref(emitter); + + return NULL; } void @@ -336,18 +248,15 @@ delta_connection_free(PurpleConnection *pc) conn->runthreads = 0; if (conn->mailbox != NULL) { - dc_maybe_network(conn->mailbox); + dc_stop_ongoing_process(conn->mailbox); + dc_stop_io(conn->mailbox); // TODO: correctly handle join failing - if (pthread_join(conn->imap_thread, NULL) != 0) { - purple_debug_info(PLUGIN_ID, "joining imap thread failed\n"); - } - if (pthread_join(conn->smtp_thread, NULL) != 0) { - purple_debug_info(PLUGIN_ID, "joining smtp thread failed\n"); + purple_debug_info(PLUGIN_ID, "Joining event thread\n"); + if (pthread_join(conn->event_thread, NULL) != 0) { + purple_debug_info(PLUGIN_ID, "joining event thread failed\n"); } - dc_stop_ongoing_process(conn->mailbox); - dc_close(conn->mailbox); dc_context_unref(conn->mailbox); } @@ -366,25 +275,23 @@ delta_connection_start_login(PurpleConnection *pc) char dbname[1024]; PurpleAccount *acct = pc->account; DeltaConnectionData *conn = purple_connection_get_protocol_data(pc); - dc_context_t *mailbox = dc_context_new(my_delta_handler, conn, NULL); + dc_context_t *mailbox = NULL; g_snprintf( dbname, 1024, "%s%sdelta_db-%s", purple_user_dir(), G_DIR_SEPARATOR_S, acct->username ); - if (!dc_open(mailbox, dbname, NULL)) { - purple_debug_info(PLUGIN_ID, "dc_open returned false...?\n"); - } + mailbox = dc_context_new(PLUGIN_ID, dbname, NULL); conn->mailbox = mailbox; _transpose_config(mailbox, acct); conn->runthreads = 1; - pthread_create(&conn->imap_thread, NULL, imap_thread_func, conn); - pthread_create(&conn->smtp_thread, NULL, smtp_thread_func, conn); + pthread_create(&conn->event_thread, NULL, delta_event_handler, conn); dc_configure(mailbox); + dc_start_io(mailbox); dc_maybe_network(mailbox); return; diff --git a/delta-connection.h b/delta-connection.h index 8feb698..92ad20e 100644 --- a/delta-connection.h +++ b/delta-connection.h @@ -14,8 +14,7 @@ typedef struct _DeltaConnectionData { // Set to 0 to convince threads to exit int runthreads; - pthread_t imap_thread; - pthread_t smtp_thread; + pthread_t event_thread; } DeltaConnectionData; #define MAX_DELTA_CONFIGURE 1000 diff --git a/vendor/deltachat-core-0.41.0.tar.gz b/vendor/deltachat-core-0.41.0.tar.gz deleted file mode 100644 index b786c69..0000000 --- a/vendor/deltachat-core-0.41.0.tar.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:04ab7ac3b0481ec161a6b81362d880b31887acc18529c3c5f930e062bf1106f0 -size 8053637 diff --git a/vendor/libetpan-1.8.tar.gz b/vendor/libetpan-1.8.tar.gz deleted file mode 100644 index dc45da0..0000000 --- a/vendor/libetpan-1.8.tar.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4e67a7b4abadcf3cc16fa16e1621a68e54d489dadfd9a7d1f960c172e953b6eb -size 6188927