diff --git a/src/command/cmd_funcs.c b/src/command/cmd_funcs.c index b260d908..804b0727 100644 --- a/src/command/cmd_funcs.c +++ b/src/command/cmd_funcs.c @@ -2109,7 +2109,7 @@ cmd_msg(ProfWin *window, const char *const command, gchar **args) ui_focus_win((ProfWin*)chatwin); if (msg) { - cl_ev_send_msg(chatwin, msg, FALSE); + cl_ev_send_msg(chatwin, msg, FALSE, FALSE); } else { #ifdef HAVE_LIBOTR if (otr_is_secure(barejid)) { @@ -4721,7 +4721,7 @@ cmd_tiny(ProfWin *window, const char *const command, gchar **args) { ProfChatWin *chatwin = (ProfChatWin*)window; assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); - cl_ev_send_msg(chatwin, tiny, FALSE); + cl_ev_send_msg(chatwin, tiny, FALSE, FALSE); break; } case WIN_PRIVATE: @@ -7051,7 +7051,7 @@ cmd_correct(ProfWin *window, const char *const command, gchar **args) cons_debug(" Original : %s", chatwin->last_message); cons_debug(" Corrected : %s", corrected); - cl_ev_send_msg(chatwin, corrected, FALSE); + cl_ev_send_msg(chatwin, corrected, FALSE, TRUE); return TRUE; } @@ -7176,7 +7176,7 @@ _cmd_execute_default(ProfWin *window, const char *inp) { ProfChatWin *chatwin = (ProfChatWin*)window; assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); - cl_ev_send_msg(chatwin, inp, FALSE); + cl_ev_send_msg(chatwin, inp, FALSE, FALSE); break; } case WIN_PRIVATE: diff --git a/src/event/client_events.c b/src/event/client_events.c index 8cbcf177..5c57f881 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 char *const m } void -cl_ev_send_msg(ProfChatWin *chatwin, const char *const msg, gboolean upload) +cl_ev_send_msg(ProfChatWin *chatwin, const char *const msg, gboolean upload, gboolean correct) { chat_state_active(chatwin->state); @@ -134,6 +134,11 @@ cl_ev_send_msg(ProfChatWin *chatwin, const char *const msg, gboolean upload) } } + char *correct_id = NULL; + if (correct) { + correct_id = chatwin->last_id; + } + char *plugin_msg = plugins_pre_chat_message_send(chatwin->barejid, msg); // OTR suported, PGP supported @@ -142,14 +147,14 @@ cl_ev_send_msg(ProfChatWin *chatwin, const char *const msg, gboolean upload) if (chatwin->pgp_send) { char *id = message_send_chat_pgp(chatwin->barejid, plugin_msg, request_receipt); chat_log_pgp_msg_out(chatwin->barejid, plugin_msg); - chatwin_outgoing_msg(chatwin, plugin_msg, id, PROF_MSG_PGP, request_receipt); + chatwin_outgoing_msg(chatwin, plugin_msg, id, PROF_MSG_PGP, request_receipt, NULL); free(id); } else { gboolean handled = otr_on_message_send(chatwin, plugin_msg, request_receipt); if (!handled) { - char *id = message_send_chat(chatwin->barejid, plugin_msg, request_receipt, upload); + char *id = message_send_chat(chatwin->barejid, plugin_msg, request_receipt, upload, correct_id); chat_log_msg_out(chatwin->barejid, plugin_msg); - chatwin_outgoing_msg(chatwin, plugin_msg, id, PROF_MSG_PLAIN, request_receipt); + chatwin_outgoing_msg(chatwin, plugin_msg, id, PROF_MSG_PLAIN, request_receipt, correct_id); free(id); } } @@ -165,9 +170,9 @@ cl_ev_send_msg(ProfChatWin *chatwin, const char *const msg, gboolean upload) #ifndef HAVE_LIBGPGME gboolean handled = otr_on_message_send(chatwin, plugin_msg, request_receipt); if (!handled) { - char *id = message_send_chat(chatwin->barejid, plugin_msg, request_receipt, upload); + char *id = message_send_chat(chatwin->barejid, plugin_msg, request_receipt, upload, correct_id); chat_log_msg_out(chatwin->barejid, plugin_msg); - chatwin_outgoing_msg(chatwin, plugin_msg, id, PROF_MSG_PLAIN, request_receipt); + chatwin_outgoing_msg(chatwin, plugin_msg, id, PROF_MSG_PLAIN, request_receipt. correct_id); free(id); } @@ -183,12 +188,12 @@ cl_ev_send_msg(ProfChatWin *chatwin, const char *const msg, gboolean upload) if (chatwin->pgp_send) { char *id = message_send_chat_pgp(chatwin->barejid, plugin_msg, request_receipt); chat_log_pgp_msg_out(chatwin->barejid, plugin_msg); - chatwin_outgoing_msg(chatwin, plugin_msg, id, PROF_MSG_PGP, request_receipt); + chatwin_outgoing_msg(chatwin, plugin_msg, id, PROF_MSG_PGP, request_receipt, NULL); free(id); } else { - char *id = message_send_chat(chatwin->barejid, plugin_msg, request_receipt, upload); + char *id = message_send_chat(chatwin->barejid, plugin_msg, request_receipt, upload, correct_id); chat_log_msg_out(chatwin->barejid, plugin_msg); - chatwin_outgoing_msg(chatwin, plugin_msg, id, PROF_MSG_PLAIN, request_receipt); + chatwin_outgoing_msg(chatwin, plugin_msg, id, PROF_MSG_PLAIN, request_receipt, correct_id); free(id); } @@ -201,9 +206,9 @@ cl_ev_send_msg(ProfChatWin *chatwin, const char *const msg, gboolean upload) // OTR unsupported, PGP unsupported #ifndef HAVE_LIBOTR #ifndef HAVE_LIBGPGME - char *id = message_send_chat(chatwin->barejid, plugin_msg, request_receipt, upload); + char *id = message_send_chat(chatwin->barejid, plugin_msg, request_receipt, upload, correct_id); chat_log_msg_out(chatwin->barejid, plugin_msg); - chatwin_outgoing_msg(chatwin, plugin_msg, id, PROF_MSG_PLAIN, request_receipt); + chatwin_outgoing_msg(chatwin, plugin_msg, id, PROF_MSG_PLAIN, request_receipt, correct_id); free(id); plugins_post_chat_message_send(chatwin->barejid, plugin_msg); diff --git a/src/event/client_events.h b/src/event/client_events.h index 70a15557..67fd4fd9 100644 --- a/src/event/client_events.h +++ b/src/event/client_events.h @@ -44,7 +44,7 @@ void cl_ev_disconnect(void); void cl_ev_presence_send(const resource_presence_t presence_type, const char *const msg, const int idle_secs); -void cl_ev_send_msg(ProfChatWin *chatwin, const char *const msg, gboolean upload); +void cl_ev_send_msg(ProfChatWin *chatwin, const char *const msg, gboolean upload, gboolean correct); void cl_ev_send_muc_msg(ProfMucWin *mucwin, const char *const msg, gboolean upload); void cl_ev_send_priv_msg(ProfPrivateWin *privwin, const char *const msg, gboolean upload); diff --git a/src/otr/otr.c b/src/otr/otr.c index 0dc56a59..a1ed1a17 100644 --- a/src/otr/otr.c +++ b/src/otr/otr.c @@ -347,7 +347,7 @@ otr_on_message_send(ProfChatWin *chatwin, const char *const message, gboolean re if (encrypted) { id = message_send_chat_otr(chatwin->barejid, encrypted, request_receipt); chat_log_otr_msg_out(chatwin->barejid, message); - chatwin_outgoing_msg(chatwin, message, id, PROF_MSG_OTR, request_receipt); + chatwin_outgoing_msg(chatwin, message, id, PROF_MSG_OTR, request_receipt, NULL); otr_free_message(encrypted); free(id); return TRUE; @@ -367,7 +367,7 @@ otr_on_message_send(ProfChatWin *chatwin, const char *const message, gboolean re if (policy == PROF_OTRPOLICY_OPPORTUNISTIC) { char *otr_tagged_msg = otr_tag_message(message); id = message_send_chat_otr(chatwin->barejid, otr_tagged_msg, request_receipt); - chatwin_outgoing_msg(chatwin, message, id, PROF_MSG_PLAIN, request_receipt); + chatwin_outgoing_msg(chatwin, message, id, PROF_MSG_PLAIN, request_receipt, NULL); chat_log_msg_out(chatwin->barejid, message); free(otr_tagged_msg); free(id); diff --git a/src/tools/http_upload.c b/src/tools/http_upload.c index aa3ffca4..e22ef48d 100644 --- a/src/tools/http_upload.c +++ b/src/tools/http_upload.c @@ -258,7 +258,7 @@ end: { ProfChatWin *chatwin = (ProfChatWin*)(upload->window); assert(chatwin->memcheck == PROFCHATWIN_MEMCHECK); - cl_ev_send_msg(chatwin, upload->get_url, TRUE); + cl_ev_send_msg(chatwin, upload->get_url, TRUE, FALSE); break; } case WIN_PRIVATE: diff --git a/src/ui/chatwin.c b/src/ui/chatwin.c index 2aee7d71..989ef624 100644 --- a/src/ui/chatwin.c +++ b/src/ui/chatwin.c @@ -292,12 +292,9 @@ chatwin_incoming_msg(ProfChatWin *chatwin, const char *const resource, const cha free(plugin_message); } -void -chatwin_outgoing_msg(ProfChatWin *chatwin, const char *const message, char *id, prof_enc_t enc_mode, - gboolean request_receipt) +static void +_chatwin_set_last_message(ProfChatWin *chatwin, const char *const id, const char *const message) { - assert(chatwin != NULL); - if (chatwin->last_message) { free(chatwin->last_message); } @@ -306,6 +303,22 @@ chatwin_outgoing_msg(ProfChatWin *chatwin, const char *const message, char *id, free(chatwin->last_id); } chatwin->last_id = strdup(id); +} + +void +chatwin_outgoing_msg(ProfChatWin *chatwin, const char *const message, char *id, prof_enc_t enc_mode, + gboolean request_receipt, char *correct_id) +{ + assert(chatwin != NULL); + + if (correct_id) { + win_correct((ProfWin*)chatwin, '+', message, id, request_receipt, correct_id); + _chatwin_set_last_message(chatwin, id, message); + + return; + } + + _chatwin_set_last_message(chatwin, id, message); char enc_char = '-'; if (enc_mode == PROF_MSG_OTR) { diff --git a/src/ui/ui.h b/src/ui/ui.h index cbaa19d0..4b37fc1d 100644 --- a/src/ui/ui.h +++ b/src/ui/ui.h @@ -123,7 +123,7 @@ void chatwin_incoming_msg(ProfChatWin *chatwin, const char *const resource, cons void chatwin_receipt_received(ProfChatWin *chatwin, const char *const id); void chatwin_recipient_gone(ProfChatWin *chatwin); void chatwin_outgoing_msg(ProfChatWin *chatwin, const char *const message, char *id, prof_enc_t enc_mode, - gboolean request_receipt); + gboolean request_receipt, char *correct_id); void chatwin_outgoing_carbon(ProfChatWin *chatwin, const char *const message, prof_enc_t enc_mode); void chatwin_contact_online(ProfChatWin *chatwin, Resource *resource, GDateTime *last_activity); void chatwin_contact_offline(ProfChatWin *chatwin, char *resource, char *status); diff --git a/src/ui/window.c b/src/ui/window.c index f5ce6a43..4f37d67f 100644 --- a/src/ui/window.c +++ b/src/ui/window.c @@ -1172,6 +1172,46 @@ win_print_outgoing(ProfWin *window, const char ch, const char *const message, co buffer_append(window, entry); } +void +win_correct(ProfWin *window, const char ch, const char *const message, const char *const id, gboolean request_receipt, + const char *const correct_id) +{ + ProfBuffEntry *entry = buffer_get_entry_by_outgoing_id(window->layout->entries, correct_id); + if (!entry) { + return; + } + + if (entry->date) { + if (entry->date->timestamp) { + g_date_time_unref(entry->date->timestamp); + } + free(entry->date); + } + + entry->date = buffer_date_new_now(); + entry->show_char = ch; + + if (entry->message) { + free(entry->message); + } + entry->message = strdup(message); + + if (entry->xmpp->outgoing_id) { + free(entry->xmpp->outgoing_id); + } + entry->xmpp->outgoing_id = strdup(id); + + if (request_receipt) { + if (entry->xmpp->receipt) { + entry->xmpp->receipt->received = FALSE; + } else { + entry->xmpp->receipt = buffer_receipt_new(); + } + } + + win_redraw(window); +} + void win_print_history(ProfWin *window, GDateTime *timestamp, const char *const message) { diff --git a/src/ui/window.h b/src/ui/window.h index a37f69ef..85248ef8 100644 --- a/src/ui/window.h +++ b/src/ui/window.h @@ -68,6 +68,8 @@ void win_print_outgoing(ProfWin *window, const char ch, const char *const messag void win_print_incoming(ProfWin *window, GDateTime *timestamp, const char *const them, const char *const message, prof_enc_t enc_mode); void win_print_history(ProfWin *window, GDateTime *timestamp, const char *const message); +void win_correct(ProfWin *window, const char ch, const char *const message, const char *const id, gboolean request_receipt, + const char *const correct_id); void win_print_upload(ProfWin *window, const char *const message, char *url); void win_update_upload(ProfWin *window, const char *const url, const char *const message); diff --git a/src/xmpp/message.c b/src/xmpp/message.c index c107766d..3fec4ba4 100644 --- a/src/xmpp/message.c +++ b/src/xmpp/message.c @@ -132,7 +132,7 @@ message_handlers_init(void) } char* -message_send_chat(const char *const barejid, const char *const msg, gboolean request_receipt, gboolean upload) +message_send_chat(const char *const barejid, const char *const msg, gboolean request_receipt, gboolean upload, char *correct_id) { xmpp_ctx_t * const ctx = connection_get_ctx(); @@ -156,6 +156,10 @@ message_send_chat(const char *const barejid, const char *const msg, gboolean req stanza_attach_receipt_request(ctx, message); } + if (correct_id) { + stanza_attach_correction(ctx, message, correct_id); + } + _send_message_stanza(message); xmpp_stanza_release(message); diff --git a/src/xmpp/stanza.c b/src/xmpp/stanza.c index 88313333..36ea157a 100644 --- a/src/xmpp/stanza.c +++ b/src/xmpp/stanza.c @@ -405,6 +405,19 @@ stanza_attach_receipt_request(xmpp_ctx_t *ctx, xmpp_stanza_t *stanza) return stanza; } +xmpp_stanza_t* +stanza_attach_correction(xmpp_ctx_t *ctx, xmpp_stanza_t *stanza, char *correct_id) +{ + xmpp_stanza_t *replace = xmpp_stanza_new(ctx); + xmpp_stanza_set_name(replace, "replace"); + xmpp_stanza_set_id(replace, correct_id); + xmpp_stanza_set_ns(replace, STANZA_NS_LASTMESSAGECORRECTION); + xmpp_stanza_add_child(stanza, replace); + xmpp_stanza_release(replace); + + return stanza; +} + xmpp_stanza_t* stanza_attach_x_oob_url(xmpp_ctx_t *ctx, xmpp_stanza_t *stanza, const char *const url) { diff --git a/src/xmpp/stanza.h b/src/xmpp/stanza.h index e3a368c5..4227a8e2 100644 --- a/src/xmpp/stanza.h +++ b/src/xmpp/stanza.h @@ -228,6 +228,7 @@ xmpp_stanza_t* stanza_attach_hints_no_copy(xmpp_ctx_t *ctx, xmpp_stanza_t *stanz xmpp_stanza_t* stanza_attach_hints_no_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_correction(xmpp_ctx_t *ctx, xmpp_stanza_t *stanza, char *correct_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 5de35fd3..8f6eae8c 100644 --- a/src/xmpp/xmpp.h +++ b/src/xmpp/xmpp.h @@ -132,7 +132,7 @@ GList* connection_get_available_resources(void); gboolean connection_supports(const char *const feature); char* connection_jid_for_feature(const char *const feature); -char* message_send_chat(const char *const barejid, const char *const msg, gboolean request_receipt, gboolean upload); +char* message_send_chat(const char *const barejid, const char *const msg, gboolean request_receipt, gboolean upload, char *correct_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_private(const char *const fulljid, const char *const msg, gboolean upload); diff --git a/tests/unittests/ui/stub_ui.c b/tests/unittests/ui/stub_ui.c index 82b7ef32..1a561b8c 100644 --- a/tests/unittests/ui/stub_ui.c +++ b/tests/unittests/ui/stub_ui.c @@ -154,7 +154,7 @@ void ui_disconnected(void) {} void chatwin_recipient_gone(ProfChatWin *chatwin) {} void chatwin_outgoing_msg(ProfChatWin *chatwin, const char * const message, char *id, prof_enc_t enc_mode, - gboolean request_receipt) {} + gboolean request_receipt, char *correct_id) {} void chatwin_outgoing_carbon(ProfChatWin *chatwin, const char * const message, prof_enc_t enc_mode) {} void privwin_outgoing_msg(ProfPrivateWin *privwin, const char * const message, const char *const id) {} diff --git a/tests/unittests/xmpp/stub_xmpp.c b/tests/unittests/xmpp/stub_xmpp.c index 2cd5bc1c..cfb9479f 100644 --- a/tests/unittests/xmpp/stub_xmpp.c +++ b/tests/unittests/xmpp/stub_xmpp.c @@ -91,7 +91,7 @@ connection_supports(const char *const feature) } // message functions -char* message_send_chat(const char * const barejid, const char * const msg, gboolean request_receipt, gboolean upload) +char* message_send_chat(const char * const barejid, const char * const msg, gboolean request_receipt, gboolean upload, char *correct) { check_expected(barejid); check_expected(msg);