Compare commits

..

6 Commits

Author SHA1 Message Date
link2xt
aecf7729d8 chore(release): prepare for 1.127.2 2023-10-29 16:29:04 +00:00
Simon Laux
f130d537b7 api(jsonrpc): add get_message_info_object 2023-10-29 16:26:01 +00:00
Ajay Gonepuri
f30f862e7e docs: fix typos 2023-10-29 13:13:44 +00:00
link2xt
81e1164358 test: compile deltachat-rpc-server in debug mode for tests
This reduces compilation times.
2023-10-29 01:09:35 +00:00
Simon Laux
542bd4cbb8 api!: jsonrpc misc_set_draft now requires setting the viewtype 2023-10-28 08:42:14 +00:00
link2xt
771b57778e test: increase pytest timeout to 10 minutes
deltachat-rpc-client tests often timeouts on CI,
this hopefully fixes the problem unless the tests actually deadlock.
2023-10-28 00:54:36 +00:00
22 changed files with 185 additions and 76 deletions

View File

@@ -1,5 +1,19 @@
# Changelog
## [1.127.2] - 2023-10-29
### API-Changes
- [**breaking**] Jsonrpc `misc_set_draft` now requires setting the viewtype.
- jsonrpc: Add `get_message_info_object`.
### Tests
- deltachat-rpc-client: Move pytest option from pyproject.toml to tox.ini and set log level.
- deltachat-rpc-client: Test securejoin.
- Increase pytest timeout to 10 minutes.
- Compile deltachat-rpc-server in debug mode for tests.
## [1.127.1] - 2023-10-27
### API-Changes
@@ -1078,7 +1092,7 @@ Bugfix release attempting to fix the [iOS build error](https://github.com/deltac
### Changes
- Look at Authentication-Results. Don't accept Autocrypt key changes
if they come with negative authentiation results while this contact
if they come with negative authentication results while this contact
sent emails with positive authentication results in the past. #3583
- jsonrpc in cffi also sends events now #3662
- jsonrpc: new format for events and better typescript autocompletion
@@ -2664,7 +2678,7 @@ Bugfix release attempting to fix the [iOS build error](https://github.com/deltac
- delete all consumed secure-join handshake messagess #1209 #1212
- rust-level cleanups #1218 #1217 #1210 #1205
- Rust-level cleanups #1218 #1217 #1210 #1205
- python-level cleanups #1204 #1202 #1201
@@ -3034,3 +3048,4 @@ https://github.com/deltachat/deltachat-core-rust/pulls?q=is%3Apr+is%3Aclosed
[1.126.1]: https://github.com/deltachat/deltachat-core-rust/compare/v1.126.0...v1.126.1
[1.127.0]: https://github.com/deltachat/deltachat-core-rust/compare/v1.126.1...v1.127.0
[1.127.1]: https://github.com/deltachat/deltachat-core-rust/compare/v1.127.0...v1.127.1
[1.127.2]: https://github.com/deltachat/deltachat-core-rust/compare/v1.127.1...v1.127.2

10
Cargo.lock generated
View File

@@ -1087,7 +1087,7 @@ dependencies = [
[[package]]
name = "deltachat"
version = "1.127.1"
version = "1.127.2"
dependencies = [
"ansi_term",
"anyhow",
@@ -1165,7 +1165,7 @@ dependencies = [
[[package]]
name = "deltachat-jsonrpc"
version = "1.127.1"
version = "1.127.2"
dependencies = [
"anyhow",
"async-channel 2.0.0",
@@ -1189,7 +1189,7 @@ dependencies = [
[[package]]
name = "deltachat-repl"
version = "1.127.1"
version = "1.127.2"
dependencies = [
"ansi_term",
"anyhow",
@@ -1204,7 +1204,7 @@ dependencies = [
[[package]]
name = "deltachat-rpc-server"
version = "1.127.1"
version = "1.127.2"
dependencies = [
"anyhow",
"deltachat",
@@ -1229,7 +1229,7 @@ dependencies = [
[[package]]
name = "deltachat_ffi"
version = "1.127.1"
version = "1.127.2"
dependencies = [
"anyhow",
"deltachat",

View File

@@ -1,6 +1,6 @@
[package]
name = "deltachat"
version = "1.127.1"
version = "1.127.2"
edition = "2021"
license = "MPL-2.0"
rust-version = "1.70"

View File

@@ -1,6 +1,6 @@
[package]
name = "deltachat_ffi"
version = "1.127.1"
version = "1.127.2"
description = "Deltachat FFI"
edition = "2018"
readme = "README.md"

View File

@@ -1,6 +1,6 @@
[package]
name = "deltachat-jsonrpc"
version = "1.127.1"
version = "1.127.2"
description = "DeltaChat JSON-RPC API"
edition = "2021"
default-run = "deltachat-jsonrpc-server"

View File

@@ -47,7 +47,7 @@ use types::provider_info::ProviderInfo;
use types::reactions::JSONRPCReactions;
use types::webxdc::WebxdcMessageInfo;
use self::types::message::MessageLoadResult;
use self::types::message::{MessageInfo, MessageLoadResult};
use self::types::{
chat::{BasicChat, JSONRPCChatVisibility, MuteDuration},
location::JsonrpcLocation,
@@ -1126,6 +1126,16 @@ impl CommandApi {
MsgId::new(message_id).get_info(&ctx).await
}
/// Returns additional information for single message.
async fn get_message_info_object(
&self,
account_id: u32,
message_id: u32,
) -> Result<MessageInfo> {
let ctx = self.get_context(account_id).await?;
MessageInfo::from_msg_id(&ctx, MsgId::new(message_id)).await
}
/// Returns contacts that sent read receipts and the time of reading.
async fn get_message_read_receipts(
&self,
@@ -2033,13 +2043,19 @@ impl CommandApi {
text: Option<String>,
file: Option<String>,
quoted_message_id: Option<u32>,
view_type: Option<MessageViewtype>,
) -> Result<()> {
let ctx = self.get_context(account_id).await?;
let mut draft = Message::new(if file.is_some() {
Viewtype::File
} else {
Viewtype::Text
});
let mut draft = Message::new(view_type.map_or_else(
|| {
if file.is_some() {
Viewtype::File
} else {
Viewtype::Text
}
},
|v| v.into(),
));
draft.set_text(text.unwrap_or_default());
if let Some(file) = file {
draft.set_file(file, None);

View File

@@ -552,3 +552,71 @@ pub struct MessageReadReceipt {
pub contact_id: u32,
pub timestamp: i64,
}
#[derive(Serialize, TypeDef, schemars::JsonSchema)]
#[serde(rename_all = "camelCase")]
pub struct MessageInfo {
rawtext: String,
ephemeral_timer: EphemeralTimer,
/// When message is ephemeral this contains the timestamp of the message expiry
ephemeral_timestamp: Option<i64>,
error: Option<String>,
rfc724_mid: String,
server_urls: Vec<String>,
hop_info: Option<String>,
}
impl MessageInfo {
pub async fn from_msg_id(context: &Context, msg_id: MsgId) -> Result<Self> {
let message = Message::load_from_db(context, msg_id).await?;
let rawtext = msg_id.rawtext(context).await?;
let ephemeral_timer = message.get_ephemeral_timer().into();
let ephemeral_timestamp = match message.get_ephemeral_timer() {
deltachat::ephemeral::Timer::Disabled => None,
deltachat::ephemeral::Timer::Enabled { .. } => Some(message.get_ephemeral_timestamp()),
};
let server_urls =
MsgId::get_info_server_urls(context, message.rfc724_mid().to_owned()).await?;
let hop_info = msg_id.hop_info(context).await?;
Ok(Self {
rawtext,
ephemeral_timer,
ephemeral_timestamp,
error: message.error(),
rfc724_mid: message.rfc724_mid().to_owned(),
server_urls,
hop_info,
})
}
}
#[derive(
Debug, PartialEq, Eq, Copy, Clone, Serialize, Deserialize, TypeDef, schemars::JsonSchema,
)]
#[serde(rename_all = "camelCase", tag = "variant")]
pub enum EphemeralTimer {
/// Timer is disabled.
Disabled,
/// Timer is enabled.
Enabled {
/// Timer duration in seconds.
///
/// The value cannot be 0.
duration: u32,
},
}
impl From<deltachat::ephemeral::Timer> for EphemeralTimer {
fn from(value: deltachat::ephemeral::Timer) -> Self {
match value {
deltachat::ephemeral::Timer::Disabled => EphemeralTimer::Disabled,
deltachat::ephemeral::Timer::Enabled { duration } => {
EphemeralTimer::Enabled { duration }
}
}
}
}

View File

@@ -55,5 +55,5 @@
},
"type": "module",
"types": "dist/deltachat.d.ts",
"version": "1.127.1"
"version": "1.127.2"
}

View File

@@ -1,6 +1,6 @@
[package]
name = "deltachat-repl"
version = "1.127.1"
version = "1.127.2"
license = "MPL-2.0"
edition = "2021"

View File

@@ -160,11 +160,12 @@ class Chat:
text: Optional[str] = None,
file: Optional[str] = None,
quoted_msg: Optional[int] = None,
viewtype: Optional[str] = None,
) -> None:
"""Set draft message."""
if isinstance(quoted_msg, Message):
quoted_msg = quoted_msg.id
self._rpc.misc_set_draft(self.account.id, self.id, text, file, quoted_msg)
self._rpc.misc_set_draft(self.account.id, self.id, text, file, quoted_msg, viewtype)
def remove_draft(self) -> None:
"""Remove draft message."""

View File

@@ -28,6 +28,6 @@ commands =
ruff src/ examples/ tests/
[pytest]
timeout = 60
timeout = 300
log_cli = true
log_level = info

View File

@@ -1,6 +1,6 @@
[package]
name = "deltachat-rpc-server"
version = "1.127.1"
version = "1.127.2"
description = "DeltaChat JSON-RPC server"
edition = "2021"
readme = "README.md"
@@ -17,7 +17,6 @@ anyhow = "1"
env_logger = { version = "0.10.0" }
futures-lite = "2.0.0"
log = "0.4"
num_cpus = "1"
serde_json = "1.0.105"
serde = { version = "1.0", features = ["derive"] }
tokio = { version = "1.33.0", features = ["io-std"] }

View File

@@ -20,18 +20,9 @@ use tokio::task::JoinHandle;
use tokio_util::sync::CancellationToken;
use yerpc::{RpcClient, RpcSession};
fn main() {
// Build multithreaded runtime with at least two threads.
// This ensures that on systems with one CPU
// such as CI runners there are at least two threads
// and it is more difficult to deadlock.
let r = tokio::runtime::Builder::new_multi_thread()
.worker_threads(std::cmp::max(2, num_cpus::get()))
.enable_all()
.build()
.unwrap()
.block_on(main_impl());
#[tokio::main(flavor = "multi_thread")]
async fn main() {
let r = main_impl().await;
// From tokio documentation:
// "For technical reasons, stdin is implemented by using an ordinary blocking read on a separate
// thread, and it is impossible to cancel that read. This can make shutdown of the runtime hang

View File

@@ -57,7 +57,7 @@ Note that usually a mail is signed by a key that has a UID matching the from add
### Notes:
- We treat protected and non-protected chats the same
- We leave the aeap transition statement away since it seems not to be needed, makes things harder on the sending side, wastes some network traffic, and is worse for privacy (since more pepole know what old addresses you had).
- We leave the aeap transition statement away since it seems not to be needed, makes things harder on the sending side, wastes some network traffic, and is worse for privacy (since more people know what old addresses you had).
- As soon as we encrypt read receipts, sending a read receipt will be enough to tell a lot of people that you transitioned
- AEAP will make the problem of inconsistent group state worse, both because it doesn't work if the message is unencrypted (even if the design allowed it, it would be problematic security-wise) and because some chat partners may have gotten the transition and some not. We should do something against this at some point in the future, like asking the user whether they want to add/remove the members to restore consistent group state.

View File

@@ -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.127.1"
"version": "1.127.2"
}

View File

@@ -85,7 +85,7 @@ commands =
addopts = -v -ra --strict-markers
norecursedirs = .tox
xfail_strict=true
timeout = 150
timeout = 300
timeout_func_only = True
markers =
ignored: ignore this test in default test runs, use --ignored to run.

View File

@@ -1 +1 @@
2023-10-27
2023-10-29

View File

@@ -3,4 +3,4 @@ set -euo pipefail
tox -c deltachat-rpc-client -e py --devenv venv
venv/bin/pip install --upgrade pip
cargo install --path deltachat-rpc-server/ --root "$PWD/venv"
cargo install --path deltachat-rpc-server/ --root "$PWD/venv" --debug

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env bash
set -euo pipefail
cargo install --path deltachat-rpc-server/ --root "$PWD/venv"
cargo install --path deltachat-rpc-server/ --root "$PWD/venv" --debug
PATH="$PWD/venv/bin:$PATH" tox -c deltachat-rpc-client

View File

@@ -192,7 +192,7 @@ in different orders, esp. on creating new groups.
To remove a member, a `Chat-Group-Member-Removed` header must be sent
with the value set to the email-address of the member to remove.
When receiving a `Chat-Group-Member-Removed` header,
only exaxtly the given member has to be removed from the member list.
only exactly the given member has to be removed from the member list.
Messenger clients MUST NOT construct the member list
on other group messages
@@ -339,7 +339,7 @@ only on image changes.
In older specs, the profile-image was sent as an attachment
and `Chat-User-Avatar:` specified its name.
However, it turned out that these attachments are kind of unuexpected to users,
However, it turned out that these attachments are kind of unexpected to users,
therefore the profile-image go to the header now.

View File

@@ -150,21 +150,53 @@ WHERE id=?;
self.0
}
/// Returns raw text of a message, used for message info
pub async fn rawtext(self, context: &Context) -> Result<String> {
Ok(context
.sql
.query_get_value("SELECT txt_raw FROM msgs WHERE id=?", (self,))
.await?
.unwrap_or_default())
}
/// Returns server foldernames and UIDs of a message, used for message info
pub async fn get_info_server_urls(
context: &Context,
rfc724_mid: String,
) -> Result<Vec<String>> {
context
.sql
.query_map(
"SELECT folder, uid FROM imap WHERE rfc724_mid=?",
(rfc724_mid,),
|row| {
let folder: String = row.get("folder")?;
let uid: u32 = row.get("uid")?;
Ok(format!("</{folder}/;UID={uid}>"))
},
|rows| {
rows.collect::<std::result::Result<Vec<_>, _>>()
.map_err(Into::into)
},
)
.await
}
/// Returns information about hops of a message, used for message info
pub async fn hop_info(self, context: &Context) -> Result<Option<String>> {
context
.sql
.query_get_value("SELECT hop_info FROM msgs WHERE id=?", (self,))
.await
}
/// Returns detailed message information in a multi-line text form.
pub async fn get_info(self, context: &Context) -> Result<String> {
let msg = Message::load_from_db(context, self).await?;
let rawtxt: Option<String> = context
.sql
.query_get_value("SELECT txt_raw FROM msgs WHERE id=?", (self,))
.await?;
let rawtxt: String = self.rawtext(context).await?;
let mut ret = String::new();
if rawtxt.is_none() {
ret += &format!("Cannot load message {self}.");
return Ok(ret);
}
let rawtxt = rawtxt.unwrap_or_default();
let rawtxt = truncate(rawtxt.trim(), DC_DESIRED_TEXT_LEN);
let fts = timestamp_to_str(msg.get_timestamp());
@@ -282,32 +314,13 @@ WHERE id=?;
if !msg.rfc724_mid.is_empty() {
ret += &format!("\nMessage-ID: {}", msg.rfc724_mid);
let server_uids = context
.sql
.query_map(
"SELECT folder, uid FROM imap WHERE rfc724_mid=?",
(msg.rfc724_mid,),
|row| {
let folder: String = row.get("folder")?;
let uid: u32 = row.get("uid")?;
Ok((folder, uid))
},
|rows| {
rows.collect::<std::result::Result<Vec<_>, _>>()
.map_err(Into::into)
},
)
.await?;
for (folder, uid) in server_uids {
let server_urls = Self::get_info_server_urls(context, msg.rfc724_mid).await?;
for server_url in server_urls {
// Format as RFC 5092 relative IMAP URL.
ret += &format!("\n</{folder}/;UID={uid}>");
ret += &format!("\n{server_url}");
}
}
let hop_info: Option<String> = context
.sql
.query_get_value("SELECT hop_info FROM msgs WHERE id=?;", (self,))
.await?;
let hop_info = self.hop_info(context).await?;
ret += "\n\n";
ret += &hop_info.unwrap_or_else(|| "No Hop Info".to_owned());
@@ -649,6 +662,12 @@ impl Message {
self.id
}
/// Returns the rfc724 message ID
/// May be empty
pub fn rfc724_mid(&self) -> &str {
&self.rfc724_mid
}
/// Returns the ID of the contact who wrote the message.
pub fn get_from_id(&self) -> ContactId {
self.from_id

View File

@@ -38,11 +38,11 @@ While this describes an already working "proof of concept" usage there are alrea
webxdc empowers FOSS developments in unprecedented ways:
- well-known paradim: use all the existing JS/html5 libraries and designs of your choice
- well-known paradigm: use all the existing JS/html5 libraries and designs of your choice
- quick onboarding: only a handful API methods to learn
- serverless (but really): no worrying about hosting a server or configuring DNS, AWS etc
- permissionless: no worrying about registering at app stores for distribution
- unbuerocratic: no worrying about login/password/expiry procedures or leaks
- unbureaucratic: no worrying about login/password/expiry procedures or leaks
- secure: no worrying about cryptographic algos or e2e-encryption complexity
On the flip side, you need to learn how to do state updates between instances of your webxdc apps. This is a classic P2P problem and there are simple (send full state update) and advanced ways (use CRDTs or similar) to arrange decentralized state. In any case, there is no DHT let alone blockchain needed and thus no Crypto or coin needed, either.