Skip to content

Commit 1479d22

Browse files
committed
fix(muc): Prevent duplicate messages if MAM is enabled
When joining a MUC the local db history is loaded when the window is created. Then the servers MAM response arrives including messages sent by the ourselves in previous sessions. The database layer correctly skips duplicate insertions. But doesn't inform the caller that it skipped the insertion. This caused the event handler to assume the replayed message was a realtime message and render it a second time. Signed-off-by: Michael Vetter <jubalh@iodoru.org>
1 parent 468c848 commit 1479d22

3 files changed

Lines changed: 35 additions & 16 deletions

File tree

src/database.c

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929

3030
static sqlite3* g_chatlog_database;
3131

32-
static void _add_to_db(ProfMessage* message, char* type, const Jid* const from_jid, const Jid* const to_jid);
32+
static gboolean _add_to_db(ProfMessage* message, char* type, const Jid* const from_jid, const Jid* const to_jid);
3333
static char* _get_db_filename(ProfAccount* account);
3434
static prof_msg_type_t _get_message_type_type(const char* const type);
3535
static prof_enc_t _get_message_enc_type(const char* const encstr);
@@ -211,13 +211,13 @@ log_database_close(void)
211211
}
212212
}
213213

214-
void
214+
gboolean
215215
log_database_add_incoming(ProfMessage* message)
216216
{
217217
if (message->to_jid) {
218-
_add_to_db(message, NULL, message->from_jid, message->to_jid);
218+
return _add_to_db(message, NULL, message->from_jid, message->to_jid);
219219
} else {
220-
_add_to_db(message, NULL, message->from_jid, connection_get_jid());
220+
return _add_to_db(message, NULL, message->from_jid, connection_get_jid());
221221
}
222222
}
223223

@@ -598,14 +598,14 @@ _get_message_enc_type(const char* const encstr)
598598
return PROF_MSG_ENC_NONE;
599599
}
600600

601-
static void
601+
static gboolean
602602
_add_to_db(ProfMessage* message, char* type, const Jid* const from_jid, const Jid* const to_jid)
603603
{
604604
auto_gchar gchar* pref_dblog = prefs_get_string(PREF_DBLOG);
605605
sqlite_int64 original_message_id = -1;
606606

607607
if (g_strcmp0(pref_dblog, "off") == 0) {
608-
return;
608+
return TRUE;
609609
} else if (g_strcmp0(pref_dblog, "redact") == 0) {
610610
if (message->plain) {
611611
free(message->plain);
@@ -615,7 +615,7 @@ _add_to_db(ProfMessage* message, char* type, const Jid* const from_jid, const Ji
615615

616616
if (!g_chatlog_database) {
617617
log_debug("log_database_add() called but db is not initialized");
618-
return;
618+
return TRUE;
619619
}
620620

621621
auto_gchar gchar* date_fmt = prof_date_time_format_iso8601(message->timestamp);
@@ -632,14 +632,14 @@ _add_to_db(ProfMessage* message, char* type, const Jid* const from_jid, const Ji
632632

633633
if (!replace_check_query) {
634634
log_error("Could not allocate memory for SQL replace query in log_database_add()");
635-
return;
635+
return FALSE;
636636
}
637637

638638
sqlite3_stmt* lmc_stmt = NULL;
639639

640640
if (SQLITE_OK != sqlite3_prepare_v2(g_chatlog_database, replace_check_query, -1, &lmc_stmt, NULL)) {
641641
log_error("SQLite error in _add_to_db() on selecting original message: %s", sqlite3_errmsg(g_chatlog_database));
642-
return;
642+
return FALSE;
643643
}
644644

645645
if (sqlite3_step(lmc_stmt) == SQLITE_ROW) {
@@ -654,7 +654,7 @@ _add_to_db(ProfMessage* message, char* type, const Jid* const from_jid, const Ji
654654
log_error("Mismatch in sender JIDs when trying to do LMC. Corrected message sender: %s. Original message sender: %s. Replace-ID: %s. Message: %s", from_jid->barejid, from_jid_orig, message->replace_id, message->plain);
655655
cons_show_error("%s sent a message correction with mismatched sender. See log for details.", from_jid->barejid);
656656
sqlite3_finalize(lmc_stmt);
657-
return;
657+
return FALSE;
658658
}
659659
} else {
660660
log_warning("Got LMC message that does not have original message counterpart in the database from %s", message->from_jid->fulljid);
@@ -688,7 +688,7 @@ _add_to_db(ProfMessage* message, char* type, const Jid* const from_jid, const Ji
688688
enc);
689689
if (!query) {
690690
log_error("Could not allocate memory for SQL insert query in log_database_add()");
691-
return;
691+
return FALSE;
692692
}
693693

694694
log_debug("Writing to DB. Query: %s", query);
@@ -697,19 +697,23 @@ _add_to_db(ProfMessage* message, char* type, const Jid* const from_jid, const Ji
697697
int rc = sqlite3_prepare_v2(g_chatlog_database, query, -1, &stmt, NULL);
698698
if (rc != SQLITE_OK) {
699699
log_error("SQLite error in _add_to_db() (prepare): %s", sqlite3_errmsg(g_chatlog_database));
700-
return;
700+
return FALSE;
701701
}
702702

703+
gboolean is_new = TRUE;
703704
rc = sqlite3_step(stmt);
704705
if (rc == SQLITE_ROW) {
705706
log_debug("Successfully inserted message into database.");
706707
} else if (rc == SQLITE_DONE) {
707708
log_debug("Message already exists in database (archive_id: %s), skipping.", message->stanzaid);
709+
is_new = FALSE;
708710
} else {
709711
log_error("SQLite error in _add_to_db() (step): %s", sqlite3_errmsg(g_chatlog_database));
712+
is_new = FALSE;
710713
}
711714

712715
sqlite3_finalize(stmt);
716+
return is_new;
713717
}
714718

715719
static int

src/database.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
#define MESSAGES_TO_RETRIEVE 10
1818

1919
gboolean log_database_init(ProfAccount* account);
20-
void log_database_add_incoming(ProfMessage* message);
20+
gboolean log_database_add_incoming(ProfMessage* message);
2121
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);
2222
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);
2323
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);

src/event/server_events.c

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -304,15 +304,15 @@ sv_ev_room_history(ProfMessage* message)
304304
}
305305
}
306306

307-
static void
307+
static gboolean
308308
_log_muc(ProfMessage* message)
309309
{
310310
if (message->enc == PROF_MSG_ENC_OMEMO) {
311311
groupchat_log_omemo_msg_in(message->from_jid->barejid, message->from_jid->resourcepart, message->plain);
312312
} else {
313313
groupchat_log_msg_in(message->from_jid->barejid, message->from_jid->resourcepart, message->plain);
314314
}
315-
log_database_add_incoming(message);
315+
return log_database_add_incoming(message);
316316
}
317317

318318
void
@@ -325,10 +325,14 @@ sv_ev_room_message(ProfMessage* message)
325325

326326
const char* const mynick = muc_nick(mucwin->roomjid);
327327

328+
gboolean is_duplicate = FALSE;
329+
328330
// only log message not coming from this client (but maybe same account, different client)
329331
// our messages are logged when outgoing
330332
if (!(g_strcmp0(mynick, message->from_jid->resourcepart) == 0 && message_is_sent_by_us(message, TRUE))) {
331-
_log_muc(message);
333+
if (!_log_muc(message)) {
334+
is_duplicate = TRUE;
335+
}
332336
}
333337

334338
char* old_plain = message->plain;
@@ -342,6 +346,17 @@ sv_ev_room_message(ProfMessage* message)
342346

343347
_clean_incoming_message(message);
344348

349+
if (is_duplicate) {
350+
log_debug("Skipping duplicate room message display: JID=%s, message=%s",
351+
message->from_jid->barejid, message->plain);
352+
g_slist_free(mentions);
353+
if (triggers) {
354+
g_list_free_full(triggers, free);
355+
}
356+
message->plain = old_plain;
357+
return;
358+
}
359+
345360
if (message->is_mam) {
346361
// For MAM, print to window but disable all notifications, unread count increment etc
347362
// And don't filter reflection of our own sent messages (so they get displayed)

0 commit comments

Comments
 (0)