mirror of
https://github.com/chatmail/core.git
synced 2026-05-02 21:06:31 +03:00
api: Forwarding messages to another profile (#7491)
Add `chat::forward_msgs_2ctx()` which takes another context as a parameter and forwards messages to it and its jsonrpc wrapper `CommandApi::forward_messages_to_account()`.
This commit is contained in:
@@ -10,8 +10,9 @@ pub use deltachat::accounts::Accounts;
|
|||||||
use deltachat::blob::BlobObject;
|
use deltachat::blob::BlobObject;
|
||||||
use deltachat::calls::ice_servers;
|
use deltachat::calls::ice_servers;
|
||||||
use deltachat::chat::{
|
use deltachat::chat::{
|
||||||
self, add_contact_to_chat, forward_msgs, get_chat_media, get_chat_msgs, get_chat_msgs_ex,
|
self, add_contact_to_chat, forward_msgs, forward_msgs_2ctx, get_chat_media, get_chat_msgs,
|
||||||
marknoticed_chat, remove_contact_from_chat, Chat, ChatId, ChatItem, MessageListOptions,
|
get_chat_msgs_ex, marknoticed_chat, remove_contact_from_chat, Chat, ChatId, ChatItem,
|
||||||
|
MessageListOptions,
|
||||||
};
|
};
|
||||||
use deltachat::chatlist::Chatlist;
|
use deltachat::chatlist::Chatlist;
|
||||||
use deltachat::config::Config;
|
use deltachat::config::Config;
|
||||||
@@ -2208,6 +2209,27 @@ impl CommandApi {
|
|||||||
forward_msgs(&ctx, &message_ids, ChatId::new(chat_id)).await
|
forward_msgs(&ctx, &message_ids, ChatId::new(chat_id)).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Forward messages to a chat in another account.
|
||||||
|
/// See [`Self::forward_messages`] for more info.
|
||||||
|
async fn forward_messages_to_account(
|
||||||
|
&self,
|
||||||
|
src_account_id: u32,
|
||||||
|
src_message_ids: Vec<u32>,
|
||||||
|
dst_account_id: u32,
|
||||||
|
dst_chat_id: u32,
|
||||||
|
) -> Result<()> {
|
||||||
|
let src_ctx = self.get_context(src_account_id).await?;
|
||||||
|
let dst_ctx = self.get_context(dst_account_id).await?;
|
||||||
|
let src_message_ids: Vec<MsgId> = src_message_ids.into_iter().map(MsgId::new).collect();
|
||||||
|
forward_msgs_2ctx(
|
||||||
|
&src_ctx,
|
||||||
|
&src_message_ids,
|
||||||
|
&dst_ctx,
|
||||||
|
ChatId::new(dst_chat_id),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
/// Resend messages and make information available for newly added chat members.
|
/// Resend messages and make information available for newly added chat members.
|
||||||
/// Resending sends out the original message, however, recipients and webxdc-status may differ.
|
/// Resending sends out the original message, however, recipients and webxdc-status may differ.
|
||||||
/// Clients that already have the original message can still ignore the resent message as
|
/// Clients that already have the original message can still ignore the resent message as
|
||||||
|
|||||||
30
src/chat.rs
30
src/chat.rs
@@ -4203,6 +4203,16 @@ pub async fn set_chat_profile_image(
|
|||||||
|
|
||||||
/// Forwards multiple messages to a chat.
|
/// Forwards multiple messages to a chat.
|
||||||
pub async fn forward_msgs(context: &Context, msg_ids: &[MsgId], chat_id: ChatId) -> Result<()> {
|
pub async fn forward_msgs(context: &Context, msg_ids: &[MsgId], chat_id: ChatId) -> Result<()> {
|
||||||
|
forward_msgs_2ctx(context, msg_ids, context, chat_id).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Forwards multiple messages to a chat in another context.
|
||||||
|
pub async fn forward_msgs_2ctx(
|
||||||
|
ctx_src: &Context,
|
||||||
|
msg_ids: &[MsgId],
|
||||||
|
ctx_dst: &Context,
|
||||||
|
chat_id: ChatId,
|
||||||
|
) -> Result<()> {
|
||||||
ensure!(!msg_ids.is_empty(), "empty msgs_ids: nothing to forward");
|
ensure!(!msg_ids.is_empty(), "empty msgs_ids: nothing to forward");
|
||||||
ensure!(!chat_id.is_special(), "can not forward to special chat");
|
ensure!(!chat_id.is_special(), "can not forward to special chat");
|
||||||
|
|
||||||
@@ -4210,16 +4220,16 @@ pub async fn forward_msgs(context: &Context, msg_ids: &[MsgId], chat_id: ChatId)
|
|||||||
let mut curr_timestamp: i64;
|
let mut curr_timestamp: i64;
|
||||||
|
|
||||||
chat_id
|
chat_id
|
||||||
.unarchive_if_not_muted(context, MessageState::Undefined)
|
.unarchive_if_not_muted(ctx_dst, MessageState::Undefined)
|
||||||
.await?;
|
.await?;
|
||||||
let mut chat = Chat::load_from_db(context, chat_id).await?;
|
let mut chat = Chat::load_from_db(ctx_dst, chat_id).await?;
|
||||||
if let Some(reason) = chat.why_cant_send(context).await? {
|
if let Some(reason) = chat.why_cant_send(ctx_dst).await? {
|
||||||
bail!("cannot send to {chat_id}: {reason}");
|
bail!("cannot send to {chat_id}: {reason}");
|
||||||
}
|
}
|
||||||
curr_timestamp = create_smeared_timestamps(context, msg_ids.len());
|
curr_timestamp = create_smeared_timestamps(ctx_dst, msg_ids.len());
|
||||||
let mut msgs = Vec::with_capacity(msg_ids.len());
|
let mut msgs = Vec::with_capacity(msg_ids.len());
|
||||||
for id in msg_ids {
|
for id in msg_ids {
|
||||||
let ts: i64 = context
|
let ts: i64 = ctx_src
|
||||||
.sql
|
.sql
|
||||||
.query_get_value("SELECT timestamp FROM msgs WHERE id=?", (id,))
|
.query_get_value("SELECT timestamp FROM msgs WHERE id=?", (id,))
|
||||||
.await?
|
.await?
|
||||||
@@ -4229,7 +4239,7 @@ pub async fn forward_msgs(context: &Context, msg_ids: &[MsgId], chat_id: ChatId)
|
|||||||
msgs.sort_unstable();
|
msgs.sort_unstable();
|
||||||
for (_, id) in msgs {
|
for (_, id) in msgs {
|
||||||
let src_msg_id: MsgId = id;
|
let src_msg_id: MsgId = id;
|
||||||
let mut msg = Message::load_from_db(context, src_msg_id).await?;
|
let mut msg = Message::load_from_db(ctx_src, src_msg_id).await?;
|
||||||
if msg.state == MessageState::OutDraft {
|
if msg.state == MessageState::OutDraft {
|
||||||
bail!("cannot forward drafts.");
|
bail!("cannot forward drafts.");
|
||||||
}
|
}
|
||||||
@@ -4264,16 +4274,16 @@ pub async fn forward_msgs(context: &Context, msg_ids: &[MsgId], chat_id: ChatId)
|
|||||||
msg.state = MessageState::OutPending;
|
msg.state = MessageState::OutPending;
|
||||||
msg.rfc724_mid = create_outgoing_rfc724_mid();
|
msg.rfc724_mid = create_outgoing_rfc724_mid();
|
||||||
msg.timestamp_sort = curr_timestamp;
|
msg.timestamp_sort = curr_timestamp;
|
||||||
chat.prepare_msg_raw(context, &mut msg, None).await?;
|
chat.prepare_msg_raw(ctx_dst, &mut msg, None).await?;
|
||||||
|
|
||||||
curr_timestamp += 1;
|
curr_timestamp += 1;
|
||||||
if !create_send_msg_jobs(context, &mut msg).await?.is_empty() {
|
if !create_send_msg_jobs(ctx_dst, &mut msg).await?.is_empty() {
|
||||||
context.scheduler.interrupt_smtp().await;
|
ctx_dst.scheduler.interrupt_smtp().await;
|
||||||
}
|
}
|
||||||
created_msgs.push(msg.id);
|
created_msgs.push(msg.id);
|
||||||
}
|
}
|
||||||
for msg_id in created_msgs {
|
for msg_id in created_msgs {
|
||||||
context.emit_msgs_changed(chat_id, msg_id);
|
ctx_dst.emit_msgs_changed(chat_id, msg_id);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5240,6 +5240,44 @@ async fn test_send_delete_request_no_encryption() -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
|
||||||
|
async fn test_forward_msgs_2ctx() -> Result<()> {
|
||||||
|
let mut tcm = TestContextManager::new();
|
||||||
|
let alice = &tcm.alice().await;
|
||||||
|
let bob = &tcm.bob().await;
|
||||||
|
|
||||||
|
let alice_chat = alice.create_chat(bob).await;
|
||||||
|
let alice_sent = alice.send_text(alice_chat.id, "hi").await;
|
||||||
|
let bob_alice_msg = bob.recv_msg(&alice_sent).await;
|
||||||
|
let bob_chat_id = bob_alice_msg.chat_id;
|
||||||
|
bob_chat_id.accept(bob).await?;
|
||||||
|
|
||||||
|
let bob_text = "Hi, did you know we're using the same device so i have access to your profile?";
|
||||||
|
let bob_sent = bob.send_text(bob_chat_id, bob_text).await;
|
||||||
|
alice.recv_msg(&bob_sent).await;
|
||||||
|
let alice_chat_len = alice_chat.id.get_msg_cnt(alice).await?;
|
||||||
|
|
||||||
|
forward_msgs_2ctx(
|
||||||
|
bob,
|
||||||
|
&[bob_alice_msg.id, bob_sent.sender_msg_id],
|
||||||
|
alice,
|
||||||
|
alice_chat.id,
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
assert_eq!(alice_chat.id.get_msg_cnt(alice).await?, alice_chat_len + 2);
|
||||||
|
let msg = alice.get_last_msg().await;
|
||||||
|
assert!(msg.is_forwarded());
|
||||||
|
assert_eq!(msg.text, bob_text);
|
||||||
|
assert_eq!(msg.from_id, ContactId::SELF);
|
||||||
|
|
||||||
|
let sent = alice.pop_sent_msg().await;
|
||||||
|
let msg = bob.recv_msg(&sent).await;
|
||||||
|
assert!(msg.is_forwarded());
|
||||||
|
assert_eq!(msg.text, bob_text);
|
||||||
|
assert_eq!(msg.from_id, bob_alice_msg.from_id);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Tests that in multi-device setup
|
/// Tests that in multi-device setup
|
||||||
/// second device learns the key of a contact
|
/// second device learns the key of a contact
|
||||||
/// via Autocrypt-Gossip in 1:1 chats.
|
/// via Autocrypt-Gossip in 1:1 chats.
|
||||||
|
|||||||
Reference in New Issue
Block a user