From 8e315a4781b2acf47cfc86cb49ca63b1a37a46d6 Mon Sep 17 00:00:00 2001 From: MarcoPolo-PasTonMolo Date: Sat, 1 Jul 2023 23:53:38 +0300 Subject: [PATCH 1/6] Implement basic mam for mucs TODO split this commit later and see if all its changes are needed See #660 --- src/event/server_events.c | 38 ++++---- src/ui/chatwin.c | 2 +- src/ui/mucwin.c | 158 ++++++++++++++++++++++--------- src/ui/ui.h | 9 +- src/ui/window.c | 81 +++++++++++----- src/ui/window.h | 4 +- src/xmpp/iq.c | 83 ++++++++++++---- src/xmpp/message.c | 23 +++-- src/xmpp/stanza.c | 24 +++-- src/xmpp/stanza.h | 2 +- src/xmpp/xmpp.h | 4 +- tests/unittests/ui/stub_ui.c | 4 +- tests/unittests/xmpp/stub_xmpp.c | 2 +- 13 files changed, 298 insertions(+), 136 deletions(-) diff --git a/src/event/server_events.c b/src/event/server_events.c index c10f69c37..d2bf7b3b2 100644 --- a/src/event/server_events.c +++ b/src/event/server_events.c @@ -273,9 +273,21 @@ sv_ev_room_subject(const char* const room, const char* const nick, const char* c } } +static void +_log_muc(ProfMessage* message) +{ + if (message->enc == PROF_MSG_ENC_OMEMO) { + groupchat_log_omemo_msg_in(message->from_jid->barejid, message->from_jid->resourcepart, message->plain); + } else { + groupchat_log_msg_in(message->from_jid->barejid, message->from_jid->resourcepart, message->plain); + } + log_database_add_incoming(message); +} + void sv_ev_room_history(ProfMessage* message) { + _log_muc(message); if (prefs_get_boolean(PREF_NOTIFY_ROOM_OFFLINE)) { // check if this message was sent while we were offline. // if so, treat it as a new message rather than a history event. @@ -314,25 +326,9 @@ sv_ev_room_history(ProfMessage* message) } mucwin->last_msg_timestamp = g_date_time_new_now_local(); } - - gboolean younger = g_date_time_compare(mucwin->last_msg_timestamp, message->timestamp) < 0 ? TRUE : FALSE; - if (ev_is_first_connect() || younger) { - mucwin_history(mucwin, message); - } } } -static void -_log_muc(ProfMessage* message) -{ - if (message->enc == PROF_MSG_ENC_OMEMO) { - groupchat_log_omemo_msg_in(message->from_jid->barejid, message->from_jid->resourcepart, message->plain); - } else { - groupchat_log_msg_in(message->from_jid->barejid, message->from_jid->resourcepart, message->plain); - } - log_database_add_incoming(message); -} - void sv_ev_room_message(ProfMessage* message) { @@ -357,7 +353,9 @@ sv_ev_room_message(ProfMessage* message) GList* triggers = prefs_message_get_triggers(message->plain); _clean_incoming_message(message); - mucwin_incoming_msg(mucwin, message, mentions, triggers, TRUE); + if (!message->is_mam) { + mucwin_incoming_msg(mucwin, message, mentions, triggers, TRUE, FALSE); + } g_slist_free(mentions); @@ -375,7 +373,7 @@ sv_ev_room_message(ProfMessage* message) } // not currently on groupchat window - } else { + } else if (!message->is_mam) { status_bar_new(num, WIN_MUC, mucwin->roomjid); if ((g_strcmp0(mynick, message->from_jid->resourcepart) != 0) && (prefs_get_boolean(PREF_FLASH))) { @@ -400,7 +398,7 @@ sv_ev_room_message(ProfMessage* message) } mucwin->last_msg_timestamp = g_date_time_new_now_local(); - if (prefs_do_room_notify(is_current, mucwin->roomjid, mynick, message->from_jid->resourcepart, message->plain, mention, triggers != NULL)) { + if (prefs_do_room_notify(is_current, mucwin->roomjid, mynick, message->from_jid->resourcepart, message->plain, mention, triggers != NULL) && !message->is_mam) { Jid* jidp = jid_create(mucwin->roomjid); if (jidp) { notify_room_message(message->from_jid->resourcepart, jidp->localpart, num, message->plain); @@ -652,7 +650,7 @@ sv_ev_incoming_message(ProfMessage* message) if (prefs_get_boolean(PREF_MAM)) { win_print_loading_history(window); - iq_mam_request(chatwin, g_date_time_add_seconds(message->timestamp, 0)); // copy timestamp + iq_mam_request(window, g_date_time_add_seconds(message->timestamp, 0)); // copy timestamp } #ifdef HAVE_OMEMO diff --git a/src/ui/chatwin.c b/src/ui/chatwin.c index b470dbd66..88f02cb39 100644 --- a/src/ui/chatwin.c +++ b/src/ui/chatwin.c @@ -146,7 +146,7 @@ chatwin_new(const char* const barejid) } if (prefs_get_boolean(PREF_MAM)) { - iq_mam_request(chatwin, NULL); + iq_mam_request(window, NULL); win_print_loading_history(window); } diff --git a/src/ui/mucwin.c b/src/ui/mucwin.c index a2c314218..961d8fe10 100644 --- a/src/ui/mucwin.c +++ b/src/ui/mucwin.c @@ -36,6 +36,7 @@ #include "config.h" +#include "database.h" #include "ui.h" #include @@ -69,6 +70,11 @@ mucwin_new(const char* const barejid) } #endif + if (prefs_get_boolean(PREF_MAM)) { + iq_mam_request(window, NULL); + win_print_loading_history(window); + } + // Force redraw here to show correct offline users; before this point muc_members returns a wrong list ui_redraw_all_room_rosters(); return mucwin; @@ -363,7 +369,7 @@ mucwin_nick_change(ProfMucWin* mucwin, const char* const nick) } void -mucwin_history(ProfMucWin* mucwin, const ProfMessage* const message) +mucwin_history(ProfMucWin* mucwin, const ProfMessage* const message, gboolean flip) { assert(mucwin != NULL); @@ -372,7 +378,7 @@ mucwin_history(ProfMucWin* mucwin, const ProfMessage* const message) GSList* mentions = get_mentions(prefs_get_boolean(PREF_NOTIFY_MENTION_WHOLE_WORD), prefs_get_boolean(PREF_NOTIFY_MENTION_CASE_SENSITIVE), message->plain, mynick); GList* triggers = prefs_message_get_triggers(message->plain); - mucwin_incoming_msg(mucwin, message, mentions, triggers, FALSE); + mucwin_incoming_msg(mucwin, message, mentions, triggers, FALSE, flip); g_slist_free(mentions); g_list_free_full(triggers, free); @@ -380,46 +386,108 @@ mucwin_history(ProfMucWin* mucwin, const ProfMessage* const message) plugins_on_room_history_message(mucwin->roomjid, nick, message->plain, message->timestamp); } -static void -_mucwin_print_mention(ProfWin* window, const char* const message, const char* const from, const char* const mynick, GSList* mentions, const char* const ch, int flags) +gboolean +mucwin_db_history(ProfMucWin* mucwin, char* start_time, char* end_time, gboolean flip) { - int last_pos = 0; - int pos; - GSList* curr = mentions; - glong mynick_len = g_utf8_strlen(mynick, -1); + if (!end_time) { + end_time = buffer_size(((ProfWin*)mucwin)->layout->buffer) == 0 ? NULL : g_date_time_format_iso8601(buffer_get_entry(((ProfWin*)mucwin)->layout->buffer, 0)->time); + } + + GSList* history = log_database_get_previous_chat(mucwin->roomjid, start_time, end_time, !flip, flip); + gboolean has_items = g_slist_length(history) != 0; + GSList* curr = history; while (curr) { - pos = GPOINTER_TO_INT(curr->data); + ProfMessage* msg = curr->data; + mucwin_history(mucwin, msg, flip); + curr = g_slist_next(curr); + } + + g_slist_free_full(history, (GDestroyNotify)message_free); + win_redraw((ProfWin*)mucwin); - auto_gchar gchar* before_str = g_utf8_substring(message, last_pos, pos); + return has_items; +} - if (last_pos == 0 && strncmp(before_str, "/me ", 4) == 0) { - win_print_them(window, THEME_ROOMMENTION, ch, flags, ""); - win_append_highlight(window, THEME_ROOMMENTION, "*%s ", from); - win_append_highlight(window, THEME_ROOMMENTION, "%s", before_str + 4); +static void +_mucwin_print_mention(ProfWin* window, const char* const message, const char* const from, const char* const mynick, GSList* mentions, const char* const ch, int flags, gboolean flip) +{ + if (flip) { + int pos; + GSList* curr = g_slist_last(mentions); + glong mynick_len = g_utf8_strlen(mynick, -1); + int last_pos = GPOINTER_TO_INT(curr->data) + mynick_len; + + glong message_len = g_utf8_strlen(message, -1); + if (last_pos < message_len) { + // get tail without allocating a new string + gchar* rest = g_utf8_offset_to_pointer(message, last_pos); + win_appendln_highlight(window, THEME_ROOMMENTION, flip, "%s", rest); } else { - // print time and nick only once at beginning of the line - if (last_pos == 0) { - win_print_them(window, THEME_ROOMMENTION, ch, flags, from); - } - win_append_highlight(window, THEME_ROOMMENTION, "%s", before_str); + win_appendln_highlight(window, THEME_ROOMMENTION, flip, ""); } - auto_gchar gchar* mynick_str = g_utf8_substring(message, pos, pos + mynick_len); - win_append_highlight(window, THEME_ROOMMENTION_TERM, "%s", mynick_str); + for (int i = g_slist_length(mentions) - 1; i >= 0; i --){ + curr = g_slist_nth(mentions, i); + pos = GPOINTER_TO_INT(curr->data); + last_pos = i == 0 ? 0 : pos + mynick_len; - last_pos = pos + mynick_len; + auto_gchar gchar* mynick_str = g_utf8_substring(message, pos, pos + mynick_len); + win_append_highlight(window, THEME_ROOMMENTION_TERM, flip, "%s", mynick_str); - curr = g_slist_next(curr); - } + auto_gchar gchar* before_str = g_utf8_substring(message, last_pos, pos); - glong message_len = g_utf8_strlen(message, -1); - if (last_pos < message_len) { - // get tail without allocating a new string - gchar* rest = g_utf8_offset_to_pointer(message, last_pos); - win_appendln_highlight(window, THEME_ROOMMENTION, "%s", rest); + if (last_pos == 0 && strncmp(before_str, "/me ", 4) == 0) { + win_append_highlight(window, THEME_ROOMMENTION, flip, "%s", before_str + 4); + win_append_highlight(window, THEME_ROOMMENTION, flip, "*%s ", from); + win_print_them(window, THEME_ROOMMENTION, ch, flags, "", flip); + } else { + win_append_highlight(window, THEME_ROOMMENTION, flip, "%s", before_str); + // print time and nick only once at beginning of the line + if (last_pos == 0) { + win_print_them(window, THEME_ROOMMENTION, ch, flags, from, flip); + } + } + } } else { - win_appendln_highlight(window, THEME_ROOMMENTION, ""); + int last_pos = 0; + int pos; + GSList* curr = mentions; + glong mynick_len = g_utf8_strlen(mynick, -1); + + while (curr) { + pos = GPOINTER_TO_INT(curr->data); + + auto_gchar gchar* before_str = g_utf8_substring(message, last_pos, pos); + + if (last_pos == 0 && strncmp(before_str, "/me ", 4) == 0) { + win_print_them(window, THEME_ROOMMENTION, ch, flags, "", flip); + win_append_highlight(window, THEME_ROOMMENTION, flip, "*%s ", from); + win_append_highlight(window, THEME_ROOMMENTION, flip, "%s", before_str + 4); + } else { + // print time and nick only once at beginning of the line + if (last_pos == 0) { + win_print_them(window, THEME_ROOMMENTION, ch, flags, from, flip); + } + win_append_highlight(window, THEME_ROOMMENTION, flip, "%s", before_str); + } + + auto_gchar gchar* mynick_str = g_utf8_substring(message, pos, pos + mynick_len); + win_append_highlight(window, THEME_ROOMMENTION_TERM, flip, "%s", mynick_str); + + last_pos = pos + mynick_len; + + curr = g_slist_next(curr); + } + + glong message_len = g_utf8_strlen(message, -1); + if (last_pos < message_len) { + // get tail without allocating a new string + gchar* rest = g_utf8_offset_to_pointer(message, last_pos); + win_appendln_highlight(window, THEME_ROOMMENTION, flip, "%s", rest); + } else { + win_appendln_highlight(window, THEME_ROOMMENTION, flip, ""); + } } } @@ -438,7 +506,7 @@ _cmp_trigger_weight(gconstpointer a, gconstpointer b) } static void -_mucwin_print_triggers(ProfWin* window, const char* const message, GList* triggers) +_mucwin_print_triggers(ProfWin* window, const char* const message, GList* triggers, const gboolean flip) { GList* weighted_triggers = NULL; GList* curr = triggers; @@ -477,7 +545,7 @@ _mucwin_print_triggers(ProfWin* window, const char* const message, GList* trigge // no triggers found if (first_trigger_pos == -1) { - win_appendln_highlight(window, THEME_ROOMTRIGGER, "%s", message); + win_appendln_highlight(window, THEME_ROOMTRIGGER, flip, "%s", message); } else { if (first_trigger_pos > 0) { char message_section[strlen(message) + 1]; @@ -487,7 +555,7 @@ _mucwin_print_triggers(ProfWin* window, const char* const message, GList* trigge i++; } message_section[i] = '\0'; - win_append_highlight(window, THEME_ROOMTRIGGER, "%s", message_section); + win_append_highlight(window, THEME_ROOMTRIGGER, flip, "%s", message_section); } char trigger_section[first_trigger_len + 1]; int i = 0; @@ -498,10 +566,10 @@ _mucwin_print_triggers(ProfWin* window, const char* const message, GList* trigge trigger_section[i] = '\0'; if (first_trigger_pos + first_trigger_len < strlen(message)) { - win_append_highlight(window, THEME_ROOMTRIGGER_TERM, "%s", trigger_section); - _mucwin_print_triggers(window, &message[first_trigger_pos + first_trigger_len], triggers); + win_append_highlight(window, THEME_ROOMTRIGGER_TERM, flip, "%s", trigger_section); + _mucwin_print_triggers(window, &message[first_trigger_pos + first_trigger_len], triggers, flip); } else { - win_appendln_highlight(window, THEME_ROOMTRIGGER_TERM, "%s", trigger_section); + win_appendln_highlight(window, THEME_ROOMTRIGGER_TERM, flip, "%s", trigger_section); } } } @@ -542,7 +610,7 @@ mucwin_outgoing_msg(ProfMucWin* mucwin, const char* const message, const char* c } void -mucwin_incoming_msg(ProfMucWin* mucwin, const ProfMessage* const message, GSList* mentions, GList* triggers, gboolean filter_reflection) +mucwin_incoming_msg(ProfMucWin* mucwin, const ProfMessage* const message, GSList* mentions, GList* triggers, gboolean filter_reflection, gboolean flip) { assert(mucwin != NULL); int flags = 0; @@ -577,17 +645,19 @@ mucwin_incoming_msg(ProfMucWin* mucwin, const ProfMessage* const message, GSList ch = strdup("-"); } - win_insert_last_read_position_marker((ProfWin*)mucwin, mucwin->roomjid); - wins_add_urls_ac(window, message, FALSE); - wins_add_quotes_ac(window, message->plain, FALSE); + if (!flip) { + win_insert_last_read_position_marker((ProfWin*)mucwin, mucwin->roomjid); + } + wins_add_urls_ac(window, message, flip); + wins_add_quotes_ac(window, message->plain, flip); if (g_slist_length(mentions) > 0) { - _mucwin_print_mention(window, message->plain, message->from_jid->resourcepart, mynick, mentions, ch, flags); + _mucwin_print_mention(window, message->plain, message->from_jid->resourcepart, mynick, mentions, ch, flags, flip); } else if (triggers) { - win_print_them(window, THEME_ROOMTRIGGER, ch, flags, message->from_jid->resourcepart); - _mucwin_print_triggers(window, message->plain, triggers); + win_print_them(window, THEME_ROOMTRIGGER, ch, flags, message->from_jid->resourcepart, flip); + _mucwin_print_triggers(window, message->plain, triggers, flip); } else { - win_println_incoming_muc_msg(window, ch, flags, message); + win_println_incoming_muc_msg(window, ch, flags, message, flip); } free(ch); diff --git a/src/ui/ui.h b/src/ui/ui.h index 79fafd75c..76003c08b 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -161,9 +161,10 @@ void mucwin_occupant_affiliation_change(ProfMucWin* mucwin, const char* const ni void mucwin_occupant_role_and_affiliation_change(ProfMucWin* mucwin, const char* const nick, const char* const role, const char* const affiliation, const char* const actor, const char* const reason); void mucwin_roster(ProfMucWin* mucwin, GList* occupants, const char* const presence); -void mucwin_history(ProfMucWin* mucwin, const ProfMessage* const message); +void mucwin_history(ProfMucWin* mucwin, const ProfMessage* const message, gboolean flip); +gboolean mucwin_db_history(ProfMucWin* mucwin, char* start_time, char* end_time, gboolean flip); void mucwin_outgoing_msg(ProfMucWin* mucwin, const char* const message, const char* const id, prof_enc_t enc_mode, const char* const replace_id); -void mucwin_incoming_msg(ProfMucWin* mucwin, const ProfMessage* const message, GSList* mentions, GList* triggers, gboolean filter_reflection); +void mucwin_incoming_msg(ProfMucWin* mucwin, const ProfMessage* const message, GSList* mentions, GList* triggers, gboolean filter_reflection, gboolean flip); void mucwin_subject(ProfMucWin* mucwin, const char* const nick, const char* const subject); void mucwin_requires_config(ProfMucWin* mucwin); void mucwin_info(ProfMucWin* mucwin); @@ -396,8 +397,8 @@ void win_println_indent(ProfWin* window, int pad, const char* const message, ... void win_append(ProfWin* window, theme_item_t theme_item, const char* const message, ...); void win_appendln(ProfWin* window, theme_item_t theme_item, const char* const message, ...); -void win_append_highlight(ProfWin* window, theme_item_t theme_item, const char* const message, ...); -void win_appendln_highlight(ProfWin* window, theme_item_t theme_item, const char* const message, ...); +void win_append_highlight(ProfWin* window, theme_item_t theme_item, const gboolean flip, const char* const message, ...); +void win_appendln_highlight(ProfWin* window, theme_item_t theme_item, const gboolean flip, const char* const message, ...); char* win_get_title(ProfWin* window); void win_show_occupant(ProfWin* window, Occupant* occupant); diff --git a/src/ui/window.c b/src/ui/window.c index 49f22ca7d..2e027dda4 100644 --- a/src/ui/window.c +++ b/src/ui/window.c @@ -35,6 +35,7 @@ */ #include "config.h" +#include "ui/win_types.h" #include "ui/window_list.h" #include @@ -70,7 +71,7 @@ #define CEILING(X) (X - (int)(X) > 0 ? (int)(X + 1) : (int)(X)) static void -_win_printf(ProfWin* window, const char* show_char, int pad_indent, GDateTime* timestamp, int flags, theme_item_t theme_item, const char* const display_from, const char* const from_jid, const char* const message_id, const char* const message, ...); +_win_printf(ProfWin* window, const char* show_char, int pad_indent, GDateTime* timestamp, int flags, theme_item_t theme_item, const char* const display_from, const char* const from_jid, const char* const message_id, const gboolean flip, const char* const message, ...); static void _win_print_internal(ProfWin* window, const char* show_char, int pad_indent, GDateTime* time, int flags, theme_item_t theme_item, const char* const from, const char* const message, DeliveryReceipt* receipt); static void _win_print_wrapped(WINDOW* win, const char* const message, size_t indent, int pad_indent); @@ -652,15 +653,29 @@ win_page_up(ProfWin* window) *page_start -= page_space; - if (*page_start == -page_space && window->type == WIN_CHAT) { - ProfChatWin* chatwin = (ProfChatWin*)window; + if (*page_start == -page_space) { ProfBuffEntry* first_entry = buffer_size(window->layout->buffer) != 0 ? buffer_get_entry(window->layout->buffer, 0) : NULL; + gboolean is_not_fetching = first_entry && !(first_entry->theme_item == THEME_ROOMINFO && g_strcmp0(first_entry->message, LOADING_MESSAGE) == 0); + + if (window->type == WIN_CHAT) { + ProfChatWin* chatwin = (ProfChatWin*)window; - // Don't do anything if still fetching mam messages - if (first_entry && !(first_entry->theme_item == THEME_ROOMINFO && g_strcmp0(first_entry->message, LOADING_MESSAGE) == 0)) { - if (!chatwin_db_history(chatwin, NULL, NULL, TRUE) && prefs_get_boolean(PREF_MAM)) { - win_print_loading_history(window); - iq_mam_request_older(chatwin); + // Don't do anything if still fetching mam messages + if (is_not_fetching) { + if (!chatwin_db_history(chatwin, NULL, NULL, TRUE) && prefs_get_boolean(PREF_MAM)) { + win_print_loading_history(window); + iq_mam_request_older(window); + } + } + } else if (window->type == WIN_MUC) { + ProfMucWin* mucwin = (ProfMucWin*)window; + + // Don't do anything if still fetching mam messages + if (is_not_fetching) { + if (!mucwin_db_history(mucwin, NULL, NULL, TRUE) && prefs_get_boolean(PREF_MAM)) { + win_print_loading_history(window); + iq_mam_request_older(window); + } } } } @@ -1430,7 +1445,7 @@ win_print_incoming(ProfWin* window, const char* const display_name_from, ProfMes } else { // Prevent duplicate messages when current client is sending a message or if it's mam if (g_strcmp0(message->from_jid->fulljid, connection_get_fulljid()) != 0 && !message->is_mam) { - _win_printf(window, enc_char, 0, message->timestamp, flags, THEME_TEXT_THEM, display_name_from, message->from_jid->barejid, message->id, "%s", message->plain); + _win_printf(window, enc_char, 0, message->timestamp, flags, THEME_TEXT_THEM, display_name_from, message->from_jid->barejid, message->id, FALSE, "%s", message->plain); } } @@ -1438,7 +1453,7 @@ win_print_incoming(ProfWin* window, const char* const display_name_from, ProfMes break; } case WIN_PRIVATE: - _win_printf(window, "-", 0, message->timestamp, flags, THEME_TEXT_THEM, display_name_from, message->from_jid->barejid, message->id, "%s", message->plain); + _win_printf(window, "-", 0, message->timestamp, flags, THEME_TEXT_THEM, display_name_from, message->from_jid->barejid, message->id, FALSE, "%s", message->plain); break; default: assert(FALSE); @@ -1447,18 +1462,18 @@ win_print_incoming(ProfWin* window, const char* const display_name_from, ProfMes } void -win_print_them(ProfWin* window, theme_item_t theme_item, const char* const show_char, int flags, const char* const them) +win_print_them(ProfWin* window, theme_item_t theme_item, const char* const show_char, int flags, const char* const them, gboolean flip) { - _win_printf(window, show_char, 0, NULL, flags | NO_ME | NO_EOL, theme_item, them, NULL, NULL, ""); + _win_printf(window, show_char, 0, NULL, flags | NO_ME | NO_EOL, theme_item, them, NULL, NULL, flip, "", NULL); } void -win_println_incoming_muc_msg(ProfWin* window, char* show_char, int flags, const ProfMessage* const message) +win_println_incoming_muc_msg(ProfWin* window, char* show_char, int flags, const ProfMessage* const message, const gboolean flip) { if (prefs_get_boolean(PREF_CORRECTION_ALLOW) && message->replace_id) { _win_correct(window, message->plain, message->id, message->replace_id, message->from_jid->fulljid); } else { - _win_printf(window, show_char, 0, message->timestamp, flags | NO_ME, THEME_TEXT_THEM, message->from_jid->resourcepart, message->from_jid->fulljid, message->id, "%s", message->plain); + _win_printf(window, show_char, 0, message->timestamp, flags | NO_ME, THEME_TEXT_THEM, message->from_jid->resourcepart, message->from_jid->fulljid, message->id, flip, "%s", message->plain); } inp_nonblocking(TRUE); @@ -1472,7 +1487,7 @@ win_print_outgoing_muc_msg(ProfWin* window, char* show_char, const char* const m if (prefs_get_boolean(PREF_CORRECTION_ALLOW) && replace_id) { _win_correct(window, message, id, replace_id, me); } else { - _win_printf(window, show_char, 0, timestamp, 0, THEME_TEXT_ME, me, me, id, "%s", message); + _win_printf(window, show_char, 0, timestamp, 0, THEME_TEXT_ME, me, me, id, FALSE, "%s", message); } inp_nonblocking(TRUE); @@ -1489,7 +1504,7 @@ win_print_outgoing(ProfWin* window, const char* show_char, const char* const id, _win_correct(window, message, id, replace_id, myjid); } else { auto_char gchar* outgoing_str = prefs_get_string(PREF_OUTGOING_STAMP); - _win_printf(window, show_char, 0, timestamp, 0, THEME_TEXT_ME, outgoing_str, myjid, id, "%s", message); + _win_printf(window, show_char, 0, timestamp, 0, THEME_TEXT_ME, outgoing_str, myjid, id, FALSE, "%s", message); } inp_nonblocking(TRUE); @@ -1657,7 +1672,7 @@ win_appendln(ProfWin* window, theme_item_t theme_item, const char* const message } void -win_append_highlight(ProfWin* window, theme_item_t theme_item, const char* const message, ...) +win_append_highlight(ProfWin* window, theme_item_t theme_item, const gboolean flip, const char* const message, ...) { GDateTime* timestamp = g_date_time_new_now_local(); @@ -1666,8 +1681,13 @@ win_append_highlight(ProfWin* window, theme_item_t theme_item, const char* const GString* fmt_msg = g_string_new(NULL); g_string_vprintf(fmt_msg, message, arg); - buffer_append(window->layout->buffer, "-", 0, timestamp, NO_DATE | NO_ME | NO_EOL, theme_item, "", NULL, fmt_msg->str, NULL, NULL); - _win_print_internal(window, "-", 0, timestamp, NO_DATE | NO_ME | NO_EOL, theme_item, "", fmt_msg->str, NULL); + if (flip) { + buffer_prepend(window->layout->buffer, "-", 0, timestamp, NO_DATE | NO_ME | NO_EOL, theme_item, "", NULL, fmt_msg->str, NULL, NULL); + win_redraw(window); + } else { + buffer_append(window->layout->buffer, "-", 0, timestamp, NO_DATE | NO_ME | NO_EOL, theme_item, "", NULL, fmt_msg->str, NULL, NULL); + _win_print_internal(window, "-", 0, timestamp, NO_DATE | NO_ME | NO_EOL, theme_item, "", fmt_msg->str, NULL); + } inp_nonblocking(TRUE); g_date_time_unref(timestamp); @@ -1677,7 +1697,7 @@ win_append_highlight(ProfWin* window, theme_item_t theme_item, const char* const } void -win_appendln_highlight(ProfWin* window, theme_item_t theme_item, const char* const message, ...) +win_appendln_highlight(ProfWin* window, theme_item_t theme_item, const gboolean flip, const char* const message, ...) { GDateTime* timestamp = g_date_time_new_now_local(); @@ -1686,8 +1706,14 @@ win_appendln_highlight(ProfWin* window, theme_item_t theme_item, const char* con GString* fmt_msg = g_string_new(NULL); g_string_vprintf(fmt_msg, message, arg); - buffer_append(window->layout->buffer, "-", 0, timestamp, NO_DATE | NO_ME, theme_item, "", NULL, fmt_msg->str, NULL, NULL); - _win_print_internal(window, "-", 0, timestamp, NO_DATE | NO_ME, theme_item, "", fmt_msg->str, NULL); + if (flip) { + buffer_prepend(window->layout->buffer, "-", 0, timestamp, NO_DATE | NO_ME, theme_item, "", NULL, fmt_msg->str, NULL, NULL); + win_redraw(window); + } else { + buffer_append(window->layout->buffer, "-", 0, timestamp, NO_DATE | NO_ME, theme_item, "", NULL, fmt_msg->str, NULL, NULL); + _win_print_internal(window, "-", 0, timestamp, NO_DATE | NO_ME, theme_item, "", fmt_msg->str, NULL); + } + inp_nonblocking(TRUE); g_date_time_unref(timestamp); @@ -1762,7 +1788,7 @@ win_newline(ProfWin* window) } static void -_win_printf(ProfWin* window, const char* show_char, int pad_indent, GDateTime* timestamp, int flags, theme_item_t theme_item, const char* const display_from, const char* const from_jid, const char* const message_id, const char* const message, ...) +_win_printf(ProfWin* window, const char* show_char, int pad_indent, GDateTime* timestamp, int flags, theme_item_t theme_item, const char* const display_from, const char* const from_jid, const char* const message_id, const gboolean flip, const char* const message, ...) { if (timestamp == NULL) { timestamp = g_date_time_new_now_local(); @@ -1775,8 +1801,13 @@ _win_printf(ProfWin* window, const char* show_char, int pad_indent, GDateTime* t GString* fmt_msg = g_string_new(NULL); g_string_vprintf(fmt_msg, message, arg); - buffer_append(window->layout->buffer, show_char, pad_indent, timestamp, flags, theme_item, display_from, from_jid, fmt_msg->str, NULL, message_id); - _win_print_internal(window, show_char, pad_indent, timestamp, flags, theme_item, display_from, fmt_msg->str, NULL); + if (flip) { + buffer_prepend(window->layout->buffer, show_char, pad_indent, timestamp, flags, theme_item, display_from, from_jid, fmt_msg->str, NULL, message_id); + win_redraw(window); + } else { + buffer_append(window->layout->buffer, show_char, pad_indent, timestamp, flags, theme_item, display_from, from_jid, fmt_msg->str, NULL, message_id); + _win_print_internal(window, show_char, pad_indent, timestamp, flags, theme_item, display_from, fmt_msg->str, NULL); + } inp_nonblocking(TRUE); g_date_time_unref(timestamp); diff --git a/src/ui/window.h b/src/ui/window.h index 1c0a9007d..d472af106 100644 --- a/src/ui/window.h +++ b/src/ui/window.h @@ -65,11 +65,11 @@ void win_show_status_string(ProfWin* window, const char* const from, GDateTime* last_activity, const char* const pre, const char* const default_show); -void win_print_them(ProfWin* window, theme_item_t theme_item, const char* const show_char, int flags, const char* const them); +void win_print_them(ProfWin* window, theme_item_t theme_item, const char* const show_char, int flags, const char* const them, const gboolean flip); void win_print_incoming(ProfWin* window, const char* const from, ProfMessage* message); void win_print_outgoing(ProfWin* window, const char* show_char, const char* const id, const char* const replace_id, const char* const message); void win_print_outgoing_with_receipt(ProfWin* window, const char* show_char, const char* const from, const char* const message, char* id, const char* const replace_id); -void win_println_incoming_muc_msg(ProfWin* window, char* show_char, int flags, const ProfMessage* const message); +void win_println_incoming_muc_msg(ProfWin* window, char* show_char, int flags, const ProfMessage* const message, const gboolean flip); void win_print_outgoing_muc_msg(ProfWin* window, char* show_char, const char* const me, const char* const id, const char* const replace_id, const char* const message); void win_print_history(ProfWin* window, const ProfMessage* const message); void win_print_old_history(ProfWin* window, const ProfMessage* const message); diff --git a/src/xmpp/iq.c b/src/xmpp/iq.c index 159ba6096..0e8cfeca2 100644 --- a/src/xmpp/iq.c +++ b/src/xmpp/iq.c @@ -34,6 +34,7 @@ */ #include "config.h" +#include "ui/win_types.h" #ifdef HAVE_GIT_VERSION #include "gitversion.h" @@ -110,12 +111,12 @@ typedef struct mam_rsm_userdata char* start_datestr; char* end_datestr; gboolean fetch_next; - ProfChatWin* win; + ProfWin* win; } MamRsmUserdata; typedef struct late_delivery_userdata { - ProfChatWin* win; + ProfWin* win; GDateTime* enddate; GDateTime* startdate; } LateDeliveryUserdata; @@ -157,7 +158,7 @@ static int _command_exec_response_handler(xmpp_stanza_t* const stanza, void* con static int _mam_rsm_id_handler(xmpp_stanza_t* const stanza, void* const userdata); static int _register_change_password_result_id_handler(xmpp_stanza_t* const stanza, void* const userdata); -static void _iq_mam_request(ProfChatWin* win, GDateTime* startdate, GDateTime* enddate); +static void _iq_mam_request(ProfWin* win, GDateTime* startdate, GDateTime* enddate); static void _iq_free_room_data(ProfRoomInfoData* roominfo); static void _iq_free_affiliation_set(ProfPrivilegeSet* affiliation_set); static void _iq_free_affiliation_list(ProfAffiliationList* affiliation_list); @@ -2610,17 +2611,24 @@ _iq_free_affiliation_list(ProfAffiliationList* affiliation_list) static int _mam_buffer_commit_handler(xmpp_stanza_t* const stanza, void* const userdata) { - ProfChatWin* chatwin = (ProfChatWin*)userdata; + ProfWin* win = (ProfWin*)userdata; // Remove the "Loading messages …" message - buffer_remove_entry(((ProfWin*)chatwin)->layout->buffer, 0); - chatwin_db_history(chatwin, NULL, NULL, TRUE); + buffer_remove_entry(win->layout->buffer, 0); + + if (win->type == WIN_CHAT) { + ProfChatWin* chatwin = (ProfChatWin*)win; + chatwin_db_history(chatwin, NULL, NULL, TRUE); + } else if (win->type == WIN_MUC) { + ProfMucWin* mucwin = (ProfMucWin*)win; + mucwin_db_history(mucwin, NULL, NULL, TRUE); + } return 0; } static const gchar* mam_timestamp_format_string = "%FT%T.%f%:z"; void -iq_mam_request_older(ProfChatWin* win) +iq_mam_request_older(ProfWin* win) { if (connection_supports(XMPP_FEATURE_MAM2) == FALSE) { log_warning("Server doesn't advertise %s feature.", XMPP_FEATURE_MAM2); @@ -2628,7 +2636,9 @@ iq_mam_request_older(ProfChatWin* win) return; } - ProfMessage* first_msg = log_database_get_limits_info(win->barejid, FALSE); + char* win_jid = win_get_tab_identifier(win); + + ProfMessage* first_msg = log_database_get_limits_info(win_jid, FALSE); char* firstid = NULL; char* enddate = NULL; @@ -2641,11 +2651,12 @@ iq_mam_request_older(ProfChatWin* win) } xmpp_ctx_t* const ctx = connection_get_ctx(); - xmpp_stanza_t* iq = stanza_create_mam_iq(ctx, win->barejid, NULL, enddate, firstid, NULL); + xmpp_stanza_t* iq = stanza_create_mam_iq(ctx, win_jid, NULL, enddate, firstid, NULL, win->type == WIN_MUC); iq_id_handler_add(xmpp_stanza_get_id(iq), _mam_buffer_commit_handler, NULL, win); g_free(enddate); message_free(first_msg); + free(win_jid); iq_send_stanza(iq); xmpp_stanza_release(iq); @@ -2666,7 +2677,7 @@ _mam_userdata_free(MamRsmUserdata* data) } void -_iq_mam_request(ProfChatWin* win, GDateTime* startdate, GDateTime* enddate) +_iq_mam_request(ProfWin* win, GDateTime* startdate, GDateTime* enddate) { if (connection_supports(XMPP_FEATURE_MAM2) == FALSE) { log_warning("Server doesn't advertise %s feature.", XMPP_FEATURE_MAM2); @@ -2696,15 +2707,16 @@ _iq_mam_request(ProfChatWin* win, GDateTime* startdate, GDateTime* enddate) g_date_time_unref(enddate); } + char* win_jid = win_get_tab_identifier(win); xmpp_ctx_t* const ctx = connection_get_ctx(); - xmpp_stanza_t* iq = stanza_create_mam_iq(ctx, win->barejid, startdate_str, enddate_str, firstid, NULL); + xmpp_stanza_t* iq = stanza_create_mam_iq(ctx, win_jid, startdate_str, enddate_str, firstid, NULL, win->type == WIN_MUC); MamRsmUserdata* data = malloc(sizeof(MamRsmUserdata)); if (data) { data->start_datestr = startdate_str; data->end_datestr = enddate_str; - data->barejid = strdup(win->barejid); + data->barejid = strdup(win_jid); data->fetch_next = fetch_next; data->win = win; @@ -2713,14 +2725,16 @@ _iq_mam_request(ProfChatWin* win, GDateTime* startdate, GDateTime* enddate) iq_send_stanza(iq); xmpp_stanza_release(iq); + free(win_jid); return; } void -iq_mam_request(ProfChatWin* win, GDateTime* enddate) +iq_mam_request(ProfWin* win, GDateTime* enddate) { - ProfMessage* last_msg = log_database_get_limits_info(win->barejid, TRUE); + char* win_jid = win_get_tab_identifier(win); + ProfMessage* last_msg = log_database_get_limits_info(win_jid, TRUE); GDateTime* startdate = g_date_time_add_seconds(last_msg->timestamp, 0); message_free(last_msg); @@ -2731,10 +2745,12 @@ iq_mam_request(ProfChatWin* win, GDateTime* enddate) cur_del_data->enddate = enddate; cur_del_data->startdate = startdate; late_delivery_windows = g_slist_append(late_delivery_windows, cur_del_data); - log_debug("Save MAM request of %s for later", win->barejid); + log_debug("Save MAM request of %s for later", win_jid); + free(win_jid); return; } + free(win_jid); _iq_mam_request(win, startdate, enddate); return; @@ -2772,11 +2788,40 @@ _mam_rsm_id_handler(xmpp_stanza_t* const stanza, void* const userdata) } if (is_complete || !data->fetch_next) { - chatwin_db_history(data->win, is_complete ? NULL : start_str, end_str, TRUE); - return 0; + switch (data->win->type) { + case WIN_CHAT: + { + ProfChatWin* chatwin = (ProfChatWin*)data->win; + chatwin_db_history(chatwin, is_complete ? NULL : start_str, end_str, TRUE); + return 0; + } + case WIN_MUC: + { + ProfMucWin* mucwin = (ProfMucWin*)data->win; + mucwin_db_history(mucwin, is_complete ? NULL : start_str, end_str, TRUE); + return 0; + } + default: + return 0; + } } - chatwin_db_history(data->win, start_str, end_str, TRUE); + switch (data->win->type) { + case WIN_CHAT: + { + ProfChatWin* chatwin = (ProfChatWin*)data->win; + chatwin_db_history(chatwin, start_str, end_str, TRUE); + return 0; + } + case WIN_MUC: + { + ProfMucWin* mucwin = (ProfMucWin*)data->win; + mucwin_db_history(mucwin, start_str, end_str, TRUE); + return 0; + } + default: + return 0; + } xmpp_stanza_t* set = xmpp_stanza_get_child_by_name_and_ns(fin, STANZA_TYPE_SET, STANZA_NS_RSM); if (set) { @@ -2793,7 +2838,7 @@ _mam_rsm_id_handler(xmpp_stanza_t* const stanza, void* const userdata) free(data->end_datestr); data->end_datestr = NULL; } - xmpp_stanza_t* iq = stanza_create_mam_iq(ctx, data->barejid, data->start_datestr, NULL, firstid, NULL); + xmpp_stanza_t* iq = stanza_create_mam_iq(ctx, data->barejid, data->start_datestr, NULL, firstid, NULL, data->win->type == WIN_MUC); free(firstid); MamRsmUserdata* ndata = malloc(sizeof(*ndata)); diff --git a/src/xmpp/message.c b/src/xmpp/message.c index a6372c4a6..9aaf42479 100644 --- a/src/xmpp/message.c +++ b/src/xmpp/message.c @@ -76,7 +76,7 @@ typedef struct p_message_handle_t static int _message_handler(xmpp_conn_t* const conn, xmpp_stanza_t* const stanza, void* const userdata); static void _handle_error(xmpp_stanza_t* const stanza); -static void _handle_groupchat(xmpp_stanza_t* const stanza); +static void _handle_groupchat(xmpp_stanza_t* const stanza, gboolean is_mam, GDateTime* timestamp); static void _handle_muc_user(xmpp_stanza_t* const stanza); static void _handle_muc_private_message(xmpp_stanza_t* const stanza); static void _handle_conference(xmpp_stanza_t* const stanza); @@ -162,7 +162,7 @@ _message_handler(xmpp_conn_t* const conn, xmpp_stanza_t* const stanza, void* con _handle_error(stanza); } else if (type && g_strcmp0(type, STANZA_TYPE_GROUPCHAT) == 0) { // XEP-0045: Multi-User Chat - _handle_groupchat(stanza); + _handle_groupchat(stanza, FALSE, NULL); } else if (type && g_strcmp0(type, STANZA_TYPE_HEADLINE) == 0) { xmpp_stanza_t* event = xmpp_stanza_get_child_by_ns(stanza, STANZA_NS_PUBSUB_EVENT); @@ -1019,7 +1019,7 @@ _room_config_handler(xmpp_stanza_t* const stanza, void* const userdata) } static void -_handle_groupchat(xmpp_stanza_t* const stanza) +_handle_groupchat(xmpp_stanza_t* const stanza, gboolean is_mam, GDateTime* timestamp) { xmpp_ctx_t* ctx = connection_get_ctx(); @@ -1093,6 +1093,7 @@ _handle_groupchat(xmpp_stanza_t* const stanza) ProfMessage* message = message_init(); jid_ref(from_jid); message->from_jid = from_jid; + message->is_mam = is_mam; message->type = PROF_MSG_TYPE_MUC; const char* id = xmpp_stanza_get_id(stanza); @@ -1156,8 +1157,11 @@ _handle_groupchat(xmpp_stanza_t* const stanza) message->timestamp = NULL; } - // we want to display the oldest delay - message->timestamp = stanza_get_oldest_delay(stanza); + message->timestamp = timestamp; + if (!timestamp) { + // we want to display the oldest delay + message->timestamp = stanza_get_oldest_delay(stanza); + } // now this has nothing to do with MUC history // it's just setting the time to the received time so upon displaying we can use this time @@ -1375,7 +1379,7 @@ _handle_chat(xmpp_stanza_t* const stanza, gboolean is_mam, gboolean is_carbon, c } // private message from chat room use full jid (room/nick) - if (muc_active(jid->barejid)) { + if (muc_active(jid->barejid) && !is_mam) { _handle_muc_private_message(stanza); return; } @@ -1557,9 +1561,14 @@ _handle_mam(xmpp_stanza_t* const stanza) GDateTime* timestamp = stanza_get_delay_from(forwarded, NULL); xmpp_stanza_t* message_stanza = xmpp_stanza_get_child_by_ns(forwarded, "jabber:client"); + const char* type = xmpp_stanza_get_type(message_stanza); - _handle_chat(message_stanza, TRUE, FALSE, result_id, timestamp); + if (type && g_strcmp0(type, STANZA_TYPE_GROUPCHAT) == 0) { + _handle_groupchat(message_stanza, TRUE, timestamp); + return TRUE; + } + _handle_chat(message_stanza, TRUE, FALSE, result_id, timestamp); return TRUE; } diff --git a/src/xmpp/stanza.c b/src/xmpp/stanza.c index bbc15c13b..6e0a116e1 100644 --- a/src/xmpp/stanza.c +++ b/src/xmpp/stanza.c @@ -2771,7 +2771,7 @@ _text_stanza(xmpp_ctx_t* ctx, const char* name, const char* text) } xmpp_stanza_t* -stanza_create_mam_iq(xmpp_ctx_t* ctx, const char* const jid, const char* const startdate, const char* const enddate, const char* const firstid, const char* const lastid) +stanza_create_mam_iq(xmpp_ctx_t* ctx, const char* const jid, const char* const startdate, const char* const enddate, const char* const firstid, const char* const lastid, const gboolean is_muc) { char* id = connection_create_stanza_id(); xmpp_stanza_t* iq = xmpp_iq_new(ctx, STANZA_TYPE_SET, id); @@ -2797,14 +2797,19 @@ stanza_create_mam_iq(xmpp_ctx_t* ctx, const char* const jid, const char* const s xmpp_stanza_add_child_ex(field_form_type, value_mam, 0); - // field 'with' - xmpp_stanza_t* field_with = xmpp_stanza_new(ctx); - xmpp_stanza_set_name(field_with, STANZA_NAME_FIELD); - xmpp_stanza_set_attribute(field_with, STANZA_ATTR_VAR, "with"); + xmpp_stanza_t* field_with; + if (is_muc) { + xmpp_stanza_set_to(iq, jid); + } else { + // field 'with' + field_with = xmpp_stanza_new(ctx); + xmpp_stanza_set_name(field_with, STANZA_NAME_FIELD); + xmpp_stanza_set_attribute(field_with, STANZA_ATTR_VAR, "with"); - xmpp_stanza_t* value_with = _text_stanza(ctx, STANZA_NAME_VALUE, jid); + xmpp_stanza_t* value_with = _text_stanza(ctx, STANZA_NAME_VALUE, jid); - xmpp_stanza_add_child_ex(field_with, value_with, 0); + xmpp_stanza_add_child_ex(field_with, value_with, 0); + } // 4.3.2 set/rsm xmpp_stanza_t* set = xmpp_stanza_new(ctx); @@ -2828,7 +2833,10 @@ stanza_create_mam_iq(xmpp_ctx_t* ctx, const char* const jid, const char* const s xmpp_stanza_add_child_ex(iq, query, 0); xmpp_stanza_add_child_ex(query, x, 0); xmpp_stanza_add_child_ex(x, field_form_type, 0); - xmpp_stanza_add_child_ex(x, field_with, 0); + + if (!is_muc) { + xmpp_stanza_add_child_ex(x, field_with, 0); + } // field 'start' if (startdate) { diff --git a/src/xmpp/stanza.h b/src/xmpp/stanza.h index 636fafb09..b56009735 100644 --- a/src/xmpp/stanza.h +++ b/src/xmpp/stanza.h @@ -420,7 +420,7 @@ xmpp_stanza_t* stanza_create_avatar_data_publish_iq(xmpp_ctx_t* ctx, const char* xmpp_stanza_t* stanza_create_avatar_metadata_publish_iq(xmpp_ctx_t* ctx, const char* img_data, gsize len, int height, int width); xmpp_stanza_t* stanza_disable_avatar_publish_iq(xmpp_ctx_t* ctx); xmpp_stanza_t* stanza_create_vcard_request_iq(xmpp_ctx_t* ctx, const char* const jid, const char* const stanza_id); -xmpp_stanza_t* stanza_create_mam_iq(xmpp_ctx_t* ctx, const char* const jid, const char* const startdate, const char* const enddate, const char* const firstid, const char* const lastid); +xmpp_stanza_t* stanza_create_mam_iq(xmpp_ctx_t* ctx, const char* const jid, const char* const startdate, const char* const enddate, const char* const firstid, const char* const lastid, const gboolean is_muc); xmpp_stanza_t* stanza_change_password(xmpp_ctx_t* ctx, const char* const user, const char* const password); xmpp_stanza_t* stanza_register_new_account(xmpp_ctx_t* ctx, const char* const user, const char* const password); xmpp_stanza_t* stanza_request_voice(xmpp_ctx_t* ctx, const char* const room); diff --git a/src/xmpp/xmpp.h b/src/xmpp/xmpp.h index 2babe536a..c2dcf8231 100644 --- a/src/xmpp/xmpp.h +++ b/src/xmpp/xmpp.h @@ -264,8 +264,8 @@ void iq_autoping_check(void); void iq_http_upload_request(HTTPUpload* upload); void iq_command_list(const char* const target); void iq_command_exec(const char* const target, const char* const command); -void iq_mam_request(ProfChatWin* win, GDateTime* enddate); -void iq_mam_request_older(ProfChatWin* win); +void iq_mam_request(ProfWin* win, GDateTime* enddate); +void iq_mam_request_older(ProfWin* win); void iq_register_change_password(const char* const user, const char* const password); void iq_muc_register_nick(const char* const roomjid); diff --git a/tests/unittests/ui/stub_ui.c b/tests/unittests/ui/stub_ui.c index 608f5003c..4fec3527c 100644 --- a/tests/unittests/ui/stub_ui.c +++ b/tests/unittests/ui/stub_ui.c @@ -363,11 +363,11 @@ mucwin_roster(ProfMucWin* mucwin, GList* occupants, const char* const presence) { } void -mucwin_history(ProfMucWin* mucwin, const ProfMessage* const message) +mucwin_history(ProfMucWin* mucwin, const ProfMessage* const message, gboolean flip) { } void -mucwin_incoming_msg(ProfMucWin* mucwin, const ProfMessage* const message, GSList* mentions, GList* triggers, gboolean filter_reflection) +mucwin_incoming_msg(ProfMucWin* mucwin, const ProfMessage* const message, GSList* mentions, GList* triggers, gboolean filter_reflection, gboolean flip) { } void diff --git a/tests/unittests/xmpp/stub_xmpp.c b/tests/unittests/xmpp/stub_xmpp.c index ffa7565d9..585f76f40 100644 --- a/tests/unittests/xmpp/stub_xmpp.c +++ b/tests/unittests/xmpp/stub_xmpp.c @@ -435,7 +435,7 @@ iq_muc_register_nick(const char* const roomjid) } void -iq_mam_request(ProfChatWin* win, GDateTime* enddate) +iq_mam_request(ProfWin* win, GDateTime* enddate) { } From 51025a41a601a9a91b73976145968ef71cf41b70 Mon Sep 17 00:00:00 2001 From: MarcoPolo-PasTonMolo Date: Sat, 8 Jul 2023 21:19:22 +0300 Subject: [PATCH 2/6] Show mentions and triggers correctly for MAM and history Show correct timestamp for mentions and triggers (it used to show current timestamp instead of the message's one), and flip commands when displaying history. See #660 --- src/ui/mucwin.c | 113 +++++++++++++++++++++++++++++++----------------- src/ui/ui.h | 4 +- src/ui/window.c | 32 ++++++++++---- src/ui/window.h | 2 +- 4 files changed, 100 insertions(+), 51 deletions(-) diff --git a/src/ui/mucwin.c b/src/ui/mucwin.c index 961d8fe10..2bbbcf49a 100644 --- a/src/ui/mucwin.c +++ b/src/ui/mucwin.c @@ -410,7 +410,7 @@ mucwin_db_history(ProfMucWin* mucwin, char* start_time, char* end_time, gboolean } static void -_mucwin_print_mention(ProfWin* window, const char* const message, const char* const from, const char* const mynick, GSList* mentions, const char* const ch, int flags, gboolean flip) +_mucwin_print_mention(ProfWin* window, const char* const message, const char* const from, const char* const mynick, GSList* mentions, const char* const ch, int flags, GDateTime* timestamp, gboolean flip) { if (flip) { int pos; @@ -422,9 +422,9 @@ _mucwin_print_mention(ProfWin* window, const char* const message, const char* co if (last_pos < message_len) { // get tail without allocating a new string gchar* rest = g_utf8_offset_to_pointer(message, last_pos); - win_appendln_highlight(window, THEME_ROOMMENTION, flip, "%s", rest); + win_appendln_highlight(window, THEME_ROOMMENTION, timestamp, flip, "%s", rest); } else { - win_appendln_highlight(window, THEME_ROOMMENTION, flip, ""); + win_appendln_highlight(window, THEME_ROOMMENTION, timestamp, flip, ""); } for (int i = g_slist_length(mentions) - 1; i >= 0; i --){ @@ -433,19 +433,19 @@ _mucwin_print_mention(ProfWin* window, const char* const message, const char* co last_pos = i == 0 ? 0 : pos + mynick_len; auto_gchar gchar* mynick_str = g_utf8_substring(message, pos, pos + mynick_len); - win_append_highlight(window, THEME_ROOMMENTION_TERM, flip, "%s", mynick_str); + win_append_highlight(window, THEME_ROOMMENTION_TERM, timestamp, flip, "%s", mynick_str); auto_gchar gchar* before_str = g_utf8_substring(message, last_pos, pos); if (last_pos == 0 && strncmp(before_str, "/me ", 4) == 0) { - win_append_highlight(window, THEME_ROOMMENTION, flip, "%s", before_str + 4); - win_append_highlight(window, THEME_ROOMMENTION, flip, "*%s ", from); - win_print_them(window, THEME_ROOMMENTION, ch, flags, "", flip); + win_append_highlight(window, THEME_ROOMMENTION, timestamp, flip, "%s", before_str + 4); + win_append_highlight(window, THEME_ROOMMENTION, timestamp, flip, "*%s ", from); + win_print_them(window, THEME_ROOMMENTION, timestamp, ch, flags, "", flip); } else { - win_append_highlight(window, THEME_ROOMMENTION, flip, "%s", before_str); + win_append_highlight(window, THEME_ROOMMENTION, timestamp, flip, "%s", before_str); // print time and nick only once at beginning of the line if (last_pos == 0) { - win_print_them(window, THEME_ROOMMENTION, ch, flags, from, flip); + win_print_them(window, THEME_ROOMMENTION, timestamp, ch, flags, from, flip); } } } @@ -461,19 +461,19 @@ _mucwin_print_mention(ProfWin* window, const char* const message, const char* co auto_gchar gchar* before_str = g_utf8_substring(message, last_pos, pos); if (last_pos == 0 && strncmp(before_str, "/me ", 4) == 0) { - win_print_them(window, THEME_ROOMMENTION, ch, flags, "", flip); - win_append_highlight(window, THEME_ROOMMENTION, flip, "*%s ", from); - win_append_highlight(window, THEME_ROOMMENTION, flip, "%s", before_str + 4); + win_print_them(window, THEME_ROOMMENTION, timestamp, ch, flags, "", flip); + win_append_highlight(window, THEME_ROOMMENTION, timestamp, flip, "*%s ", from); + win_append_highlight(window, THEME_ROOMMENTION, timestamp, flip, "%s", before_str + 4); } else { // print time and nick only once at beginning of the line if (last_pos == 0) { - win_print_them(window, THEME_ROOMMENTION, ch, flags, from, flip); + win_print_them(window, THEME_ROOMMENTION, timestamp, ch, flags, from, flip); } - win_append_highlight(window, THEME_ROOMMENTION, flip, "%s", before_str); + win_append_highlight(window, THEME_ROOMMENTION, timestamp, flip, "%s", before_str); } auto_gchar gchar* mynick_str = g_utf8_substring(message, pos, pos + mynick_len); - win_append_highlight(window, THEME_ROOMMENTION_TERM, flip, "%s", mynick_str); + win_append_highlight(window, THEME_ROOMMENTION_TERM, timestamp, flip, "%s", mynick_str); last_pos = pos + mynick_len; @@ -484,9 +484,9 @@ _mucwin_print_mention(ProfWin* window, const char* const message, const char* co if (last_pos < message_len) { // get tail without allocating a new string gchar* rest = g_utf8_offset_to_pointer(message, last_pos); - win_appendln_highlight(window, THEME_ROOMMENTION, flip, "%s", rest); + win_appendln_highlight(window, THEME_ROOMMENTION, timestamp, flip, "%s", rest); } else { - win_appendln_highlight(window, THEME_ROOMMENTION, flip, ""); + win_appendln_highlight(window, THEME_ROOMMENTION, timestamp, flip, ""); } } } @@ -506,7 +506,7 @@ _cmp_trigger_weight(gconstpointer a, gconstpointer b) } static void -_mucwin_print_triggers(ProfWin* window, const char* const message, GList* triggers, const gboolean flip) +_mucwin_print_triggers(ProfWin* window, const char* const message, GList* triggers, GDateTime* timestamp, const gboolean flip) { GList* weighted_triggers = NULL; GList* curr = triggers; @@ -545,31 +545,59 @@ _mucwin_print_triggers(ProfWin* window, const char* const message, GList* trigge // no triggers found if (first_trigger_pos == -1) { - win_appendln_highlight(window, THEME_ROOMTRIGGER, flip, "%s", message); + win_appendln_highlight(window, THEME_ROOMTRIGGER, timestamp, flip, "%s", message); } else { - if (first_trigger_pos > 0) { - char message_section[strlen(message) + 1]; + if (!flip) { + if (first_trigger_pos > 0) { + char message_section[strlen(message) + 1]; + int i = 0; + while (i < first_trigger_pos) { + message_section[i] = message[i]; + i++; + } + message_section[i] = '\0'; + win_append_highlight(window, THEME_ROOMTRIGGER, timestamp, flip, "%s", message_section); + } + char trigger_section[first_trigger_len + 1]; int i = 0; - while (i < first_trigger_pos) { - message_section[i] = message[i]; + while (i < first_trigger_len) { + trigger_section[i] = message[first_trigger_pos + i]; i++; } - message_section[i] = '\0'; - win_append_highlight(window, THEME_ROOMTRIGGER, flip, "%s", message_section); - } - char trigger_section[first_trigger_len + 1]; - int i = 0; - while (i < first_trigger_len) { - trigger_section[i] = message[first_trigger_pos + i]; - i++; - } - trigger_section[i] = '\0'; + trigger_section[i] = '\0'; - if (first_trigger_pos + first_trigger_len < strlen(message)) { - win_append_highlight(window, THEME_ROOMTRIGGER_TERM, flip, "%s", trigger_section); - _mucwin_print_triggers(window, &message[first_trigger_pos + first_trigger_len], triggers, flip); + if (first_trigger_pos + first_trigger_len < strlen(message)) { + win_append_highlight(window, THEME_ROOMTRIGGER_TERM, timestamp, flip, "%s", trigger_section); + _mucwin_print_triggers(window, &message[first_trigger_pos + first_trigger_len], triggers, timestamp, flip); + } else { + win_appendln_highlight(window, THEME_ROOMTRIGGER_TERM, timestamp, flip, "%s", trigger_section); + } } else { - win_appendln_highlight(window, THEME_ROOMTRIGGER_TERM, flip, "%s", trigger_section); + char trigger_section[first_trigger_len + 1]; + int i = 0; + while (i < first_trigger_len) { + trigger_section[i] = message[first_trigger_pos + i]; + i++; + } + trigger_section[i] = '\0'; + + if (first_trigger_pos + first_trigger_len < strlen(message)) { + _mucwin_print_triggers(window, &message[first_trigger_pos + first_trigger_len], triggers, timestamp, flip); + win_append_highlight(window, THEME_ROOMTRIGGER_TERM, timestamp, flip, "%s", trigger_section); + } else { + win_appendln_highlight(window, THEME_ROOMTRIGGER_TERM, timestamp, flip, "%s", trigger_section); + } + + if (first_trigger_pos > 0) { + char message_section[strlen(message) + 1]; + int i = 0; + while (i < first_trigger_pos) { + message_section[i] = message[i]; + i++; + } + message_section[i] = '\0'; + win_append_highlight(window, THEME_ROOMTRIGGER, timestamp, flip, "%s", message_section); + } } } } @@ -652,10 +680,15 @@ mucwin_incoming_msg(ProfMucWin* mucwin, const ProfMessage* const message, GSList wins_add_quotes_ac(window, message->plain, flip); if (g_slist_length(mentions) > 0) { - _mucwin_print_mention(window, message->plain, message->from_jid->resourcepart, mynick, mentions, ch, flags, flip); + _mucwin_print_mention(window, message->plain, message->from_jid->resourcepart, mynick, mentions, ch, flags, message->timestamp, flip); } else if (triggers) { - win_print_them(window, THEME_ROOMTRIGGER, ch, flags, message->from_jid->resourcepart, flip); - _mucwin_print_triggers(window, message->plain, triggers, flip); + if (!flip) { + win_print_them(window, THEME_ROOMTRIGGER, message->timestamp, ch, flags, message->from_jid->resourcepart, flip); + _mucwin_print_triggers(window, message->plain, triggers, message->timestamp, flip); + } else { + _mucwin_print_triggers(window, message->plain, triggers, message->timestamp, flip); + win_print_them(window, THEME_ROOMTRIGGER, message->timestamp, ch, flags, message->from_jid->resourcepart, flip); + } } else { win_println_incoming_muc_msg(window, ch, flags, message, flip); } diff --git a/src/ui/ui.h b/src/ui/ui.h index 76003c08b..9966633c0 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -397,8 +397,8 @@ void win_println_indent(ProfWin* window, int pad, const char* const message, ... void win_append(ProfWin* window, theme_item_t theme_item, const char* const message, ...); void win_appendln(ProfWin* window, theme_item_t theme_item, const char* const message, ...); -void win_append_highlight(ProfWin* window, theme_item_t theme_item, const gboolean flip, const char* const message, ...); -void win_appendln_highlight(ProfWin* window, theme_item_t theme_item, const gboolean flip, const char* const message, ...); +void win_append_highlight(ProfWin* window, theme_item_t theme_item, GDateTime* timestamp, const gboolean flip, const char* const message, ...); +void win_appendln_highlight(ProfWin* window, theme_item_t theme_item, GDateTime* timestamp, const gboolean flip, const char* const message, ...); char* win_get_title(ProfWin* window); void win_show_occupant(ProfWin* window, Occupant* occupant); diff --git a/src/ui/window.c b/src/ui/window.c index 2e027dda4..ce9916171 100644 --- a/src/ui/window.c +++ b/src/ui/window.c @@ -1462,9 +1462,9 @@ win_print_incoming(ProfWin* window, const char* const display_name_from, ProfMes } void -win_print_them(ProfWin* window, theme_item_t theme_item, const char* const show_char, int flags, const char* const them, gboolean flip) +win_print_them(ProfWin* window, theme_item_t theme_item, GDateTime* timestamp, const char* const show_char, int flags, const char* const them, gboolean flip) { - _win_printf(window, show_char, 0, NULL, flags | NO_ME | NO_EOL, theme_item, them, NULL, NULL, flip, "", NULL); + _win_printf(window, show_char, 0, timestamp , flags | NO_ME | NO_EOL, theme_item, them, NULL, NULL, flip, "", NULL); } void @@ -1672,9 +1672,14 @@ win_appendln(ProfWin* window, theme_item_t theme_item, const char* const message } void -win_append_highlight(ProfWin* window, theme_item_t theme_item, const gboolean flip, const char* const message, ...) +win_append_highlight(ProfWin* window, theme_item_t theme_item, GDateTime* timestamp, const gboolean flip, const char* const message, ...) { - GDateTime* timestamp = g_date_time_new_now_local(); + gboolean hadTimestamp = TRUE; + + if (!timestamp) { + timestamp = g_date_time_new_now_local(); + hadTimestamp = FALSE; + } va_list arg; va_start(arg, message); @@ -1690,16 +1695,24 @@ win_append_highlight(ProfWin* window, theme_item_t theme_item, const gboolean fl } inp_nonblocking(TRUE); - g_date_time_unref(timestamp); + + if (!hadTimestamp) { + g_date_time_unref(timestamp); + } g_string_free(fmt_msg, TRUE); va_end(arg); } void -win_appendln_highlight(ProfWin* window, theme_item_t theme_item, const gboolean flip, const char* const message, ...) +win_appendln_highlight(ProfWin* window, theme_item_t theme_item, GDateTime* timestamp, const gboolean flip, const char* const message, ...) { - GDateTime* timestamp = g_date_time_new_now_local(); + gboolean hadTimestamp = TRUE; + + if (!timestamp) { + timestamp = g_date_time_new_now_local(); + hadTimestamp = FALSE; + } va_list arg; va_start(arg, message); @@ -1716,7 +1729,10 @@ win_appendln_highlight(ProfWin* window, theme_item_t theme_item, const gboolean inp_nonblocking(TRUE); - g_date_time_unref(timestamp); + + if (!hadTimestamp) { + g_date_time_unref(timestamp); + } g_string_free(fmt_msg, TRUE); va_end(arg); diff --git a/src/ui/window.h b/src/ui/window.h index d472af106..3e8bc1eff 100644 --- a/src/ui/window.h +++ b/src/ui/window.h @@ -65,7 +65,7 @@ void win_show_status_string(ProfWin* window, const char* const from, GDateTime* last_activity, const char* const pre, const char* const default_show); -void win_print_them(ProfWin* window, theme_item_t theme_item, const char* const show_char, int flags, const char* const them, const gboolean flip); +void win_print_them(ProfWin* window, theme_item_t theme_item, GDateTime* timestamp, const char* const show_char, int flags, const char* const them, const gboolean flip); void win_print_incoming(ProfWin* window, const char* const from, ProfMessage* message); void win_print_outgoing(ProfWin* window, const char* show_char, const char* const id, const char* const replace_id, const char* const message); void win_print_outgoing_with_receipt(ProfWin* window, const char* show_char, const char* const from, const char* const message, char* id, const char* const replace_id); From 5acd29eaa79861347e12721e665913ea0c06fe77 Mon Sep 17 00:00:00 2001 From: MarcoPolo-PasTonMolo Date: Sat, 22 Jul 2023 20:17:28 +0300 Subject: [PATCH 3/6] Print history when joining an muc if mam not enabed See #660 --- src/ui/mucwin.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ui/mucwin.c b/src/ui/mucwin.c index 2bbbcf49a..5e71bd4e3 100644 --- a/src/ui/mucwin.c +++ b/src/ui/mucwin.c @@ -73,6 +73,8 @@ mucwin_new(const char* const barejid) if (prefs_get_boolean(PREF_MAM)) { iq_mam_request(window, NULL); win_print_loading_history(window); + } else if ((prefs_get_boolean(PREF_CHLOG) && prefs_get_boolean(PREF_HISTORY))) { + mucwin_db_history(mucwin, NULL, NULL, TRUE); } // Force redraw here to show correct offline users; before this point muc_members returns a wrong list From 787124edd09959bb176c5d773191bf38d83e9109 Mon Sep 17 00:00:00 2001 From: MarcoPolo-PasTonMolo Date: Sat, 22 Jul 2023 23:14:23 +0300 Subject: [PATCH 4/6] Delete mam loading message on lost connection see #660 --- src/ui/window_list.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/ui/window_list.c b/src/ui/window_list.c index 0a96b4610..4ba5817be 100644 --- a/src/ui/window_list.c +++ b/src/ui/window_list.c @@ -47,6 +47,7 @@ #include "config/theme.h" #include "plugins/plugins.h" #include "ui/ui.h" +#include "ui/window.h" #include "ui/window_list.h" #include "xmpp/xmpp.h" #include "xmpp/roster_list.h" @@ -885,6 +886,12 @@ wins_lost_connection(void) ProfWin* window = curr->data; if (window->type != WIN_CONSOLE) { win_println(window, THEME_ERROR, "-", "Lost connection."); + ProfBuffEntry* first_message = buffer_size(window->layout->buffer) != 0 ? buffer_get_entry(window->layout->buffer, 0) : NULL; + gboolean is_fetching_mam = first_message && (first_message->theme_item == THEME_ROOMINFO && g_strcmp0(first_message->message, LOADING_MESSAGE) == 0); + + if (is_fetching_mam) { + buffer_remove_entry(window->layout->buffer, 0); + } // if current win, set current_win_dirty if (wins_is_current(window)) { From 40a0b993b2ca0c873baa1b96c0f3b79d577be3d3 Mon Sep 17 00:00:00 2001 From: MarcoPolo-PasTonMolo Date: Sun, 23 Jul 2023 00:31:17 +0300 Subject: [PATCH 5/6] Disable muc history when joining an muc since we now have muc mam Disable muc history when MAM is enabled see #660 --- src/xmpp/stanza.c | 10 ++++++++++ src/xmpp/stanza.h | 1 + 2 files changed, 11 insertions(+) diff --git a/src/xmpp/stanza.c b/src/xmpp/stanza.c index 6e0a116e1..43440f1cf 100644 --- a/src/xmpp/stanza.c +++ b/src/xmpp/stanza.c @@ -34,6 +34,7 @@ */ #include "config.h" +#include "config/preferences.h" #ifdef HAVE_GIT_VERSION #include "gitversion.h" @@ -563,6 +564,15 @@ stanza_create_room_join_presence(xmpp_ctx_t* const ctx, xmpp_stanza_release(pass); } + // Disable muc history + if (prefs_get_boolean(PREF_MAM)) { + xmpp_stanza_t* history = xmpp_stanza_new(ctx); + xmpp_stanza_set_name(history, STANZA_NAME_HISTORY); + xmpp_stanza_set_attribute(history, "maxchars", "0"); + xmpp_stanza_add_child(x, history); + xmpp_stanza_release(history); + } + xmpp_stanza_add_child(presence, x); xmpp_stanza_release(x); diff --git a/src/xmpp/stanza.h b/src/xmpp/stanza.h index b56009735..75b4edb41 100644 --- a/src/xmpp/stanza.h +++ b/src/xmpp/stanza.h @@ -56,6 +56,7 @@ #define STANZA_NAME_PRESENCE "presence" #define STANZA_NAME_PRIORITY "priority" #define STANZA_NAME_X "x" +#define STANZA_NAME_HISTORY "history" // XEP-0373: OpenPGP for XMPP #define STANZA_NAME_OPENPGP "openpgp" #define STANZA_NAME_PUPKEY "pubkey" From ca31c1102f9f3de6e37499ac7076d8ba8ca7aca5 Mon Sep 17 00:00:00 2001 From: MarcoPolo-PasTonMolo Date: Thu, 19 Oct 2023 23:37:44 +0300 Subject: [PATCH 6/6] MAM on reconnect wip This commit should not go into production, its all testing, might or might not work. Mapped pagedown to cause a disconnect so I could easily test MAM on reconnect. --- src/database.c | 43 +++++++++-- src/database.h | 4 +- src/event/common.c | 1 + src/event/server_events.c | 2 +- src/ui/chatwin.c | 8 +- src/ui/inputwin.c | 2 + src/ui/mucwin.c | 8 +- src/ui/ui.h | 4 +- src/ui/window.c | 6 +- src/ui/window_list.c | 4 + src/xmpp/iq.c | 127 +++++++++++++++++++------------ src/xmpp/xmpp.h | 3 +- tests/unittests/xmpp/stub_xmpp.c | 5 +- 13 files changed, 143 insertions(+), 74 deletions(-) diff --git a/src/database.c b/src/database.c index 80439b9ad..4cb886191 100644 --- a/src/database.c +++ b/src/database.c @@ -201,9 +201,9 @@ log_database_add_outgoing_muc_pm(const char* const id, const char* const barejid _log_database_add_outgoing("mucpm", id, barejid, message, replace_id, enc); } -// Get info (timestamp and stanza_id) of the first or last message in db +// Get info (timestamp and stanza_id) of the first or last message in db after or before from_timestamp ProfMessage* -log_database_get_limits_info(const gchar* const contact_barejid, gboolean is_last) +log_database_get_limits_info(const gchar* const contact_barejid, gboolean is_last, char* from_timestamp) { sqlite3_stmt* stmt = NULL; gchar* query; @@ -212,10 +212,10 @@ log_database_get_limits_info(const gchar* const contact_barejid, gboolean is_las if (!myjid) return NULL; - if (is_last) { - query = sqlite3_mprintf("SELECT * FROM (SELECT `archive_id`, `timestamp` from `ChatLogs` WHERE (`from_jid` = '%q' AND `to_jid` = '%q') OR (`from_jid` = '%q' AND `to_jid` = '%q') ORDER BY `timestamp` DESC LIMIT 1) ORDER BY `timestamp` ASC;", contact_barejid, myjid->barejid, myjid->barejid, contact_barejid); + if (from_timestamp) { + query = sqlite3_mprintf("SELECT * FROM (SELECT `archive_id`, `timestamp` from `ChatLogs` WHERE ((`from_jid` = '%q' AND `to_jid` = '%q') OR (`from_jid` = '%q' AND `to_jid` = '%q')) AND `timestamp` %c '%q' ORDER BY `timestamp` %s LIMIT 1) ORDER BY `timestamp` ASC;", contact_barejid, myjid->barejid, myjid->barejid, contact_barejid, is_last ? '<' : '>', from_timestamp, is_last ? "DESC" : "ASC"); } else { - query = sqlite3_mprintf("SELECT * FROM (SELECT `archive_id`, `timestamp` from `ChatLogs` WHERE (`from_jid` = '%q' AND `to_jid` = '%q') OR (`from_jid` = '%q' AND `to_jid` = '%q') ORDER BY `timestamp` ASC LIMIT 1) ORDER BY `timestamp` ASC;", contact_barejid, myjid->barejid, myjid->barejid, contact_barejid); + query = sqlite3_mprintf("SELECT * FROM (SELECT `archive_id`, `timestamp` from `ChatLogs` WHERE (`from_jid` = '%q' AND `to_jid` = '%q') OR (`from_jid` = '%q' AND `to_jid` = '%q') ORDER BY `timestamp` %s LIMIT 1) ORDER BY `timestamp` ASC;", contact_barejid, myjid->barejid, myjid->barejid, contact_barejid, is_last ? "DESC" : "ASC"); } if (!query) { @@ -250,7 +250,7 @@ log_database_get_limits_info(const gchar* const contact_barejid, gboolean is_las // null the current time is used. from_start gets first few messages if true // otherwise the last ones. Flip flips the order of the results GSList* -log_database_get_previous_chat(const gchar* const contact_barejid, const char* start_time, char* end_time, gboolean from_start, gboolean flip) +log_database_get_previous_chat(const gchar* const contact_barejid, const char* start_time, char* end_time, gboolean from_start, gboolean flip, gboolean limit_results) { sqlite3_stmt* stmt = NULL; const char* jid = connection_get_fulljid(); @@ -263,7 +263,36 @@ log_database_get_previous_chat(const gchar* const contact_barejid, const char* s gchar* sort2 = !flip ? "ASC" : "DESC"; GDateTime* now = g_date_time_new_now_local(); gchar* end_date_fmt = end_time ? end_time : g_date_time_format_iso8601(now); - auto_sqlite gchar* query = sqlite3_mprintf("SELECT * FROM (SELECT COALESCE(B.`message`, A.`message`) AS message, A.`timestamp`, A.`from_jid`, A.`type`, A.`encryption` from `ChatLogs` AS A LEFT JOIN `ChatLogs` AS B ON A.`stanza_id` = B.`replace_id` WHERE A.`replace_id` = '' AND ((A.`from_jid` = '%q' AND A.`to_jid` = '%q') OR (A.`from_jid` = '%q' AND A.`to_jid` = '%q')) AND A.`timestamp` < '%q' AND (%Q IS NULL OR A.`timestamp` > %Q) ORDER BY A.`timestamp` %s LIMIT %d) ORDER BY `timestamp` %s;", contact_barejid, myjid->barejid, myjid->barejid, contact_barejid, end_date_fmt, start_time, start_time, sort1, MESSAGES_TO_RETRIEVE, sort2); + auto_sqlite gchar* query; + + if (limit_results) { + query = sqlite3_mprintf( + "SELECT * FROM (SELECT COALESCE(B.`message`, A.`message`) AS message, A.`timestamp`, A.`from_jid`, A.`type`, A.`encryption` from `ChatLogs` AS A LEFT JOIN `ChatLogs` AS B ON A.`stanza_id` = B.`replace_id` WHERE A.`replace_id` = '' AND ((A.`from_jid` = '%q' AND A.`to_jid` = '%q') OR (A.`from_jid` = '%q' AND A.`to_jid` = '%q')) AND A.`timestamp` < '%q' AND (%Q IS NULL OR A.`timestamp` > %Q) ORDER BY A.`timestamp` %s LIMIT %d) ORDER BY `timestamp` %s;", + contact_barejid, + myjid->barejid, + myjid->barejid, + contact_barejid, + end_date_fmt, + start_time, + start_time, + sort1, + MESSAGES_TO_RETRIEVE, + sort2 + ); + } else { + query = sqlite3_mprintf( + "SELECT * FROM (SELECT COALESCE(B.`message`, A.`message`) AS message, A.`timestamp`, A.`from_jid`, A.`type`, A.`encryption` from `ChatLogs` AS A LEFT JOIN `ChatLogs` AS B ON A.`stanza_id` = B.`replace_id` WHERE A.`replace_id` = '' AND ((A.`from_jid` = '%q' AND A.`to_jid` = '%q') OR (A.`from_jid` = '%q' AND A.`to_jid` = '%q')) AND A.`timestamp` < '%q' AND (%Q IS NULL OR A.`timestamp` > %Q) ORDER BY A.`timestamp`) ORDER BY `timestamp` %s;", + contact_barejid, + myjid->barejid, + myjid->barejid, + contact_barejid, + end_date_fmt, + start_time, + start_time, + sort1, + sort2 + ); + } g_date_time_unref(now); g_free(end_date_fmt); diff --git a/src/database.h b/src/database.h index 1e73c874f..1483eeb6e 100644 --- a/src/database.h +++ b/src/database.h @@ -47,8 +47,8 @@ void log_database_add_incoming(ProfMessage* message); void log_database_add_outgoing_chat(const char* const id, const char* const barejid, const char* const message, const char* const replace_id, prof_enc_t enc); void log_database_add_outgoing_muc(const char* const id, const char* const barejid, const char* const message, const char* const replace_id, prof_enc_t enc); void log_database_add_outgoing_muc_pm(const char* const id, const char* const barejid, const char* const message, const char* const replace_id, prof_enc_t enc); -GSList* log_database_get_previous_chat(const gchar* const contact_barejid, const char* start_time, char* end_time, gboolean from_start, gboolean flip); -ProfMessage* log_database_get_limits_info(const gchar* const contact_barejid, gboolean is_last); +GSList* log_database_get_previous_chat(const gchar* const contact_barejid, const char* start_time, char* end_time, gboolean from_start, gboolean flip, gboolean limit_results); +ProfMessage* log_database_get_limits_info(const gchar* const contact_barejid, gboolean is_last, char* from_timestamp); void log_database_close(void); #endif // DATABASE_H diff --git a/src/event/common.c b/src/event/common.c index 1844d2ffd..45dc93913 100644 --- a/src/event/common.c +++ b/src/event/common.c @@ -61,6 +61,7 @@ ev_disconnect_cleanup(void) ui_disconnected(); session_disconnect(); roster_destroy(); + iq_disco_items_on_disconnect(); iq_autoping_timer_cancel(); muc_invites_clear(); muc_confserver_clear(); diff --git a/src/event/server_events.c b/src/event/server_events.c index d2bf7b3b2..3394c6a79 100644 --- a/src/event/server_events.c +++ b/src/event/server_events.c @@ -650,7 +650,7 @@ sv_ev_incoming_message(ProfMessage* message) if (prefs_get_boolean(PREF_MAM)) { win_print_loading_history(window); - iq_mam_request(window, g_date_time_add_seconds(message->timestamp, 0)); // copy timestamp + iq_mam_request(window, g_date_time_add_seconds(message->timestamp, 0), FALSE); // copy timestamp } #ifdef HAVE_OMEMO diff --git a/src/ui/chatwin.c b/src/ui/chatwin.c index 88f02cb39..b3eb74fac 100644 --- a/src/ui/chatwin.c +++ b/src/ui/chatwin.c @@ -146,7 +146,7 @@ chatwin_new(const char* const barejid) } if (prefs_get_boolean(PREF_MAM)) { - iq_mam_request(window, NULL); + iq_mam_request(window, NULL, FALSE); win_print_loading_history(window); } @@ -575,7 +575,7 @@ static void _chatwin_history(ProfChatWin* chatwin, const char* const contact_barejid) { if (!chatwin->history_shown) { - GSList* history = log_database_get_previous_chat(contact_barejid, NULL, NULL, FALSE, FALSE); + GSList* history = log_database_get_previous_chat(contact_barejid, NULL, NULL, FALSE, FALSE, TRUE); GSList* curr = history; while (curr) { @@ -598,13 +598,13 @@ _chatwin_history(ProfChatWin* chatwin, const char* const contact_barejid) // first entry's timestamp in the buffer is used. Flip true to prepend to buffer. // Timestamps should be in iso8601 gboolean -chatwin_db_history(ProfChatWin* chatwin, const char* start_time, char* end_time, gboolean flip) +chatwin_db_history(ProfChatWin* chatwin, const char* start_time, char* end_time, gboolean flip, gboolean limit_results) { if (!end_time) { end_time = buffer_size(((ProfWin*)chatwin)->layout->buffer) == 0 ? NULL : g_date_time_format_iso8601(buffer_get_entry(((ProfWin*)chatwin)->layout->buffer, 0)->time); } - GSList* history = log_database_get_previous_chat(chatwin->barejid, start_time, end_time, !flip, flip); + GSList* history = log_database_get_previous_chat(chatwin->barejid, start_time, end_time, !flip, flip, limit_results); gboolean has_items = g_slist_length(history) != 0; GSList* curr = history; diff --git a/src/ui/inputwin.c b/src/ui/inputwin.c index 9b652f1c3..c2dd6260a 100644 --- a/src/ui/inputwin.c +++ b/src/ui/inputwin.c @@ -33,6 +33,7 @@ * */ +#include "xmpp/session.h" #define _XOPEN_SOURCE_EXTENDED #include "config.h" @@ -913,6 +914,7 @@ _inp_rl_win_pageup_handler(int count, int key) static int _inp_rl_win_pagedown_handler(int count, int key) { + session_lost_connection(); ProfWin* current = wins_get_current(); win_page_down(current); return 0; diff --git a/src/ui/mucwin.c b/src/ui/mucwin.c index 5e71bd4e3..f958f61d6 100644 --- a/src/ui/mucwin.c +++ b/src/ui/mucwin.c @@ -71,10 +71,10 @@ mucwin_new(const char* const barejid) #endif if (prefs_get_boolean(PREF_MAM)) { - iq_mam_request(window, NULL); + iq_mam_request(window, NULL, FALSE); win_print_loading_history(window); } else if ((prefs_get_boolean(PREF_CHLOG) && prefs_get_boolean(PREF_HISTORY))) { - mucwin_db_history(mucwin, NULL, NULL, TRUE); + mucwin_db_history(mucwin, NULL, NULL, TRUE, TRUE); } // Force redraw here to show correct offline users; before this point muc_members returns a wrong list @@ -389,13 +389,13 @@ mucwin_history(ProfMucWin* mucwin, const ProfMessage* const message, gboolean fl } gboolean -mucwin_db_history(ProfMucWin* mucwin, char* start_time, char* end_time, gboolean flip) +mucwin_db_history(ProfMucWin* mucwin, char* start_time, char* end_time, gboolean flip, gboolean limit_results) { if (!end_time) { end_time = buffer_size(((ProfWin*)mucwin)->layout->buffer) == 0 ? NULL : g_date_time_format_iso8601(buffer_get_entry(((ProfWin*)mucwin)->layout->buffer, 0)->time); } - GSList* history = log_database_get_previous_chat(mucwin->roomjid, start_time, end_time, !flip, flip); + GSList* history = log_database_get_previous_chat(mucwin->roomjid, start_time, end_time, !flip, flip, limit_results); gboolean has_items = g_slist_length(history) != 0; GSList* curr = history; diff --git a/src/ui/ui.h b/src/ui/ui.h index 9966633c0..89b8ee015 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -145,7 +145,7 @@ void chatwin_set_incoming_char(ProfChatWin* chatwin, const char* const ch); void chatwin_unset_incoming_char(ProfChatWin* chatwin); void chatwin_set_outgoing_char(ProfChatWin* chatwin, const char* const ch); void chatwin_unset_outgoing_char(ProfChatWin* chatwin); -gboolean chatwin_db_history(ProfChatWin* chatwin, const char* start_time, char* end_time, gboolean flip); +gboolean chatwin_db_history(ProfChatWin* chatwin, const char* start_time, char* end_time, gboolean flip, gboolean limit_results); // MUC window ProfMucWin* mucwin_new(const char* const barejid); @@ -162,7 +162,7 @@ void mucwin_occupant_role_and_affiliation_change(ProfMucWin* mucwin, const char* const char* const role, const char* const affiliation, const char* const actor, const char* const reason); void mucwin_roster(ProfMucWin* mucwin, GList* occupants, const char* const presence); void mucwin_history(ProfMucWin* mucwin, const ProfMessage* const message, gboolean flip); -gboolean mucwin_db_history(ProfMucWin* mucwin, char* start_time, char* end_time, gboolean flip); +gboolean mucwin_db_history(ProfMucWin* mucwin, char* start_time, char* end_time, gboolean flip, gboolean limit_results); void mucwin_outgoing_msg(ProfMucWin* mucwin, const char* const message, const char* const id, prof_enc_t enc_mode, const char* const replace_id); void mucwin_incoming_msg(ProfMucWin* mucwin, const ProfMessage* const message, GSList* mentions, GList* triggers, gboolean filter_reflection, gboolean flip); void mucwin_subject(ProfMucWin* mucwin, const char* const nick, const char* const subject); diff --git a/src/ui/window.c b/src/ui/window.c index ce9916171..40cb0661c 100644 --- a/src/ui/window.c +++ b/src/ui/window.c @@ -662,7 +662,7 @@ win_page_up(ProfWin* window) // Don't do anything if still fetching mam messages if (is_not_fetching) { - if (!chatwin_db_history(chatwin, NULL, NULL, TRUE) && prefs_get_boolean(PREF_MAM)) { + if (!chatwin_db_history(chatwin, NULL, NULL, TRUE, TRUE) && prefs_get_boolean(PREF_MAM)) { win_print_loading_history(window); iq_mam_request_older(window); } @@ -672,7 +672,7 @@ win_page_up(ProfWin* window) // Don't do anything if still fetching mam messages if (is_not_fetching) { - if (!mucwin_db_history(mucwin, NULL, NULL, TRUE) && prefs_get_boolean(PREF_MAM)) { + if (!mucwin_db_history(mucwin, NULL, NULL, TRUE, TRUE) && prefs_get_boolean(PREF_MAM)) { win_print_loading_history(window); iq_mam_request_older(window); } @@ -710,7 +710,7 @@ win_page_down(ProfWin* window) char* start = g_date_time_format_iso8601(buffer_get_entry(window->layout->buffer, bf_size - 1)->time); GDateTime* now = g_date_time_new_now_local(); char* end = g_date_time_format_iso8601(now); - chatwin_db_history((ProfChatWin*)window, start, end, FALSE); + chatwin_db_history((ProfChatWin*)window, start, end, FALSE, TRUE); g_free(start); g_date_time_unref(now); diff --git a/src/ui/window_list.c b/src/ui/window_list.c index 4ba5817be..fbbcc2ed2 100644 --- a/src/ui/window_list.c +++ b/src/ui/window_list.c @@ -932,6 +932,10 @@ wins_reestablished_connection(void) } #endif + if (prefs_get_boolean(PREF_MAM)) { + iq_mam_request(window, g_date_time_new_now_local(), TRUE); + } + // if current win, set current_win_dirty if (wins_is_current(window)) { win_update_virtual(window); diff --git a/src/xmpp/iq.c b/src/xmpp/iq.c index 0e8cfeca2..70f5de4da 100644 --- a/src/xmpp/iq.c +++ b/src/xmpp/iq.c @@ -111,6 +111,7 @@ typedef struct mam_rsm_userdata char* start_datestr; char* end_datestr; gboolean fetch_next; + gboolean is_reconnect; ProfWin* win; } MamRsmUserdata; @@ -119,6 +120,7 @@ typedef struct late_delivery_userdata ProfWin* win; GDateTime* enddate; GDateTime* startdate; + gboolean is_reconnect; } LateDeliveryUserdata; static int _iq_handler(xmpp_conn_t* const conn, xmpp_stanza_t* const stanza, void* const userdata); @@ -158,7 +160,7 @@ static int _command_exec_response_handler(xmpp_stanza_t* const stanza, void* con static int _mam_rsm_id_handler(xmpp_stanza_t* const stanza, void* const userdata); static int _register_change_password_result_id_handler(xmpp_stanza_t* const stanza, void* const userdata); -static void _iq_mam_request(ProfWin* win, GDateTime* startdate, GDateTime* enddate); +static void _iq_mam_request(ProfWin* win, GDateTime* startdate, GDateTime* enddate, gboolean is_reconnect); static void _iq_free_room_data(ProfRoomInfoData* roominfo); static void _iq_free_affiliation_set(ProfPrivilegeSet* affiliation_set); static void _iq_free_affiliation_list(ProfAffiliationList* affiliation_list); @@ -308,6 +310,12 @@ iq_id_handler_add(const char* const id, ProfIqCallback func, ProfIqFreeCallback } } +void +iq_disco_items_on_disconnect(void) +{ + received_disco_items = FALSE; +} + void iq_autoping_timer_cancel(void) { @@ -2552,7 +2560,7 @@ _disco_items_result_handler(xmpp_stanza_t* const stanza) while (late_delivery_windows) { LateDeliveryUserdata* del_data = late_delivery_windows->data; - _iq_mam_request(del_data->win, del_data->startdate, del_data->enddate); + _iq_mam_request(del_data->win, del_data->startdate, del_data->enddate, del_data->is_reconnect); free(del_data); late_delivery_windows = g_slist_delete_link(late_delivery_windows, late_delivery_windows); @@ -2617,10 +2625,10 @@ _mam_buffer_commit_handler(xmpp_stanza_t* const stanza, void* const userdata) if (win->type == WIN_CHAT) { ProfChatWin* chatwin = (ProfChatWin*)win; - chatwin_db_history(chatwin, NULL, NULL, TRUE); + chatwin_db_history(chatwin, NULL, NULL, TRUE, TRUE); } else if (win->type == WIN_MUC) { ProfMucWin* mucwin = (ProfMucWin*)win; - mucwin_db_history(mucwin, NULL, NULL, TRUE); + mucwin_db_history(mucwin, NULL, NULL, TRUE, TRUE); } return 0; } @@ -2638,7 +2646,7 @@ iq_mam_request_older(ProfWin* win) char* win_jid = win_get_tab_identifier(win); - ProfMessage* first_msg = log_database_get_limits_info(win_jid, FALSE); + ProfMessage* first_msg = log_database_get_limits_info(win_jid, FALSE, NULL); char* firstid = NULL; char* enddate = NULL; @@ -2677,7 +2685,7 @@ _mam_userdata_free(MamRsmUserdata* data) } void -_iq_mam_request(ProfWin* win, GDateTime* startdate, GDateTime* enddate) +_iq_mam_request(ProfWin* win, GDateTime* startdate, GDateTime* enddate, gboolean is_reconnect) { if (connection_supports(XMPP_FEATURE_MAM2) == FALSE) { log_warning("Server doesn't advertise %s feature.", XMPP_FEATURE_MAM2); @@ -2687,7 +2695,8 @@ _iq_mam_request(ProfWin* win, GDateTime* startdate, GDateTime* enddate) return; } - char* firstid = ""; + // Empty firstid means that the rsm paging will start from the last/most recent page + char* firstid = is_reconnect ? NULL : ""; char* startdate_str = NULL; char* enddate_str = NULL; gboolean fetch_next = FALSE; @@ -2719,10 +2728,12 @@ _iq_mam_request(ProfWin* win, GDateTime* startdate, GDateTime* enddate) data->barejid = strdup(win_jid); data->fetch_next = fetch_next; data->win = win; + data->is_reconnect = is_reconnect; iq_id_handler_add(xmpp_stanza_get_id(iq), _mam_rsm_id_handler, (ProfIqFreeCallback)_mam_userdata_free, data); } + win_println(win, THEME_DEFAULT, "-", "(%s) (%s) (%s) (%d)", startdate_str, enddate_str, win_jid, fetch_next); iq_send_stanza(iq); xmpp_stanza_release(iq); free(win_jid); @@ -2731,10 +2742,10 @@ _iq_mam_request(ProfWin* win, GDateTime* startdate, GDateTime* enddate) } void -iq_mam_request(ProfWin* win, GDateTime* enddate) +iq_mam_request(ProfWin* win, GDateTime* enddate, gboolean is_reconnect) { char* win_jid = win_get_tab_identifier(win); - ProfMessage* last_msg = log_database_get_limits_info(win_jid, TRUE); + ProfMessage* last_msg = log_database_get_limits_info(win_jid, TRUE, NULL); GDateTime* startdate = g_date_time_add_seconds(last_msg->timestamp, 0); message_free(last_msg); @@ -2744,6 +2755,7 @@ iq_mam_request(ProfWin* win, GDateTime* enddate) cur_del_data->win = win; cur_del_data->enddate = enddate; cur_del_data->startdate = startdate; + cur_del_data->is_reconnect = is_reconnect; late_delivery_windows = g_slist_append(late_delivery_windows, cur_del_data); log_debug("Save MAM request of %s for later", win_jid); free(win_jid); @@ -2751,11 +2763,32 @@ iq_mam_request(ProfWin* win, GDateTime* enddate) } free(win_jid); - _iq_mam_request(win, startdate, enddate); + _iq_mam_request(win, startdate, enddate, is_reconnect); return; } +void +_handle_mam_db_history(ProfWin* win, char* start_time, char* end_time, gboolean flip, gboolean limit_results) +{ + switch (win->type) { + case WIN_CHAT: + { + ProfChatWin* chatwin = (ProfChatWin*)win; + chatwin_db_history(chatwin, start_time, end_time, flip, limit_results); + return; + } + case WIN_MUC: + { + ProfMucWin* mucwin = (ProfMucWin*)win; + mucwin_db_history(mucwin, start_time, end_time, flip, limit_results); + return; + } + default: + return; + } +} + static int _mam_rsm_id_handler(xmpp_stanza_t* const stanza, void* const userdata) { @@ -2770,9 +2803,7 @@ _mam_rsm_id_handler(xmpp_stanza_t* const stanza, void* const userdata) if (fin) { gboolean is_complete = g_strcmp0(xmpp_stanza_get_attribute(fin, "complete"), "true") == 0; MamRsmUserdata* data = (MamRsmUserdata*)userdata; - ProfWin* window = (ProfWin*)data->win; - - buffer_remove_entry(window->layout->buffer, 0); + ProfWin* window = data->win; auto_char char* start_str = NULL; if (data->start_datestr) { @@ -2787,49 +2818,43 @@ _mam_rsm_id_handler(xmpp_stanza_t* const stanza, void* const userdata) end_str[strlen(end_str) - 3] = '\0'; } - if (is_complete || !data->fetch_next) { - switch (data->win->type) { - case WIN_CHAT: - { - ProfChatWin* chatwin = (ProfChatWin*)data->win; - chatwin_db_history(chatwin, is_complete ? NULL : start_str, end_str, TRUE); - return 0; - } - case WIN_MUC: - { - ProfMucWin* mucwin = (ProfMucWin*)data->win; - mucwin_db_history(mucwin, is_complete ? NULL : start_str, end_str, TRUE); + if (data->is_reconnect) { + _handle_mam_db_history(data->win, start_str, end_str, FALSE, FALSE); + if (is_complete) { + char* old_end = end_str; + GDateTime* now = g_date_time_new_now_local(); + end_str = g_date_time_format(now, mam_timestamp_format_string); + end_str[strlen(end_str) - 3] = '\0'; + _handle_mam_db_history(data->win, old_end, end_str, FALSE, FALSE); return 0; } - default: + } else { + buffer_remove_entry(window->layout->buffer, 0); + if (is_complete || !data->fetch_next) { + _handle_mam_db_history(data->win, is_complete ? NULL : start_str, end_str, TRUE, TRUE); return 0; } - } - switch (data->win->type) { - case WIN_CHAT: - { - ProfChatWin* chatwin = (ProfChatWin*)data->win; - chatwin_db_history(chatwin, start_str, end_str, TRUE); - return 0; - } - case WIN_MUC: - { - ProfMucWin* mucwin = (ProfMucWin*)data->win; - mucwin_db_history(mucwin, start_str, end_str, TRUE); - return 0; - } - default: - return 0; + _handle_mam_db_history(data->win, start_str, end_str, TRUE, TRUE); } + xmpp_stanza_t* set = xmpp_stanza_get_child_by_name_and_ns(fin, STANZA_TYPE_SET, STANZA_NS_RSM); if (set) { - win_print_loading_history(window); - - char* firstid = NULL; - xmpp_stanza_t* first = xmpp_stanza_get_child_by_name(set, STANZA_NAME_FIRST); - firstid = xmpp_stanza_get_text(first); + char* firstid = NULL, *lastid = NULL; + if (!data->is_reconnect) { + win_print_loading_history(window); + xmpp_stanza_t* first = xmpp_stanza_get_child_by_name(set, STANZA_NAME_FIRST); + firstid = xmpp_stanza_get_text(first); + } else { + char* win_jid = win_get_tab_identifier(window); + ProfMessage* last_msg = log_database_get_limits_info(win_jid, TRUE, data->end_datestr); + GDateTime* startdate = g_date_time_add_seconds(last_msg->timestamp, 0); + _iq_mam_request(window, startdate, g_date_time_new_from_iso8601(data->end_datestr, NULL), TRUE); + message_free(last_msg); + free(win_jid); + return 0; + } // 4.3.2. send same stanza with set,max stanza xmpp_ctx_t* const ctx = connection_get_ctx(); @@ -2838,8 +2863,12 @@ _mam_rsm_id_handler(xmpp_stanza_t* const stanza, void* const userdata) free(data->end_datestr); data->end_datestr = NULL; } - xmpp_stanza_t* iq = stanza_create_mam_iq(ctx, data->barejid, data->start_datestr, NULL, firstid, NULL, data->win->type == WIN_MUC); - free(firstid); + + xmpp_stanza_t* iq = stanza_create_mam_iq(ctx, data->barejid, data->start_datestr, NULL, firstid, lastid, data->win->type == WIN_MUC); + + if (!data->is_reconnect) { + free(data->is_reconnect ? lastid : firstid); + } MamRsmUserdata* ndata = malloc(sizeof(*ndata)); *ndata = *data; diff --git a/src/xmpp/xmpp.h b/src/xmpp/xmpp.h index c2dcf8231..0da7d8051 100644 --- a/src/xmpp/xmpp.h +++ b/src/xmpp/xmpp.h @@ -259,12 +259,13 @@ void iq_room_affiliation_set(const char* const room, const char* const jid, char void iq_room_kick_occupant(const char* const room, const char* const nick, const char* const reason); void iq_room_role_set(const char* const room, const char* const nick, char* role, const char* const reason); void iq_room_role_list(const char* const room, char* role); +void iq_disco_items_on_disconnect(void); void iq_autoping_timer_cancel(void); void iq_autoping_check(void); void iq_http_upload_request(HTTPUpload* upload); void iq_command_list(const char* const target); void iq_command_exec(const char* const target, const char* const command); -void iq_mam_request(ProfWin* win, GDateTime* enddate); +void iq_mam_request(ProfWin* win, GDateTime* enddate, gboolean is_reconnect); void iq_mam_request_older(ProfWin* win); void iq_register_change_password(const char* const user, const char* const password); void iq_muc_register_nick(const char* const roomjid); diff --git a/tests/unittests/xmpp/stub_xmpp.c b/tests/unittests/xmpp/stub_xmpp.c index 585f76f40..6153e4749 100644 --- a/tests/unittests/xmpp/stub_xmpp.c +++ b/tests/unittests/xmpp/stub_xmpp.c @@ -404,6 +404,9 @@ void iq_last_activity_request(gchar* jid) { } +iq_disco_items_on_disconnect(void) +{ +} void iq_autoping_timer_cancel(void) { @@ -435,7 +438,7 @@ iq_muc_register_nick(const char* const roomjid) } void -iq_mam_request(ProfWin* win, GDateTime* enddate) +iq_mam_request(ProfWin* win, GDateTime* enddate, gboolean is_reconnect) { }