diff --git a/deltachat-ffi/deltachat.h b/deltachat-ffi/deltachat.h index abc3f0ef0..759ad65ff 100644 --- a/deltachat-ffi/deltachat.h +++ b/deltachat-ffi/deltachat.h @@ -6784,8 +6784,8 @@ void dc_event_unref(dc_event_t* event); * UI should update the list. * * The event is emitted when the transports are modified on another device - * using the JSON-RPC calls `add_or_update_transport`, `add_transport_from_qr`, `delete_transport` - * or `set_config(configured_addr)`. + * using the JSON-RPC calls `add_or_update_transport`, `add_transport_from_qr`, `delete_transport`, + * `set_transport_unpublished` or `set_config(configured_addr)`. */ #define DC_EVENT_TRANSPORTS_MODIFIED 2600 diff --git a/deltachat-jsonrpc/src/api.rs b/deltachat-jsonrpc/src/api.rs index 3bf828850..a07df3530 100644 --- a/deltachat-jsonrpc/src/api.rs +++ b/deltachat-jsonrpc/src/api.rs @@ -528,6 +528,7 @@ impl CommandApi { /// from a server encoded in a QR code. /// - [Self::list_transports()] to get a list of all configured transports. /// - [Self::delete_transport()] to remove a transport. + /// - [Self::set_transport_unpublished()] to set whether contacts see this transport. async fn add_or_update_transport( &self, account_id: u32, @@ -571,6 +572,33 @@ impl CommandApi { ctx.delete_transport(&addr).await } + /// Change whether the transport is unpublished. + /// + /// Unpublished transports are not advertised to contacts, + /// and self-sent messages are not sent there, + /// so that we don't cause extra messages to the corresponding inbox, + /// but can still receive messages from contacts who don't know the new relay addresses yet. + /// + /// The default is true, but when updating, + /// existing secondary transports are set to unpublished, + /// so that an existing transport address doesn't suddenly get spammed with a lot of messages. + async fn set_transport_unpublished( + &self, + account_id: u32, + addr: String, + unpublished: bool, + ) -> Result<()> { + let ctx = self.get_context(account_id).await?; + ctx.set_transport_unpublished(&addr, unpublished).await + } + + /// Check whether the transport is unpublished. + /// See [`Self::set_transport_unpublished`] / `setTransportUnpublished` for details. + async fn is_transport_unpublished(&self, account_id: u32, addr: String) -> Result { + let ctx = self.get_context(account_id).await?; + ctx.is_transport_unpublished(&addr).await + } + /// Signal an ongoing process to stop. async fn stop_ongoing_process(&self, account_id: u32) -> Result<()> { let ctx = self.get_context(account_id).await?; diff --git a/src/config.rs b/src/config.rs index f524efb64..34792aae1 100644 --- a/src/config.rs +++ b/src/config.rs @@ -827,6 +827,7 @@ impl Context { "UPDATE config SET value=? WHERE keyname='configured_addr'", (addr,), )?; + // TODO set as published // Update the timestamp for the primary transport // so it becomes the first in `get_all_self_addrs()` list @@ -974,7 +975,23 @@ impl Context { .await } + /// Returns all published self addresses, newest first. + /// See `[Context::set_transport_unpublished]` + pub(crate) async fn get_published_self_addrs(&self) -> Result> { + self.sql + .query_map_vec( + "SELECT addr FROM transports WHERE is_published=1 ORDER BY add_timestamp DESC", + (), + |row| { + let addr: String = row.get(0)?; + Ok(addr) + }, + ) + .await + } + /// Returns all secondary self addresses. + // TODO this function might be refactored out pub(crate) async fn get_secondary_self_addrs(&self) -> Result> { self.sql.query_map_vec("SELECT addr FROM transports WHERE addr NOT IN (SELECT value FROM config WHERE keyname='configured_addr')", (), |row| { let addr: String = row.get(0)?; @@ -982,6 +999,23 @@ impl Context { }).await } + /// Returns all published secondary self addresses. + /// See `[Context::set_transport_unpublished]` + pub(crate) async fn get_published_secondary_self_addrs(&self) -> Result> { + self.sql + .query_map_vec( + "SELECT addr FROM transports + WHERE is_published=1 + AND addr NOT IN (SELECT value FROM config WHERE keyname='configured_addr')", + (), + |row| { + let addr: String = row.get(0)?; + Ok(addr) + }, + ) + .await + } + /// Returns the primary self address. /// Returns an error if no self addr is configured. pub async fn get_primary_self_addr(&self) -> Result { diff --git a/src/configure.rs b/src/configure.rs index 099f1ecac..c65c50515 100644 --- a/src/configure.rs +++ b/src/configure.rs @@ -110,6 +110,7 @@ impl Context { /// from a server encoded in a QR code. /// - [Self::list_transports()] to get a list of all configured transports. /// - [Self::delete_transport()] to remove a transport. + /// - [Self::set_transport_unpublished()] to set whether contacts see this transport. pub async fn add_or_update_transport(&self, param: &mut EnteredLoginParam) -> Result<()> { self.stop_io().await; let result = self.add_transport_inner(param).await; @@ -261,6 +262,39 @@ impl Context { Ok(()) } + /// Change whether the transport is unpublished. + /// + /// Unpublished transports are not advertised to contacts, + /// and self-sent messages are not sent there, + /// so that we don't cause extra messages to the corresponding inbox, + /// but can still receive messages from contacts who don't know the new relay addresses yet. + /// + /// The default is true, but when updating, + /// existing secondary transports are set to unpublished, + /// so that an existing transport address doesn't suddenly get spammed with a lot of messages. + pub async fn set_transport_unpublished(&self, addr: &str, unpublished: bool) -> Result<()> { + // TODO check if this is the primary transport + self.sql + .execute( + "UPDATE transports SET is_published=? WHERE addr=?", + (!unpublished, addr), + ) + .await?; + send_sync_transports(self).await?; + Ok(()) + } + + /// Check whether the transport is unpublished. + /// See [`Self::set_transport_unpublished`] for details. + pub async fn is_transport_unpublished(&self, addr: &str) -> Result { + let published: bool = self + .sql + .query_get_value("SELECT is_published FROM transports WHERE addr=?", (addr,)) + .await? + .context("is_published is not supposed to be NULL")?; + Ok(!published) + } + async fn inner_configure(&self, param: &EnteredLoginParam) -> Result<()> { info!(self, "Configure ..."); @@ -627,7 +661,7 @@ async fn configure(ctx: &Context, param: &EnteredLoginParam) -> Result Result