Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
Librem5
lurch
Commits
664709cf
Commit
664709cf
authored
Feb 12, 2020
by
Richard Bayerle
Browse files
Add 'status' for chats to API
parent
ed3af540
Changes
5
Hide whitespace changes
Inline
Side-by-side
Makefile
View file @
664709cf
...
...
@@ -171,7 +171,9 @@ $(BDIR)/test_lurch_api: $(OBJECTS_W_COVERAGE) $(VENDOR_LIBS) $(BDIR)/test_lurch_
-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
\
...
...
src/lurch_api.c
View file @
664709cf
...
...
@@ -2,6 +2,7 @@
#include
<glib.h>
#include
<purple.h>
#include
"chat.h"
#include
"pep.h"
#include
"axc.h"
...
...
@@ -460,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
);
...
...
@@ -480,7 +564,7 @@ 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 1
0
#define NUM_OF_SIGNALS 1
1
const
char
*
signal_names
[
NUM_OF_SIGNALS
]
=
{
"lurch-id-list"
,
...
...
src/lurch_api.h
View file @
664709cf
...
...
@@ -12,6 +12,13 @@ typedef enum {
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.
*/
...
...
@@ -118,3 +125,12 @@ void lurch_api_fp_other_handler(PurpleAccount * acc_p, const char * contact_bare
* 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
);
src/lurch_cmd_ui.c
View file @
664709cf
...
...
@@ -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."
;
break
;
case
LURCH_STATUS_CHAT_OK
:
msg
=
"OMEMO is enabled for this conversation and everything should work. You can turn it off by typing '/lurch disable'."
;
break
;
default:
msg
=
"Received unknown status code."
;
}
lurch_cmd_print
(
conv_p
,
msg
);
}
static
void
lurch_cmd_id
(
PurpleConversation
*
conv_p
,
const
char
*
arg
,
const
char
*
param
)
{
PurpleAccount
*
acc_p
=
purple_conversation_get_account
(
conv_p
);
void
*
plugins_handle
=
purple_plugins_get_handle
();
...
...
@@ -257,14 +286,25 @@ static void lurch_cmd_fp(PurpleConversation * conv_p, const char * arg) {
}
static
void
lurch_cmd_status
(
PurpleConversation
*
conv_p
)
{
char
*
bare_jid
=
(
void
*
)
0
;
const
char
*
conv_name
=
purple_conversation_get_name
(
conv_p
);
PurpleConversationType
conv_type
=
purple_conversation_get_type
(
conv_p
);
char
*
conv_bare_jid
=
jabber_get_bare_jid
(
purple_conversation_get_name
(
conv_p
));
void
*
plugins_handle
=
purple_plugins_get_handle
();
PurpleAccount
*
acc_p
=
purple_conversation_get_account
(
conv_p
);
if
(
conv_type
==
PURPLE_CONV_TYPE_IM
)
{
purple_signal_emit
(
purple_plugins_get_handle
(),
"lurch-status-im"
,
purple_conversation_get_account
(
conv_p
),
conv_bare_jid
,
lurch_status_im_print
,
conv_p
);
switch
(
conv_type
)
{
case
PURPLE_CONV_TYPE_IM
:
bare_jid
=
jabber_get_bare_jid
(
conv_name
);
purple_signal_emit
(
plugins_handle
,
"lurch-status-im"
,
acc_p
,
bare_jid
,
lurch_status_im_print
,
conv_p
);
break
;
case
PURPLE_CONV_TYPE_CHAT
:
purple_signal_emit
(
plugins_handle
,
"lurch-status-chat"
,
acc_p
,
conv_name
,
lurch_status_chat_print
,
conv_p
);
break
;
default:
lurch_cmd_print_err
(
conv_p
,
"Conversation type not supported."
);
}
g_free
(
conv_
bare_jid
);
g_free
(
bare_jid
);
}
PurpleCmdRet
lurch_cmd_func_v2
(
PurpleConversation
*
conv_p
,
...
...
test/test_lurch_api.c
View file @
664709cf
...
...
@@ -5,6 +5,7 @@
#include
<purple.h>
#include
"jabber.h"
#include
"chat.h"
#include
"axc.h"
#include
"libomemo.h"
...
...
@@ -62,6 +63,16 @@ int __wrap_axc_get_device_id(axc_context * ctx_p, uint32_t * id_p) {
return
ret_val
;
}
PurpleConversation
*
__wrap_purple_find_conversation_with_account
(
PurpleConversationType
type
,
const
char
*
name
,
const
PurpleAccount
*
account
)
{
check_expected
(
type
);
check_expected
(
name
);
PurpleConversation
*
ret_val
;
ret_val
=
mock_ptr_type
(
PurpleConversation
*
);
return
ret_val
;
}
void
__wrap_jabber_pep_publish
(
JabberStream
*
js_p
,
xmlnode
*
publish_node_p
)
{
xmlnode
*
item_node_p
=
xmlnode_get_child
(
publish_node_p
,
"item"
);
xmlnode
*
list_node_p
=
xmlnode_get_child
(
item_node_p
,
"list"
);
...
...
@@ -73,6 +84,12 @@ void __wrap_jabber_pep_publish(JabberStream * js_p, xmlnode * publish_node_p) {
check_expected_ptr
(
device_node_p
->
next
);
}
JabberChat
*
__wrap_jabber_chat_find_by_conv
(
PurpleConversation
*
conv_p
)
{
JabberChat
*
ret_val
;
ret_val
=
mock_ptr_type
(
JabberChat
*
);
return
ret_val
;
}
int
__wrap_omemo_storage_chatlist_delete
(
const
char
*
chat
,
const
char
*
db_fn
)
{
check_expected
(
chat
);
...
...
@@ -921,14 +938,189 @@ static void test_lurch_api_status_im_handler_err(void ** state) {
lurch_api_status_im_handler
(
NULL
,
other_bare_jid
,
lurch_api_status_im_handler_cb_mock
,
mock_user_data
);
}
static
void
lurch_api_status_chat_handler_cb_mock
(
int32_t
err
,
lurch_status_chat_t
status
,
void
*
user_data_p
)
{
check_expected
(
err
);
check_expected
(
status
);
check_expected
(
user_data_p
);
}
/**
* Returns the "anonymous" status when a chat members' JID cannot be accessed, i.e. the chat is anonymous.
*/
static
void
test_lurch_api_status_chat_handler_anonymous
(
void
**
state
)
{
(
void
)
state
;
const
char
*
own_jid
=
"me-testing@test.org/resource"
;
const
char
*
test_conversation_name
=
"test-room@conference.test.org"
;
will_return
(
__wrap_purple_account_get_username
,
own_jid
);
PurpleConversation
conversation_mock
=
{
.
name
=
test_conversation_name
};
expect_value
(
__wrap_purple_find_conversation_with_account
,
type
,
PURPLE_CONV_TYPE_CHAT
);
expect_value
(
__wrap_purple_find_conversation_with_account
,
name
,
test_conversation_name
);
will_return
(
__wrap_purple_find_conversation_with_account
,
&
conversation_mock
);
JabberChatMember
member
=
{
.
handle
=
"anonymous member without jid"
};
// keys do not really matter as the tests function loops over the values
GHashTable
*
member_table_mock
=
g_hash_table_new
(
g_str_hash
,
g_str_equal
);
g_hash_table_insert
(
member_table_mock
,
"anon member"
,
&
member
);
JabberChat
muc_mock
=
{
.
members
=
member_table_mock
};
will_return
(
__wrap_jabber_chat_find_by_conv
,
&
muc_mock
);
expect_value
(
lurch_api_status_chat_handler_cb_mock
,
err
,
EXIT_SUCCESS
);
expect_value
(
lurch_api_status_chat_handler_cb_mock
,
status
,
LURCH_STATUS_CHAT_ANONYMOUS
);
const
char
*
mock_user_data
=
"MOCK_USER_DATA"
;
expect_value
(
lurch_api_status_chat_handler_cb_mock
,
user_data_p
,
mock_user_data
);
lurch_api_status_chat_handler
(
NULL
,
test_conversation_name
,
lurch_api_status_chat_handler_cb_mock
,
mock_user_data
);
}
/**
* Returns the "no devicelist" status when a devicelist for a chat member can not be found.
* This usually means the member is not in the user's contact list.
*/
static
void
test_lurch_api_status_chat_handler_no_devicelist
(
void
**
state
)
{
(
void
)
state
;
const
char
*
own_jid
=
"me-testing@test.org/resource"
;
const
char
*
test_conversation_name
=
"test-room@conference.test.org"
;
will_return
(
__wrap_purple_account_get_username
,
own_jid
);
PurpleConversation
conversation_mock
=
{
.
name
=
test_conversation_name
};
expect_value
(
__wrap_purple_find_conversation_with_account
,
type
,
PURPLE_CONV_TYPE_CHAT
);
expect_value
(
__wrap_purple_find_conversation_with_account
,
name
,
test_conversation_name
);
will_return
(
__wrap_purple_find_conversation_with_account
,
&
conversation_mock
);
JabberChatMember
member
=
{
.
handle
=
"n0t4fr13nd"
,
.
jid
=
"not-a-contact@test.org/phone"
};
// keys do not really matter as the tests function loops over the values
GHashTable
*
member_table_mock
=
g_hash_table_new
(
g_str_hash
,
g_str_equal
);
g_hash_table_insert
(
member_table_mock
,
"non-contact member"
,
&
member
);
JabberChat
muc_mock
=
{
.
members
=
member_table_mock
};
will_return
(
__wrap_jabber_chat_find_by_conv
,
&
muc_mock
);
char
*
devicelist
=
"<items node='urn:xmpp:omemo:0:devicelist'>"
"<item>"
"<list xmlns='urn:xmpp:omemo:0'>"
"</list>"
"</item>"
"</items>"
;
omemo_devicelist
*
dl_p
;
omemo_devicelist_import
(
devicelist
,
member
.
jid
,
&
dl_p
);
will_return
(
__wrap_omemo_storage_user_devicelist_retrieve
,
dl_p
);
will_return
(
__wrap_omemo_storage_user_devicelist_retrieve
,
EXIT_SUCCESS
);
expect_value
(
lurch_api_status_chat_handler_cb_mock
,
err
,
EXIT_SUCCESS
);
expect_value
(
lurch_api_status_chat_handler_cb_mock
,
status
,
LURCH_STATUS_CHAT_NO_DEVICELIST
);
const
char
*
mock_user_data
=
"MOCK_USER_DATA"
;
expect_value
(
lurch_api_status_chat_handler_cb_mock
,
user_data_p
,
mock_user_data
);
lurch_api_status_chat_handler
(
NULL
,
test_conversation_name
,
lurch_api_status_chat_handler_cb_mock
,
mock_user_data
);
}
/**
* Returns the "OK" status when for all members all necessary information could be found.
*/
static
void
test_lurch_api_status_chat_handler_ok
(
void
**
state
)
{
(
void
)
state
;
const
char
*
own_jid
=
"me-testing@test.org/resource"
;
const
char
*
test_conversation_name
=
"test-room@conference.test.org"
;
will_return
(
__wrap_purple_account_get_username
,
own_jid
);
PurpleConversation
conversation_mock
=
{
.
name
=
test_conversation_name
};
expect_value
(
__wrap_purple_find_conversation_with_account
,
type
,
PURPLE_CONV_TYPE_CHAT
);
expect_value
(
__wrap_purple_find_conversation_with_account
,
name
,
test_conversation_name
);
will_return
(
__wrap_purple_find_conversation_with_account
,
&
conversation_mock
);
JabberChatMember
member
=
{
.
handle
=
"perfect-contact"
,
.
jid
=
"perfect-contact@test.org/lurch"
};
// keys do not really matter as the tests function loops over the values
GHashTable
*
member_table_mock
=
g_hash_table_new
(
g_str_hash
,
g_str_equal
);
g_hash_table_insert
(
member_table_mock
,
"contact member"
,
&
member
);
JabberChat
muc_mock
=
{
.
members
=
member_table_mock
};
will_return
(
__wrap_jabber_chat_find_by_conv
,
&
muc_mock
);
char
*
devicelist
=
"<items node='urn:xmpp:omemo:0:devicelist'>"
"<item>"
"<list xmlns='urn:xmpp:omemo:0'>"
"<device id='4223' />"
"</list>"
"</item>"
"</items>"
;
omemo_devicelist
*
dl_p
;
omemo_devicelist_import
(
devicelist
,
member
.
jid
,
&
dl_p
);
will_return
(
__wrap_omemo_storage_user_devicelist_retrieve
,
dl_p
);
will_return
(
__wrap_omemo_storage_user_devicelist_retrieve
,
EXIT_SUCCESS
);
expect_value
(
lurch_api_status_chat_handler_cb_mock
,
err
,
EXIT_SUCCESS
);
expect_value
(
lurch_api_status_chat_handler_cb_mock
,
status
,
LURCH_STATUS_CHAT_OK
);
const
char
*
mock_user_data
=
"MOCK_USER_DATA"
;
expect_value
(
lurch_api_status_chat_handler_cb_mock
,
user_data_p
,
mock_user_data
);
lurch_api_status_chat_handler
(
NULL
,
test_conversation_name
,
lurch_api_status_chat_handler_cb_mock
,
mock_user_data
);
}
/**
* Returns "disabled" and an error return value when the conversation could not be found, i.e. an error.
*/
static
void
test_lurch_api_status_chat_handler_conv_not_found
(
void
**
state
)
{
(
void
)
state
;
const
char
*
own_jid
=
"me-testing@test.org/resource"
;
const
char
*
test_conversation_name
=
"nonexistent-test-room@conference.test.org"
;
will_return
(
__wrap_purple_account_get_username
,
own_jid
);
expect_value
(
__wrap_purple_find_conversation_with_account
,
type
,
PURPLE_CONV_TYPE_CHAT
);
expect_value
(
__wrap_purple_find_conversation_with_account
,
name
,
test_conversation_name
);
will_return
(
__wrap_purple_find_conversation_with_account
,
NULL
);
expect_value
(
lurch_api_status_chat_handler_cb_mock
,
err
,
EXIT_FAILURE
);
expect_value
(
lurch_api_status_chat_handler_cb_mock
,
status
,
LURCH_STATUS_CHAT_DISABLED
);
const
char
*
mock_user_data
=
"MOCK_USER_DATA"
;
expect_value
(
lurch_api_status_chat_handler_cb_mock
,
user_data_p
,
mock_user_data
);
lurch_api_status_chat_handler
(
NULL
,
test_conversation_name
,
lurch_api_status_chat_handler_cb_mock
,
mock_user_data
);
}
/**
* Registers and connects all signals.
*/
static
void
test_lurch_api_init
(
void
**
state
)
{
(
void
)
state
;
// currently, there are 9 signals
size_t
signals
=
10
;
size_t
signals
=
11
;
for
(
int
i
=
0
;
i
<
signals
;
i
++
)
{
expect_function_call
(
__wrap_purple_signal_register
);
...
...
@@ -944,7 +1136,7 @@ static void test_lurch_api_init(void ** state) {
static
void
test_lurch_api_unload
(
void
**
state
)
{
(
void
)
state
;
size_t
signals
=
1
0
;
size_t
signals
=
1
1
;
for
(
int
i
=
0
;
i
<
signals
;
i
++
)
{
expect_function_call
(
__wrap_purple_signal_disconnect
);
...
...
@@ -981,6 +1173,10 @@ int main(void) {
cmocka_unit_test
(
test_lurch_api_status_im_handler_no_session
),
cmocka_unit_test
(
test_lurch_api_status_im_handler_ok
),
cmocka_unit_test
(
test_lurch_api_status_im_handler_err
),
cmocka_unit_test
(
test_lurch_api_status_chat_handler_anonymous
),
cmocka_unit_test
(
test_lurch_api_status_chat_handler_no_devicelist
),
cmocka_unit_test
(
test_lurch_api_status_chat_handler_ok
),
cmocka_unit_test
(
test_lurch_api_status_chat_handler_conv_not_found
),
cmocka_unit_test
(
test_lurch_api_init
),
cmocka_unit_test
(
test_lurch_api_unload
)
};
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment