Commit 108a7a5a authored by Andrea Schaefer's avatar Andrea Schaefer
Browse files

Merge branch 'dev' of https://github.com/gkdr/lurch into dev

parents f0f83e86 664709cf
......@@ -11,10 +11,10 @@ build_script:
- sh: make
test_script:
- sh: CMOCKA_MESSAGE_OUTPUT=XML CMOCKA_XML_FILE=build/cmocka_results.xml make test
- sh: CMOCKA_MESSAGE_OUTPUT=XML CMOCKA_XML_FILE=build/cmocka_results_%g.xml make test --ignore-errors
after_test:
- sh: curl -v -F "file=@$APPVEYOR_BUILD_FOLDER/build/cmocka_results.xml" "https://ci.appveyor.com/api/testresults/junit/$APPVEYOR_JOB_ID"
- sh: find build/ -type f -name *.xml -exec curl -v -F "file=@$APPVEYOR_BUILD_FOLDER/{}" "https://ci.appveyor.com/api/testresults/junit/$APPVEYOR_JOB_ID" \;
- sh: bash <(curl -s https://codecov.io/bash) -g test/ -B $APPVEYOR_REPO_BRANCH -b $APPVEYOR_BUILD_VERSION
artifacts:
......
......@@ -58,13 +58,7 @@ PLUGIN_CPPFLAGS=-DPURPLE_PLUGINS
# -D_BSD_SOURCE can be removed once nobody uses glibc <= 2.18 any more
CPPFLAGS += -D_XOPEN_SOURCE=700 -D_BSD_SOURCE -D_DEFAULT_SOURCE
LDFLAGS += -ldl -lm $(PKGCFG_L) $(LJABBER) -Wl,-rpath,$(PURPLE_PLUGIN_DIR)
LDFLAGS_T=$(LDFLAGS) -lpurple -lcmocka \
-Wl,--wrap=purple_user_dir \
-Wl,--wrap=purple_prefs_get_bool \
-Wl,--wrap=purple_prefs_get_int \
-Wl,--wrap=purple_debug_error \
-Wl,--wrap=purple_debug_info \
-Wl,--wrap=purple_debug_misc \
LDFLAGS_T=$(LDFLAGS) -lpurple -lcmocka
### directories
#
......@@ -95,6 +89,7 @@ OBJECTS := $(patsubst $(SDIR)/%.c, $(BDIR)/%.o, $(SOURCES))
OBJECTS_W_COVERAGE := $(patsubst $(SDIR)/%.c, $(BDIR)/%_w_coverage.o, $(SOURCES))
TEST_SOURCES := $(wildcard $(TDIR)/test_*.c)
TEST_OBJECTS := $(patsubst $(TDIR)/test_%.c, $(BDIR)/test_%.o, $(TEST_SOURCES))
TEST_TARGETS := $(patsubst $(TDIR)/test_%.c, $(BDIR)/test_%, $(TEST_SOURCES))
VENDOR_LIBS=$(LOMEMO_PATH) $(AXC_PATH) $(AX_PATH)
......@@ -157,9 +152,41 @@ tarball: | clean-all $(BDIR)
mv $(TARBALL_FILE_NAME) $(TARBALL_DIR_NAME)/
mv $(TARBALL_DIR_NAME) $(BDIR)/
test: $(TEST_OBJECTS) $(OBJECTS_W_COVERAGE) $(VENDOR_LIBS)
$(CC) $(CFLAGS) $(CPPFLAGS) -O0 --coverage $^ $(PURPLE_DIR)/libjabber.so.0 -o $(BDIR)/$@ $(LDFLAGS_T)
-$(BDIR)/$@ 2>&1 | grep -Ev ".*CRITICAL.*" | tr -s '\n' # filter annoying and irrelevant glib output
$(BDIR)/test_lurch_util: $(OBJECTS_W_COVERAGE) $(VENDOR_LIBS) $(BDIR)/test_lurch_util.o
$(CC) $(CFLAGS) $(CPPFLAGS) -O0 --coverage $^ $(PURPLE_DIR)/libjabber.so.0 -o $@ $(LDFLAGS_T) \
-Wl,--wrap=purple_user_dir \
-Wl,--wrap=purple_prefs_get_bool \
-Wl,--wrap=purple_prefs_get_int \
-Wl,--wrap=purple_debug_error \
-Wl,--wrap=purple_debug_info \
-Wl,--wrap=purple_debug_misc \
-Wl,--wrap=purple_base16_encode_chunked
bash -c "set -o pipefail; $@ 2>&1 | grep -Ev ".*CRITICAL.*" | tr -s '\n'" # filter annoying and irrelevant glib output
$(BDIR)/test_lurch_api: $(OBJECTS_W_COVERAGE) $(VENDOR_LIBS) $(BDIR)/test_lurch_api.o
$(CC) $(CFLAGS) $(CPPFLAGS) -O0 --coverage $^ $(PURPLE_DIR)/libjabber.so.0 -o $@ $(LDFLAGS_T) \
-Wl,--wrap=purple_account_get_username \
-Wl,--wrap=purple_account_get_connection \
-Wl,--wrap=purple_signal_register \
-Wl,--wrap=purple_signal_unregister \
-Wl,--wrap=purple_signal_connect \
-Wl,--wrap=purple_signal_disconnect \
-Wl,--wrap=purple_find_conversation_with_account \
-Wl,--wrap=jabber_pep_publish \
-Wl,--wrap=jabber_chat_find_by_conv \
-Wl,--wrap=axc_get_device_id \
-Wl,--wrap=axc_key_load_public_own \
-Wl,--wrap=axc_key_load_public_addr \
-Wl,--wrap=axc_session_exists_any \
-Wl,--wrap=omemo_storage_user_devicelist_retrieve \
-Wl,--wrap=omemo_storage_chatlist_delete \
-Wl,--wrap=omemo_storage_chatlist_save \
-Wl,--wrap=omemo_storage_chatlist_exists \
-Wl,--wrap=omemo_storage_user_devicelist_retrieve \
-Wl,--wrap=lurch_util_fp_get_printable
bash -c "set -o pipefail; $@ 2>&1 | grep -Ev ".*CRITICAL.*" | tr -s '\n'" # filter annoying and irrelevant glib output
test: $(OBJECTS_W_COVERAGE) $(VENDOR_LIBS) $(TEST_TARGETS)
coverage: test
gcovr -r . --html --html-details -o build/coverage.html
......
Subproject commit 3c8268172829996ec1f1e7b7a12df5c63ceb0ef1
Subproject commit e3b2125eb630e7137ea2b904bf4ddc6bdc106092
......@@ -37,8 +37,6 @@
#define JABBER_MAX_LEN_DOMAIN 1023
#define JABBER_MAX_LEN_BARE JABBER_MAX_LEN_NODE + JABBER_MAX_LEN_DOMAIN + 1
#define LURCH_ACC_SETTING_INITIALIZED "lurch_initialised"
#define LURCH_ERR_STRING_ENCRYPT "There was an error encrypting the message and it was not sent. " \
"You can try again, or try to find the problem by looking at the debug log."
#define LURCH_ERR_STRING_DECRYPT "There was an error decrypting an OMEMO message addressed to this device. " \
......@@ -146,6 +144,9 @@ static char * lurch_queue_make_key_string_s(const char * name, const char * devi
* Does the first-time install of the axc DB.
* As specified in OMEMO, it checks if the generated device ID already exists.
* Therefore, it should be called at a point in time when other entries exist.
*
* If an initialized DB already exists, this function exits with success without doing anything.
* This is checked by trying to retrieve the device ID from it.
*
* @param uname The username.
* @return 0 on success, negative on error.
......@@ -996,7 +997,6 @@ static void lurch_pep_own_devicelist_request_handler(JabberStream * js_p, const
int len = 0;
PurpleAccount * acc_p = (void *) 0;
char * uname = (void *) 0;
int install = 0;
axc_context * axc_ctx_p = (void *) 0;
uint32_t own_id = 0;
int needs_publishing = 1;
......@@ -1007,9 +1007,7 @@ static void lurch_pep_own_devicelist_request_handler(JabberStream * js_p, const
acc_p = purple_connection_get_account(js_p->gc);
uname = lurch_util_uname_strip(purple_account_get_username(acc_p));
install = (purple_account_get_bool(acc_p, LURCH_ACC_SETTING_INITIALIZED, FALSE)) ? 0 : 1;
if (install && !uninstall) {
if (!uninstall) {
purple_debug_info("lurch", "%s: %s\n", __func__, "preparing installation...");
ret_val = lurch_axc_prepare(uname);
if (ret_val) {
......@@ -1092,10 +1090,6 @@ static void lurch_pep_own_devicelist_request_handler(JabberStream * js_p, const
goto cleanup;
}
if (install && !uninstall) {
purple_account_set_bool(acc_p, LURCH_ACC_SETTING_INITIALIZED, TRUE);
}
ret_val = lurch_devicelist_process(uname, dl_p, js_p);
if (ret_val) {
err_msg_dbg = g_strdup_printf("failed to process the devicelist");
......@@ -1157,25 +1151,24 @@ cleanup:
/**
* Set as callback for the "account connected" signal.
* Requests the own devicelist, as that requires an active connection (as
* opposed to just registering PEP handlers).
* Also inits the msg queue hashtable.
* Requests the own devicelist, as that requires an active connection (as opposed to just registering PEP handlers).
*/
static void lurch_account_connect_cb(PurpleAccount * acc_p) {
int ret_val = 0;
char * uname = (void *) 0;
JabberStream * js_p = (void *) 0;
char * uname = (void *) 0;
char * dl_ns = (void *) 0;
// purple_account_set_bool(acc_p, LURCH_ACC_SETTING_INITIALIZED, FALSE);
js_p = purple_connection_get_protocol_data(purple_account_get_connection(acc_p));
if (strncmp(purple_account_get_protocol_id(acc_p), JABBER_PROTOCOL_ID, strlen(JABBER_PROTOCOL_ID))) {
return;
}
// remove unused account preferences
purple_account_remove_setting(acc_p, "lurch_initialised");
ret_val = omemo_devicelist_get_pep_node_name(&dl_ns);
if (ret_val) {
purple_debug_error("lurch", "%s: %s (%i)\n", __func__, "failed to get devicelist pep node name", ret_val);
......@@ -2142,7 +2135,6 @@ static PurpleCmdRet lurch_cmd_func(PurpleConversation * conv_p,
uint32_t id = 0;
uint32_t remove_id = 0;
axc_buf * key_buf_p = (void *) 0;
gchar * fp = (void *) 0;
char * fp_printable = (void *) 0;
omemo_devicelist * own_dl_p = (void *) 0;
omemo_devicelist * other_dl_p = (void *) 0;
......@@ -2205,7 +2197,6 @@ static PurpleCmdRet lurch_cmd_func(PurpleConversation * conv_p,
}
uninstall = 1;
purple_account_set_bool(purple_conversation_get_account(conv_p), LURCH_ACC_SETTING_INITIALIZED, FALSE);
dl_node_p = xmlnode_from_str(temp_msg_1, -1);
jabber_pep_publish(purple_connection_get_protocol_data(purple_conversation_get_gc(conv_p)), dl_node_p);
msg = g_strdup_printf("Published devicelist minus this device's ID. "
......@@ -2302,8 +2293,7 @@ static PurpleCmdRet lurch_cmd_func(PurpleConversation * conv_p,
goto cleanup;
}
fp = purple_base16_encode_chunked(axc_buf_get_data(key_buf_p), axc_buf_get_len(key_buf_p));
fp_printable = lurch_util_fp_get_printable(fp);
fp_printable = lurch_util_fp_get_printable(key_buf_p);
msg = g_strdup_printf("This device's fingerprint is:\n%s\n"
"You should make sure that your conversation partner gets displayed the same for this device.", fp_printable);
} else if (!g_strcmp0(args[2], "conv")) {
......@@ -2314,8 +2304,7 @@ static PurpleCmdRet lurch_cmd_func(PurpleConversation * conv_p,
goto cleanup;
}
fp = purple_base16_encode_chunked(axc_buf_get_data(key_buf_p), axc_buf_get_len(key_buf_p));
fp_printable = lurch_util_fp_get_printable(fp);
fp_printable = lurch_util_fp_get_printable(key_buf_p);
temp_msg_1 = g_strdup_printf("The devices participating in this conversation and their fingerprints are as follows:\n"
"This device's (%s:%i) fingerprint:\n%s\n", uname, id, fp_printable);
......@@ -2337,9 +2326,7 @@ static PurpleCmdRet lurch_cmd_func(PurpleConversation * conv_p,
continue;
}
g_free(fp);
fp = purple_base16_encode_chunked(axc_buf_get_data(key_buf_p), axc_buf_get_len(key_buf_p));
fp_printable = lurch_util_fp_get_printable(fp);
fp_printable = lurch_util_fp_get_printable(key_buf_p);
axc_buf_free(key_buf_p);
key_buf_p = (void *) 0;
......@@ -2371,9 +2358,7 @@ static PurpleCmdRet lurch_cmd_func(PurpleConversation * conv_p,
continue;
}
g_free(fp);
fp = purple_base16_encode_chunked(axc_buf_get_data(key_buf_p), axc_buf_get_len(key_buf_p));
fp_printable = lurch_util_fp_get_printable(fp);
fp_printable = lurch_util_fp_get_printable(key_buf_p);
axc_buf_free(key_buf_p);
key_buf_p = (void *) 0;
......@@ -2475,7 +2460,6 @@ cleanup:
axc_context_destroy_all(axc_ctx_p);
g_free(msg);
axc_buf_free(key_buf_p);
g_free(fp);
g_free(fp_printable);
omemo_devicelist_destroy(own_dl_p);
omemo_devicelist_destroy(other_dl_p);
......
......@@ -2,6 +2,7 @@
#include <glib.h>
#include <purple.h>
#include "chat.h"
#include "pep.h"
#include "axc.h"
......@@ -185,12 +186,49 @@ void lurch_api_disable_im_handler(PurpleAccount * acc_p, const char * contact_ba
g_free(db_fn_omemo);
}
void lurch_api_enable_chat_handler(PurpleAccount * acc_p, const char * full_conversation_name, void (*cb)(int32_t err, void * user_data_p), void * user_data_p) {
int32_t ret_val = 0;
char * uname = (void *) 0;
char * db_fn_omemo = (void *) 0;
uname = lurch_util_uname_strip(purple_account_get_username(acc_p));
db_fn_omemo = lurch_util_uname_get_db_fn(uname, LURCH_DB_NAME_OMEMO);
ret_val = omemo_storage_chatlist_save(full_conversation_name, db_fn_omemo);
if (ret_val) {
purple_debug_error(MODULE_NAME, "Failed to enable OMEMO for chat %s using DB %s.\n", full_conversation_name, db_fn_omemo);
}
cb(ret_val, user_data_p);
g_free(uname);
g_free(db_fn_omemo);
}
void lurch_api_disable_chat_handler(PurpleAccount * acc_p, const char * full_conversation_name, void (*cb)(int32_t err, void * user_data_p), void * user_data_p) {
int32_t ret_val = 0;
char * uname = (void *) 0;
char * db_fn_omemo = (void *) 0;
uname = lurch_util_uname_strip(purple_account_get_username(acc_p));
db_fn_omemo = lurch_util_uname_get_db_fn(uname, LURCH_DB_NAME_OMEMO);
ret_val = omemo_storage_chatlist_delete(full_conversation_name, db_fn_omemo);
if (ret_val) {
purple_debug_error(MODULE_NAME, "Failed to disable OMEMO for chat %s using DB %s.\n", full_conversation_name, db_fn_omemo);
}
cb(ret_val, user_data_p);
g_free(uname);
g_free(db_fn_omemo);
}
void lurch_api_fp_get_handler(PurpleAccount * acc_p, void (*cb)(int32_t err, const char * fp_printable, void * user_data_p), void * user_data_p) {
int32_t ret_val = 0;
char * uname = (void *) 0;
axc_context * axc_ctx_p = (void *) 0;
axc_buf * key_buf_p = (void *) 0;
gchar * fp = (void *) 0;
char * fp_printable = (void *) 0;
uname = lurch_util_uname_strip(purple_account_get_username(acc_p));
......@@ -207,20 +245,18 @@ void lurch_api_fp_get_handler(PurpleAccount * acc_p, void (*cb)(int32_t err, con
goto cleanup;
}
fp = purple_base16_encode_chunked(axc_buf_get_data(key_buf_p), axc_buf_get_len(key_buf_p));
fp_printable = lurch_util_fp_get_printable(fp);
fp_printable = lurch_util_fp_get_printable(key_buf_p);
cleanup:
cb(ret_val, fp_printable, user_data_p);
g_free(fp_printable);
g_free(fp);
axc_buf_free(key_buf_p);
axc_context_destroy_all(axc_ctx_p);
}
/**
* Given a list of IDs, retrieves the public keys from the libsignal sessions and creates hash table with ID to fingerprint pairs.
* Given a list of IDs, retrieves the public keys from the libsignal sessions and creates a hash table with ID to fingerprint pairs.
* If there is an entry in the devicelist, but no session yet, the fingerprint cannot be retrieved this way and the value will be NULL.
* g_hash_table_destroy() the table when done with it.
*/
......@@ -230,7 +266,6 @@ static int32_t lurch_api_fp_create_table(const char * jid, axc_context * axc_ct
const GList * curr_p = (void *) 0;
uint32_t curr_device_id = 0;
axc_buf * key_buf_p = (void *) 0;
gchar * fp = (void *) 0;
id_fp_table = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, g_free);
......@@ -247,13 +282,10 @@ static int32_t lurch_api_fp_create_table(const char * jid, axc_context * axc_ct
continue;
}
fp = purple_base16_encode_chunked(axc_buf_get_data(key_buf_p), axc_buf_get_len(key_buf_p));
(void) g_hash_table_insert(id_fp_table, curr_p->data, lurch_util_fp_get_printable(fp));
(void) g_hash_table_insert(id_fp_table, curr_p->data, lurch_util_fp_get_printable(key_buf_p));
axc_buf_free(key_buf_p);
key_buf_p = (void *) 0;
g_free(fp);
fp = (void *) 0;
ret_val = 0;
}
......@@ -276,7 +308,6 @@ void lurch_api_fp_list_handler(PurpleAccount * acc_p, void (*cb)(int32_t err, GH
axc_context * axc_ctx_p = (void *) 0;
GHashTable * id_fp_table = (void *) 0;
axc_buf * key_buf_p = (void *) 0;
gchar * fp = (void *) 0;
ret_val = lurch_api_id_list_get_own(acc_p, &own_id_list);
if (ret_val) {
......@@ -306,10 +337,7 @@ void lurch_api_fp_list_handler(PurpleAccount * acc_p, void (*cb)(int32_t err, GH
goto cleanup;
}
fp = purple_base16_encode_chunked(axc_buf_get_data(key_buf_p), axc_buf_get_len(key_buf_p));
(void) g_hash_table_insert(id_fp_table, own_id_list->data, lurch_util_fp_get_printable(fp));
g_free(fp);
fp = (void *) 0;
(void) g_hash_table_insert(id_fp_table, own_id_list->data, lurch_util_fp_get_printable(key_buf_p));
cleanup:
cb(ret_val, id_fp_table, user_data_p);
......@@ -319,7 +347,6 @@ cleanup:
axc_context_destroy_all(axc_ctx_p);
g_hash_table_destroy(id_fp_table);
axc_buf_free(key_buf_p);
g_free(fp);
}
// returns NULL as hash table if devicelist is empty
......@@ -434,6 +461,89 @@ cleanup:
axc_context_destroy_all(axc_ctx_p);
}
void lurch_api_status_chat_handler(PurpleAccount * acc_p, const char * full_conversation_name, void (*cb)(int32_t err, lurch_status_chat_t status, void * user_data_p), void * user_data_p) {
int32_t ret_val = 0;
lurch_status_chat_t status = LURCH_STATUS_CHAT_DISABLED;
char * uname = (void *) 0;
char * db_fn_omemo = (void *) 0;
PurpleConversation * conv_p = (void *) 0;
JabberChat * muc_p = (void *) 0;
GList * curr_item_p = (void *) 0;
JabberChatMember * curr_muc_member_p = (void *) 0;
char * curr_muc_member_bare_jid = (void *) 0;
omemo_devicelist * curr_dl_p = (void *) 0;
uname = lurch_util_uname_strip(purple_account_get_username(acc_p));
db_fn_omemo = lurch_util_uname_get_db_fn(uname, LURCH_DB_NAME_OMEMO);
conv_p = purple_find_conversation_with_account(PURPLE_CONV_TYPE_CHAT, full_conversation_name, acc_p);
if (!conv_p) {
purple_debug_error(MODULE_NAME, "Could not find groupchat %s.\n", full_conversation_name);
ret_val = EXIT_FAILURE;
goto cleanup;
}
muc_p = jabber_chat_find_by_conv(conv_p);
if (!muc_p) {
purple_debug_error(MODULE_NAME, "Could not find the data for groupchat %s.\n", full_conversation_name);
ret_val = EXIT_FAILURE;
goto cleanup;
}
for (curr_item_p = g_hash_table_get_values(muc_p->members); curr_item_p; curr_item_p = curr_item_p->next) {
curr_muc_member_p = (JabberChatMember *) curr_item_p->data;
curr_muc_member_bare_jid = jabber_get_bare_jid(curr_muc_member_p->jid);
if (!curr_muc_member_bare_jid) {
purple_debug_warning(
MODULE_NAME,
"Could not get the JID of chat member with handle %s, which probably means the chat is anonymous.\n",
curr_muc_member_p->handle
);
status = LURCH_STATUS_CHAT_ANONYMOUS;
goto cleanup;
}
ret_val = omemo_storage_user_devicelist_retrieve(curr_muc_member_bare_jid, db_fn_omemo, &curr_dl_p);
if (ret_val) {
purple_debug_error(MODULE_NAME, "Could not retrieve the devicelist for %s from %s.\n", curr_muc_member_bare_jid, db_fn_omemo);
goto cleanup;
}
if (omemo_devicelist_is_empty(curr_dl_p)) {
purple_debug_warning(
MODULE_NAME,
"Could not find %s's devicelist in chat %s. The user is probably not in %s's contact list.\n",
curr_muc_member_bare_jid, full_conversation_name, uname
);
status = LURCH_STATUS_CHAT_NO_DEVICELIST;
goto cleanup;
}
g_free(curr_muc_member_bare_jid);
curr_muc_member_bare_jid = (void *) 0;
omemo_devicelist_destroy(curr_dl_p);
curr_dl_p = (void *) 0;
}
status = LURCH_STATUS_CHAT_OK;
cleanup:
cb(ret_val, status, user_data_p);
g_free(uname);
g_free(db_fn_omemo);
// if loop was exited early
g_free(curr_muc_member_bare_jid);
omemo_devicelist_destroy(curr_dl_p);
}
static void lurch_api_marshal_VOID__POINTER_INT_POINTER_POINTER(PurpleCallback cb, va_list args, void * data, void ** return_val) {
void * arg1 = va_arg(args, void *);
gint32 arg2 = va_arg(args, guint);
......@@ -454,13 +564,15 @@ typedef enum {
* When adding a new signal: increase this number and add the name, handler function, and handler function type
* to the respective array.
*/
#define NUM_OF_SIGNALS 8
#define NUM_OF_SIGNALS 11
const char * signal_names[NUM_OF_SIGNALS] = {
"lurch-id-list",
"lurch-id-remove",
"lurch-enable-im",
"lurch-disable-im",
"lurch-enable-chat",
"lurch-disable-chat",
"lurch-fp-get",
"lurch-fp-list",
"lurch-fp-other",
......@@ -472,6 +584,8 @@ const void * signal_handlers[NUM_OF_SIGNALS] = {
lurch_api_id_remove_handler,
lurch_api_enable_im_handler,
lurch_api_disable_im_handler,
lurch_api_enable_chat_handler,
lurch_api_disable_chat_handler,
lurch_api_fp_get_handler,
lurch_api_fp_list_handler,
lurch_api_fp_other_handler,
......@@ -483,6 +597,8 @@ const lurch_api_handler_t signal_handler_types[NUM_OF_SIGNALS] = {
LURCH_API_HANDLER_ACC_DID_CB_DATA,
LURCH_API_HANDLER_ACC_JID_CB_DATA,
LURCH_API_HANDLER_ACC_JID_CB_DATA,
LURCH_API_HANDLER_ACC_JID_CB_DATA,
LURCH_API_HANDLER_ACC_JID_CB_DATA,
LURCH_API_HANDLER_ACC_CB_DATA,
LURCH_API_HANDLER_ACC_CB_DATA,
LURCH_API_HANDLER_ACC_JID_CB_DATA,
......@@ -563,4 +679,4 @@ void lurch_api_unload() {
purple_signal_unregister(plugins_handle_p, signal_name);
}
}
\ No newline at end of file
}
......@@ -5,6 +5,20 @@
#define LURCH_ERR_NO_BUNDLE -1000010
#define LURCH_ERR_DEVICE_NOT_IN_LIST -1000100
typedef enum {
LURCH_STATUS_DISABLED = 0, // manually disabled
LURCH_STATUS_NOT_SUPPORTED, // no OMEMO support, i.e. there is no devicelist node
LURCH_STATUS_NO_SESSION, // OMEMO is supported, but there is no libsignal session yet
LURCH_STATUS_OK // OMEMO is supported and session exists
} lurch_status_t;
typedef enum {
LURCH_STATUS_CHAT_DISABLED = 0, // OMEMO was not manually enabled
LURCH_STATUS_CHAT_ANONYMOUS, // chat is anonymous, i.e. a member's JID could not be accessed
LURCH_STATUS_CHAT_NO_DEVICELIST, // a member's devicelist could not be accessed, probably because s/he is not a contact
LURCH_STATUS_CHAT_OK // in theory, OMEMO should work
} lurch_status_chat_t;
/**
* Initializes the API by registering the signals and signal handlers.
*/
......@@ -15,14 +29,6 @@ void lurch_api_init();
*/
void lurch_api_unload();
typedef enum {
LURCH_STATUS_DISABLED = 0, // manually disabled
LURCH_STATUS_NOT_SUPPORTED, // no OMEMO support, i.e. there is no devicelist node
LURCH_STATUS_NO_SESSION, // OMEMO is supported, but there is no libsignal session yet
LURCH_STATUS_OK // OMEMO is supported and session exists
} lurch_status_t;
/**
* USAGE
*
......@@ -43,4 +49,88 @@ typedef enum {
* - Emit the signal using the plugin system handle as the instance and pass the necessary data.
* If you do it wrong, there will be no compiler errors and the pointers are gibberish, so take care.
* You can easily get the plugin system handle anywhere by calling purple_plugins_get_handle().
*/
\ No newline at end of file
*/
/**
* SIGNAL: lurch-id-list
*
* Gets the specified account's OMEMO devicelist and passes it to the callback as a GList containing uint32_t *.
* To access the actual ID, cast the data member to a uint32_t * and dereference it.
* This device's ID will be the first item in the list.
*/
void lurch_api_id_list_handler(PurpleAccount * acc_p, void (*cb)(int32_t err, GList * id_list, void * user_data_p), void * user_data_p);
/**
* SIGNAL: lurch-id-remove
*
* Removes the specified OMEMO device ID from the specified account's devicelist.
*/
void lurch_api_id_remove_handler(PurpleAccount * acc_p, uint32_t device_id, void (*cb)(int32_t err, void * user_data_p), void * user_data_p);
/**
* SIGNAL: lurch-enable-im
*
* Enables OMEMO for the specified contact.
*/
void lurch_api_enable_im_handler(PurpleAccount * acc_p, const char * contact_bare_jid, void (*cb)(int32_t err, void * user_data_p), void * user_data_p);
/**
* SIGNAL: lurch-disable-im
*
* Disables OMEMO for the specified contact.
*/
void lurch_api_disable_im_handler(PurpleAccount * acc_p, const char * contact_bare_jid, void (*cb)(int32_t err, void * user_data_p), void * user_data_p);
/**
* SIGNAL: lurch-enable-chat
*
* Enables OMEMO for the specified chat. The conversation name can be obtained by simply calling purple_conversation_get_name().
*/
void lurch_api_enable_chat_handler(PurpleAccount * acc_p, const char * full_conversation_name, void (*cb)(int32_t err, void * user_data_p), void * user_data_p);
/**
* SIGNAL: lurch-disable-chat
*
* Disables OMEMO for the specified chat.
*/
void lurch_api_disable_chat_handler(PurpleAccount * acc_p, const char * full_conversation_name, void (*cb)(int32_t err, void * user_data_p), void * user_data_p);
/**
* SIGNAL: lurch-fp-get
*
* Gets the this device's fingerprint in a printable format.
*/
void lurch_api_fp_get_handler(PurpleAccount * acc_p, void (*cb)(int32_t err, const char * fp_printable, void * user_data_p), void * user_data_p);
/**
* SIGNAL: lurch-fp-list
*
* Gets the fingerprints of all devices belonging to the specified account and creates a device-ID-to-fingerprint table.
* This is based on sessions, so if there is an entry in the OMEMO devicelist, but no libsignal session yet, the value will be NULL.
* If the whole devicelist is empty, i.e. the account is not an OMEMO user, the whole table will be NULL.
* Watch out as this is not a valid GHashTable.
*/
void lurch_api_fp_list_handler(PurpleAccount * acc_p, void (*cb)(int32_t err, GHashTable * id_fp_table, void * user_data_p), void * user_data_p);
/**
* SIGNAL: lurch-fp-other
*
* Same as above, but for the specified contact.
*/
void lurch_api_fp_other_handler(PurpleAccount * acc_p, const char * contact_bare_jid, void (*cb)(int32_t err, GHashTable * id_fp_table, void * user_data_p), void * user_data_p);
/**
* SIGNAL: lurch-status-im
*
* Checks the OMEMO status for the given contact. Result is one of lurch_status_t.
*/
void lurch_api_status_im_handler(PurpleAccount * acc_p, const char * contact_bare_jid, void (*cb)(int32_t err, lurch_status_t status, void * user_data_p), void * user_data_p);
/**
* SIGNAL: lurch-status-chat
*
* Checks the OMEMO status for a MUC.
* It not only looks up whether OMEMO was enabled, but also checks the preconditions for this feature, i.e.
* whether all chat members' JIDs are visible (non-anonymous) and their devicelists accessible (in contact list).
*/
void lurch_api_status_chat_handler(PurpleAccount * acc_p, const char * full_conversation_name, void (*cb)(int32_t err, lurch_status_chat_t status, void * user_data_p), void * user_data_p);
......@@ -175,6 +175,35 @@ void lurch_status_im_print(int32_t err, lurch_status_t status, void * user_data_
lurch_cmd_print(conv_p, msg);
}
void lurch_status_chat_print(int32_t err, lurch_status_chat_t status, void * user_data_p) {
PurpleConversation * conv_p = (PurpleConversation *) user_data_p;
const char * msg = (void *) 0;
if (err) {
lurch_cmd_print_err(conv_p, "Failed to get the conversation status. Check the debug log for details.");
return;
}
switch (status) {
case LURCH_STATUS_CHAT_DISABLED:
msg = "OMEMO was not enabled for this conversation. Type '/lurch enable' to switch it on.";
break;
case LURCH_STATUS_CHAT_ANONYMOUS:
msg = "Could not access the JID of at least one of the chat members. The MUC is probably set to anonymous.";
break;
case LURCH_STATUS_CHAT_NO_DEVICELIST:
msg = "Could not access the OMEMO devicelist of at least one of the chat members. Make sure every member is in every other member's contact list.";