1
0
mirror of https://github.com/profanity-im/profanity.git synced 2024-09-01 19:24:15 -04:00

Use OMEMO for offline MUC members (#1242)

This commit is contained in:
Paul Fariello 2020-01-20 14:28:13 +01:00 committed by Michael Vetter
parent 4420463541
commit 84506cbaeb
9 changed files with 129 additions and 38 deletions

View File

@ -3586,6 +3586,9 @@ cmd_join(ProfWin *window, const char *const command, gchar **args)
if (!muc_active(room)) { if (!muc_active(room)) {
presence_join_room(room, nick, passwd); presence_join_room(room, nick, passwd);
muc_join(room, nick, passwd, FALSE); muc_join(room, nick, passwd, FALSE);
iq_room_affiliation_list(room, "member", false);
iq_room_affiliation_list(room, "admin", false);
iq_room_affiliation_list(room, "owner", false);
} else if (muc_roster_complete(room)) { } else if (muc_roster_complete(room)) {
ui_switch_to_room(room); ui_switch_to_room(room);
} }
@ -4131,14 +4134,14 @@ cmd_affiliation(ProfWin *window, const char *const command, gchar **args)
if (g_strcmp0(cmd, "list") == 0) { if (g_strcmp0(cmd, "list") == 0) {
if (!affiliation) { if (!affiliation) {
iq_room_affiliation_list(mucwin->roomjid, "owner"); iq_room_affiliation_list(mucwin->roomjid, "owner", true);
iq_room_affiliation_list(mucwin->roomjid, "admin"); iq_room_affiliation_list(mucwin->roomjid, "admin", true);
iq_room_affiliation_list(mucwin->roomjid, "member"); iq_room_affiliation_list(mucwin->roomjid, "member", true);
iq_room_affiliation_list(mucwin->roomjid, "outcast"); iq_room_affiliation_list(mucwin->roomjid, "outcast", true);
} else if (g_strcmp0(affiliation, "none") == 0) { } else if (g_strcmp0(affiliation, "none") == 0) {
win_println(window, THEME_DEFAULT, '!', "Cannot list users with no affiliation."); win_println(window, THEME_DEFAULT, '!', "Cannot list users with no affiliation.");
} else { } else {
iq_room_affiliation_list(mucwin->roomjid, affiliation); iq_room_affiliation_list(mucwin->roomjid, affiliation, true);
} }
return TRUE; return TRUE;
} }
@ -8124,12 +8127,13 @@ cmd_omemo_start(ProfWin *window, const char *const command, gchar **args)
ProfMucWin *mucwin = (ProfMucWin*)window; ProfMucWin *mucwin = (ProfMucWin*)window;
assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
if (muc_anonymity_type(mucwin->roomjid) == MUC_ANONYMITY_TYPE_NONANONYMOUS) { if (muc_anonymity_type(mucwin->roomjid) == MUC_ANONYMITY_TYPE_NONANONYMOUS
&& muc_member_type(mucwin->roomjid) == MUC_MEMBER_TYPE_MEMBERS_ONLY) {
accounts_add_omemo_state(session_get_account_name(), mucwin->roomjid, TRUE); accounts_add_omemo_state(session_get_account_name(), mucwin->roomjid, TRUE);
omemo_start_muc_sessions(mucwin->roomjid); omemo_start_muc_sessions(mucwin->roomjid);
mucwin->is_omemo = TRUE; mucwin->is_omemo = TRUE;
} else { } else {
win_println(window, THEME_DEFAULT, '!', "MUC must be non-anonymous (i.e. be configured to present real jid to anyone) in order to support OMEMO."); win_println(window, THEME_DEFAULT, '!', "MUC must be non-anonymous (i.e. be configured to present real jid to anyone) and members-only in order to support OMEMO.");
} }
} else { } else {
win_println(window, THEME_DEFAULT, '-', "You must be in a regular chat window to start an OMEMO session."); win_println(window, THEME_DEFAULT, '-', "You must be in a regular chat window to start an OMEMO session.");

View File

@ -1199,6 +1199,10 @@ sv_ev_muc_occupant_online(const char *const room, const char *const nick, const
gboolean updated = muc_roster_add(room, nick, jid, role, affiliation, show, status); gboolean updated = muc_roster_add(room, nick, jid, role, affiliation, show, status);
if (jid != NULL && affiliation != NULL) {
muc_members_update(room, jid, affiliation);
}
// not yet finished joining room // not yet finished joining room
if (!muc_roster_complete(room)) { if (!muc_roster_complete(room)) {
return; return;
@ -1424,6 +1428,9 @@ sv_ev_bookmark_autojoin(Bookmark *bookmark)
if (!muc_active(bookmark->barejid)) { if (!muc_active(bookmark->barejid)) {
presence_join_room(bookmark->barejid, nick, bookmark->password); presence_join_room(bookmark->barejid, nick, bookmark->password);
muc_join(bookmark->barejid, nick, bookmark->password, TRUE); muc_join(bookmark->barejid, nick, bookmark->password, TRUE);
iq_room_affiliation_list(bookmark->barejid, "member", false);
iq_room_affiliation_list(bookmark->barejid, "admin", false);
iq_room_affiliation_list(bookmark->barejid, "owner", false);
} }
free(nick); free(nick);

View File

@ -421,19 +421,14 @@ omemo_start_session(const char *const barejid)
void void
omemo_start_muc_sessions(const char *const roomjid) omemo_start_muc_sessions(const char *const roomjid)
{ {
GList *roster = muc_roster(roomjid); GList *members = muc_members(roomjid);
GList *iter; GList *iter;
for (iter = roster; iter != NULL; iter = iter->next) { for (iter = members; iter != NULL; iter = iter->next) {
Occupant *occupant = (Occupant *)iter->data; Jid *jid = jid_create(iter->data);
if (occupant->jid != NULL) { omemo_start_session(jid->barejid);
Jid *jid = jid_create(occupant->jid); jid_destroy(jid);
omemo_start_session(jid->barejid);
jid_destroy(jid);
} else {
log_error("OMEMO: cannot get real jid for %s in %s", occupant->nick, roomjid);
}
} }
g_list_free(roster); g_list_free(members);
} }
gboolean gboolean
@ -712,19 +707,14 @@ omemo_on_message_send(ProfWin *win, const char *const message, gboolean request_
if (muc) { if (muc) {
ProfMucWin *mucwin = (ProfMucWin *)win; ProfMucWin *mucwin = (ProfMucWin *)win;
assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK); assert(mucwin->memcheck == PROFMUCWIN_MEMCHECK);
GList *roster = muc_roster(mucwin->roomjid); GList *members = muc_members(mucwin->roomjid);
GList *iter; GList *iter;
for (iter = roster; iter != NULL; iter = iter->next) { for (iter = members; iter != NULL; iter = iter->next) {
Occupant *occupant = (Occupant *)iter->data; Jid *jid = jid_create(iter->data);
Jid *jid = jid_create(occupant->jid); recipients = g_list_append(recipients, strdup(jid->barejid));
if (!jid->barejid) {
log_warning("OMEMO: missing barejid for MUC %s occupant %s", mucwin->roomjid, occupant->nick);
} else {
recipients = g_list_append(recipients, strdup(jid->barejid));
}
jid_destroy(jid); jid_destroy(jid);
} }
g_list_free(roster); g_list_free(members);
} else { } else {
ProfChatWin *chatwin = (ProfChatWin *)win; ProfChatWin *chatwin = (ProfChatWin *)win;
assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK);

View File

@ -185,6 +185,9 @@ bookmark_join(const char *jid)
} }
presence_join_room(bookmark->barejid, nick, bookmark->password); presence_join_room(bookmark->barejid, nick, bookmark->password);
muc_join(bookmark->barejid, nick, bookmark->password, FALSE); muc_join(bookmark->barejid, nick, bookmark->password, FALSE);
iq_room_affiliation_list(bookmark->barejid, "member", false);
iq_room_affiliation_list(bookmark->barejid, "admin", false);
iq_room_affiliation_list(bookmark->barejid, "owner", false);
account_free(account); account_free(account);
} else if (muc_roster_complete(bookmark->barejid)) { } else if (muc_roster_complete(bookmark->barejid)) {
ui_room_join(bookmark->barejid, TRUE); ui_room_join(bookmark->barejid, TRUE);

View File

@ -93,6 +93,11 @@ typedef struct privilege_set_t {
char *privilege; char *privilege;
} ProfPrivilegeSet; } ProfPrivilegeSet;
typedef struct affiliation_list_t {
char *affiliation;
bool show_ui_message;
} ProfAffiliationList;
typedef struct command_config_data_t { typedef struct command_config_data_t {
char *sessionid; char *sessionid;
char *command; char *command;
@ -135,6 +140,7 @@ static int _command_exec_response_handler(xmpp_stanza_t *const stanza, void *con
static void _iq_free_room_data(ProfRoomInfoData *roominfo); static void _iq_free_room_data(ProfRoomInfoData *roominfo);
static void _iq_free_affiliation_set(ProfPrivilegeSet *affiliation_set); static void _iq_free_affiliation_set(ProfPrivilegeSet *affiliation_set);
static void _iq_free_affiliation_list(ProfAffiliationList *affiliation_list);
static void _iq_id_handler_free(ProfIqHandler *handler); static void _iq_id_handler_free(ProfIqHandler *handler);
// scheduled // scheduled
@ -637,13 +643,18 @@ iq_room_config_cancel(ProfConfWin *confwin)
} }
void void
iq_room_affiliation_list(const char *const room, char *affiliation) iq_room_affiliation_list(const char *const room, char *affiliation, bool show_ui_message)
{ {
xmpp_ctx_t * const ctx = connection_get_ctx(); xmpp_ctx_t * const ctx = connection_get_ctx();
xmpp_stanza_t *iq = stanza_create_room_affiliation_list_iq(ctx, room, affiliation); xmpp_stanza_t *iq = stanza_create_room_affiliation_list_iq(ctx, room, affiliation);
const char *id = xmpp_stanza_get_id(iq); const char *id = xmpp_stanza_get_id(iq);
iq_id_handler_add(id, _room_affiliation_list_result_id_handler, free, strdup(affiliation));
ProfAffiliationList *affiliation_list = malloc(sizeof(ProfAffiliationList));
affiliation_list->affiliation = strdup(affiliation);
affiliation_list->show_ui_message = show_ui_message;
iq_id_handler_add(id, _room_affiliation_list_result_id_handler, (ProfIqFreeCallback)_iq_free_affiliation_list, affiliation_list);
iq_send_stanza(iq); iq_send_stanza(iq);
xmpp_stanza_release(iq); xmpp_stanza_release(iq);
@ -1851,7 +1862,7 @@ _room_affiliation_list_result_id_handler(xmpp_stanza_t *const stanza, void *cons
const char *id = xmpp_stanza_get_id(stanza); const char *id = xmpp_stanza_get_id(stanza);
const char *type = xmpp_stanza_get_type(stanza); const char *type = xmpp_stanza_get_type(stanza);
const char *from = xmpp_stanza_get_from(stanza); const char *from = xmpp_stanza_get_from(stanza);
char *affiliation = (char *)userdata; ProfAffiliationList *affiliation_list = (ProfAffiliationList *)userdata;
if (id) { if (id) {
log_debug("IQ affiliation list result handler fired, id: %s.", id); log_debug("IQ affiliation list result handler fired, id: %s.", id);
@ -1862,10 +1873,10 @@ _room_affiliation_list_result_id_handler(xmpp_stanza_t *const stanza, void *cons
// handle error responses // handle error responses
if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) { if (g_strcmp0(type, STANZA_TYPE_ERROR) == 0) {
char *error_message = stanza_get_error_message(stanza); char *error_message = stanza_get_error_message(stanza);
log_debug("Error retrieving %s list for room %s: %s", affiliation, from, error_message); log_debug("Error retrieving %s list for room %s: %s", affiliation_list->affiliation, from, error_message);
ProfMucWin *mucwin = wins_get_muc(from); ProfMucWin *mucwin = wins_get_muc(from);
if (mucwin) { if (mucwin && affiliation_list->show_ui_message) {
mucwin_affiliation_list_error(mucwin, affiliation, error_message); mucwin_affiliation_list_error(mucwin, affiliation_list->affiliation, error_message);
} }
free(error_message); free(error_message);
return 0; return 0;
@ -1880,6 +1891,11 @@ _room_affiliation_list_result_id_handler(xmpp_stanza_t *const stanza, void *cons
if (g_strcmp0(name, "item") == 0) { if (g_strcmp0(name, "item") == 0) {
const char *jid = xmpp_stanza_get_attribute(child, STANZA_ATTR_JID); const char *jid = xmpp_stanza_get_attribute(child, STANZA_ATTR_JID);
if (jid) { if (jid) {
if (g_strcmp0(affiliation_list->affiliation, "member") == 0
|| g_strcmp0(affiliation_list->affiliation, "owner") == 0
|| g_strcmp0(affiliation_list->affiliation, "admin") == 0) {
muc_members_add(from, jid);
}
jids = g_slist_insert_sorted(jids, (gpointer)jid, (GCompareFunc)g_strcmp0); jids = g_slist_insert_sorted(jids, (gpointer)jid, (GCompareFunc)g_strcmp0);
} }
} }
@ -1889,8 +1905,8 @@ _room_affiliation_list_result_id_handler(xmpp_stanza_t *const stanza, void *cons
muc_jid_autocomplete_add_all(from, jids); muc_jid_autocomplete_add_all(from, jids);
ProfMucWin *mucwin = wins_get_muc(from); ProfMucWin *mucwin = wins_get_muc(from);
if (mucwin) { if (mucwin && affiliation_list->show_ui_message) {
mucwin_handle_affiliation_list(mucwin, affiliation, jids); mucwin_handle_affiliation_list(mucwin, affiliation_list->affiliation, jids);
} }
g_slist_free(jids); g_slist_free(jids);
@ -2429,3 +2445,12 @@ _iq_free_affiliation_set(ProfPrivilegeSet *affiliation_set)
free(affiliation_set); free(affiliation_set);
} }
} }
static void
_iq_free_affiliation_list(ProfAffiliationList *affiliation_list)
{
if (affiliation_list) {
free(affiliation_list->affiliation);
free(affiliation_list);
}
}

View File

@ -47,6 +47,10 @@
#include "xmpp/muc.h" #include "xmpp/muc.h"
#include "xmpp/contact.h" #include "xmpp/contact.h"
#ifdef HAVE_OMEMO
#include "omemo/omemo.h"
#endif
typedef struct _muc_room_t { typedef struct _muc_room_t {
char *room; // e.g. test@conference.server char *room; // e.g. test@conference.server
char *nick; // e.g. Some User char *nick; // e.g. Some User
@ -60,6 +64,7 @@ typedef struct _muc_room_t {
gboolean autojoin; gboolean autojoin;
gboolean pending_nick_change; gboolean pending_nick_change;
GHashTable *roster; GHashTable *roster;
GHashTable *members;
Autocomplete nick_ac; Autocomplete nick_ac;
Autocomplete jid_ac; Autocomplete jid_ac;
GHashTable *nick_changes; GHashTable *nick_changes;
@ -220,6 +225,7 @@ muc_join(const char *const room, const char *const nick, const char *const passw
new_room->pending_broadcasts = NULL; new_room->pending_broadcasts = NULL;
new_room->pending_config = FALSE; new_room->pending_config = FALSE;
new_room->roster = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)_occupant_free); new_room->roster = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)_occupant_free);
new_room->members = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
new_room->nick_ac = autocomplete_new(); new_room->nick_ac = autocomplete_new();
new_room->jid_ac = autocomplete_new(); new_room->jid_ac = autocomplete_new();
new_room->nick_changes = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); new_room->nick_changes = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
@ -858,6 +864,54 @@ muc_anonymity_type(const char *const room)
} }
} }
/*
* Return the list of jid affiliated as member in the room
*/
GList*
muc_members(const char *const room)
{
ChatRoom *chat_room = g_hash_table_lookup(rooms, room);
if (chat_room) {
return g_hash_table_get_keys(chat_room->members);
} else {
return NULL;
}
}
void
muc_members_add(const char *const room, const char *const jid)
{
ChatRoom *chat_room = g_hash_table_lookup(rooms, room);
if (chat_room) {
if (g_hash_table_insert(chat_room->members, strdup(jid), NULL)) {
#ifdef HAVE_OMEMO
Jid *our_jid = jid_create(connection_get_fulljid());
if (strcmp(jid, our_jid->barejid) != 0) {
omemo_start_session(jid);
}
#endif
}
}
}
void
muc_members_remove(const char *const room, const char *const jid)
{
ChatRoom *chat_room = g_hash_table_lookup(rooms, room);
if (chat_room) {
g_hash_table_remove(chat_room->members, jid);
}
}
void
muc_members_update(const char *const room, const char *const jid, const char *const affiliation)
{
if (strcmp(affiliation, "outcast") == 0 || strcmp(affiliation, "none") == 0) {
muc_members_remove(room, jid);
} else if (strcmp(affiliation, "member") == 0 || strcmp(affiliation, "admin") == 0 || strcmp(affiliation, "owner") == 0) {
muc_members_add(room, jid);
}
}
static void static void
_free_room(ChatRoom *room) _free_room(ChatRoom *room)
@ -871,6 +925,9 @@ _free_room(ChatRoom *room)
if (room->roster) { if (room->roster) {
g_hash_table_destroy(room->roster); g_hash_table_destroy(room->roster);
} }
if (room->members) {
g_hash_table_destroy(room->members);
}
autocomplete_free(room->nick_ac); autocomplete_free(room->nick_ac);
autocomplete_free(room->jid_ac); autocomplete_free(room->jid_ac);
if (room->nick_changes) { if (room->nick_changes) {

View File

@ -159,4 +159,9 @@ char* muc_affiliation_str(const char *const room);
muc_member_type_t muc_member_type(const char *const room); muc_member_type_t muc_member_type(const char *const room);
muc_anonymity_type_t muc_anonymity_type(const char *const room); muc_anonymity_type_t muc_anonymity_type(const char *const room);
GList* muc_members(const char *const room);
void muc_members_add(const char *const room, const char *const jid);
void muc_members_remove(const char *const room, const char *const jid);
void muc_members_update(const char *const room, const char *const jid, const char *const affiliation);
#endif #endif

View File

@ -212,7 +212,7 @@ void iq_submit_room_config(ProfConfWin *confwin);
void iq_room_config_cancel(ProfConfWin *confwin); void iq_room_config_cancel(ProfConfWin *confwin);
void iq_send_ping(const char *const target); void iq_send_ping(const char *const target);
void iq_room_info_request(const char *const room, gboolean display_result); void iq_room_info_request(const char *const room, gboolean display_result);
void iq_room_affiliation_list(const char *const room, char *affiliation); void iq_room_affiliation_list(const char *const room, char *affiliation, bool show);
void iq_room_affiliation_set(const char *const room, const char *const jid, char *affiliation, void iq_room_affiliation_set(const char *const room, const char *const jid, char *affiliation,
const char *const reason); const char *const reason);
void iq_room_kick_occupant(const char *const room, const char *const nick, const char *const reason); void iq_room_kick_occupant(const char *const room, const char *const nick, const char *const reason);

View File

@ -206,7 +206,7 @@ void iq_send_caps_request_for_jid(const char * const to, const char * const id,
void iq_send_caps_request_legacy(const char * const to, const char * const id, void iq_send_caps_request_legacy(const char * const to, const char * const id,
const char * const node, const char * const ver) {} const char * const node, const char * const ver) {}
void iq_room_info_request(const char * const room, gboolean display) {} void iq_room_info_request(const char * const room, gboolean display) {}
void iq_room_affiliation_list(const char * const room, char *affiliation) {} void iq_room_affiliation_list(const char * const room, char *affiliation, bool show) {}
void iq_room_affiliation_set(const char * const room, const char * const jid, char *affiliation, void iq_room_affiliation_set(const char * const room, const char * const jid, char *affiliation,
const char * const reason) {} const char * const reason) {}
void iq_room_kick_occupant(const char * const room, const char * const nick, const char * const reason) {} void iq_room_kick_occupant(const char * const room, const char * const nick, const char * const reason) {}