From 2156c6cd7a4b3ade7e45df9da492ed953bcfb2bf Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Mon, 25 May 2020 12:28:04 +0200 Subject: [PATCH 1/2] basic documentation of ffi --- deltachat-ffi/deltachat.h | 312 ++++++++++++++++++++++---------------- 1 file changed, 184 insertions(+), 128 deletions(-) diff --git a/deltachat-ffi/deltachat.h b/deltachat-ffi/deltachat.h index d084dfc68..25d63057e 100644 --- a/deltachat-ffi/deltachat.h +++ b/deltachat-ffi/deltachat.h @@ -32,63 +32,41 @@ typedef struct _dc_event_emitter dc_event_emitter_t; * * Let's start. * - * First of all, you have to **define an event-handler-function** - * that is called by the library on specific events - * (eg. when the configuration is done or when fresh messages arrive). - * With this function you can create a Delta Chat context then: + * First of all, you have to **create a context object** + * bound to a database. + * The database is a normal sqlite-file and is created as needed: * * ~~~ - * #include + * dc_context_t* context = dc_context_new(NULL, "example.db", NULL); + * ~~~ * - * uintptr_t event_handler_func(dc_context_t* context, int event, - * uintptr_t data1, uintptr_t data2) + * After that, make sure, you can **receive events from the context**. + * For that purpose, create an event emitter you can ask for events. + * If there are no event, the emitter will wait until there is one, + * so, in many situations you will do this in a thread: + * + * ~~~ + * dc_event_emitter_t* emitter = dc_get_event_emitter(context); + * + * void* event_handler(void* emitter) * { - * return 0; - * } - * - * dc_context_t* context = dc_context_new(event_handler_func, NULL, NULL); - * ~~~ - * - * After that, you should make sure, - * sending and receiving jobs are processed as needed. - * For this purpose, you have to **create two threads:** - * - * ~~~ - * #include - * - * void* imap_thread_func(void* context) - * { - * while (true) { - * dc_perform_imap_jobs(context); - * dc_perform_imap_fetch(context); - * dc_perform_imap_idle(context); + * dc_event_t* event; + * while ((event = dc_get_next_event(emitter)) != NULL) { + * // use the event as needed, eg. dc_event_get_id() returns the type. + * // once you're done, unref the event to avoid memory leakage: + * dc_event_unref(event); * } + * dc_event_emitter_unref(emitter); * } * - * void* smtp_thread_func(void* context) - * { - * while (true) { - * dc_perform_smtp_jobs(context); - * dc_perform_smtp_idle(context); - * } - * } - * - * static pthread_t imap_thread, smtp_thread; - * pthread_create(&imap_thread, NULL, imap_thread_func, context); - * pthread_create(&smtp_thread, NULL, smtp_thread_func, context); + * static pthread_t event_thread; + * pthread_create(&event_thread, NULL, event_handler, emitter); * ~~~ * * The example above uses "pthreads", * however, you can also use anything else for thread handling. * All deltachat-core-functions, unless stated otherwise, are thread-safe. * - * After that you can **define and open a database.** - * The database is a normal sqlite-file and is created as needed: - * - * ~~~ - * dc_open(context, "example.db", NULL); - * ~~~ - * * Now you can **configure the context:** * * ~~~ @@ -98,15 +76,22 @@ typedef struct _dc_event_emitter dc_event_emitter_t; * dc_configure(context); * ~~~ * - * dc_configure() returns immediately, the configuration itself may take a while - * and is done by a job in the imap-thread you've defined above. + * dc_configure() returns immediately, + * the configuration itself runs in background and may take a while. * Once done, the #DC_EVENT_CONFIGURE_PROGRESS reports success - * to the event_handler_func() that is also defined above. + * to the event_handler() you've defined above. * * The configuration result is saved in the database, * on subsequent starts it is not needed to call dc_configure() * (you can check this using dc_is_configured()). * + * On a successfully configured context, + * you can finally **connect to the servers:** + * + * ~~~ + * dc_start_io(context); + * ~~~ + * * Now you can **send the first message:** * * ~~~ @@ -166,19 +151,6 @@ typedef struct _dc_event_emitter dc_event_emitter_t; * - The issue-tracker for the core library is here: * * - * The following points are important mainly - * for the authors of the library itself: - * - * - For indentation, use tabs. - * Alignments that are not placed at the beginning of a line - * should be done with spaces. - * - * - For padding between functions, - * classes etc. use 2 empty lines - * - * - Source files are encoded as UTF-8 with Unix line endings - * (a simple `LF`, `0x0A` or `\n`) - * * If you need further assistance, * please do not hesitate to contact us * through the channels shown at https://delta.chat/en/contribute @@ -191,24 +163,6 @@ typedef struct _dc_event_emitter dc_event_emitter_t; */ -/** - * TODO: document - */ -dc_event_t* dc_get_next_event(dc_event_emitter_t* emitter); - -dc_event_emitter_t* dc_get_event_emitter(dc_context_t* context); -void dc_event_emitter_unref(dc_event_emitter_t* emitter); - -int dc_event_get_id (dc_event_t* event); -int dc_event_get_data1_int(dc_event_t* event); -int dc_event_get_data2_int(dc_event_t* event); -char* dc_event_get_data3_str(dc_event_t* event); - -/** - * TODO: document - */ -void dc_event_unref (dc_event_t* event); - /** * @class dc_context_t * @@ -226,21 +180,6 @@ void dc_event_unref (dc_event_t* event); * opened, connected and mails are fetched. * * @memberof dc_context_t - * @param cb a callback function that is called for events (update, - * state changes etc.) and to get some information from the client (eg. translation - * for a given string). - * See @ref DC_EVENT for a list of possible events that may be passed to the callback. - * - The callback MAY be called from _any_ thread, not only the main/GUI thread! - * - The callback MUST NOT call any dc_* and related functions unless stated - * otherwise! - * - The callback SHOULD return _fast_, for GUI updates etc. you should - * post yourself an asynchronous message to your GUI thread, if needed. - * - events do not expect a return value, just always return 0. - * @param dbfile The file to use to store the database, something like `~/file` won't - * work on all systems, if in doubt, use absolute paths. - * @param blobdir A directory to store the blobs in; a trailing slash is not needed. - * If you pass NULL or the empty string, deltachat-core creates a directory - * beside _dbfile_ with the same name and the suffix `-blobs`. * @param os_name is only for decorative use * and is shown eg. in the `X-Mailer:` header * in the form "Delta Chat Core /". @@ -248,6 +187,11 @@ void dc_event_unref (dc_event_t* event); * the used environment and/or the version here. * It is okay to give NULL, in this case `X-Mailer:` header * is set to "Delta Chat Core ". + * @param dbfile The file to use to store the database, + * something like `~/file` won't work, use absolute paths. + * @param blobdir A directory to store the blobs in; a trailing slash is not needed. + * If you pass NULL or the empty string, deltachat-core creates a directory + * beside _dbfile_ with the same name and the suffix `-blobs`. * @return A context object with some public members. * The object must be passed to the other context functions * and must be freed using dc_context_unref() after usage. @@ -269,6 +213,25 @@ dc_context_t* dc_context_new (const char* os_name, const char* d */ void dc_context_unref (dc_context_t* context); + +/** + * Create the event emitter that is used to receive events. + * The library will emit various @ref DC_EVENT events as "new message", "message read" etc. + * To get these events, you have to create an event emitter using this function + * and call dc_get_next_event() on the emitter. + * + * @memberof dc_context_t + * @param context The context object as created by dc_context_new(). + * @return Returns the event emitter, NULL on errors. + * Must be freed using dc_event_emitter_unref() after usage. + * + * Note: Use only one event emitter per context. + * Having more than one event emitter running at the same time on the same context + * will result in events randomly delivered to the one or to the other. + */ +dc_event_emitter_t* dc_get_event_emitter(dc_context_t* context); + + /** * Get the blob directory. * @@ -3857,11 +3820,122 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot); #define DC_EMPTY_INBOX 0x02 // Deprecated, flag for dc_empty_server(): Clear all INBOX messages +/** + * @class dc_event_emitter_t + * + * Opaque object that is used to get events. + * You can get an event emitter from a context using dc_get_event_emitter(). + */ + +/** + * Get the next event from an event emitter object. + * + * @memberof dc_event_emitter_t + * @param emitter Event emitter object as returned from dc_get_event_emitter(). + * @return An event as an dc_event_t object. + * You can query the event for information using dc_event_get_id(), dc_event_get_data1_int() and so on; + * if you are done with the event, you have to free the event using dc_event_unref(). + * If NULL is returned, the context belonging to the event emitter is unref'd and the no more events will come; + * in this case, free the event emitter using dc_event_emitter_unref(). + */ +dc_event_t* dc_get_next_event(dc_event_emitter_t* emitter); + + +/** + * Free an event emitter object. + * + * @memberof dc_event_emitter_t + * @param emitter Event emitter object as returned from dc_get_event_emitter(). + * If NULL is given, nothing is done and an error is logged. + * @return None. + */ +void dc_event_emitter_unref(dc_event_emitter_t* emitter); + + +/** + * @class dc_event_t + * + * Opaque object describing a single event. + * To get events, call dc_get_next_event() on an event emitter created by dc_get_event_emitter(). + */ + +/** + * Get the event-id from an event object. + * The event-id is one of the @ref DC_EVENT constants. + * There may be additional data belonging to an event, + * to get them, use dc_event_get_data1_int(), dc_event_get_data2_int() and dc_event_get_data3_str(). + * + * @memberof dc_event_t + * @param event Event object as returned from dc_get_next_event(). + * @return once of the @ref DC_EVENT constants. + * 0 on errors. + */ +int dc_event_get_id(dc_event_t* event); + + +/** + * Get a data associated with an event object. + * The meaning of the data depends on the event-id + * returned as @ref DC_EVENT constants by dc_event_get_id(). + * See also dc_event_get_data2_int() and dc_event_get_data3_str(). + * + * @memberof dc_event_t + * @param event Event object as returned from dc_get_next_event(). + * @return "data1" as a signed integer, at least 32bit, + * the meaning depends on the event type associated with this event. + */ +int dc_event_get_data1_int(dc_event_t* event); + + +/** + * Get a data associated with an event object. + * The meaning of the data depends on the event-id + * returned as @ref DC_EVENT constants by dc_event_get_id(). + * See also dc_event_get_data2_int() and dc_event_get_data3_str(). + * + * @memberof dc_event_t + * @param event Event object as returned from dc_get_next_event(). + * @return "data2" as a signed integer, at least 32bit, + * the meaning depends on the event type associated with this event. + */ +int dc_event_get_data2_int(dc_event_t* event); + + +/** + * Get a data associated with an event object. + * The meaning of the data depends on the event-id + * returned as @ref DC_EVENT constants by dc_event_get_id(). + * See also dc_event_get_data1_int() and dc_event_get_data2_int(). + * + * @memberof dc_event_t + * @param event Event object as returned from dc_get_next_event(). + * @return "data3" as a string, + * the meaning depends on the event type associated with this event. + * Once you're done with the string, you have to unref it using dc_unref_str(). + */ +char* dc_event_get_data3_str(dc_event_t* event); + + +/** + * Free memory used by an event object. + * If you forget to do this for an event, this will result in memory leakage. + * + * @memberof dc_event_t + * @param event Event object as returned from dc_get_next_event(). + * @return None. + */ +void dc_event_unref(dc_event_t* event); + + /** * @defgroup DC_EVENT DC_EVENT * - * These constants are used as events - * reported to the callback given to dc_context_new(). + * These constants are used as event-id + * in events returned by dc_get_next_event(). + * + * Events typically come with some additional data, + * use dc_event_get_data1_int(), dc_event_get_data2_int() and dc_event_get_data3_str() to read this data. + * The meaning of the data depends on the event. * * @addtogroup DC_EVENT * @{ @@ -3869,13 +3943,11 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot); /** * The library-user may write an informational string to the log. - * Passed to the callback given to dc_context_new(). * * This event should not be reported to the end-user using a popup or something like that. * * @param data1 0 - * @param data2 (const char*) Info string in english language. - * Must not be unref'd or modified and is valid only until the callback returns. + * @param data2 (char*) Info string in english language. */ #define DC_EVENT_INFO 100 @@ -3884,8 +3956,7 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot); * Emitted when SMTP connection is established and login was successful. * * @param data1 0 - * @param data2 (const char*) Info string in english language. - * Must not be unref'd or modified and is valid only until the callback returns. + * @param data2 (char*) Info string in english language. */ #define DC_EVENT_SMTP_CONNECTED 101 @@ -3894,8 +3965,7 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot); * Emitted when IMAP connection is established and login was successful. * * @param data1 0 - * @param data2 (const char*) Info string in english language. - * Must not be unref'd or modified and is valid only until the callback returns. + * @param data2 (char*) Info string in english language. */ #define DC_EVENT_IMAP_CONNECTED 102 @@ -3903,8 +3973,7 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot); * Emitted when a message was successfully sent to the SMTP server. * * @param data1 0 - * @param data2 (const char*) Info string in english language. - * Must not be unref'd or modified and is valid only until the callback returns. + * @param data2 (char*) Info string in english language. */ #define DC_EVENT_SMTP_MESSAGE_SENT 103 @@ -3912,8 +3981,7 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot); * Emitted when a message was successfully marked as deleted on the IMAP server. * * @param data1 0 - * @param data2 (const char*) Info string in english language. - * Must not be unref'd or modified and is valid only until the callback returns. + * @param data2 (char*) Info string in english language. */ #define DC_EVENT_IMAP_MESSAGE_DELETED 104 @@ -3921,8 +3989,7 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot); * Emitted when a message was successfully moved on IMAP. * * @param data1 0 - * @param data2 (const char*) Info string in english language. - * Must not be unref'd or modified and is valid only until the callback returns. + * @param data2 (char*) Info string in english language. */ #define DC_EVENT_IMAP_MESSAGE_MOVED 105 @@ -3930,8 +3997,7 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot); * Emitted when an IMAP folder was emptied. * * @param data1 0 - * @param data2 (const char*) folder name. - * Must not be unref'd or modified and is valid only until the callback returns. + * @param data2 (char*) Folder name. */ #define DC_EVENT_IMAP_FOLDER_EMPTIED 106 @@ -3939,8 +4005,7 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot); * Emitted when a new blob file was successfully written * * @param data1 0 - * @param data2 (const char*) path name - * Must not be unref'd or modified and is valid only until the callback returns. + * @param data2 (char*) Path name */ #define DC_EVENT_NEW_BLOB_FILE 150 @@ -3948,27 +4013,23 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot); * Emitted when a blob file was successfully deleted * * @param data1 0 - * @param data2 (const char*) path name - * Must not be unref'd or modified and is valid only until the callback returns. + * @param data2 (char*) Path name */ #define DC_EVENT_DELETED_BLOB_FILE 151 /** * The library-user should write a warning string to the log. - * Passed to the callback given to dc_context_new(). * * This event should not be reported to the end-user using a popup or something like that. * * @param data1 0 - * @param data2 (const char*) Warning string in english language. - * Must not be unref'd or modified and is valid only until the callback returns. + * @param data2 (char*) Warning string in english language. */ #define DC_EVENT_WARNING 300 /** * The library-user should report an error to the end-user. - * Passed to the callback given to dc_context_new(). * * As most things are asynchronous, things may go wrong at any time and the user * should not be disturbed by a dialog or so. Instead, use a bubble or so. @@ -3980,10 +4041,9 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot); * in a messasge box then. * * @param data1 0 - * @param data2 (const char*) Error string, always set, never NULL. + * @param data2 (char*) Error string, always set, never NULL. * Some error strings are taken from dc_set_stock_translation(), * however, most error strings will be in english language. - * Must not be unref'd or modified and is valid only until the callback returns. */ #define DC_EVENT_ERROR 400 @@ -4005,8 +4065,7 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot); * * @param data1 (int) 1=first/new network error, should be reported the user; * 0=subsequent network error, should be logged only - * @param data2 (const char*) Error string, always set, never NULL. - * Must not be unref'd or modified and is valid only until the callback returns. + * @param data2 (char*) Error string, always set, never NULL. */ #define DC_EVENT_ERROR_NETWORK 401 @@ -4019,9 +4078,7 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot); * dc_send_text_msg() or another sending function. * * @param data1 0 - * @param data2 (const char*) Info string in english language. - * Must not be unref'd or modified - * and is valid only until the callback returns. + * @param data2 (char*) Info string in english language. */ #define DC_EVENT_ERROR_SELF_NOT_IN_GROUP 410 @@ -4139,9 +4196,8 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot); * A typical purpose for a handler of this event may be to make the file public to some system * services. * - * @param data1 (const char*) Path and file name. - * Must not be unref'd or modified and is valid only until the callback returns. - * @param data2 0 + * @param data1 0 + * @param data2 (char*) Path and file name. */ #define DC_EVENT_IMEX_FILE_WRITTEN 2052 From ec601a3381943600852d5a4897e3121dd85a08f3 Mon Sep 17 00:00:00 2001 From: "B. Petersen" Date: Mon, 25 May 2020 12:58:21 +0200 Subject: [PATCH 2/2] revert renaming of data2_str to data3_str, while this looks clearer at a first glance, it would mean to introduce much noise in the existing bindings and understandings --- deltachat-ffi/deltachat.h | 12 ++++++------ deltachat-ffi/src/lib.rs | 4 ++-- python/src/deltachat/events.py | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/deltachat-ffi/deltachat.h b/deltachat-ffi/deltachat.h index 25d63057e..b6e2f74cc 100644 --- a/deltachat-ffi/deltachat.h +++ b/deltachat-ffi/deltachat.h @@ -3863,7 +3863,7 @@ void dc_event_emitter_unref(dc_event_emitter_t* emitter); * Get the event-id from an event object. * The event-id is one of the @ref DC_EVENT constants. * There may be additional data belonging to an event, - * to get them, use dc_event_get_data1_int(), dc_event_get_data2_int() and dc_event_get_data3_str(). + * to get them, use dc_event_get_data1_int(), dc_event_get_data2_int() and dc_event_get_data2_str(). * * @memberof dc_event_t * @param event Event object as returned from dc_get_next_event(). @@ -3877,7 +3877,7 @@ int dc_event_get_id(dc_event_t* event); * Get a data associated with an event object. * The meaning of the data depends on the event-id * returned as @ref DC_EVENT constants by dc_event_get_id(). - * See also dc_event_get_data2_int() and dc_event_get_data3_str(). + * See also dc_event_get_data2_int() and dc_event_get_data2_str(). * * @memberof dc_event_t * @param event Event object as returned from dc_get_next_event(). @@ -3891,7 +3891,7 @@ int dc_event_get_data1_int(dc_event_t* event); * Get a data associated with an event object. * The meaning of the data depends on the event-id * returned as @ref DC_EVENT constants by dc_event_get_id(). - * See also dc_event_get_data2_int() and dc_event_get_data3_str(). + * See also dc_event_get_data2_int() and dc_event_get_data2_str(). * * @memberof dc_event_t * @param event Event object as returned from dc_get_next_event(). @@ -3909,11 +3909,11 @@ int dc_event_get_data2_int(dc_event_t* event); * * @memberof dc_event_t * @param event Event object as returned from dc_get_next_event(). - * @return "data3" as a string, + * @return "data2" as a string, * the meaning depends on the event type associated with this event. * Once you're done with the string, you have to unref it using dc_unref_str(). */ -char* dc_event_get_data3_str(dc_event_t* event); +char* dc_event_get_data2_str(dc_event_t* event); /** @@ -3934,7 +3934,7 @@ void dc_event_unref(dc_event_t* event); * in events returned by dc_get_next_event(). * * Events typically come with some additional data, - * use dc_event_get_data1_int(), dc_event_get_data2_int() and dc_event_get_data3_str() to read this data. + * use dc_event_get_data1_int(), dc_event_get_data2_int() and dc_event_get_data2_str() to read this data. * The meaning of the data depends on the event. * * @addtogroup DC_EVENT diff --git a/deltachat-ffi/src/lib.rs b/deltachat-ffi/src/lib.rs index 5e4a6b51b..f3fe11c37 100644 --- a/deltachat-ffi/src/lib.rs +++ b/deltachat-ffi/src/lib.rs @@ -403,9 +403,9 @@ pub unsafe extern "C" fn dc_event_get_data2_int(event: *mut dc_event_t) -> libc: } #[no_mangle] -pub unsafe extern "C" fn dc_event_get_data3_str(event: *mut dc_event_t) -> *mut libc::c_char { +pub unsafe extern "C" fn dc_event_get_data2_str(event: *mut dc_event_t) -> *mut libc::c_char { if event.is_null() { - eprintln!("ignoring careless call to dc_event_get_data3_str()"); + eprintln!("ignoring careless call to dc_event_get_data2_str()"); return ptr::null_mut(); } diff --git a/python/src/deltachat/events.py b/python/src/deltachat/events.py index 43999fe0e..967002f65 100644 --- a/python/src/deltachat/events.py +++ b/python/src/deltachat/events.py @@ -172,7 +172,7 @@ class EventThread(threading.Thread): # function which provides us signature info of an event call evt_name = deltachat.get_dc_event_name(evt) if lib.dc_event_has_string_data(evt): - data2 = from_dc_charpointer(lib.dc_event_get_data3_str(event)) + data2 = from_dc_charpointer(lib.dc_event_get_data2_str(event)) else: data2 = lib.dc_event_get_data2_int(event)