diff --git a/src/command/cmd_ac.c b/src/command/cmd_ac.c index 0b411bcb..17629d87 100644 --- a/src/command/cmd_ac.c +++ b/src/command/cmd_ac.c @@ -114,6 +114,7 @@ static char* _logging_autocomplete(ProfWin *window, const char *const input, gbo static char* _color_autocomplete(ProfWin *window, const char *const input, gboolean previous); static char* _avatar_autocomplete(ProfWin *window, const char *const input, gboolean previous); static char* _correction_autocomplete(ProfWin *window, const char *const input, gboolean previous); +static char* _correct_autocomplete(ProfWin *window, const char *const input, gboolean previous); static char* _script_autocomplete_func(const char *const prefix, gboolean previous, void *context); @@ -1640,6 +1641,7 @@ _cmd_ac_complete_params(ProfWin *window, const char *const input, gboolean previ g_hash_table_insert(ac_funcs, "/color", _color_autocomplete); g_hash_table_insert(ac_funcs, "/avatar", _avatar_autocomplete); g_hash_table_insert(ac_funcs, "/correction", _correction_autocomplete); + g_hash_table_insert(ac_funcs, "/correct", _correct_autocomplete); int len = strlen(input); char parsed[len+1]; @@ -3736,3 +3738,12 @@ _correction_autocomplete(ProfWin *window, const char *const input, gboolean prev return NULL; } + +static char* +_correct_autocomplete(ProfWin *window, const char *const input, gboolean previous) +{ + char *result = NULL; + + //TODO: get last message + return result; +} diff --git a/src/command/cmd_defs.c b/src/command/cmd_defs.c index 982d81f6..db719b17 100644 --- a/src/command/cmd_defs.c +++ b/src/command/cmd_defs.c @@ -2367,6 +2367,7 @@ static struct cmd_t command_defs[] = CMD_NOSUBFUNCS CMD_MAINFUNC(cmd_correction) CMD_TAGS( + CMD_TAG_UI, CMD_TAG_CHAT, CMD_TAG_GROUPCHAT) CMD_SYN( @@ -2379,6 +2380,22 @@ static struct cmd_t command_defs[] = { "char", "Set character that will prefix corrected messages. Default: +"}) CMD_NOEXAMPLES }, + + { "/correct", + parse_args, 1, 1, NULL, + CMD_NOSUBFUNCS + CMD_MAINFUNC(cmd_correct) + CMD_TAGS( + CMD_TAG_CHAT, + CMD_TAG_GROUPCHAT) + CMD_SYN( + "/correct ") + CMD_DESC( + "Correct and resend the last message (XEP-0308).") + CMD_ARGS( + { "", "The corrected message."}) + CMD_NOEXAMPLES + }, }; static GHashTable *search_index; diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c index 70a6dcc0..9620f0d7 100644 --- a/src/command/cmd_funcs.c +++ b/src/command/cmd_funcs.c @@ -8680,3 +8680,44 @@ cmd_correction(ProfWin *window, const char *const command, gchar **args) return TRUE; } + +gboolean +cmd_correct(ProfWin *window, const char *const command, gchar **args) +{ + jabber_conn_status_t conn_status = connection_get_status(); + if (conn_status != JABBER_CONNECTED) { + cons_show("You are currently not connected."); + return TRUE; + } + + if (window->type == WIN_CHAT) { + ProfChatWin *chatwin = (ProfChatWin*)window; + assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); + + if (chatwin->last_msg_id == NULL || chatwin->last_message == NULL) { + win_println(window, THEME_DEFAULT, '!', "No last message to correct."); + return TRUE; + } + + /* + char *session_jid = chat_session_get_jid(chatwin->barejid); + if (session_jid == NULL) { + win_println(window, THEME_DEFAULT, '!', "Cannot determine if recipeint supports last message correction."); + free(session_jid); + return TRUE; + } + + if (caps_jid_has_feature(session_jid, XMPP_FEATURE_LAST_MESSAGE_CORRECTION) == FALSE) { + win_println(window, THEME_DEFAULT, '!', "Recipient does not support last message correction."); + free(session_jid); + return TRUE; + } + + */ + // speciel send with replace tag + cl_ev_send_msg_correct(chatwin, args[0], FALSE, TRUE); + } + + win_println(window, THEME_DEFAULT, '!', "Command /correct only valid in regular chat windows."); + return TRUE; +} diff --git a/src/command/cmd_funcs.h b/src/command/cmd_funcs.h index a2ccd000..768e14a2 100644 --- a/src/command/cmd_funcs.h +++ b/src/command/cmd_funcs.h @@ -228,4 +228,5 @@ gboolean cmd_color(ProfWin *window, const char *const command, gchar **args); gboolean cmd_avatar(ProfWin *window, const char *const command, gchar **args); gboolean cmd_os(ProfWin *window, const char *const command, gchar **args); gboolean cmd_correction(ProfWin *window, const char *const command, gchar **args); +gboolean cmd_correct(ProfWin *window, const char *const command, gchar **args); #endif diff --git a/src/event/client_events.c b/src/event/client_events.c index 6716b7e2..50a46ccc 100644 --- a/src/event/client_events.c +++ b/src/event/client_events.c @@ -115,7 +115,7 @@ cl_ev_presence_send(const resource_presence_t presence_type, const int idle_secs } void -cl_ev_send_msg(ProfChatWin *chatwin, const char *const msg, const char *const oob_url) +cl_ev_send_msg_correct(ProfChatWin *chatwin, const char *const msg, const char *const oob_url, gboolean correct_last_msg) { chat_state_active(chatwin->state); @@ -139,11 +139,17 @@ cl_ev_send_msg(ProfChatWin *chatwin, const char *const msg, const char *const oo return; } + char *replace_id = NULL; + if (correct_last_msg) { + replace_id = chatwin->last_msg_id; + } + // OTR suported, PGP supported, OMEMO unsupported #ifdef HAVE_LIBOTR #ifdef HAVE_LIBGPGME #ifndef HAVE_OMEMO if (chatwin->pgp_send) { + // TODO: replace_id char *id = message_send_chat_pgp(chatwin->barejid, plugin_msg, request_receipt); chat_log_pgp_msg_out(chatwin->barejid, plugin_msg, NULL); chatwin_outgoing_msg(chatwin, plugin_msg, id, PROF_MSG_ENC_PGP, request_receipt); @@ -151,7 +157,7 @@ cl_ev_send_msg(ProfChatWin *chatwin, const char *const msg, const char *const oo } else { gboolean handled = otr_on_message_send(chatwin, plugin_msg, request_receipt); if (!handled) { - char *id = message_send_chat(chatwin->barejid, plugin_msg, oob_url, request_receipt); + char *id = message_send_chat(chatwin->barejid, plugin_msg, oob_url, request_receipt, replace_id); chat_log_msg_out(chatwin->barejid, plugin_msg, NULL); chatwin_outgoing_msg(chatwin, plugin_msg, id, PROF_MSG_ENC_PLAIN, request_receipt); free(id); @@ -171,7 +177,7 @@ cl_ev_send_msg(ProfChatWin *chatwin, const char *const msg, const char *const oo #ifndef HAVE_OMEMO gboolean handled = otr_on_message_send(chatwin, plugin_msg, request_receipt); if (!handled) { - char *id = message_send_chat(chatwin->barejid, plugin_msg, oob_url, request_receipt); + char *id = message_send_chat(chatwin->barejid, plugin_msg, oob_url, request_receipt, replace_id); chat_log_msg_out(chatwin->barejid, plugin_msg, NULL); chatwin_outgoing_msg(chatwin, plugin_msg, id, PROF_MSG_ENC_PLAIN, request_receipt); free(id); @@ -194,7 +200,7 @@ cl_ev_send_msg(ProfChatWin *chatwin, const char *const msg, const char *const oo chatwin_outgoing_msg(chatwin, plugin_msg, id, PROF_MSG_ENC_PGP, request_receipt); free(id); } else { - char *id = message_send_chat(chatwin->barejid, plugin_msg, oob_url, request_receipt); + char *id = message_send_chat(chatwin->barejid, plugin_msg, oob_url, request_receipt, replace_id); chat_log_msg_out(chatwin->barejid, plugin_msg, NULL); chatwin_outgoing_msg(chatwin, plugin_msg, id, PROF_MSG_ENC_PLAIN, request_receipt); free(id); @@ -217,7 +223,7 @@ cl_ev_send_msg(ProfChatWin *chatwin, const char *const msg, const char *const oo chatwin_outgoing_msg(chatwin, plugin_msg, id, PROF_MSG_ENC_OMEMO, request_receipt); free(id); } else { - char *id = message_send_chat(chatwin->barejid, plugin_msg, oob_url, request_receipt); + char *id = message_send_chat(chatwin->barejid, plugin_msg, oob_url, request_receipt, replace_id); chat_log_msg_out(chatwin->barejid, plugin_msg, NULL); chatwin_outgoing_msg(chatwin, plugin_msg, id, PROF_MSG_ENC_PLAIN, request_receipt); free(id); @@ -242,7 +248,7 @@ cl_ev_send_msg(ProfChatWin *chatwin, const char *const msg, const char *const oo } else { gboolean handled = otr_on_message_send(chatwin, plugin_msg, request_receipt); if (!handled) { - char *id = message_send_chat(chatwin->barejid, plugin_msg, oob_url, request_receipt); + char *id = message_send_chat(chatwin->barejid, plugin_msg, oob_url, request_receipt, replace_id); chat_log_msg_out(chatwin->barejid, plugin_msg, NULL); chatwin_outgoing_msg(chatwin, plugin_msg, id, PROF_MSG_ENC_PLAIN, request_receipt); free(id); @@ -301,7 +307,7 @@ cl_ev_send_msg(ProfChatWin *chatwin, const char *const msg, const char *const oo } else { gboolean handled = otr_on_message_send(chatwin, plugin_msg, request_receipt); if (!handled) { - char *id = message_send_chat(chatwin->barejid, plugin_msg, oob_url, request_receipt); + char *id = message_send_chat(chatwin->barejid, plugin_msg, oob_url, request_receipt, replace_id); chat_log_msg_out(chatwin->barejid, plugin_msg, NULL); chatwin_outgoing_msg(chatwin, plugin_msg, id, PROF_MSG_ENC_PLAIN, request_receipt); free(id); @@ -332,6 +338,12 @@ cl_ev_send_msg(ProfChatWin *chatwin, const char *const msg, const char *const oo #endif } +void +cl_ev_send_msg(ProfChatWin *chatwin, const char *const msg, const char *const oob_url) +{ + cl_ev_send_msg_correct(chatwin, msg, oob_url, FALSE); +} + void cl_ev_send_muc_msg(ProfMucWin *mucwin, const char *const msg, const char *const oob_url) { diff --git a/src/event/client_events.h b/src/event/client_events.h index 82150f2e..66ade679 100644 --- a/src/event/client_events.h +++ b/src/event/client_events.h @@ -45,6 +45,7 @@ void cl_ev_disconnect(void); void cl_ev_presence_send(const resource_presence_t presence_type, const int idle_secs); +void cl_ev_send_msg_correct(ProfChatWin *chatwin, const char *const msg, const char *const oob_url, gboolean correct_last_msg); void cl_ev_send_msg(ProfChatWin *chatwin, const char *const msg, const char *const oob_url); void cl_ev_send_muc_msg(ProfMucWin *mucwin, const char *const msg, const char *const oob_url); void cl_ev_send_priv_msg(ProfPrivateWin *privwin, const char *const msg, const char *const oob_url); diff --git a/src/ui/chatwin.c b/src/ui/chatwin.c index 8faf4934..d7906815 100644 --- a/src/ui/chatwin.c +++ b/src/ui/chatwin.c @@ -56,6 +56,7 @@ #endif static void _chatwin_history(ProfChatWin *chatwin, const char *const contact); +static void _chatwin_set_last_message(ProfChatWin *chatwin, const char *const id, const char *const message); ProfChatWin* chatwin_new(const char *const barejid) @@ -323,6 +324,11 @@ chatwin_outgoing_msg(ProfChatWin *chatwin, const char *const message, char *id, enc_char = prefs_get_omemo_char(); } + // save last id and message for LMC + if (id) { + _chatwin_set_last_message(chatwin, id, message); + } + if (request_receipt && id) { win_print_with_receipt((ProfWin*)chatwin, enc_char, "me", message, id); } else { @@ -496,3 +502,13 @@ _chatwin_history(ProfChatWin *chatwin, const char *const contact) g_slist_free_full(history, free); } } + +static void +_chatwin_set_last_message(ProfChatWin *chatwin, const char *const id, const char *const message) +{ + free(chatwin->last_message); + chatwin->last_message = strdup(message); + + free(chatwin->last_msg_id); + chatwin->last_msg_id = strdup(id); +} diff --git a/src/ui/win_types.h b/src/ui/win_types.h index 68ed719e..0a0545bd 100644 --- a/src/ui/win_types.h +++ b/src/ui/win_types.h @@ -160,6 +160,9 @@ typedef struct prof_chat_win_t { char *enctext; char *incoming_char; char *outgoing_char; + // For LMC + char *last_message; + char *last_msg_id; } ProfChatWin; typedef struct prof_muc_win_t { diff --git a/src/ui/window.c b/src/ui/window.c index 339f4456..c668bd34 100644 --- a/src/ui/window.c +++ b/src/ui/window.c @@ -152,6 +152,8 @@ win_create_chat(const char *const barejid) new_win->enctext = NULL; new_win->incoming_char = NULL; new_win->outgoing_char = NULL; + new_win->last_message = NULL; + new_win->last_msg_id = NULL; new_win->memcheck = PROFCHATWIN_MEMCHECK; @@ -488,6 +490,8 @@ win_free(ProfWin* window) free(chatwin->enctext); free(chatwin->incoming_char); free(chatwin->outgoing_char); + free(chatwin->last_message); + free(chatwin->last_msg_id); chat_state_free(chatwin->state); break; } diff --git a/src/xmpp/message.c b/src/xmpp/message.c index f6100fa8..027b88f1 100644 --- a/src/xmpp/message.c +++ b/src/xmpp/message.c @@ -259,8 +259,7 @@ message_pubsub_event_handler_add(const char *const node, ProfMessageCallback fun } char* -message_send_chat(const char *const barejid, const char *const msg, const char *const oob_url, - gboolean request_receipt) +message_send_chat(const char *const barejid, const char *const msg, const char *const oob_url, gboolean request_receipt, const char *const replace_id) { xmpp_ctx_t * const ctx = connection_get_ctx(); @@ -284,6 +283,10 @@ message_send_chat(const char *const barejid, const char *const msg, const char * stanza_attach_receipt_request(ctx, message); } + if (replace_id) { + stanza_attach_correction(ctx, message, replace_id); + } + _send_message_stanza(message); xmpp_stanza_release(message); diff --git a/src/xmpp/stanza.c b/src/xmpp/stanza.c index f398a268..7b0db5c7 100644 --- a/src/xmpp/stanza.c +++ b/src/xmpp/stanza.c @@ -2606,3 +2606,15 @@ stanza_create_avatar_retrieve_data_request(xmpp_ctx_t *ctx, const char *stanza_i return iq; } + +xmpp_stanza_t* +stanza_attach_correction(xmpp_ctx_t *ctx, xmpp_stanza_t *stanza, const char *const replace_id) +{ + xmpp_stanza_t *replace_stanza = xmpp_stanza_new(ctx); + xmpp_stanza_set_name(replace_stanza, "replace"); + xmpp_stanza_set_id(replace_stanza, replace_id); + xmpp_stanza_set_ns(replace_stanza, STANZA_NS_LAST_MESSAGE_CORRECTION); + xmpp_stanza_add_child(stanza, replace_stanza); + + return stanza; +} diff --git a/src/xmpp/stanza.h b/src/xmpp/stanza.h index dc8c4e34..ee5c6772 100644 --- a/src/xmpp/stanza.h +++ b/src/xmpp/stanza.h @@ -245,6 +245,7 @@ xmpp_stanza_t* stanza_attach_hints_store(xmpp_ctx_t *ctx, xmpp_stanza_t *stanza) xmpp_stanza_t* stanza_attach_receipt_request(xmpp_ctx_t *ctx, xmpp_stanza_t *stanza); xmpp_stanza_t* stanza_attach_x_oob_url(xmpp_ctx_t *ctx, xmpp_stanza_t *stanza, const char *const url); xmpp_stanza_t* stanza_attach_origin_id(xmpp_ctx_t *ctx, xmpp_stanza_t *stanza, const char *const id); +xmpp_stanza_t* stanza_attach_correction(xmpp_ctx_t *ctx, xmpp_stanza_t *stanza, const char *const replace_id); xmpp_stanza_t* stanza_create_room_join_presence(xmpp_ctx_t *const ctx, const char *const full_room_jid, const char *const passwd); diff --git a/src/xmpp/xmpp.h b/src/xmpp/xmpp.h index dc1cdf27..15c61fa8 100644 --- a/src/xmpp/xmpp.h +++ b/src/xmpp/xmpp.h @@ -171,8 +171,7 @@ char* connection_jid_for_feature(const char *const feature); const char* connection_get_profanity_identifier(void); -char* message_send_chat(const char *const barejid, const char *const msg, const char *const oob_url, - gboolean request_receipt); +char* message_send_chat(const char *const barejid, const char *const msg, const char *const oob_url, gboolean request_receipt, const char *const replace_id); char* message_send_chat_otr(const char *const barejid, const char *const msg, gboolean request_receipt); char* message_send_chat_pgp(const char *const barejid, const char *const msg, gboolean request_receipt); char* message_send_chat_omemo(const char *const jid, uint32_t sid, GList *keys, const unsigned char *const iv, size_t iv_len, const unsigned char *const ciphertext, size_t ciphertext_len, gboolean request_receipt, gboolean muc);