about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorMarcoPolo-PasTonMolo <marcopolopastonmolo@protonmail.com>2022-08-20 22:48:02 +0300
committerMarcoPolo-PasTonMolo <marcopolopastonmolo@protonmail.com>2022-08-20 22:48:02 +0300
commita704838152b9aec0bef2446f742b1eb548f71d1a (patch)
treeaed0eba30c8f27cb4f310b66752cd2fee30ba776
parent4b9ff6d4dcf2e1c16f12f9039d57530245ce1c4d (diff)
downloadprofani-tty-a704838152b9aec0bef2446f742b1eb548f71d1a.tar.gz
Handle late delivery
-rw-r--r--src/event/server_events.c2
-rw-r--r--src/ui/chatwin.c10
-rw-r--r--src/ui/window.c1
-rw-r--r--src/xmpp/iq.c121
-rw-r--r--src/xmpp/xmpp.h2
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);