Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
b154ef0
feat(muc): Track MAM support for MUCs
jubalh Jun 24, 2026
896bd35
feat(mam): implement room-targeted MAM stanza creation
jubalh Jun 24, 2026
3bcc265
feat(mam): Generalize mam and rsm functions to work on more window types
jubalh Jun 24, 2026
4eb8a91
feat(ui): Load MUC history from database
jubalh Jun 24, 2026
9fa062a
feat(mam): Distinguish between MAM and regular MUC message
jubalh Jun 24, 2026
13ba287
feat(mam): trigger MAM queries on joined MUC rooms
jubalh Jun 24, 2026
a55ca9f
fix(mam): fix compiler warnings and add missing casts
jubalh Jun 24, 2026
04731c3
fix(mam): resolve endless loading and database log pollution
jubalh Jun 24, 2026
aa9b423
feat(mam): suppress duplicate history replay on room join
jubalh Jun 25, 2026
d12255b
fix(mam): filter out non-groupchat messages from MUC archives
jubalh Jun 25, 2026
35a42f9
feat(mam): add end of archive visual indicator
jubalh Jun 25, 2026
f0c5685
feat(mam): Implement ondemand history loading
jubalh Jun 25, 2026
dbbed80
feat(ui): Display correct timestamps on historical mentions and triggers
jubalh Jun 25, 2026
5181093
feat(mam): Trigger automatic MAM catchup sync on reconnection
jubalh Jun 25, 2026
56a0f95
feat: Add `/mam verify` autocompleter
jubalh Jun 25, 2026
b2b85e5
feat: Update `/mam` command description
jubalh Jun 25, 2026
f11bcda
fix(xmpp): accept MAM results without 'by' attribute for active MUCs
jubalh Jun 26, 2026
5896d10
refactor: Use a const for "End of archive reached"
jubalh Jun 26, 2026
542760b
fix: Ensure end of archive is visible and redrawn correctly
jubalh Jun 26, 2026
fa73af9
fix: Prevent redundant MAM requests after archive ends
jubalh Jun 26, 2026
1ab997a
fix: Add space between titlebar name and SCROLLED indicator
jubalh Jun 26, 2026
eb2aa09
fix(muc): delay bookmark autojoin to prevent muc history
jubalh Jun 26, 2026
63e710d
fix(carbons): Enable message carbons conditionally
jubalh Jun 26, 2026
91e044b
fix(muc): Prevent duplicate messages if MAM is enabled
jubalh Jun 26, 2026
51c86a6
chore: Mark MAM as done in doap
jubalh Jun 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion profanity.doap
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@
<xmpp:status>partial</xmpp:status>
<xmpp:version>1.1.0</xmpp:version>
<xmpp:since>0.14.0</xmpp:since>
<xmpp:note xml:lang='en'>No MUC MAM</xmpp:note>
<xmpp:note xml:lang='en'>MAM since 0.14.0. MUC MAM since DEV</xmpp:note>
</xmpp:SupportedXep>
</implements>

Expand Down
20 changes: 19 additions & 1 deletion src/command/cmd_ac.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ static char* _strophe_autocomplete(ProfWin* window, const char* const input, gbo
static char* _stamp_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _adhoc_cmd_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _vcard_autocomplete(ProfWin* window, const char* const input, gboolean previous);
static char* _mam_autocomplete(ProfWin* window, const char* const input, gboolean previous);

static char* _script_autocomplete_func(const char* const prefix, gboolean previous, void* context);

Expand Down Expand Up @@ -276,6 +277,7 @@ static Autocomplete vcard_name_ac;
static Autocomplete vcard_set_param_ac;
static Autocomplete vcard_togglable_param_ac;
static Autocomplete vcard_address_type_ac;
static Autocomplete mam_ac;

static char* last_filepath_input = NULL;

Expand Down Expand Up @@ -434,6 +436,7 @@ static Autocomplete* all_acs[] = {
&vcard_set_param_ac,
&vcard_togglable_param_ac,
&vcard_address_type_ac,
&mam_ac,
};

static GHashTable* ac_funcs = NULL;
Expand Down Expand Up @@ -1345,6 +1348,10 @@ cmd_ac_init(void)
autocomplete_add(vcard_address_type_ac, "domestic");
autocomplete_add(vcard_address_type_ac, "international");

autocomplete_add(mam_ac, "on");
autocomplete_add(mam_ac, "off");
autocomplete_add(mam_ac, "verify");

if (ac_funcs != NULL)
g_hash_table_destroy(ac_funcs);
ac_funcs = g_hash_table_new(g_str_hash, g_str_equal);
Expand Down Expand Up @@ -1376,6 +1383,7 @@ cmd_ac_init(void)
g_hash_table_insert(ac_funcs, "/lastactivity", _lastactivity_autocomplete);
g_hash_table_insert(ac_funcs, "/log", _log_autocomplete);
g_hash_table_insert(ac_funcs, "/logging", _logging_autocomplete);
g_hash_table_insert(ac_funcs, "/mam", _mam_autocomplete);
g_hash_table_insert(ac_funcs, "/privacy", _privacy_autocomplete);
g_hash_table_insert(ac_funcs, "/mood", _mood_autocomplete);
g_hash_table_insert(ac_funcs, "/notify", _notify_autocomplete);
Expand Down Expand Up @@ -1771,6 +1779,16 @@ _spellcheck_autocomplete(ProfWin* window, const char* const input, gboolean prev
return result;
}

static char*
_mam_autocomplete(ProfWin* window, const char* const input, gboolean previous)
{
char* result = NULL;

result = autocomplete_param_with_ac(input, "/mam", mam_ac, TRUE, previous);

return result;
}

static char*
_cmd_ac_complete_params(ProfWin* window, const char* const input, gboolean previous)
{
Expand All @@ -1781,7 +1799,7 @@ _cmd_ac_complete_params(ProfWin* window, const char* const input, gboolean previ
// autocomplete boolean settings
gchar* boolean_choices[] = { "/beep", "/states", "/outtype", "/flash", "/splash",
"/history", "/vercheck", "/privileges", "/wrap",
"/carbons", "/slashguard", "/mam", "/silence" };
"/carbons", "/slashguard", "/silence" };

for (size_t i = 0; i < ARRAY_SIZE(boolean_choices); i++) {
result = autocomplete_param_with_func(input, boolean_choices[i], prefs_autocomplete_boolean_choice, previous, NULL);
Expand Down
28 changes: 15 additions & 13 deletions src/command/cmd_defs.c
Original file line number Diff line number Diff line change
Expand Up @@ -2615,19 +2615,21 @@ static const struct cmd_t command_defs[] = {
},

{ CMD_PREAMBLE("/mam",
parse_args, 1, 1, &cons_mam_setting)
CMD_MAINFUNC(cmd_mam)
CMD_TAGS(
CMD_TAG_CHAT)
CMD_SYN(
"/mam <on>|<off>")
CMD_DESC(
"Enable/Disable Message Archive Management (XEP-0313) "
"Currently MAM in groupchats (MUCs) is not supported. "
"Use the PG UP key to load more history.")
CMD_ARGS(
{ "on|off", "Enable or disable MAM" })
},
parse_args, 1, 1, &cons_mam_setting)
CMD_MAINFUNC(cmd_mam)
CMD_TAGS(
CMD_TAG_CHAT,
CMD_TAG_GROUPCHAT)
CMD_SYN(
"/mam <on>|<off>",
"/mam verify")
CMD_DESC(
"Enable or disable Message Archive Management (XEP-0313), or verify loaded history. "
"Use the PG UP key to load more history.")
CMD_ARGS(
{ "on|off", "Enable or disable MAM" },
{ "verify", "Verify history between the oldest and newest loaded messages in the current window and fetch any missing ones from the server" })
},

{ CMD_PREAMBLE("/changepassword",
parse_args, 0, 0, NULL)
Expand Down
55 changes: 55 additions & 0 deletions src/command/cmd_funcs.c
Original file line number Diff line number Diff line change
Expand Up @@ -9648,6 +9648,61 @@ cmd_executable_vcard_photo(ProfWin* window, const char* const command, gchar** a
gboolean
cmd_mam(ProfWin* window, const char* const command, gchar** args)
{
if (g_strcmp0(args[0], "verify") == 0) {
if (connection_get_status() != JABBER_CONNECTED) {
cons_show("You are not currently connected.");
return TRUE;
}
if (window->type != WIN_CHAT && window->type != WIN_MUC) {
cons_show("MAM verification can only be performed in chat or groupchat windows.");
return TRUE;
}
if (!prefs_get_boolean(PREF_MAM)) {
cons_show("Message Archive Management (MAM) is currently disabled.");
return TRUE;
}
if (!connection_supports(XMPP_FEATURE_MAM2)) {
cons_show("Your server does not support Message Archive Management (MAM2).");
return TRUE;
}

unsigned int buf_size = buffer_size(window->layout->buffer);
if (buf_size == 0) {
cons_show("No loaded history in this window to verify.");
return TRUE;
}

ProfBuffEntry* first_msg = NULL;
ProfBuffEntry* last_msg = NULL;

for (unsigned int i = 0; i < buf_size; i++) {
ProfBuffEntry* entry = buffer_get_entry(window->layout->buffer, i);
if (entry && entry->message && entry->message[0] != '-') {
if (!first_msg) {
first_msg = entry;
}
last_msg = entry;
}
}

if (!first_msg || !last_msg) {
cons_show("No messages found in the active scrollback buffer.");
return TRUE;
}

GDateTime* utc_start = g_date_time_to_timezone(first_msg->time, g_time_zone_new_utc());
GDateTime* utc_end = g_date_time_to_timezone(last_msg->time, g_time_zone_new_utc());
auto_gchar gchar* start_str = g_date_time_format(utc_start, "%FT%T.%f%:z");
auto_gchar gchar* end_str = g_date_time_format(utc_end, "%FT%T.%f%:z");
g_date_time_unref(utc_start);
g_date_time_unref(utc_end);

cons_show("Verifying history from %s to %s...", start_str, end_str);
iq_mam_verify_request(window, start_str, end_str);

return TRUE;
}

_cmd_set_boolean_preference(args[0], "Message Archive Management", PREF_MAM);

return TRUE;
Expand Down
Loading
Loading