diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f937129f..4c70a3614 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,7 +36,7 @@ - Synchronize Seen status across devices #2942 - Add API to set the database password #2956 - Add information about whether the database is encrypted or not to `dc_get_info()` #3000 -- Add Webxdc #2826 #2971 #2975 #2977 #2979 #2993 #2998 +- Add Webxdc #2826 #2971 #2975 #2977 #2979 #2993 #2998 #3001 ### Changed - selfstatus now defaults to empty diff --git a/draft/webxdc-dev-reference.md b/draft/webxdc-dev-reference.md index 83801deee..2052e21d8 100644 --- a/draft/webxdc-dev-reference.md +++ b/draft/webxdc-dev-reference.md @@ -44,6 +44,13 @@ To get a shared state, the peers use `sendUpdate()` to send updates to each othe All peers, including the sending one, will receive the update by the callback given to `setUpdateListener()`. +There are situations where the user cannot send messages to a chat, +eg. contact requests or if the user has left a group. +In these cases, you can still call `sendUpdate()`, +however, the update won't be sent to other peers +and you won't get the update by `setUpdateListener()` nor by `getAllUpdates()`. + + ### setUpdateListener() ```js diff --git a/src/webxdc.rs b/src/webxdc.rs index 624c3a8fb..257973657 100644 --- a/src/webxdc.rs +++ b/src/webxdc.rs @@ -1,5 +1,6 @@ //! # Handle webxdc messages. +use crate::chat::Chat; use crate::constants::Viewtype; use crate::context::Context; use crate::dc_tools::{dc_create_smeared_timestamp, dc_open_file_std}; @@ -246,6 +247,9 @@ impl Context { bail!("send_webxdc_status_update: is no webxdc message"); } + let chat = Chat::load_from_db(self, instance.chat_id).await?; + ensure!(chat.can_send(self).await?, "cannot send to {}", chat.id); + let status_update_id = self .create_status_update_record( &mut instance, @@ -683,6 +687,48 @@ mod tests { Ok(()) } + #[async_std::test] + async fn test_webxdc_contact_request() -> Result<()> { + let alice = TestContext::new_alice().await; + let bob = TestContext::new_bob().await; + + // Alice sends an webxdc instance to Bob + let alice_chat = alice.create_chat(&bob).await; + let _alice_instance = send_webxdc_instance(&alice, alice_chat.id).await?; + bob.recv_msg(&alice.pop_sent_msg().await).await; + + // Bob can start the webxdc from a contact request (get index.html) + // but cannot send updates to contact requests + let bob_instance = bob.get_last_msg().await; + let bob_chat = Chat::load_from_db(&bob, bob_instance.chat_id).await?; + assert!(bob_chat.is_contact_request()); + assert!(bob_instance + .get_webxdc_blob(&bob, "index.html") + .await + .is_ok()); + assert!(bob + .send_webxdc_status_update(bob_instance.id, r#"{"payload":42}"#, "descr") + .await + .is_err()); + assert_eq!( + bob.get_webxdc_status_updates(bob_instance.id, None).await?, + "[]" + ); + + // Once the contact request is accepted, Bob can send updates + bob_chat.id.accept(&bob).await?; + assert!(bob + .send_webxdc_status_update(bob_instance.id, r#"{"payload":42}"#, "descr") + .await + .is_ok()); + assert_eq!( + bob.get_webxdc_status_updates(bob_instance.id, None).await?, + r#"[{"payload":42}]"# + ); + + Ok(()) + } + #[async_std::test] async fn test_delete_webxdc_instance() -> Result<()> { let t = TestContext::new_alice().await;