From a704838152b9aec0bef2446f742b1eb548f71d1a Mon Sep 17 00:00:00 2001 From: MarcoPolo-PasTonMolo Date: Sat, 20 Aug 2022 22:48:02 +0300 Subject: Handle late delivery --- src/event/server_events.c | 2 +- src/ui/chatwin.c | 10 ++-- src/ui/window.c | 1 + src/xmpp/iq.c | 121 ++++++++++++++++++++++++++++++++++++++-------- src/xmpp/xmpp.h | 2 +- 5 files changed, 109 insertions(+), 27 deletions(-) diff --git a/src/event/server_events.c b/src/event/server_events.c index 26c4963e..8c1ee04f 100644 --- a/src/event/server_events.c +++ b/src/event/server_events.c @@ -640,8 +640,8 @@ sv_ev_incoming_message(ProfMessage* message) new_win = TRUE; if (prefs_get_boolean(PREF_MAM)) { - iq_mam_request(chatwin); win_print_loading_history(window); + iq_mam_request(chatwin, 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 7d583b43..fbb5183f 100644 --- a/src/ui/chatwin.c +++ b/src/ui/chatwin.c @@ -98,7 +98,7 @@ chatwin_new(const char* const barejid) #endif // HAVE_OMEMO if (prefs_get_boolean(PREF_MAM)) { - iq_mam_request(chatwin); + iq_mam_request(chatwin, NULL); win_print_loading_history(window); } @@ -320,10 +320,7 @@ chatwin_incoming_msg(ProfChatWin* chatwin, ProfMessage* message, gboolean win_cr } win_insert_last_read_position_marker((ProfWin*)chatwin, chatwin->barejid); - - if (!win_created || !prefs_get_boolean(PREF_MAM)) { - win_print_incoming(window, display_name, message); - } + win_print_incoming(window, display_name, message); } wins_add_urls_ac(window, message); @@ -542,7 +539,8 @@ _chatwin_history(ProfChatWin* chatwin, const char* const contact_barejid) } // Print history starting from start_time to end_time if end_time is null the -// first entrie's timestamp in the buffer is used. Flip true to prepend to buffer. +// 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, char* start_time, char* end_time, gboolean flip) { diff --git a/src/ui/window.c b/src/ui/window.c index 4ac45f9c..0470b3de 100644 --- a/src/ui/window.c +++ b/src/ui/window.c @@ -1869,6 +1869,7 @@ win_print_loading_history(ProfWin* window) { GDateTime* timestamp = buffer_size(window->layout->buffer) != 0 ? buffer_get_entry(window->layout->buffer, 0)->time : g_date_time_new_now_local(); buffer_prepend(window->layout->buffer, "-", 0, timestamp, NO_DATE, THEME_ROOMINFO, NULL, NULL, LOADING_MESSAGE, NULL, NULL); + g_date_time_unref(timestamp); win_redraw(window); } diff --git a/src/xmpp/iq.c b/src/xmpp/iq.c index a1784b45..4c1ec90b 100644 --- a/src/xmpp/iq.c +++ b/src/xmpp/iq.c @@ -109,9 +109,17 @@ typedef struct mam_rsm_userdata char* barejid; char* start_datestr; char* end_datestr; + gboolean fetch_next; ProfChatWin* win; } MamRsmUserdata; +typedef struct late_delivery_userdata +{ + ProfChatWin* win; + GDateTime* enddate; + GDateTime* startdate; +} LateDeliveryUserdata; + static int _iq_handler(xmpp_conn_t* const conn, xmpp_stanza_t* const stanza, void* const userdata); static void _error_handler(xmpp_stanza_t* const stanza); @@ -149,6 +157,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_free_room_data(ProfRoomInfoData* roominfo); static void _iq_free_affiliation_set(ProfPrivilegeSet* affiliation_set); static void _iq_free_affiliation_list(ProfAffiliationList* affiliation_list); @@ -164,6 +173,8 @@ static gboolean autoping_wait = FALSE; static GTimer* autoping_time = NULL; static GHashTable* id_handlers; static GHashTable* rooms_cache = NULL; +static GSList* late_delivery_windows = NULL; +static gboolean received_disco_items = FALSE; static int _iq_handler(xmpp_conn_t* const conn, xmpp_stanza_t* const stanza, void* const userdata) @@ -258,6 +269,8 @@ iq_handlers_init(void) id_handlers = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)_iq_id_handler_free); rooms_cache = g_hash_table_new_full(g_str_hash, g_str_equal, free, (GDestroyNotify)xmpp_stanza_release); + late_delivery_windows = malloc(sizeof(GSList *)); + late_delivery_windows->data = NULL; } void @@ -2525,7 +2538,16 @@ _disco_items_result_handler(xmpp_stanza_t* const stanza) if (g_strcmp0(id, "discoitemsreq") == 0) { cons_show_disco_items(items, from); } else if (g_strcmp0(id, "discoitemsreq_onconnect") == 0) { + received_disco_items = TRUE; connection_set_disco_items(items); + + while (late_delivery_windows->data) { + LateDeliveryUserdata* del_data = late_delivery_windows->data; + _iq_mam_request(del_data->win, del_data->startdate, del_data->enddate); + + late_delivery_windows = g_slist_next(late_delivery_windows); + free(del_data); + } } g_slist_free_full(items, (GDestroyNotify)_item_destroy); @@ -2622,7 +2644,7 @@ iq_mam_request_older(ProfChatWin* win) } void -iq_mam_request(ProfChatWin* win) +_iq_mam_request(ProfChatWin* win, GDateTime* startdate, GDateTime* enddate) { if (connection_supports(XMPP_FEATURE_MAM2) == FALSE) { log_warning("Server doesn't advertise %s feature.", XMPP_FEATURE_MAM2); @@ -2630,43 +2652,72 @@ iq_mam_request(ProfChatWin* win) return; } - ProfMessage* last_msg = log_database_get_limits_info(win->barejid, TRUE); - // To get last page and have flipped paging set firstid to empty string char* firstid = ""; - char* startdate = NULL; - char* enddate = NULL; - - // If last message found - if (last_msg->timestamp) { - startdate = g_date_time_format(last_msg->timestamp, "%FT%T.%f%:z"); - } else { + char* startdate_str = NULL; + char* enddate_str = NULL; + gboolean fetch_next = FALSE; + + if (startdate) { + startdate_str = g_date_time_format(startdate, "%FT%T.%f%:z"); + fetch_next = TRUE; + g_date_time_unref(startdate); + } else if (!enddate) { GDateTime* now = g_date_time_new_now_utc(); - enddate = g_date_time_format(now, "%FT%T.%f%:z"); + enddate_str = g_date_time_format(now, "%FT%T.%f%:z"); g_date_time_unref(now); } + if (enddate) { + enddate_str = g_date_time_format(enddate, "%FT%T.%f%:z"); + g_date_time_unref(enddate); + } + xmpp_ctx_t* const ctx = connection_get_ctx(); - xmpp_stanza_t* iq = stanza_create_mam_iq(ctx, win->barejid, startdate, enddate, firstid, NULL); + xmpp_stanza_t* iq = stanza_create_mam_iq(ctx, win->barejid, startdate_str, enddate_str, firstid, NULL); MamRsmUserdata* data = malloc(sizeof(MamRsmUserdata)); if (data) { - data->start_datestr = startdate; - data->end_datestr = enddate; + data->start_datestr = startdate_str; + data->end_datestr = enddate_str; data->barejid = strdup(win->barejid); + data->fetch_next = fetch_next; data->win = win; iq_id_handler_add(xmpp_stanza_get_id(iq), _mam_rsm_id_handler, NULL, data); } - message_free(last_msg); - iq_send_stanza(iq); xmpp_stanza_release(iq); return; } +void +iq_mam_request(ProfChatWin* win, GDateTime* enddate) +{ + ProfMessage* last_msg = log_database_get_limits_info(win->barejid, TRUE); + GDateTime* startdate = last_msg->timestamp ? g_date_time_add_seconds(last_msg->timestamp, 0) : NULL; // copy timestamp + message_free(last_msg); + + // Save request for later if disco items haven't been received yet + if (!received_disco_items) { + if (late_delivery_windows->data == NULL) { + LateDeliveryUserdata* cur_del_data = malloc(sizeof(LateDeliveryUserdata)); + cur_del_data->win = win; + cur_del_data->enddate = enddate; + cur_del_data->startdate = startdate; + late_delivery_windows->data = cur_del_data; + } + late_delivery_windows = g_slist_append(late_delivery_windows, NULL); + } + + + _iq_mam_request(win, startdate, enddate); + + return; +} + static int _mam_rsm_id_handler(xmpp_stanza_t* const stanza, void* const userdata) { @@ -2684,11 +2735,39 @@ _mam_rsm_id_handler(xmpp_stanza_t* const stanza, void* const userdata) ProfWin* window = (ProfWin*)data->win; buffer_remove_entry(window->layout->buffer, 0); - if (is_complete || data->end_datestr) { - chatwin_db_history(data->win, is_complete ? NULL : data->start_datestr, NULL, TRUE); + + char *start_str = NULL; + if (data->start_datestr) { + start_str = strdup(data->start_datestr); + // Convert to iso8601 + start_str[strlen(start_str) - 3] = '\0'; + } + char *end_str = NULL; + if (data->end_datestr) { + end_str = strdup(data->end_datestr); + // Convert to iso8601 + end_str[strlen(end_str) - 3] = '\0'; + } + + if (is_complete || !data->fetch_next) { + chatwin_db_history(data->win, is_complete ? NULL : start_str, end_str, TRUE); + // TODO free memory + if (start_str) { + free(start_str); + free(data->start_datestr); + } + + if (end_str) { + free(data->end_datestr); + } + + free(data->barejid); + free(data); return 0; } - chatwin_db_history(data->win, data->start_datestr, NULL, TRUE); + + chatwin_db_history(data->win, start_str, end_str, TRUE); + if (start_str) free(start_str); xmpp_stanza_t* set = xmpp_stanza_get_child_by_name_and_ns(fin, STANZA_TYPE_SET, STANZA_NS_RSM); if (set) { @@ -2701,6 +2780,10 @@ _mam_rsm_id_handler(xmpp_stanza_t* const stanza, void* const userdata) // 4.3.2. send same stanza with set,max stanza xmpp_ctx_t* const ctx = connection_get_ctx(); + if (end_str) { + free(data->end_datestr); + } + data->end_datestr = NULL; xmpp_stanza_t* iq = stanza_create_mam_iq(ctx, data->barejid, data->start_datestr, data->end_datestr, firstid, NULL); free(firstid); diff --git a/src/xmpp/xmpp.h b/src/xmpp/xmpp.h index 6b1f21df..dc14285a 100644 --- a/src/xmpp/xmpp.h +++ b/src/xmpp/xmpp.h @@ -261,7 +261,7 @@ 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); +void iq_mam_request(ProfChatWin* win, GDateTime* enddate); void iq_mam_request_older(ProfChatWin* win); void iq_register_change_password(const char* const user, const char* const password); void iq_muc_register_nick(const char* const roomjid); -- cgit 1.4.1-2-gfad0