From ee28298d7fd4576441cd5f0b4fa8e8d4bd3901bb Mon Sep 17 00:00:00 2001 From: iequidoo Date: Sun, 13 Aug 2023 22:48:34 -0300 Subject: [PATCH 1/5] fix: W/a sending images sent as stickers on some platforms (#4611) Check if a sticker has at least one fully transparent corner and otherwise change the Sticker type to Image. This would fix both Android and iOS at the same time and prevent similar bug on future platforms that may get this bug like Ubuntu Touch. --- src/blob.rs | 95 +++++++++++++++++++++++++++++++++------ src/chat.rs | 51 ++++++++++++++------- test-data/image/logo.gif | Bin 0 -> 5894 bytes test-data/image/logo.png | Bin 0 -> 13377 bytes 4 files changed, 118 insertions(+), 28 deletions(-) create mode 100644 test-data/image/logo.gif create mode 100644 test-data/image/logo.png diff --git a/src/blob.rs b/src/blob.rs index 579a2ad4e..a75021747 100644 --- a/src/blob.rs +++ b/src/blob.rs @@ -9,7 +9,7 @@ use std::path::{Path, PathBuf}; use anyhow::{format_err, Context as _, Result}; use futures::StreamExt; -use image::{DynamicImage, ImageFormat, ImageOutputFormat}; +use image::{DynamicImage, GenericImageView, ImageFormat, ImageOutputFormat}; use num_traits::FromPrimitive; use tokio::io::AsyncWriteExt; use tokio::{fs, io}; @@ -323,18 +323,35 @@ impl<'a> BlobObject<'a> { MediaQuality::Worse => constants::WORSE_AVATAR_SIZE, }; + let maybe_sticker = &mut false; let strict_limits = true; // max_bytes is 20_000 bytes: Outlook servers don't allow headers larger than 32k. // 32 / 4 * 3 = 24k if you account for base64 encoding. To be safe, we reduced this to 20k. - if let Some(new_name) = - self.recode_to_size(context, blob_abs, img_wh, 20_000, strict_limits)? - { + if let Some(new_name) = self.recode_to_size( + context, + blob_abs, + maybe_sticker, + img_wh, + 20_000, + strict_limits, + )? { self.name = new_name; } Ok(()) } - pub async fn recode_to_image_size(&mut self, context: &Context) -> Result<()> { + /// Recodes an image pointed by a [BlobObject] so that it fits into limits on the image width, + /// height and file size specified by the config. + /// + /// On some platforms images are passed to the core as [`crate::message::Viewtype::Sticker`] in + /// which case `maybe_sticker` flag should be set. We recheck if an image is a true sticker + /// assuming that it must have at least one fully transparent corner, otherwise this flag is + /// reset. + pub async fn recode_to_image_size( + &mut self, + context: &Context, + maybe_sticker: &mut bool, + ) -> Result<()> { let blob_abs = self.to_abs_path(); let (img_wh, max_bytes) = match MediaQuality::from_i32(context.get_config_int(Config::MediaQuality).await?) @@ -347,9 +364,14 @@ impl<'a> BlobObject<'a> { MediaQuality::Worse => (constants::WORSE_IMAGE_SIZE, constants::WORSE_IMAGE_BYTES), }; let strict_limits = false; - if let Some(new_name) = - self.recode_to_size(context, blob_abs, img_wh, max_bytes, strict_limits)? - { + if let Some(new_name) = self.recode_to_size( + context, + blob_abs, + maybe_sticker, + img_wh, + max_bytes, + strict_limits, + )? { self.name = new_name; } Ok(()) @@ -358,9 +380,10 @@ impl<'a> BlobObject<'a> { /// If `!strict_limits`, then if `max_bytes` is exceeded, reduce the image to `img_wh` and just /// proceed with the result. fn recode_to_size( - &self, + &mut self, context: &Context, mut blob_abs: PathBuf, + maybe_sticker: &mut bool, mut img_wh: u32, max_bytes: usize, strict_limits: bool, @@ -372,6 +395,19 @@ impl<'a> BlobObject<'a> { let mut encoded = Vec::new(); let mut changed_name = None; + if *maybe_sticker { + let x_max = img.width().saturating_sub(1); + let y_max = img.height().saturating_sub(1); + *maybe_sticker = img.in_bounds(x_max, y_max) + && (img.get_pixel(0, 0).0[3] == 0 + || img.get_pixel(x_max, 0).0[3] == 0 + || img.get_pixel(0, y_max).0[3] == 0 + || img.get_pixel(x_max, y_max).0[3] == 0); + } + if *maybe_sticker && exif.is_none() { + return Ok(None); + } + img = match orientation { Some(90) => img.rotate90(), Some(180) => img.rotate180(), @@ -860,10 +896,18 @@ mod tests { file.metadata().await.unwrap().len() } - let blob = BlobObject::new_from_path(&t, &avatar_blob).await.unwrap(); + let mut blob = BlobObject::new_from_path(&t, &avatar_blob).await.unwrap(); + let maybe_sticker = &mut false; let strict_limits = true; - blob.recode_to_size(&t, blob.to_abs_path(), 1000, 3000, strict_limits) - .unwrap(); + blob.recode_to_size( + &t, + blob.to_abs_path(), + maybe_sticker, + 1000, + 3000, + strict_limits, + ) + .unwrap(); assert!(file_size(&avatar_blob).await <= 3000); assert!(file_size(&avatar_blob).await > 2000); tokio::task::block_in_place(move || { @@ -923,6 +967,7 @@ mod tests { async fn test_recode_image_1() { let bytes = include_bytes!("../test-data/image/avatar1000x1000.jpg"); send_image_check_mediaquality( + Viewtype::Image, Some("0"), bytes, "jpg", @@ -936,6 +981,7 @@ mod tests { .await .unwrap(); send_image_check_mediaquality( + Viewtype::Image, Some("1"), bytes, "jpg", @@ -955,6 +1001,7 @@ mod tests { // The "-rotated" files are rotated by 270 degrees using the Exif metadata let bytes = include_bytes!("../test-data/image/rectangle2000x1800-rotated.jpg"); let img_rotated = send_image_check_mediaquality( + Viewtype::Image, Some("0"), bytes, "jpg", @@ -974,6 +1021,7 @@ mod tests { let bytes = buf.into_inner(); let img_rotated = send_image_check_mediaquality( + Viewtype::Image, Some("1"), &bytes, "jpg", @@ -994,6 +1042,7 @@ mod tests { let bytes = include_bytes!("../test-data/image/screenshot.png"); send_image_check_mediaquality( + Viewtype::Image, Some("0"), bytes, "png", @@ -1008,6 +1057,7 @@ mod tests { .unwrap(); send_image_check_mediaquality( + Viewtype::Image, Some("1"), bytes, "png", @@ -1020,12 +1070,29 @@ mod tests { ) .await .unwrap(); + + // This will be sent as Image, see [`BlobObject::maybe_sticker`] for explanation. + send_image_check_mediaquality( + Viewtype::Sticker, + Some("0"), + bytes, + "png", + false, // no Exif + 1920, + 1080, + 0, + 1920, + 1080, + ) + .await + .unwrap(); } #[tokio::test(flavor = "multi_thread", worker_threads = 2)] async fn test_recode_image_huge_jpg() { let bytes = include_bytes!("../test-data/image/screenshot.jpg"); send_image_check_mediaquality( + Viewtype::Image, Some("0"), bytes, "jpg", @@ -1059,6 +1126,7 @@ mod tests { #[allow(clippy::too_many_arguments)] async fn send_image_check_mediaquality( + viewtype: Viewtype, media_quality_config: Option<&str>, bytes: &[u8], extension: &str, @@ -1090,7 +1158,7 @@ mod tests { assert!(exif.is_none()); } - let mut msg = Message::new(Viewtype::Image); + let mut msg = Message::new(viewtype); msg.set_file(file.to_str().unwrap(), None); let chat = alice.create_chat(&bob).await; let sent = alice.send_msg(chat.id, &mut msg).await; @@ -1104,6 +1172,7 @@ mod tests { ); let bob_msg = bob.recv_msg(&sent).await; + assert_eq!(bob_msg.get_viewtype(), Viewtype::Image); assert_eq!(bob_msg.get_width() as u32, compressed_width); assert_eq!(bob_msg.get_height() as u32, compressed_height); let file = bob_msg.get_file(&bob).unwrap(); diff --git a/src/chat.rs b/src/chat.rs index ec5dac52b..27fa71c73 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -2033,13 +2033,18 @@ async fn prepare_msg_blob(context: &Context, msg: &mut Message) -> Result<()> { .await? .with_context(|| format!("attachment missing for message of type #{}", msg.viewtype))?; - if msg.viewtype == Viewtype::Image { - if let Err(err) = blob.recode_to_image_size(context).await { + let mut maybe_sticker = msg.viewtype == Viewtype::Sticker; + if msg.viewtype == Viewtype::Image || maybe_sticker { + // TODO: Ignore errors only if the image has no Exif. + if let Err(err) = blob.recode_to_image_size(context, &mut maybe_sticker).await { warn!( context, "Cannot recode image, using original data: {err:#}." ); } + if !maybe_sticker { + msg.viewtype = Viewtype::Image; + } } msg.param.set(Param::File, blob.as_name()); if let (Some(filename), Some(blob_ext)) = (msg.param.get(Param::Filename), blob.suffix()) { @@ -5510,7 +5515,13 @@ mod tests { Ok(()) } - async fn test_sticker(filename: &str, bytes: &[u8], w: i32, h: i32) -> Result<()> { + async fn test_sticker( + filename: &str, + bytes: &[u8], + res_viewtype: Viewtype, + w: i32, + h: i32, + ) -> Result<()> { let alice = TestContext::new_alice().await; let bob = TestContext::new_bob().await; let alice_chat = alice.create_chat(&bob).await; @@ -5524,12 +5535,19 @@ mod tests { let sent_msg = alice.send_msg(alice_chat.id, &mut msg).await; let mime = sent_msg.payload(); - assert_eq!(mime.match_indices("Chat-Content: sticker").count(), 1); + if res_viewtype == Viewtype::Sticker { + assert_eq!(mime.match_indices("Chat-Content: sticker").count(), 1); + } let msg = bob.recv_msg(&sent_msg).await; assert_eq!(msg.chat_id, bob_chat.id); - assert_eq!(msg.get_viewtype(), Viewtype::Sticker); - assert_eq!(msg.get_filename().unwrap(), filename); + assert_eq!(msg.get_viewtype(), res_viewtype); + let msg_filename = msg.get_filename().unwrap(); + match res_viewtype { + Viewtype::Sticker => assert_eq!(msg_filename, filename), + Viewtype::Image => assert!(msg_filename.starts_with("image_")), + _ => panic!("Not implemented"), + } assert_eq!(msg.get_width(), w); assert_eq!(msg.get_height(), h); assert!(msg.get_filebytes(&bob).await?.unwrap() > 250); @@ -5541,9 +5559,10 @@ mod tests { async fn test_sticker_png() -> Result<()> { test_sticker( "sticker.png", - include_bytes!("../test-data/image/avatar64x64.png"), - 64, - 64, + include_bytes!("../test-data/image/logo.png"), + Viewtype::Sticker, + 135, + 135, ) .await } @@ -5553,6 +5572,7 @@ mod tests { test_sticker( "sticker.jpg", include_bytes!("../test-data/image/avatar1000x1000.jpg"), + Viewtype::Image, 1000, 1000, ) @@ -5563,9 +5583,10 @@ mod tests { async fn test_sticker_gif() -> Result<()> { test_sticker( "sticker.gif", - include_bytes!("../test-data/image/image100x50.gif"), - 100, - 50, + include_bytes!("../test-data/image/logo.gif"), + Viewtype::Sticker, + 135, + 135, ) .await } @@ -5579,8 +5600,8 @@ mod tests { let bob_chat = bob.create_chat(&alice).await; // create sticker - let file_name = "sticker.jpg"; - let bytes = include_bytes!("../test-data/image/avatar1000x1000.jpg"); + let file_name = "sticker.png"; + let bytes = include_bytes!("../test-data/image/logo.png"); let file = alice.get_blobdir().join(file_name); tokio::fs::write(&file, bytes).await?; let mut msg = Message::new(Viewtype::Sticker); @@ -6117,7 +6138,7 @@ mod tests { chat_id1, Viewtype::Sticker, "b.png", - include_bytes!("../test-data/image/avatar64x64.png"), + include_bytes!("../test-data/image/logo.png"), ) .await?; let second_image_msg_id = send_media( diff --git a/test-data/image/logo.gif b/test-data/image/logo.gif new file mode 100644 index 0000000000000000000000000000000000000000..f25b2d0ed74e393d7d46c8f9fff52c25238fdc52 GIT binary patch literal 5894 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 Mst8x8lrs Date: Mon, 14 Aug 2023 17:51:05 -0300 Subject: [PATCH 2/5] fix: prepare_msg_blob(): If cannot recode image, don't use it if it has Exif We mustn't send images with Exif as it can leak metadata such as location, camera model, etc. --- src/blob.rs | 23 ++++++++++++++++++++--- src/chat.rs | 9 ++------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/blob.rs b/src/blob.rs index a75021747..40072cb53 100644 --- a/src/blob.rs +++ b/src/blob.rs @@ -388,9 +388,12 @@ impl<'a> BlobObject<'a> { max_bytes: usize, strict_limits: bool, ) -> Result> { - tokio::task::block_in_place(move || { - let mut img = image::open(&blob_abs).context("image decode failure")?; + let mut no_exif = false; + let no_exif_ref = &mut no_exif; + let res = tokio::task::block_in_place(move || { let (nr_bytes, exif) = self.metadata()?; + *no_exif_ref = exif.is_none(); + let mut img = image::open(&blob_abs).context("image decode failure")?; let orientation = exif.as_ref().map(|exif| exif_orientation(exif, context)); let mut encoded = Vec::new(); let mut changed_name = None; @@ -505,7 +508,21 @@ impl<'a> BlobObject<'a> { } Ok(changed_name) - }) + }); + match res { + Ok(_) => res, + Err(err) => { + if !strict_limits && no_exif { + warn!( + context, + "Cannot recode image, using original data: {err:#}.", + ); + Ok(None) + } else { + Err(err) + } + } + } } /// Returns image file size and Exif. diff --git a/src/chat.rs b/src/chat.rs index 27fa71c73..387593e90 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -2035,13 +2035,8 @@ async fn prepare_msg_blob(context: &Context, msg: &mut Message) -> Result<()> { let mut maybe_sticker = msg.viewtype == Viewtype::Sticker; if msg.viewtype == Viewtype::Image || maybe_sticker { - // TODO: Ignore errors only if the image has no Exif. - if let Err(err) = blob.recode_to_image_size(context, &mut maybe_sticker).await { - warn!( - context, - "Cannot recode image, using original data: {err:#}." - ); - } + blob.recode_to_image_size(context, &mut maybe_sticker) + .await?; if !maybe_sticker { msg.viewtype = Viewtype::Image; } From 9ef34890faadd9ab4e74ddf22a19e6254b762a5f Mon Sep 17 00:00:00 2001 From: link2xt Date: Mon, 28 Aug 2023 03:23:30 +0000 Subject: [PATCH 3/5] chore: fix beta clippy warnings --- src/job.rs | 6 +++--- src/quota.rs | 2 +- src/webxdc.rs | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/job.rs b/src/job.rs index f739f4f63..d1ae367ea 100644 --- a/src/job.rs +++ b/src/job.rs @@ -155,8 +155,8 @@ impl<'a> Connection<'a> { pub(crate) async fn perform_job(context: &Context, mut connection: Connection<'_>, mut job: Job) { info!(context, "Job {} started...", &job); - let try_res = match perform_job_action(context, &mut job, &mut connection, 0).await { - Status::RetryNow => perform_job_action(context, &mut job, &mut connection, 1).await, + let try_res = match perform_job_action(context, &job, &mut connection, 0).await { + Status::RetryNow => perform_job_action(context, &job, &mut connection, 1).await, x => x, }; @@ -205,7 +205,7 @@ pub(crate) async fn perform_job(context: &Context, mut connection: Connection<'_ async fn perform_job_action( context: &Context, - job: &mut Job, + job: &Job, connection: &mut Connection<'_>, tries: u32, ) -> Status { diff --git a/src/quota.rs b/src/quota.rs index cc3f428fd..f2a4b921d 100644 --- a/src/quota.rs +++ b/src/quota.rs @@ -71,7 +71,7 @@ async fn get_unique_quota_roots_and_usage( // messages could be received and so the usage could have been changed *unique_quota_roots .entry(quota_root_name.clone()) - .or_insert_with(Vec::new) = quota.resources; + .or_default() = quota.resources; } } } diff --git a/src/webxdc.rs b/src/webxdc.rs index a622e41e5..46ada2fab 100644 --- a/src/webxdc.rs +++ b/src/webxdc.rs @@ -707,7 +707,7 @@ fn parse_webxdc_manifest(bytes: &[u8]) -> Result { Ok(manifest) } -async fn get_blob(archive: &mut async_zip::read::fs::ZipFileReader, name: &str) -> Result> { +async fn get_blob(archive: &async_zip::read::fs::ZipFileReader, name: &str) -> Result> { let (i, _) = find_zip_entry(archive.file(), name) .ok_or_else(|| anyhow!("no entry found for {}", name))?; let mut reader = archive.entry(i).await?; @@ -750,10 +750,10 @@ impl Message { name }; - let mut archive = self.get_webxdc_archive(context).await?; + let archive = self.get_webxdc_archive(context).await?; if name == "index.html" { - if let Ok(bytes) = get_blob(&mut archive, "manifest.toml").await { + if let Ok(bytes) = get_blob(&archive, "manifest.toml").await { if let Ok(manifest) = parse_webxdc_manifest(&bytes) { if let Some(min_api) = manifest.min_api { if min_api > WEBXDC_API_VERSION { @@ -766,15 +766,15 @@ impl Message { } } - get_blob(&mut archive, name).await + get_blob(&archive, name).await } /// Return info from manifest.toml or from fallbacks. pub async fn get_webxdc_info(&self, context: &Context) -> Result { ensure!(self.viewtype == Viewtype::Webxdc, "No webxdc instance."); - let mut archive = self.get_webxdc_archive(context).await?; + let archive = self.get_webxdc_archive(context).await?; - let mut manifest = get_blob(&mut archive, "manifest.toml") + let mut manifest = get_blob(&archive, "manifest.toml") .await .map(|bytes| parse_webxdc_manifest(&bytes).unwrap_or_default()) .unwrap_or_default(); From 0a94fbc735b37b3f93f3b405167f54086f772a91 Mon Sep 17 00:00:00 2001 From: link2xt Date: Mon, 28 Aug 2023 02:13:02 +0000 Subject: [PATCH 4/5] fix: update async-imap to 0.9.1 to fix memory leak --- Cargo.lock | 32 +++----------------------------- Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f2528c303..c1835254e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -221,13 +221,13 @@ dependencies = [ [[package]] name = "async-imap" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da93622739d458dd9a6abc1abf0e38e81965a5824a3b37f9500437c82a8bb572" +checksum = "b538b767cbf9c162a6c5795d4b932bd2c20ba10b5a91a94d2b2b6886c1dce6a8" dependencies = [ "async-channel", "base64 0.21.2", - "byte-pool", + "bytes", "chrono", "futures", "imap-proto", @@ -544,16 +544,6 @@ version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" -[[package]] -name = "byte-pool" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2f1b21189f50b5625efa6227cf45e9d4cfdc2e73582df2b879e9689e78a7158" -dependencies = [ - "crossbeam-queue", - "stable_deref_trait", -] - [[package]] name = "bytemuck" version = "1.13.1" @@ -924,16 +914,6 @@ dependencies = [ "scopeguard", ] -[[package]] -name = "crossbeam-queue" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - [[package]] name = "crossbeam-utils" version = "0.8.16" @@ -4596,12 +4576,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - [[package]] name = "static_assertions" version = "1.1.0" diff --git a/Cargo.toml b/Cargo.toml index 9cabd3b71..c9a2c9790 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,7 @@ ratelimit = { path = "./deltachat-ratelimit" } anyhow = "1" async-channel = "1.8.0" -async-imap = { version = "0.9.0", default-features = false, features = ["runtime-tokio"] } +async-imap = { version = "0.9.1", default-features = false, features = ["runtime-tokio"] } async-native-tls = { version = "0.5", default-features = false, features = ["runtime-tokio"] } async-smtp = { version = "0.9", default-features = false, features = ["runtime-tokio"] } async_zip = { version = "0.0.12", default-features = false, features = ["deflate", "fs"] } From 4d74f625d3962877a7462eec86f894d9c3bd68ea Mon Sep 17 00:00:00 2001 From: link2xt Date: Mon, 28 Aug 2023 11:47:36 +0000 Subject: [PATCH 5/5] chore(release): prepare for 1.120.0 --- CHANGELOG.md | 34 +++++++++++++++++++++++ Cargo.lock | 10 +++---- Cargo.toml | 2 +- deltachat-ffi/Cargo.toml | 2 +- deltachat-jsonrpc/Cargo.toml | 2 +- deltachat-jsonrpc/typescript/package.json | 2 +- deltachat-repl/Cargo.toml | 2 +- deltachat-rpc-server/Cargo.toml | 2 +- package.json | 2 +- release-date.in | 2 +- 10 files changed, 47 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 25740972d..8e54a6826 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,38 @@ # Changelog +## [1.120.0] - 2023-08-28 + +### API-Changes + +- jsonrpc: Add `resend_messages`. + +### Fixes + +- Update async-imap to 0.9.1 to fix memory leak. +- Delete messages from SMTP queue only on user demand ([#4579](https://github.com/deltachat/deltachat-core-rust/pull/4579)). +- Do not send images without transparency as stickers ([#4611](https://github.com/deltachat/deltachat-core-rust/pull/4611)). +- `prepare_msg_blob()`: do not use the image if it has Exif metadata but the image cannot be recoded. + +### Refactor + +- Hide accounts.rs constants from public API. +- Hide pgp module from public API. + +### Build system + +- Update to Zig 0.11.0. +- Update to Rust 1.72.0. + +### CI + +- Run on push to stable branch. + +### Miscellaneous Tasks + +- python: Fix lint errors. +- python: Fix `ruff` 0.0.286 warnings. +- Fix beta clippy warnings. + ## [1.119.1] - 2023-08-06 Bugfix release attempting to fix the [iOS build error](https://github.com/deltachat/deltachat-core-rust/issues/4610). @@ -2730,3 +2763,4 @@ https://github.com/deltachat/deltachat-core-rust/pulls?q=is%3Apr+is%3Aclosed [1.118.0]: https://github.com/deltachat/deltachat-core-rust/compare/v1.117.0...v1.118.0 [1.119.0]: https://github.com/deltachat/deltachat-core-rust/compare/v1.118.0...v1.119.0 [1.119.1]: https://github.com/deltachat/deltachat-core-rust/compare/v1.119.0...v1.119.1 +[1.120.0]: https://github.com/deltachat/deltachat-core-rust/compare/v1.119.1...v1.120.0 diff --git a/Cargo.lock b/Cargo.lock index c1835254e..1f09a5f93 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1103,7 +1103,7 @@ dependencies = [ [[package]] name = "deltachat" -version = "1.119.1" +version = "1.120.0" dependencies = [ "ansi_term", "anyhow", @@ -1179,7 +1179,7 @@ dependencies = [ [[package]] name = "deltachat-jsonrpc" -version = "1.119.1" +version = "1.120.0" dependencies = [ "anyhow", "async-channel", @@ -1203,7 +1203,7 @@ dependencies = [ [[package]] name = "deltachat-repl" -version = "1.119.1" +version = "1.120.0" dependencies = [ "ansi_term", "anyhow", @@ -1218,7 +1218,7 @@ dependencies = [ [[package]] name = "deltachat-rpc-server" -version = "1.119.1" +version = "1.120.0" dependencies = [ "anyhow", "deltachat", @@ -1243,7 +1243,7 @@ dependencies = [ [[package]] name = "deltachat_ffi" -version = "1.119.1" +version = "1.120.0" dependencies = [ "anyhow", "deltachat", diff --git a/Cargo.toml b/Cargo.toml index c9a2c9790..25b1ea712 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "deltachat" -version = "1.119.1" +version = "1.120.0" edition = "2021" license = "MPL-2.0" rust-version = "1.65" diff --git a/deltachat-ffi/Cargo.toml b/deltachat-ffi/Cargo.toml index 232199630..546fec81d 100644 --- a/deltachat-ffi/Cargo.toml +++ b/deltachat-ffi/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "deltachat_ffi" -version = "1.119.1" +version = "1.120.0" description = "Deltachat FFI" edition = "2018" readme = "README.md" diff --git a/deltachat-jsonrpc/Cargo.toml b/deltachat-jsonrpc/Cargo.toml index 11a481099..f6f35f0a2 100644 --- a/deltachat-jsonrpc/Cargo.toml +++ b/deltachat-jsonrpc/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "deltachat-jsonrpc" -version = "1.119.1" +version = "1.120.0" description = "DeltaChat JSON-RPC API" edition = "2021" default-run = "deltachat-jsonrpc-server" diff --git a/deltachat-jsonrpc/typescript/package.json b/deltachat-jsonrpc/typescript/package.json index c020bb4fa..0c0e4b6bd 100644 --- a/deltachat-jsonrpc/typescript/package.json +++ b/deltachat-jsonrpc/typescript/package.json @@ -55,5 +55,5 @@ }, "type": "module", "types": "dist/deltachat.d.ts", - "version": "1.119.1" + "version": "1.120.0" } diff --git a/deltachat-repl/Cargo.toml b/deltachat-repl/Cargo.toml index 4c2790391..32402d1d0 100644 --- a/deltachat-repl/Cargo.toml +++ b/deltachat-repl/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "deltachat-repl" -version = "1.119.1" +version = "1.120.0" license = "MPL-2.0" edition = "2021" diff --git a/deltachat-rpc-server/Cargo.toml b/deltachat-rpc-server/Cargo.toml index 51256daf0..2b446d99b 100644 --- a/deltachat-rpc-server/Cargo.toml +++ b/deltachat-rpc-server/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "deltachat-rpc-server" -version = "1.119.1" +version = "1.120.0" description = "DeltaChat JSON-RPC server" edition = "2021" readme = "README.md" diff --git a/package.json b/package.json index 1c1c618fa..46f77993d 100644 --- a/package.json +++ b/package.json @@ -60,5 +60,5 @@ "test:mocha": "mocha -r esm node/test/test.js --growl --reporter=spec --bail --exit" }, "types": "node/dist/index.d.ts", - "version": "1.119.1" + "version": "1.120.0" } diff --git a/release-date.in b/release-date.in index a6535abb7..13b929383 100644 --- a/release-date.in +++ b/release-date.in @@ -1 +1 @@ -2023-08-06 \ No newline at end of file +2023-08-28 \ No newline at end of file