mirror of
https://github.com/chatmail/core.git
synced 2026-05-07 17:06:35 +03:00
upgrade repl
This commit is contained in:
11
Cargo.lock
generated
11
Cargo.lock
generated
@@ -50,6 +50,14 @@ dependencies = [
|
|||||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ansi_term"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "arrayref"
|
name = "arrayref"
|
||||||
version = "0.3.6"
|
version = "0.3.6"
|
||||||
@@ -619,6 +627,7 @@ dependencies = [
|
|||||||
name = "deltachat"
|
name = "deltachat"
|
||||||
version = "1.27.0"
|
version = "1.27.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"ansi_term 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"async-imap 0.2.0 (git+https://github.com/async-email/async-imap?branch=feat/send)",
|
"async-imap 0.2.0 (git+https://github.com/async-email/async-imap?branch=feat/send)",
|
||||||
"async-native-tls 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"async-native-tls 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"async-smtp 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"async-smtp 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@@ -646,6 +655,7 @@ dependencies = [
|
|||||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"lettre_email 0.9.2 (git+https://github.com/deltachat/lettre)",
|
"lettre_email 0.9.2 (git+https://github.com/deltachat/lettre)",
|
||||||
"libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"mailparse 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"mailparse 0.10.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"native-tls 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"native-tls 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"num-derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@@ -3139,6 +3149,7 @@ dependencies = [
|
|||||||
"checksum aesni 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f70a6b5f971e473091ab7cfb5ffac6cde81666c4556751d8d5620ead8abf100"
|
"checksum aesni 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f70a6b5f971e473091ab7cfb5ffac6cde81666c4556751d8d5620ead8abf100"
|
||||||
"checksum aho-corasick 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada"
|
"checksum aho-corasick 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada"
|
||||||
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
|
||||||
|
"checksum ansi_term 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
||||||
"checksum arrayref 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
|
"checksum arrayref 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
|
||||||
"checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9"
|
"checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9"
|
||||||
"checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
|
"checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
|
||||||
|
|||||||
13
Cargo.toml
13
Cargo.toml
@@ -57,12 +57,15 @@ mailparse = "0.10.2"
|
|||||||
encoded-words = { git = "https://github.com/async-email/encoded-words", branch="master" }
|
encoded-words = { git = "https://github.com/async-email/encoded-words", branch="master" }
|
||||||
native-tls = "0.2.3"
|
native-tls = "0.2.3"
|
||||||
image = { version = "0.22.4", default-features=false, features = ["gif_codec", "jpeg", "ico", "png_codec", "pnm", "webp", "bmp"] }
|
image = { version = "0.22.4", default-features=false, features = ["gif_codec", "jpeg", "ico", "png_codec", "pnm", "webp", "bmp"] }
|
||||||
pretty_env_logger = "0.3.1"
|
|
||||||
|
|
||||||
rustyline = { version = "4.1.0", optional = true }
|
|
||||||
futures = "0.3.4"
|
futures = "0.3.4"
|
||||||
crossbeam-queue = "0.2.1"
|
crossbeam-queue = "0.2.1"
|
||||||
|
|
||||||
|
|
||||||
|
pretty_env_logger = { version = "0.3.1", optional = true }
|
||||||
|
log = {version = "0.4.8", optional = true }
|
||||||
|
rustyline = { version = "4.1.0", optional = true }
|
||||||
|
ansi_term = { version = "0.12.1", optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tempfile = "3.0"
|
tempfile = "3.0"
|
||||||
pretty_assertions = "0.6.1"
|
pretty_assertions = "0.6.1"
|
||||||
@@ -83,10 +86,12 @@ path = "examples/simple.rs"
|
|||||||
[[example]]
|
[[example]]
|
||||||
name = "repl"
|
name = "repl"
|
||||||
path = "examples/repl/main.rs"
|
path = "examples/repl/main.rs"
|
||||||
required-features = ["rustyline"]
|
required-features = ["repl"]
|
||||||
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["nightly"]
|
default = ["nightly"]
|
||||||
|
internals = []
|
||||||
|
repl = ["internals", "rustyline", "log", "pretty_env_logger", "ansi_term"]
|
||||||
vendored = ["async-native-tls/vendored", "reqwest/native-tls-vendored", "async-smtp/native-tls-vendored"]
|
vendored = ["async-native-tls/vendored", "reqwest/native-tls-vendored", "async-smtp/native-tls-vendored"]
|
||||||
nightly = ["pgp/nightly"]
|
nightly = ["pgp/nightly"]
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
To download and install the official compiler for the Rust programming language, and the Cargo package manager, run the command in your user environment:
|
To download and install the official compiler for the Rust programming language, and the Cargo package manager, run the command in your user environment:
|
||||||
|
|
||||||
```
|
```
|
||||||
curl https://sh.rustup.rs -sSf | sh
|
$ curl https://sh.rustup.rs -sSf | sh
|
||||||
```
|
```
|
||||||
|
|
||||||
## Using the CLI client
|
## Using the CLI client
|
||||||
@@ -17,7 +17,7 @@ curl https://sh.rustup.rs -sSf | sh
|
|||||||
Compile and run Delta Chat Core command line utility, using `cargo`:
|
Compile and run Delta Chat Core command line utility, using `cargo`:
|
||||||
|
|
||||||
```
|
```
|
||||||
cargo run --example repl -- /path/to/db
|
$ RUST_LOG=info cargo run --example repl --features repl -- /path/to/db
|
||||||
```
|
```
|
||||||
|
|
||||||
Configure your account (if not already configured):
|
Configure your account (if not already configured):
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use std::path::Path;
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use async_std::path::Path;
|
||||||
|
|
||||||
use deltachat::chat::{self, Chat, ChatId, ChatVisibility};
|
use deltachat::chat::{self, Chat, ChatId, ChatVisibility};
|
||||||
use deltachat::chatlist::*;
|
use deltachat::chatlist::*;
|
||||||
use deltachat::constants::*;
|
use deltachat::constants::*;
|
||||||
@@ -10,7 +11,6 @@ use deltachat::dc_receive_imf::*;
|
|||||||
use deltachat::dc_tools::*;
|
use deltachat::dc_tools::*;
|
||||||
use deltachat::error::Error;
|
use deltachat::error::Error;
|
||||||
use deltachat::imex::*;
|
use deltachat::imex::*;
|
||||||
use deltachat::job::*;
|
|
||||||
use deltachat::location;
|
use deltachat::location;
|
||||||
use deltachat::lot::LotState;
|
use deltachat::lot::LotState;
|
||||||
use deltachat::message::{self, Message, MessageState, MsgId};
|
use deltachat::message::{self, Message, MessageState, MsgId};
|
||||||
@@ -23,63 +23,66 @@ use deltachat::{config, provider};
|
|||||||
/// Reset database tables.
|
/// Reset database tables.
|
||||||
/// Argument is a bitmask, executing single or multiple actions in one call.
|
/// Argument is a bitmask, executing single or multiple actions in one call.
|
||||||
/// e.g. bitmask 7 triggers actions definded with bits 1, 2 and 4.
|
/// e.g. bitmask 7 triggers actions definded with bits 1, 2 and 4.
|
||||||
fn dc_reset_tables(context: &Context, bits: i32) -> i32 {
|
async fn reset_tables(context: &Context, bits: i32) {
|
||||||
println!("Resetting tables ({})...", bits);
|
println!("Resetting tables ({})...", bits);
|
||||||
if 0 != bits & 1 {
|
if 0 != bits & 1 {
|
||||||
sql::execute(context, &context.sql, "DELETE FROM jobs;", params![]).unwrap();
|
context
|
||||||
|
.sql()
|
||||||
|
.execute("DELETE FROM jobs;", paramsv![])
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
println!("(1) Jobs reset.");
|
println!("(1) Jobs reset.");
|
||||||
}
|
}
|
||||||
if 0 != bits & 2 {
|
if 0 != bits & 2 {
|
||||||
sql::execute(
|
context
|
||||||
context,
|
.sql()
|
||||||
&context.sql,
|
.execute("DELETE FROM acpeerstates;", paramsv![])
|
||||||
"DELETE FROM acpeerstates;",
|
.await
|
||||||
params![],
|
.unwrap();
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
println!("(2) Peerstates reset.");
|
println!("(2) Peerstates reset.");
|
||||||
}
|
}
|
||||||
if 0 != bits & 4 {
|
if 0 != bits & 4 {
|
||||||
sql::execute(context, &context.sql, "DELETE FROM keypairs;", params![]).unwrap();
|
context
|
||||||
|
.sql()
|
||||||
|
.execute("DELETE FROM keypairs;", paramsv![])
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
println!("(4) Private keypairs reset.");
|
println!("(4) Private keypairs reset.");
|
||||||
}
|
}
|
||||||
if 0 != bits & 8 {
|
if 0 != bits & 8 {
|
||||||
sql::execute(
|
context
|
||||||
context,
|
.sql()
|
||||||
&context.sql,
|
.execute("DELETE FROM contacts WHERE id>9;", paramsv![])
|
||||||
"DELETE FROM contacts WHERE id>9;",
|
.await
|
||||||
params![],
|
.unwrap();
|
||||||
)
|
context
|
||||||
.unwrap();
|
.sql()
|
||||||
sql::execute(
|
.execute("DELETE FROM chats WHERE id>9;", paramsv![])
|
||||||
context,
|
.await
|
||||||
&context.sql,
|
.unwrap();
|
||||||
"DELETE FROM chats WHERE id>9;",
|
context
|
||||||
params![],
|
.sql()
|
||||||
)
|
.execute("DELETE FROM chats_contacts;", paramsv![])
|
||||||
.unwrap();
|
.await
|
||||||
sql::execute(
|
.unwrap();
|
||||||
context,
|
context
|
||||||
&context.sql,
|
.sql()
|
||||||
"DELETE FROM chats_contacts;",
|
.execute("DELETE FROM msgs WHERE id>9;", paramsv![])
|
||||||
params![],
|
.await
|
||||||
)
|
.unwrap();
|
||||||
.unwrap();
|
context
|
||||||
sql::execute(
|
.sql()
|
||||||
context,
|
.execute(
|
||||||
&context.sql,
|
"DELETE FROM config WHERE keyname LIKE 'imap.%' OR keyname LIKE 'configured%';",
|
||||||
"DELETE FROM msgs WHERE id>9;",
|
paramsv![],
|
||||||
params![],
|
)
|
||||||
)
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
sql::execute(
|
context
|
||||||
context,
|
.sql()
|
||||||
&context.sql,
|
.execute("DELETE FROM leftgrps;", paramsv![])
|
||||||
"DELETE FROM config WHERE keyname LIKE 'imap.%' OR keyname LIKE 'configured%';",
|
.await
|
||||||
params![],
|
.unwrap();
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
sql::execute(context, &context.sql, "DELETE FROM leftgrps;", params![]).unwrap();
|
|
||||||
println!("(8) Rest but server config reset.");
|
println!("(8) Rest but server config reset.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,14 +90,12 @@ fn dc_reset_tables(context: &Context, bits: i32) -> i32 {
|
|||||||
chat_id: ChatId::new(0),
|
chat_id: ChatId::new(0),
|
||||||
msg_id: MsgId::new(0),
|
msg_id: MsgId::new(0),
|
||||||
});
|
});
|
||||||
|
|
||||||
1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn dc_poke_eml_file(context: &Context, filename: impl AsRef<Path>) -> Result<(), Error> {
|
async fn poke_eml_file(context: &Context, filename: impl AsRef<Path>) -> Result<(), Error> {
|
||||||
let data = dc_read_file(context, filename)?;
|
let data = dc_read_file(context, filename).await?;
|
||||||
|
|
||||||
if let Err(err) = dc_receive_imf(context, &data, "import", 0, false) {
|
if let Err(err) = dc_receive_imf(context, &data, "import", 0, false).await {
|
||||||
println!("dc_receive_imf errored: {:?}", err);
|
println!("dc_receive_imf errored: {:?}", err);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -103,38 +104,29 @@ fn dc_poke_eml_file(context: &Context, filename: impl AsRef<Path>) -> Result<(),
|
|||||||
/// Import a file to the database.
|
/// Import a file to the database.
|
||||||
/// For testing, import a folder with eml-files, a single eml-file, e-mail plus public key and so on.
|
/// For testing, import a folder with eml-files, a single eml-file, e-mail plus public key and so on.
|
||||||
/// For normal importing, use imex().
|
/// For normal importing, use imex().
|
||||||
///
|
async fn poke_spec(context: &Context, spec: Option<&str>) -> bool {
|
||||||
/// @private @memberof Context
|
let mut read_cnt: usize = 0;
|
||||||
/// @param context The context as created by dc_context_new().
|
|
||||||
/// @param spec The file or directory to import. NULL for the last command.
|
|
||||||
/// @return 1=success, 0=error.
|
|
||||||
fn poke_spec(context: &Context, spec: Option<&str>) -> libc::c_int {
|
|
||||||
if !context.sql.is_open() {
|
|
||||||
error!(context, "Import: Database not opened.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut read_cnt = 0;
|
|
||||||
|
|
||||||
let real_spec: String;
|
let real_spec: String;
|
||||||
|
|
||||||
/* if `spec` is given, remember it for later usage; if it is not given, try to use the last one */
|
// if `spec` is given, remember it for later usage; if it is not given, try to use the last one
|
||||||
if let Some(spec) = spec {
|
if let Some(spec) = spec {
|
||||||
real_spec = spec.to_string();
|
real_spec = spec.to_string();
|
||||||
context
|
context
|
||||||
.sql
|
.sql()
|
||||||
.set_raw_config(context, "import_spec", Some(&real_spec))
|
.set_raw_config(context, "import_spec", Some(&real_spec))
|
||||||
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
} else {
|
} else {
|
||||||
let rs = context.sql.get_raw_config(context, "import_spec");
|
let rs = context.sql().get_raw_config(context, "import_spec").await;
|
||||||
if rs.is_none() {
|
if rs.is_none() {
|
||||||
error!(context, "Import: No file or folder given.");
|
error!(context, "Import: No file or folder given.");
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
real_spec = rs.unwrap();
|
real_spec = rs.unwrap();
|
||||||
}
|
}
|
||||||
if let Some(suffix) = dc_get_filesuffix_lc(&real_spec) {
|
if let Some(suffix) = dc_get_filesuffix_lc(&real_spec) {
|
||||||
if suffix == "eml" && dc_poke_eml_file(context, &real_spec).is_ok() {
|
if suffix == "eml" && poke_eml_file(context, &real_spec).await.is_ok() {
|
||||||
read_cnt += 1
|
read_cnt += 1
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -143,7 +135,7 @@ fn poke_spec(context: &Context, spec: Option<&str>) -> libc::c_int {
|
|||||||
let dir = std::fs::read_dir(dir_name);
|
let dir = std::fs::read_dir(dir_name);
|
||||||
if dir.is_err() {
|
if dir.is_err() {
|
||||||
error!(context, "Import: Cannot open directory \"{}\".", &real_spec,);
|
error!(context, "Import: Cannot open directory \"{}\".", &real_spec,);
|
||||||
return 0;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
let dir = dir.unwrap();
|
let dir = dir.unwrap();
|
||||||
for entry in dir {
|
for entry in dir {
|
||||||
@@ -156,7 +148,7 @@ fn poke_spec(context: &Context, spec: Option<&str>) -> libc::c_int {
|
|||||||
if name.ends_with(".eml") {
|
if name.ends_with(".eml") {
|
||||||
let path_plus_name = format!("{}/{}", &real_spec, name);
|
let path_plus_name = format!("{}/{}", &real_spec, name);
|
||||||
println!("Import: {}", path_plus_name);
|
println!("Import: {}", path_plus_name);
|
||||||
if dc_poke_eml_file(context, path_plus_name).is_ok() {
|
if poke_eml_file(context, path_plus_name).await.is_ok() {
|
||||||
read_cnt += 1
|
read_cnt += 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -170,11 +162,14 @@ fn poke_spec(context: &Context, spec: Option<&str>) -> libc::c_int {
|
|||||||
msg_id: MsgId::new(0),
|
msg_id: MsgId::new(0),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
1
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn log_msg(context: &Context, prefix: impl AsRef<str>, msg: &Message) {
|
async fn log_msg(context: &Context, prefix: impl AsRef<str>, msg: &Message) {
|
||||||
let contact = Contact::get_by_id(context, msg.get_from_id()).expect("invalid contact");
|
let contact = Contact::get_by_id(context, msg.get_from_id())
|
||||||
|
.await
|
||||||
|
.expect("invalid contact");
|
||||||
|
|
||||||
let contact_name = contact.get_name();
|
let contact_name = contact.get_name();
|
||||||
let contact_id = contact.get_id();
|
let contact_id = contact.get_id();
|
||||||
|
|
||||||
@@ -217,7 +212,7 @@ fn log_msg(context: &Context, prefix: impl AsRef<str>, msg: &Message) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn log_msglist(context: &Context, msglist: &Vec<MsgId>) -> Result<(), Error> {
|
async fn log_msglist(context: &Context, msglist: &Vec<MsgId>) -> Result<(), Error> {
|
||||||
let mut lines_out = 0;
|
let mut lines_out = 0;
|
||||||
for &msg_id in msglist {
|
for &msg_id in msglist {
|
||||||
if msg_id.is_daymarker() {
|
if msg_id.is_daymarker() {
|
||||||
@@ -233,8 +228,8 @@ fn log_msglist(context: &Context, msglist: &Vec<MsgId>) -> Result<(), Error> {
|
|||||||
);
|
);
|
||||||
lines_out += 1
|
lines_out += 1
|
||||||
}
|
}
|
||||||
let msg = Message::load_from_db(context, msg_id)?;
|
let msg = Message::load_from_db(context, msg_id).await?;
|
||||||
log_msg(context, "", &msg);
|
log_msg(context, "", &msg).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if lines_out > 0 {
|
if lines_out > 0 {
|
||||||
@@ -245,7 +240,7 @@ fn log_msglist(context: &Context, msglist: &Vec<MsgId>) -> Result<(), Error> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn log_contactlist(context: &Context, contacts: &Vec<u32>) {
|
async fn log_contactlist(context: &Context, contacts: &Vec<u32>) {
|
||||||
let mut contacts = contacts.clone();
|
let mut contacts = contacts.clone();
|
||||||
if !contacts.contains(&1) {
|
if !contacts.contains(&1) {
|
||||||
contacts.push(1);
|
contacts.push(1);
|
||||||
@@ -253,10 +248,10 @@ fn log_contactlist(context: &Context, contacts: &Vec<u32>) {
|
|||||||
for contact_id in contacts {
|
for contact_id in contacts {
|
||||||
let line;
|
let line;
|
||||||
let mut line2 = "".to_string();
|
let mut line2 = "".to_string();
|
||||||
if let Ok(contact) = Contact::get_by_id(context, contact_id) {
|
if let Ok(contact) = Contact::get_by_id(context, contact_id).await {
|
||||||
let name = contact.get_name();
|
let name = contact.get_name();
|
||||||
let addr = contact.get_addr();
|
let addr = contact.get_addr();
|
||||||
let verified_state = contact.is_verified(context);
|
let verified_state = contact.is_verified(context).await;
|
||||||
let verified_str = if VerifiedStatus::Unverified != verified_state {
|
let verified_str = if VerifiedStatus::Unverified != verified_state {
|
||||||
if verified_state == VerifiedStatus::BidirectVerified {
|
if verified_state == VerifiedStatus::BidirectVerified {
|
||||||
" √√"
|
" √√"
|
||||||
@@ -280,7 +275,7 @@ fn log_contactlist(context: &Context, contacts: &Vec<u32>) {
|
|||||||
"addr unset"
|
"addr unset"
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
let peerstate = Peerstate::from_addr(context, &context.sql, &addr);
|
let peerstate = Peerstate::from_addr(context, &addr).await;
|
||||||
if peerstate.is_some() && contact_id != 1 as libc::c_uint {
|
if peerstate.is_some() && contact_id != 1 as libc::c_uint {
|
||||||
line2 = format!(
|
line2 = format!(
|
||||||
", prefer-encrypt={}",
|
", prefer-encrypt={}",
|
||||||
@@ -297,10 +292,13 @@ fn chat_prefix(chat: &Chat) -> &'static str {
|
|||||||
chat.typ.into()
|
chat.typ.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::Error> {
|
pub async fn cmdline(
|
||||||
let chat_id = *context.cmdline_sel_chat_id.read().unwrap();
|
context: Context,
|
||||||
|
line: &str,
|
||||||
|
chat_id: &mut ChatId,
|
||||||
|
) -> Result<(), failure::Error> {
|
||||||
let mut sel_chat = if !chat_id.is_unset() {
|
let mut sel_chat = if !chat_id.is_unset() {
|
||||||
Chat::load_from_db(context, chat_id).ok()
|
Chat::load_from_db(&context, *chat_id).await.ok()
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
@@ -341,7 +339,6 @@ pub fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::Error> {
|
|||||||
configure\n\
|
configure\n\
|
||||||
connect\n\
|
connect\n\
|
||||||
disconnect\n\
|
disconnect\n\
|
||||||
interrupt\n\
|
|
||||||
maybenetwork\n\
|
maybenetwork\n\
|
||||||
housekeeping\n\
|
housekeeping\n\
|
||||||
help imex (Import/Export)\n\
|
help imex (Import/Export)\n\
|
||||||
@@ -403,7 +400,7 @@ pub fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::Error> {
|
|||||||
============================================="
|
============================================="
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
"initiate-key-transfer" => match initiate_key_transfer(context) {
|
"initiate-key-transfer" => match initiate_key_transfer(&context).await {
|
||||||
Ok(setup_code) => println!(
|
Ok(setup_code) => println!(
|
||||||
"Setup code for the transferred setup message: {}",
|
"Setup code for the transferred setup message: {}",
|
||||||
setup_code,
|
setup_code,
|
||||||
@@ -413,9 +410,9 @@ pub fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::Error> {
|
|||||||
"get-setupcodebegin" => {
|
"get-setupcodebegin" => {
|
||||||
ensure!(!arg1.is_empty(), "Argument <msg-id> missing.");
|
ensure!(!arg1.is_empty(), "Argument <msg-id> missing.");
|
||||||
let msg_id: MsgId = MsgId::new(arg1.parse()?);
|
let msg_id: MsgId = MsgId::new(arg1.parse()?);
|
||||||
let msg = Message::load_from_db(context, msg_id)?;
|
let msg = Message::load_from_db(&context, msg_id).await?;
|
||||||
if msg.is_setupmessage() {
|
if msg.is_setupmessage() {
|
||||||
let setupcodebegin = msg.get_setupcodebegin(context);
|
let setupcodebegin = msg.get_setupcodebegin(&context).await;
|
||||||
println!(
|
println!(
|
||||||
"The setup code for setup message {} starts with: {}",
|
"The setup code for setup message {} starts with: {}",
|
||||||
msg_id,
|
msg_id,
|
||||||
@@ -430,29 +427,29 @@ pub fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::Error> {
|
|||||||
!arg1.is_empty() && !arg2.is_empty(),
|
!arg1.is_empty() && !arg2.is_empty(),
|
||||||
"Arguments <msg-id> <setup-code> expected"
|
"Arguments <msg-id> <setup-code> expected"
|
||||||
);
|
);
|
||||||
continue_key_transfer(context, MsgId::new(arg1.parse()?), &arg2)?;
|
continue_key_transfer(&context, MsgId::new(arg1.parse()?), &arg2).await?;
|
||||||
}
|
}
|
||||||
"has-backup" => {
|
"has-backup" => {
|
||||||
has_backup(context, blobdir)?;
|
has_backup(&context, blobdir).await?;
|
||||||
}
|
}
|
||||||
"export-backup" => {
|
"export-backup" => {
|
||||||
imex(context, ImexMode::ExportBackup, Some(blobdir));
|
imex(&context, ImexMode::ExportBackup, Some(blobdir)).await?;
|
||||||
}
|
}
|
||||||
"import-backup" => {
|
"import-backup" => {
|
||||||
ensure!(!arg1.is_empty(), "Argument <backup-file> missing.");
|
ensure!(!arg1.is_empty(), "Argument <backup-file> missing.");
|
||||||
imex(context, ImexMode::ImportBackup, Some(arg1));
|
imex(&context, ImexMode::ImportBackup, Some(arg1)).await?;
|
||||||
}
|
}
|
||||||
"export-keys" => {
|
"export-keys" => {
|
||||||
imex(context, ImexMode::ExportSelfKeys, Some(blobdir));
|
imex(&context, ImexMode::ExportSelfKeys, Some(blobdir)).await?;
|
||||||
}
|
}
|
||||||
"import-keys" => {
|
"import-keys" => {
|
||||||
imex(context, ImexMode::ImportSelfKeys, Some(blobdir));
|
imex(&context, ImexMode::ImportSelfKeys, Some(blobdir)).await?;
|
||||||
}
|
}
|
||||||
"export-setup" => {
|
"export-setup" => {
|
||||||
let setup_code = create_setup_code(context);
|
let setup_code = create_setup_code(&context);
|
||||||
let file_name = blobdir.join("autocrypt-setup-message.html");
|
let file_name = blobdir.join("autocrypt-setup-message.html");
|
||||||
let file_content = render_setup_file(context, &setup_code)?;
|
let file_content = render_setup_file(&context, &setup_code).await?;
|
||||||
std::fs::write(&file_name, file_content)?;
|
async_std::fs::write(&file_name, file_content).await?;
|
||||||
println!(
|
println!(
|
||||||
"Setup message written to: {}\nSetup code: {}",
|
"Setup message written to: {}\nSetup code: {}",
|
||||||
file_name.display(),
|
file_name.display(),
|
||||||
@@ -460,49 +457,47 @@ pub fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::Error> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
"poke" => {
|
"poke" => {
|
||||||
ensure!(0 != poke_spec(context, Some(arg1)), "Poke failed");
|
ensure!(poke_spec(&context, Some(arg1)).await, "Poke failed");
|
||||||
}
|
}
|
||||||
"reset" => {
|
"reset" => {
|
||||||
ensure!(!arg1.is_empty(), "Argument <bits> missing: 1=jobs, 2=peerstates, 4=private keys, 8=rest but server config");
|
ensure!(!arg1.is_empty(), "Argument <bits> missing: 1=jobs, 2=peerstates, 4=private keys, 8=rest but server config");
|
||||||
let bits: i32 = arg1.parse()?;
|
let bits: i32 = arg1.parse()?;
|
||||||
ensure!(bits < 16, "<bits> must be lower than 16.");
|
ensure!(bits < 16, "<bits> must be lower than 16.");
|
||||||
ensure!(0 != dc_reset_tables(context, bits), "Reset failed");
|
reset_tables(&context, bits).await;
|
||||||
}
|
}
|
||||||
"stop" => {
|
"stop" => {
|
||||||
context.stop_ongoing();
|
context.stop_ongoing().await;
|
||||||
}
|
}
|
||||||
"set" => {
|
"set" => {
|
||||||
ensure!(!arg1.is_empty(), "Argument <key> missing.");
|
ensure!(!arg1.is_empty(), "Argument <key> missing.");
|
||||||
let key = config::Config::from_str(&arg1)?;
|
let key = config::Config::from_str(&arg1)?;
|
||||||
let value = if arg2.is_empty() { None } else { Some(arg2) };
|
let value = if arg2.is_empty() { None } else { Some(arg2) };
|
||||||
context.set_config(key, value)?;
|
context.set_config(key, value).await?;
|
||||||
}
|
}
|
||||||
"get" => {
|
"get" => {
|
||||||
ensure!(!arg1.is_empty(), "Argument <key> missing.");
|
ensure!(!arg1.is_empty(), "Argument <key> missing.");
|
||||||
let key = config::Config::from_str(&arg1)?;
|
let key = config::Config::from_str(&arg1)?;
|
||||||
let val = context.get_config(key);
|
let val = context.get_config(key).await;
|
||||||
println!("{}={:?}", key, val);
|
println!("{}={:?}", key, val);
|
||||||
}
|
}
|
||||||
"info" => {
|
"info" => {
|
||||||
println!("{:#?}", context.get_info());
|
println!("{:#?}", context.get_info().await);
|
||||||
}
|
|
||||||
"interrupt" => {
|
|
||||||
interrupt_inbox_idle(context);
|
|
||||||
}
|
}
|
||||||
"maybenetwork" => {
|
"maybenetwork" => {
|
||||||
maybe_network(context);
|
context.maybe_network().await;
|
||||||
}
|
}
|
||||||
"housekeeping" => {
|
"housekeeping" => {
|
||||||
sql::housekeeping(context);
|
sql::housekeeping(&context).await;
|
||||||
}
|
}
|
||||||
"listchats" | "listarchived" | "chats" => {
|
"listchats" | "listarchived" | "chats" => {
|
||||||
let listflags = if arg0 == "listarchived" { 0x01 } else { 0 };
|
let listflags = if arg0 == "listarchived" { 0x01 } else { 0 };
|
||||||
let chatlist = Chatlist::try_load(
|
let chatlist = Chatlist::try_load(
|
||||||
context,
|
&context,
|
||||||
listflags,
|
listflags,
|
||||||
if arg1.is_empty() { None } else { Some(arg1) },
|
if arg1.is_empty() { None } else { Some(arg1) },
|
||||||
None,
|
None,
|
||||||
)?;
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
let cnt = chatlist.len();
|
let cnt = chatlist.len();
|
||||||
if cnt > 0 {
|
if cnt > 0 {
|
||||||
@@ -511,20 +506,20 @@ pub fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::Error> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
for i in (0..cnt).rev() {
|
for i in (0..cnt).rev() {
|
||||||
let chat = Chat::load_from_db(context, chatlist.get_chat_id(i))?;
|
let chat = Chat::load_from_db(&context, chatlist.get_chat_id(i)).await?;
|
||||||
println!(
|
println!(
|
||||||
"{}#{}: {} [{} fresh] {}",
|
"{}#{}: {} [{} fresh] {}",
|
||||||
chat_prefix(&chat),
|
chat_prefix(&chat),
|
||||||
chat.get_id(),
|
chat.get_id(),
|
||||||
chat.get_name(),
|
chat.get_name(),
|
||||||
chat.get_id().get_fresh_msg_cnt(context),
|
chat.get_id().get_fresh_msg_cnt(&context).await,
|
||||||
match chat.visibility {
|
match chat.visibility {
|
||||||
ChatVisibility::Normal => "",
|
ChatVisibility::Normal => "",
|
||||||
ChatVisibility::Archived => "📦",
|
ChatVisibility::Archived => "📦",
|
||||||
ChatVisibility::Pinned => "📌",
|
ChatVisibility::Pinned => "📌",
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
let lot = chatlist.get_summary(context, i, Some(&chat));
|
let lot = chatlist.get_summary(&context, i, Some(&chat)).await;
|
||||||
let statestr = if chat.visibility == ChatVisibility::Archived {
|
let statestr = if chat.visibility == ChatVisibility::Archived {
|
||||||
" [Archived]"
|
" [Archived]"
|
||||||
} else {
|
} else {
|
||||||
@@ -557,7 +552,7 @@ pub fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::Error> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if location::is_sending_locations_to_chat(context, ChatId::new(0)) {
|
if location::is_sending_locations_to_chat(&context, ChatId::new(0)).await {
|
||||||
println!("Location streaming enabled.");
|
println!("Location streaming enabled.");
|
||||||
}
|
}
|
||||||
println!("{} chats", cnt);
|
println!("{} chats", cnt);
|
||||||
@@ -567,21 +562,21 @@ pub fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::Error> {
|
|||||||
bail!("Argument [chat-id] is missing.");
|
bail!("Argument [chat-id] is missing.");
|
||||||
}
|
}
|
||||||
if !arg1.is_empty() {
|
if !arg1.is_empty() {
|
||||||
let chat_id = ChatId::new(arg1.parse()?);
|
let id = ChatId::new(arg1.parse()?);
|
||||||
println!("Selecting chat {}", chat_id);
|
println!("Selecting chat {}", id);
|
||||||
sel_chat = Some(Chat::load_from_db(context, chat_id)?);
|
sel_chat = Some(Chat::load_from_db(&context, id).await?);
|
||||||
*context.cmdline_sel_chat_id.write().unwrap() = chat_id;
|
*chat_id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
ensure!(sel_chat.is_some(), "Failed to select chat");
|
ensure!(sel_chat.is_some(), "Failed to select chat");
|
||||||
let sel_chat = sel_chat.as_ref().unwrap();
|
let sel_chat = sel_chat.as_ref().unwrap();
|
||||||
|
|
||||||
let msglist = chat::get_chat_msgs(context, sel_chat.get_id(), 0x1, None);
|
let msglist = chat::get_chat_msgs(&context, sel_chat.get_id(), 0x1, None).await;
|
||||||
let members = chat::get_chat_contacts(context, sel_chat.id);
|
let members = chat::get_chat_contacts(&context, sel_chat.id).await;
|
||||||
let subtitle = if sel_chat.is_device_talk() {
|
let subtitle = if sel_chat.is_device_talk() {
|
||||||
"device-talk".to_string()
|
"device-talk".to_string()
|
||||||
} else if sel_chat.get_type() == Chattype::Single && !members.is_empty() {
|
} else if sel_chat.get_type() == Chattype::Single && !members.is_empty() {
|
||||||
let contact = Contact::get_by_id(context, members[0])?;
|
let contact = Contact::get_by_id(&context, members[0]).await?;
|
||||||
contact.get_addr().to_string()
|
contact.get_addr().to_string()
|
||||||
} else {
|
} else {
|
||||||
format!("{} member(s)", members.len())
|
format!("{} member(s)", members.len())
|
||||||
@@ -597,7 +592,7 @@ pub fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::Error> {
|
|||||||
} else {
|
} else {
|
||||||
""
|
""
|
||||||
},
|
},
|
||||||
match sel_chat.get_profile_image(context) {
|
match sel_chat.get_profile_image(&context).await {
|
||||||
Some(icon) => match icon.to_str() {
|
Some(icon) => match icon.to_str() {
|
||||||
Some(icon) => format!(" Icon: {}", icon),
|
Some(icon) => format!(" Icon: {}", icon),
|
||||||
_ => " Icon: Err".to_string(),
|
_ => " Icon: Err".to_string(),
|
||||||
@@ -605,38 +600,42 @@ pub fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::Error> {
|
|||||||
_ => "".to_string(),
|
_ => "".to_string(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
log_msglist(context, &msglist)?;
|
log_msglist(&context, &msglist).await?;
|
||||||
if let Some(draft) = sel_chat.get_id().get_draft(context)? {
|
if let Some(draft) = sel_chat.get_id().get_draft(&context).await? {
|
||||||
log_msg(context, "Draft", &draft);
|
log_msg(&context, "Draft", &draft).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("{} messages.", sel_chat.get_id().get_msg_cnt(context));
|
println!(
|
||||||
chat::marknoticed_chat(context, sel_chat.get_id())?;
|
"{} messages.",
|
||||||
|
sel_chat.get_id().get_msg_cnt(&context).await
|
||||||
|
);
|
||||||
|
chat::marknoticed_chat(&context, sel_chat.get_id()).await?;
|
||||||
}
|
}
|
||||||
"createchat" => {
|
"createchat" => {
|
||||||
ensure!(!arg1.is_empty(), "Argument <contact-id> missing.");
|
ensure!(!arg1.is_empty(), "Argument <contact-id> missing.");
|
||||||
let contact_id: libc::c_int = arg1.parse()?;
|
let contact_id: libc::c_int = arg1.parse()?;
|
||||||
let chat_id = chat::create_by_contact_id(context, contact_id as u32)?;
|
let chat_id = chat::create_by_contact_id(&context, contact_id as u32).await?;
|
||||||
|
|
||||||
println!("Single#{} created successfully.", chat_id,);
|
println!("Single#{} created successfully.", chat_id,);
|
||||||
}
|
}
|
||||||
"createchatbymsg" => {
|
"createchatbymsg" => {
|
||||||
ensure!(!arg1.is_empty(), "Argument <msg-id> missing");
|
ensure!(!arg1.is_empty(), "Argument <msg-id> missing");
|
||||||
let msg_id = MsgId::new(arg1.parse()?);
|
let msg_id = MsgId::new(arg1.parse()?);
|
||||||
let chat_id = chat::create_by_msg_id(context, msg_id)?;
|
let chat_id = chat::create_by_msg_id(&context, msg_id).await?;
|
||||||
let chat = Chat::load_from_db(context, chat_id)?;
|
let chat = Chat::load_from_db(&context, chat_id).await?;
|
||||||
|
|
||||||
println!("{}#{} created successfully.", chat_prefix(&chat), chat_id,);
|
println!("{}#{} created successfully.", chat_prefix(&chat), chat_id,);
|
||||||
}
|
}
|
||||||
"creategroup" => {
|
"creategroup" => {
|
||||||
ensure!(!arg1.is_empty(), "Argument <name> missing.");
|
ensure!(!arg1.is_empty(), "Argument <name> missing.");
|
||||||
let chat_id = chat::create_group_chat(context, VerifiedStatus::Unverified, arg1)?;
|
let chat_id =
|
||||||
|
chat::create_group_chat(&context, VerifiedStatus::Unverified, arg1).await?;
|
||||||
|
|
||||||
println!("Group#{} created successfully.", chat_id);
|
println!("Group#{} created successfully.", chat_id);
|
||||||
}
|
}
|
||||||
"createverified" => {
|
"createverified" => {
|
||||||
ensure!(!arg1.is_empty(), "Argument <name> missing.");
|
ensure!(!arg1.is_empty(), "Argument <name> missing.");
|
||||||
let chat_id = chat::create_group_chat(context, VerifiedStatus::Verified, arg1)?;
|
let chat_id = chat::create_group_chat(&context, VerifiedStatus::Verified, arg1).await?;
|
||||||
|
|
||||||
println!("VerifiedGroup#{} created successfully.", chat_id);
|
println!("VerifiedGroup#{} created successfully.", chat_id);
|
||||||
}
|
}
|
||||||
@@ -646,10 +645,12 @@ pub fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::Error> {
|
|||||||
|
|
||||||
let contact_id_0: libc::c_int = arg1.parse()?;
|
let contact_id_0: libc::c_int = arg1.parse()?;
|
||||||
if chat::add_contact_to_chat(
|
if chat::add_contact_to_chat(
|
||||||
context,
|
&context,
|
||||||
sel_chat.as_ref().unwrap().get_id(),
|
sel_chat.as_ref().unwrap().get_id(),
|
||||||
contact_id_0 as u32,
|
contact_id_0 as u32,
|
||||||
) {
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
println!("Contact added to chat.");
|
println!("Contact added to chat.");
|
||||||
} else {
|
} else {
|
||||||
bail!("Cannot add contact to chat.");
|
bail!("Cannot add contact to chat.");
|
||||||
@@ -660,17 +661,18 @@ pub fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::Error> {
|
|||||||
ensure!(!arg1.is_empty(), "Argument <contact-id> missing.");
|
ensure!(!arg1.is_empty(), "Argument <contact-id> missing.");
|
||||||
let contact_id_1: libc::c_int = arg1.parse()?;
|
let contact_id_1: libc::c_int = arg1.parse()?;
|
||||||
chat::remove_contact_from_chat(
|
chat::remove_contact_from_chat(
|
||||||
context,
|
&context,
|
||||||
sel_chat.as_ref().unwrap().get_id(),
|
sel_chat.as_ref().unwrap().get_id(),
|
||||||
contact_id_1 as u32,
|
contact_id_1 as u32,
|
||||||
)?;
|
)
|
||||||
|
.await?;
|
||||||
|
|
||||||
println!("Contact added to chat.");
|
println!("Contact added to chat.");
|
||||||
}
|
}
|
||||||
"groupname" => {
|
"groupname" => {
|
||||||
ensure!(sel_chat.is_some(), "No chat selected.");
|
ensure!(sel_chat.is_some(), "No chat selected.");
|
||||||
ensure!(!arg1.is_empty(), "Argument <name> missing.");
|
ensure!(!arg1.is_empty(), "Argument <name> missing.");
|
||||||
chat::set_chat_name(context, sel_chat.as_ref().unwrap().get_id(), arg1)?;
|
chat::set_chat_name(&context, sel_chat.as_ref().unwrap().get_id(), arg1).await?;
|
||||||
|
|
||||||
println!("Chat name set");
|
println!("Chat name set");
|
||||||
}
|
}
|
||||||
@@ -678,24 +680,27 @@ pub fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::Error> {
|
|||||||
ensure!(sel_chat.is_some(), "No chat selected.");
|
ensure!(sel_chat.is_some(), "No chat selected.");
|
||||||
ensure!(!arg1.is_empty(), "Argument <image> missing.");
|
ensure!(!arg1.is_empty(), "Argument <image> missing.");
|
||||||
|
|
||||||
chat::set_chat_profile_image(context, sel_chat.as_ref().unwrap().get_id(), arg1)?;
|
chat::set_chat_profile_image(&context, sel_chat.as_ref().unwrap().get_id(), arg1)
|
||||||
|
.await?;
|
||||||
|
|
||||||
println!("Chat image set");
|
println!("Chat image set");
|
||||||
}
|
}
|
||||||
"chatinfo" => {
|
"chatinfo" => {
|
||||||
ensure!(sel_chat.is_some(), "No chat selected.");
|
ensure!(sel_chat.is_some(), "No chat selected.");
|
||||||
|
|
||||||
let contacts = chat::get_chat_contacts(context, sel_chat.as_ref().unwrap().get_id());
|
let contacts =
|
||||||
|
chat::get_chat_contacts(&context, sel_chat.as_ref().unwrap().get_id()).await;
|
||||||
println!("Memberlist:");
|
println!("Memberlist:");
|
||||||
|
|
||||||
log_contactlist(context, &contacts);
|
log_contactlist(&context, &contacts).await;
|
||||||
println!(
|
println!(
|
||||||
"{} contacts\nLocation streaming: {}",
|
"{} contacts\nLocation streaming: {}",
|
||||||
contacts.len(),
|
contacts.len(),
|
||||||
location::is_sending_locations_to_chat(
|
location::is_sending_locations_to_chat(
|
||||||
context,
|
&context,
|
||||||
sel_chat.as_ref().unwrap().get_id()
|
sel_chat.as_ref().unwrap().get_id()
|
||||||
),
|
)
|
||||||
|
.await,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
"getlocations" => {
|
"getlocations" => {
|
||||||
@@ -703,12 +708,13 @@ pub fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::Error> {
|
|||||||
|
|
||||||
let contact_id = arg1.parse().unwrap_or_default();
|
let contact_id = arg1.parse().unwrap_or_default();
|
||||||
let locations = location::get_range(
|
let locations = location::get_range(
|
||||||
context,
|
&context,
|
||||||
sel_chat.as_ref().unwrap().get_id(),
|
sel_chat.as_ref().unwrap().get_id(),
|
||||||
contact_id,
|
contact_id,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
);
|
)
|
||||||
|
.await;
|
||||||
let default_marker = "-".to_string();
|
let default_marker = "-".to_string();
|
||||||
for location in &locations {
|
for location in &locations {
|
||||||
let marker = location.marker.as_ref().unwrap_or(&default_marker);
|
let marker = location.marker.as_ref().unwrap_or(&default_marker);
|
||||||
@@ -734,7 +740,12 @@ pub fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::Error> {
|
|||||||
ensure!(!arg1.is_empty(), "No timeout given.");
|
ensure!(!arg1.is_empty(), "No timeout given.");
|
||||||
|
|
||||||
let seconds = arg1.parse()?;
|
let seconds = arg1.parse()?;
|
||||||
location::send_locations_to_chat(context, sel_chat.as_ref().unwrap().get_id(), seconds);
|
location::send_locations_to_chat(
|
||||||
|
&context,
|
||||||
|
sel_chat.as_ref().unwrap().get_id(),
|
||||||
|
seconds,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
println!(
|
println!(
|
||||||
"Locations will be sent to Chat#{} for {} seconds. Use 'setlocation <lat> <lng>' to play around.",
|
"Locations will be sent to Chat#{} for {} seconds. Use 'setlocation <lat> <lng>' to play around.",
|
||||||
sel_chat.as_ref().unwrap().get_id(),
|
sel_chat.as_ref().unwrap().get_id(),
|
||||||
@@ -749,7 +760,7 @@ pub fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::Error> {
|
|||||||
let latitude = arg1.parse()?;
|
let latitude = arg1.parse()?;
|
||||||
let longitude = arg2.parse()?;
|
let longitude = arg2.parse()?;
|
||||||
|
|
||||||
let continue_streaming = location::set(context, latitude, longitude, 0.);
|
let continue_streaming = location::set(&context, latitude, longitude, 0.).await;
|
||||||
if continue_streaming {
|
if continue_streaming {
|
||||||
println!("Success, streaming should be continued.");
|
println!("Success, streaming should be continued.");
|
||||||
} else {
|
} else {
|
||||||
@@ -757,7 +768,7 @@ pub fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::Error> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"dellocations" => {
|
"dellocations" => {
|
||||||
location::delete_all(context)?;
|
location::delete_all(&context).await?;
|
||||||
}
|
}
|
||||||
"send" => {
|
"send" => {
|
||||||
ensure!(sel_chat.is_some(), "No chat selected.");
|
ensure!(sel_chat.is_some(), "No chat selected.");
|
||||||
@@ -765,11 +776,11 @@ pub fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::Error> {
|
|||||||
|
|
||||||
let msg = format!("{} {}", arg1, arg2);
|
let msg = format!("{} {}", arg1, arg2);
|
||||||
|
|
||||||
chat::send_text_msg(context, sel_chat.as_ref().unwrap().get_id(), msg)?;
|
chat::send_text_msg(&context, sel_chat.as_ref().unwrap().get_id(), msg).await?;
|
||||||
}
|
}
|
||||||
"sendempty" => {
|
"sendempty" => {
|
||||||
ensure!(sel_chat.is_some(), "No chat selected.");
|
ensure!(sel_chat.is_some(), "No chat selected.");
|
||||||
chat::send_text_msg(context, sel_chat.as_ref().unwrap().get_id(), "".into())?;
|
chat::send_text_msg(&context, sel_chat.as_ref().unwrap().get_id(), "".into()).await?;
|
||||||
}
|
}
|
||||||
"sendimage" | "sendfile" => {
|
"sendimage" | "sendfile" => {
|
||||||
ensure!(sel_chat.is_some(), "No chat selected.");
|
ensure!(sel_chat.is_some(), "No chat selected.");
|
||||||
@@ -784,7 +795,7 @@ pub fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::Error> {
|
|||||||
if !arg2.is_empty() {
|
if !arg2.is_empty() {
|
||||||
msg.set_text(Some(arg2.to_string()));
|
msg.set_text(Some(arg2.to_string()));
|
||||||
}
|
}
|
||||||
chat::send_msg(context, sel_chat.as_ref().unwrap().get_id(), &mut msg)?;
|
chat::send_msg(&context, sel_chat.as_ref().unwrap().get_id(), &mut msg).await?;
|
||||||
}
|
}
|
||||||
"listmsgs" => {
|
"listmsgs" => {
|
||||||
ensure!(!arg1.is_empty(), "Argument <query> missing.");
|
ensure!(!arg1.is_empty(), "Argument <query> missing.");
|
||||||
@@ -795,9 +806,9 @@ pub fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::Error> {
|
|||||||
ChatId::new(0)
|
ChatId::new(0)
|
||||||
};
|
};
|
||||||
|
|
||||||
let msglist = context.search_msgs(chat, arg1);
|
let msglist = context.search_msgs(chat, arg1).await;
|
||||||
|
|
||||||
log_msglist(context, &msglist)?;
|
log_msglist(&context, &msglist).await?;
|
||||||
println!("{} messages.", msglist.len());
|
println!("{} messages.", msglist.len());
|
||||||
}
|
}
|
||||||
"draft" => {
|
"draft" => {
|
||||||
@@ -810,10 +821,16 @@ pub fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::Error> {
|
|||||||
.as_ref()
|
.as_ref()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.get_id()
|
.get_id()
|
||||||
.set_draft(context, Some(&mut draft));
|
.set_draft(&context, Some(&mut draft))
|
||||||
|
.await;
|
||||||
println!("Draft saved.");
|
println!("Draft saved.");
|
||||||
} else {
|
} else {
|
||||||
sel_chat.as_ref().unwrap().get_id().set_draft(context, None);
|
sel_chat
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.get_id()
|
||||||
|
.set_draft(&context, None)
|
||||||
|
.await;
|
||||||
println!("Draft deleted.");
|
println!("Draft deleted.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -824,21 +841,22 @@ pub fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::Error> {
|
|||||||
);
|
);
|
||||||
let mut msg = Message::new(Viewtype::Text);
|
let mut msg = Message::new(Viewtype::Text);
|
||||||
msg.set_text(Some(arg1.to_string()));
|
msg.set_text(Some(arg1.to_string()));
|
||||||
chat::add_device_msg(context, None, Some(&mut msg))?;
|
chat::add_device_msg(&context, None, Some(&mut msg)).await?;
|
||||||
}
|
}
|
||||||
"updatedevicechats" => {
|
"updatedevicechats" => {
|
||||||
context.update_device_chats()?;
|
context.update_device_chats().await?;
|
||||||
}
|
}
|
||||||
"listmedia" => {
|
"listmedia" => {
|
||||||
ensure!(sel_chat.is_some(), "No chat selected.");
|
ensure!(sel_chat.is_some(), "No chat selected.");
|
||||||
|
|
||||||
let images = chat::get_chat_media(
|
let images = chat::get_chat_media(
|
||||||
context,
|
&context,
|
||||||
sel_chat.as_ref().unwrap().get_id(),
|
sel_chat.as_ref().unwrap().get_id(),
|
||||||
Viewtype::Image,
|
Viewtype::Image,
|
||||||
Viewtype::Gif,
|
Viewtype::Gif,
|
||||||
Viewtype::Video,
|
Viewtype::Video,
|
||||||
);
|
)
|
||||||
|
.await;
|
||||||
println!("{} images or videos: ", images.len());
|
println!("{} images or videos: ", images.len());
|
||||||
for (i, data) in images.iter().enumerate() {
|
for (i, data) in images.iter().enumerate() {
|
||||||
if 0 == i {
|
if 0 == i {
|
||||||
@@ -852,31 +870,33 @@ pub fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::Error> {
|
|||||||
"archive" | "unarchive" | "pin" | "unpin" => {
|
"archive" | "unarchive" | "pin" | "unpin" => {
|
||||||
ensure!(!arg1.is_empty(), "Argument <chat-id> missing.");
|
ensure!(!arg1.is_empty(), "Argument <chat-id> missing.");
|
||||||
let chat_id = ChatId::new(arg1.parse()?);
|
let chat_id = ChatId::new(arg1.parse()?);
|
||||||
chat_id.set_visibility(
|
chat_id
|
||||||
context,
|
.set_visibility(
|
||||||
match arg0 {
|
&context,
|
||||||
"archive" => ChatVisibility::Archived,
|
match arg0 {
|
||||||
"unarchive" | "unpin" => ChatVisibility::Normal,
|
"archive" => ChatVisibility::Archived,
|
||||||
"pin" => ChatVisibility::Pinned,
|
"unarchive" | "unpin" => ChatVisibility::Normal,
|
||||||
_ => panic!("Unexpected command (This should never happen)"),
|
"pin" => ChatVisibility::Pinned,
|
||||||
},
|
_ => panic!("Unexpected command (This should never happen)"),
|
||||||
)?;
|
},
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
"delchat" => {
|
"delchat" => {
|
||||||
ensure!(!arg1.is_empty(), "Argument <chat-id> missing.");
|
ensure!(!arg1.is_empty(), "Argument <chat-id> missing.");
|
||||||
let chat_id = ChatId::new(arg1.parse()?);
|
let chat_id = ChatId::new(arg1.parse()?);
|
||||||
chat_id.delete(context)?;
|
chat_id.delete(&context).await?;
|
||||||
}
|
}
|
||||||
"msginfo" => {
|
"msginfo" => {
|
||||||
ensure!(!arg1.is_empty(), "Argument <msg-id> missing.");
|
ensure!(!arg1.is_empty(), "Argument <msg-id> missing.");
|
||||||
let id = MsgId::new(arg1.parse()?);
|
let id = MsgId::new(arg1.parse()?);
|
||||||
let res = message::get_msg_info(context, id);
|
let res = message::get_msg_info(&context, id).await;
|
||||||
println!("{}", res);
|
println!("{}", res);
|
||||||
}
|
}
|
||||||
"listfresh" => {
|
"listfresh" => {
|
||||||
let msglist = context.get_fresh_msgs();
|
let msglist = context.get_fresh_msgs().await;
|
||||||
|
|
||||||
log_msglist(context, &msglist)?;
|
log_msglist(&context, &msglist).await?;
|
||||||
print!("{} fresh messages.", msglist.len());
|
print!("{} fresh messages.", msglist.len());
|
||||||
}
|
}
|
||||||
"forward" => {
|
"forward" => {
|
||||||
@@ -888,37 +908,38 @@ pub fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::Error> {
|
|||||||
let mut msg_ids = [MsgId::new(0); 1];
|
let mut msg_ids = [MsgId::new(0); 1];
|
||||||
let chat_id = ChatId::new(arg2.parse()?);
|
let chat_id = ChatId::new(arg2.parse()?);
|
||||||
msg_ids[0] = MsgId::new(arg1.parse()?);
|
msg_ids[0] = MsgId::new(arg1.parse()?);
|
||||||
chat::forward_msgs(context, &msg_ids, chat_id)?;
|
chat::forward_msgs(&context, &msg_ids, chat_id).await?;
|
||||||
}
|
}
|
||||||
"markseen" => {
|
"markseen" => {
|
||||||
ensure!(!arg1.is_empty(), "Argument <msg-id> missing.");
|
ensure!(!arg1.is_empty(), "Argument <msg-id> missing.");
|
||||||
let mut msg_ids = [MsgId::new(0); 1];
|
let mut msg_ids = vec![MsgId::new(0)];
|
||||||
msg_ids[0] = MsgId::new(arg1.parse()?);
|
msg_ids[0] = MsgId::new(arg1.parse()?);
|
||||||
message::markseen_msgs(context, &msg_ids);
|
message::markseen_msgs(&context, msg_ids).await;
|
||||||
}
|
}
|
||||||
"star" | "unstar" => {
|
"star" | "unstar" => {
|
||||||
ensure!(!arg1.is_empty(), "Argument <msg-id> missing.");
|
ensure!(!arg1.is_empty(), "Argument <msg-id> missing.");
|
||||||
let mut msg_ids = [MsgId::new(0); 1];
|
let mut msg_ids = vec![MsgId::new(0); 1];
|
||||||
msg_ids[0] = MsgId::new(arg1.parse()?);
|
msg_ids[0] = MsgId::new(arg1.parse()?);
|
||||||
message::star_msgs(context, &msg_ids, arg0 == "star");
|
message::star_msgs(&context, msg_ids, arg0 == "star").await;
|
||||||
}
|
}
|
||||||
"delmsg" => {
|
"delmsg" => {
|
||||||
ensure!(!arg1.is_empty(), "Argument <msg-id> missing.");
|
ensure!(!arg1.is_empty(), "Argument <msg-id> missing.");
|
||||||
let mut ids = [MsgId::new(0); 1];
|
let mut ids = [MsgId::new(0); 1];
|
||||||
ids[0] = MsgId::new(arg1.parse()?);
|
ids[0] = MsgId::new(arg1.parse()?);
|
||||||
message::delete_msgs(context, &ids);
|
message::delete_msgs(&context, &ids).await;
|
||||||
}
|
}
|
||||||
"listcontacts" | "contacts" | "listverified" => {
|
"listcontacts" | "contacts" | "listverified" => {
|
||||||
let contacts = Contact::get_all(
|
let contacts = Contact::get_all(
|
||||||
context,
|
&context,
|
||||||
if arg0 == "listverified" {
|
if arg0 == "listverified" {
|
||||||
0x1 | 0x2
|
0x1 | 0x2
|
||||||
} else {
|
} else {
|
||||||
0x2
|
0x2
|
||||||
},
|
},
|
||||||
Some(arg1),
|
Some(arg1),
|
||||||
)?;
|
)
|
||||||
log_contactlist(context, &contacts);
|
.await?;
|
||||||
|
log_contactlist(&context, &contacts).await;
|
||||||
println!("{} contacts.", contacts.len());
|
println!("{} contacts.", contacts.len());
|
||||||
}
|
}
|
||||||
"addcontact" => {
|
"addcontact" => {
|
||||||
@@ -926,30 +947,30 @@ pub fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::Error> {
|
|||||||
|
|
||||||
if !arg2.is_empty() {
|
if !arg2.is_empty() {
|
||||||
let book = format!("{}\n{}", arg1, arg2);
|
let book = format!("{}\n{}", arg1, arg2);
|
||||||
Contact::add_address_book(context, book)?;
|
Contact::add_address_book(&context, book).await?;
|
||||||
} else {
|
} else {
|
||||||
Contact::create(context, "", arg1)?;
|
Contact::create(&context, "", arg1).await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"contactinfo" => {
|
"contactinfo" => {
|
||||||
ensure!(!arg1.is_empty(), "Argument <contact-id> missing.");
|
ensure!(!arg1.is_empty(), "Argument <contact-id> missing.");
|
||||||
|
|
||||||
let contact_id = arg1.parse()?;
|
let contact_id = arg1.parse()?;
|
||||||
let contact = Contact::get_by_id(context, contact_id)?;
|
let contact = Contact::get_by_id(&context, contact_id).await?;
|
||||||
let name_n_addr = contact.get_name_n_addr();
|
let name_n_addr = contact.get_name_n_addr();
|
||||||
|
|
||||||
let mut res = format!(
|
let mut res = format!(
|
||||||
"Contact info for: {}:\nIcon: {}\n",
|
"Contact info for: {}:\nIcon: {}\n",
|
||||||
name_n_addr,
|
name_n_addr,
|
||||||
match contact.get_profile_image(context) {
|
match contact.get_profile_image(&context).await {
|
||||||
Some(image) => image.to_str().unwrap().to_string(),
|
Some(image) => image.to_str().unwrap().to_string(),
|
||||||
None => "NoIcon".to_string(),
|
None => "NoIcon".to_string(),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
res += &Contact::get_encrinfo(context, contact_id)?;
|
res += &Contact::get_encrinfo(&context, contact_id).await?;
|
||||||
|
|
||||||
let chatlist = Chatlist::try_load(context, 0, None, Some(contact_id))?;
|
let chatlist = Chatlist::try_load(&context, 0, None, Some(contact_id)).await?;
|
||||||
let chatlist_cnt = chatlist.len();
|
let chatlist_cnt = chatlist.len();
|
||||||
if chatlist_cnt > 0 {
|
if chatlist_cnt > 0 {
|
||||||
res += &format!(
|
res += &format!(
|
||||||
@@ -960,7 +981,7 @@ pub fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::Error> {
|
|||||||
if 0 != i {
|
if 0 != i {
|
||||||
res += ", ";
|
res += ", ";
|
||||||
}
|
}
|
||||||
let chat = Chat::load_from_db(context, chatlist.get_chat_id(i))?;
|
let chat = Chat::load_from_db(&context, chatlist.get_chat_id(i)).await?;
|
||||||
res += &format!("{}#{}", chat_prefix(&chat), chat.get_id());
|
res += &format!("{}#{}", chat_prefix(&chat), chat.get_id());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -969,11 +990,11 @@ pub fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::Error> {
|
|||||||
}
|
}
|
||||||
"delcontact" => {
|
"delcontact" => {
|
||||||
ensure!(!arg1.is_empty(), "Argument <contact-id> missing.");
|
ensure!(!arg1.is_empty(), "Argument <contact-id> missing.");
|
||||||
Contact::delete(context, arg1.parse()?)?;
|
Contact::delete(&context, arg1.parse()?).await?;
|
||||||
}
|
}
|
||||||
"checkqr" => {
|
"checkqr" => {
|
||||||
ensure!(!arg1.is_empty(), "Argument <qr-content> missing.");
|
ensure!(!arg1.is_empty(), "Argument <qr-content> missing.");
|
||||||
let res = check_qr(context, arg1);
|
let res = check_qr(&context, arg1).await;
|
||||||
println!(
|
println!(
|
||||||
"state={}, id={}, text1={:?}, text2={:?}",
|
"state={}, id={}, text1={:?}, text2={:?}",
|
||||||
res.get_state(),
|
res.get_state(),
|
||||||
@@ -984,7 +1005,7 @@ pub fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::Error> {
|
|||||||
}
|
}
|
||||||
"setqr" => {
|
"setqr" => {
|
||||||
ensure!(!arg1.is_empty(), "Argument <qr-content> missing.");
|
ensure!(!arg1.is_empty(), "Argument <qr-content> missing.");
|
||||||
match set_config_from_qr(context, arg1) {
|
match set_config_from_qr(&context, arg1).await {
|
||||||
Ok(()) => println!("Config set from QR code, you can now call 'configure'"),
|
Ok(()) => println!("Config set from QR code, you can now call 'configure'"),
|
||||||
Err(err) => println!("Cannot set config from QR code: {:?}", err),
|
Err(err) => println!("Cannot set config from QR code: {:?}", err),
|
||||||
}
|
}
|
||||||
@@ -1021,7 +1042,7 @@ pub fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::Error> {
|
|||||||
"fileinfo" => {
|
"fileinfo" => {
|
||||||
ensure!(!arg1.is_empty(), "Argument <file> missing.");
|
ensure!(!arg1.is_empty(), "Argument <file> missing.");
|
||||||
|
|
||||||
if let Ok(buf) = dc_read_file(context, &arg1) {
|
if let Ok(buf) = dc_read_file(&context, &arg1).await {
|
||||||
let (width, height) = dc_get_filemeta(&buf)?;
|
let (width, height) = dc_get_filemeta(&buf)?;
|
||||||
println!("width={}, height={}", width, height);
|
println!("width={}, height={}", width, height);
|
||||||
} else {
|
} else {
|
||||||
@@ -1031,7 +1052,7 @@ pub fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::Error> {
|
|||||||
"emptyserver" => {
|
"emptyserver" => {
|
||||||
ensure!(!arg1.is_empty(), "Argument <flags> missing");
|
ensure!(!arg1.is_empty(), "Argument <flags> missing");
|
||||||
|
|
||||||
message::dc_empty_server(context, arg1.parse()?);
|
message::dc_empty_server(&context, arg1.parse()?).await;
|
||||||
}
|
}
|
||||||
"" => (),
|
"" => (),
|
||||||
_ => bail!("Unknown command: \"{}\" type ? for help.", arg0),
|
_ => bail!("Unknown command: \"{}\" type ? for help.", arg0),
|
||||||
|
|||||||
@@ -8,25 +8,20 @@
|
|||||||
extern crate deltachat;
|
extern crate deltachat;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate failure;
|
extern crate failure;
|
||||||
#[macro_use]
|
|
||||||
extern crate lazy_static;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate rusqlite;
|
|
||||||
|
|
||||||
use std::borrow::Cow::{self, Borrowed, Owned};
|
use std::borrow::Cow::{self, Borrowed, Owned};
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
use std::path::Path;
|
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
|
||||||
use std::sync::{Arc, Mutex, RwLock};
|
|
||||||
|
|
||||||
|
use ansi_term::Color;
|
||||||
|
use async_std::path::Path;
|
||||||
use deltachat::chat::ChatId;
|
use deltachat::chat::ChatId;
|
||||||
use deltachat::config;
|
use deltachat::config;
|
||||||
use deltachat::context::*;
|
use deltachat::context::*;
|
||||||
use deltachat::job::*;
|
|
||||||
use deltachat::oauth2::*;
|
use deltachat::oauth2::*;
|
||||||
use deltachat::securejoin::*;
|
use deltachat::securejoin::*;
|
||||||
use deltachat::Event;
|
use deltachat::Event;
|
||||||
|
use log::{error, info, warn};
|
||||||
use rustyline::completion::{Completer, FilenameCompleter, Pair};
|
use rustyline::completion::{Completer, FilenameCompleter, Pair};
|
||||||
use rustyline::config::OutputStreamType;
|
use rustyline::config::OutputStreamType;
|
||||||
use rustyline::error::ReadlineError;
|
use rustyline::error::ReadlineError;
|
||||||
@@ -39,179 +34,83 @@ use rustyline::{
|
|||||||
mod cmdline;
|
mod cmdline;
|
||||||
use self::cmdline::*;
|
use self::cmdline::*;
|
||||||
|
|
||||||
// Event Handler
|
/// Event Handler
|
||||||
|
fn receive_event(event: Event) {
|
||||||
fn receive_event(_context: &Context, event: Event) {
|
let yellow = Color::Yellow.normal();
|
||||||
match event {
|
match event {
|
||||||
Event::Info(msg) => {
|
Event::Info(msg) => {
|
||||||
/* do not show the event as this would fill the screen */
|
/* do not show the event as this would fill the screen */
|
||||||
println!("{}", msg);
|
info!("{}", msg);
|
||||||
}
|
}
|
||||||
Event::SmtpConnected(msg) => {
|
Event::SmtpConnected(msg) => {
|
||||||
println!("[DC_EVENT_SMTP_CONNECTED] {}", msg);
|
info!("[SMTP_CONNECTED] {}", msg);
|
||||||
}
|
}
|
||||||
Event::ImapConnected(msg) => {
|
Event::ImapConnected(msg) => {
|
||||||
println!("[DC_EVENT_IMAP_CONNECTED] {}", msg);
|
info!("[IMAP_CONNECTED] {}", msg);
|
||||||
}
|
}
|
||||||
Event::SmtpMessageSent(msg) => {
|
Event::SmtpMessageSent(msg) => {
|
||||||
println!("[DC_EVENT_SMTP_MESSAGE_SENT] {}", msg);
|
info!("[SMTP_MESSAGE_SENT] {}", msg);
|
||||||
}
|
}
|
||||||
Event::Warning(msg) => {
|
Event::Warning(msg) => {
|
||||||
println!("[Warning] {}", msg);
|
warn!("{}", msg);
|
||||||
}
|
}
|
||||||
Event::Error(msg) => {
|
Event::Error(msg) => {
|
||||||
println!("\x1b[31m[DC_EVENT_ERROR] {}\x1b[0m", msg);
|
error!("{}", msg);
|
||||||
}
|
}
|
||||||
Event::ErrorNetwork(msg) => {
|
Event::ErrorNetwork(msg) => {
|
||||||
println!("\x1b[31m[DC_EVENT_ERROR_NETWORK] msg={}\x1b[0m", msg);
|
error!("[NETWORK] msg={}", msg);
|
||||||
}
|
}
|
||||||
Event::ErrorSelfNotInGroup(msg) => {
|
Event::ErrorSelfNotInGroup(msg) => {
|
||||||
println!("\x1b[31m[DC_EVENT_ERROR_SELF_NOT_IN_GROUP] {}\x1b[0m", msg);
|
error!("[SELF_NOT_IN_GROUP] {}", msg);
|
||||||
}
|
}
|
||||||
Event::MsgsChanged { chat_id, msg_id } => {
|
Event::MsgsChanged { chat_id, msg_id } => {
|
||||||
print!(
|
info!(
|
||||||
"\x1b[33m{{Received DC_EVENT_MSGS_CHANGED(chat_id={}, msg_id={})}}\n\x1b[0m",
|
"{}",
|
||||||
chat_id, msg_id,
|
yellow.paint(format!(
|
||||||
|
"Received MSGS_CHANGED(chat_id={}, msg_id={})",
|
||||||
|
chat_id, msg_id,
|
||||||
|
))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Event::ContactsChanged(_) => {
|
Event::ContactsChanged(_) => {
|
||||||
print!("\x1b[33m{{Received DC_EVENT_CONTACTS_CHANGED()}}\n\x1b[0m");
|
info!("{}", yellow.paint("Received CONTACTS_CHANGED()"));
|
||||||
}
|
}
|
||||||
Event::LocationChanged(contact) => {
|
Event::LocationChanged(contact) => {
|
||||||
print!(
|
info!(
|
||||||
"\x1b[33m{{Received DC_EVENT_LOCATION_CHANGED(contact={:?})}}\n\x1b[0m",
|
"{}",
|
||||||
contact,
|
yellow.paint(format!("Received LOCATION_CHANGED(contact={:?})", contact))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Event::ConfigureProgress(progress) => {
|
Event::ConfigureProgress(progress) => {
|
||||||
print!(
|
info!(
|
||||||
"\x1b[33m{{Received DC_EVENT_CONFIGURE_PROGRESS({} ‰)}}\n\x1b[0m",
|
"{}",
|
||||||
progress,
|
yellow.paint(format!("Received CONFIGURE_PROGRESS({} ‰)", progress))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Event::ImexProgress(progress) => {
|
Event::ImexProgress(progress) => {
|
||||||
print!(
|
info!(
|
||||||
"\x1b[33m{{Received DC_EVENT_IMEX_PROGRESS({} ‰)}}\n\x1b[0m",
|
"{}",
|
||||||
progress,
|
yellow.paint(format!("Received IMEX_PROGRESS({} ‰)", progress))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Event::ImexFileWritten(file) => {
|
Event::ImexFileWritten(file) => {
|
||||||
print!(
|
info!(
|
||||||
"\x1b[33m{{Received DC_EVENT_IMEX_FILE_WRITTEN({})}}\n\x1b[0m",
|
"{}",
|
||||||
file.display()
|
yellow.paint(format!("Received IMEX_FILE_WRITTEN({})", file.display()))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Event::ChatModified(chat) => {
|
Event::ChatModified(chat) => {
|
||||||
print!(
|
info!(
|
||||||
"\x1b[33m{{Received DC_EVENT_CHAT_MODIFIED({})}}\n\x1b[0m",
|
"{}",
|
||||||
chat
|
yellow.paint(format!("Received CHAT_MODIFIED({})", chat))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
print!("\x1b[33m{{Received {:?}}}\n\x1b[0m", event);
|
info!("Received {:?}", event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Threads for waiting for messages and for jobs
|
|
||||||
|
|
||||||
lazy_static! {
|
|
||||||
static ref HANDLE: Arc<Mutex<Option<Handle>>> = Arc::new(Mutex::new(None));
|
|
||||||
static ref IS_RUNNING: AtomicBool = AtomicBool::new(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Handle {
|
|
||||||
handle_imap: Option<std::thread::JoinHandle<()>>,
|
|
||||||
handle_mvbox: Option<std::thread::JoinHandle<()>>,
|
|
||||||
handle_sentbox: Option<std::thread::JoinHandle<()>>,
|
|
||||||
handle_smtp: Option<std::thread::JoinHandle<()>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! while_running {
|
|
||||||
($code:block) => {
|
|
||||||
if IS_RUNNING.load(Ordering::Relaxed) {
|
|
||||||
$code
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn start_threads(c: Arc<RwLock<Context>>) {
|
|
||||||
if HANDLE.clone().lock().unwrap().is_some() {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("Starting threads");
|
|
||||||
IS_RUNNING.store(true, Ordering::Relaxed);
|
|
||||||
|
|
||||||
let ctx = c.clone();
|
|
||||||
let handle_imap = std::thread::spawn(move || loop {
|
|
||||||
while_running!({
|
|
||||||
perform_inbox_jobs(&ctx.read().unwrap());
|
|
||||||
perform_inbox_fetch(&ctx.read().unwrap());
|
|
||||||
while_running!({
|
|
||||||
let context = ctx.read().unwrap();
|
|
||||||
perform_inbox_idle(&context);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
let ctx = c.clone();
|
|
||||||
let handle_mvbox = std::thread::spawn(move || loop {
|
|
||||||
while_running!({
|
|
||||||
perform_mvbox_fetch(&ctx.read().unwrap());
|
|
||||||
while_running!({
|
|
||||||
perform_mvbox_idle(&ctx.read().unwrap());
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
let ctx = c.clone();
|
|
||||||
let handle_sentbox = std::thread::spawn(move || loop {
|
|
||||||
while_running!({
|
|
||||||
perform_sentbox_fetch(&ctx.read().unwrap());
|
|
||||||
while_running!({
|
|
||||||
perform_sentbox_idle(&ctx.read().unwrap());
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
let ctx = c;
|
|
||||||
let handle_smtp = std::thread::spawn(move || loop {
|
|
||||||
while_running!({
|
|
||||||
perform_smtp_jobs(&ctx.read().unwrap());
|
|
||||||
while_running!({
|
|
||||||
perform_smtp_idle(&ctx.read().unwrap());
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
*HANDLE.clone().lock().unwrap() = Some(Handle {
|
|
||||||
handle_imap: Some(handle_imap),
|
|
||||||
handle_mvbox: Some(handle_mvbox),
|
|
||||||
handle_sentbox: Some(handle_sentbox),
|
|
||||||
handle_smtp: Some(handle_smtp),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn stop_threads(context: &Context) {
|
|
||||||
if let Some(ref mut handle) = *HANDLE.clone().lock().unwrap() {
|
|
||||||
println!("Stopping threads");
|
|
||||||
IS_RUNNING.store(false, Ordering::Relaxed);
|
|
||||||
|
|
||||||
interrupt_inbox_idle(context);
|
|
||||||
interrupt_mvbox_idle(context);
|
|
||||||
interrupt_sentbox_idle(context);
|
|
||||||
interrupt_smtp_idle(context);
|
|
||||||
|
|
||||||
handle.handle_imap.take().unwrap().join().unwrap();
|
|
||||||
handle.handle_mvbox.take().unwrap().join().unwrap();
|
|
||||||
handle.handle_sentbox.take().unwrap().join().unwrap();
|
|
||||||
handle.handle_smtp.take().unwrap().join().unwrap();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// === The main loop
|
// === The main loop
|
||||||
|
|
||||||
struct DcHelper {
|
struct DcHelper {
|
||||||
@@ -361,21 +260,22 @@ impl Highlighter for DcHelper {
|
|||||||
|
|
||||||
impl Helper for DcHelper {}
|
impl Helper for DcHelper {}
|
||||||
|
|
||||||
fn main_0(args: Vec<String>) -> Result<(), failure::Error> {
|
async fn start(args: Vec<String>) -> Result<(), failure::Error> {
|
||||||
if args.len() < 2 {
|
if args.len() < 2 {
|
||||||
println!("Error: Bad arguments, expected [db-name].");
|
println!("Error: Bad arguments, expected [db-name].");
|
||||||
return Err(format_err!("No db-name specified"));
|
return Err(format_err!("No db-name specified"));
|
||||||
}
|
}
|
||||||
let context = Context::new(
|
let context = Context::new("CLI".into(), Path::new(&args[1]).to_path_buf()).await?;
|
||||||
Box::new(receive_event),
|
|
||||||
"CLI".into(),
|
let ctx = context.clone();
|
||||||
Path::new(&args[1]).to_path_buf(),
|
std::thread::spawn(move || loop {
|
||||||
)?;
|
if let Ok(event) = ctx.get_next_event() {
|
||||||
|
receive_event(event);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
println!("Delta Chat Core is awaiting your commands.");
|
println!("Delta Chat Core is awaiting your commands.");
|
||||||
|
|
||||||
let ctx = Arc::new(RwLock::new(context));
|
|
||||||
|
|
||||||
let config = Config::builder()
|
let config = Config::builder()
|
||||||
.history_ignore_space(true)
|
.history_ignore_space(true)
|
||||||
.completion_type(CompletionType::List)
|
.completion_type(CompletionType::List)
|
||||||
@@ -395,6 +295,8 @@ fn main_0(args: Vec<String>) -> Result<(), failure::Error> {
|
|||||||
println!("No previous history.");
|
println!("No previous history.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut selected_chat = ChatId::default();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let p = "> ";
|
let p = "> ";
|
||||||
let readline = rl.readline(&p);
|
let readline = rl.readline(&p);
|
||||||
@@ -402,8 +304,7 @@ fn main_0(args: Vec<String>) -> Result<(), failure::Error> {
|
|||||||
Ok(line) => {
|
Ok(line) => {
|
||||||
// TODO: ignore "set mail_pw"
|
// TODO: ignore "set mail_pw"
|
||||||
rl.add_history_entry(line.as_str());
|
rl.add_history_entry(line.as_str());
|
||||||
let ctx = ctx.clone();
|
match handle_cmd(line.trim(), context.clone(), &mut selected_chat).await {
|
||||||
match handle_cmd(line.trim(), ctx) {
|
|
||||||
Ok(ExitResult::Continue) => {}
|
Ok(ExitResult::Continue) => {}
|
||||||
Ok(ExitResult::Exit) => break,
|
Ok(ExitResult::Exit) => break,
|
||||||
Err(err) => println!("Error: {}", err),
|
Err(err) => println!("Error: {}", err),
|
||||||
@@ -421,9 +322,8 @@ fn main_0(args: Vec<String>) -> Result<(), failure::Error> {
|
|||||||
}
|
}
|
||||||
rl.save_history(".dc-history.txt")?;
|
rl.save_history(".dc-history.txt")?;
|
||||||
println!("history saved");
|
println!("history saved");
|
||||||
{
|
|
||||||
stop_threads(&ctx.read().unwrap());
|
context.stop().await;
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -434,43 +334,29 @@ enum ExitResult {
|
|||||||
Exit,
|
Exit,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_cmd(line: &str, ctx: Arc<RwLock<Context>>) -> Result<ExitResult, failure::Error> {
|
async fn handle_cmd(
|
||||||
|
line: &str,
|
||||||
|
ctx: Context,
|
||||||
|
selected_chat: &mut ChatId,
|
||||||
|
) -> Result<ExitResult, failure::Error> {
|
||||||
let mut args = line.splitn(2, ' ');
|
let mut args = line.splitn(2, ' ');
|
||||||
let arg0 = args.next().unwrap_or_default();
|
let arg0 = args.next().unwrap_or_default();
|
||||||
let arg1 = args.next().unwrap_or_default();
|
let arg1 = args.next().unwrap_or_default();
|
||||||
|
|
||||||
match arg0 {
|
match arg0 {
|
||||||
"connect" => {
|
"connect" => {
|
||||||
start_threads(ctx);
|
ctx.run().await;
|
||||||
}
|
}
|
||||||
"disconnect" => {
|
"disconnect" => {
|
||||||
stop_threads(&ctx.read().unwrap());
|
ctx.stop().await;
|
||||||
}
|
|
||||||
"smtp-jobs" => {
|
|
||||||
if HANDLE.clone().lock().unwrap().is_some() {
|
|
||||||
println!("smtp-jobs are already running in a thread.",);
|
|
||||||
} else {
|
|
||||||
perform_smtp_jobs(&ctx.read().unwrap());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
"imap-jobs" => {
|
|
||||||
if HANDLE.clone().lock().unwrap().is_some() {
|
|
||||||
println!("inbox-jobs are already running in a thread.");
|
|
||||||
} else {
|
|
||||||
perform_inbox_jobs(&ctx.read().unwrap());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
"configure" => {
|
"configure" => {
|
||||||
start_threads(ctx.clone());
|
ctx.configure().await?;
|
||||||
ctx.read().unwrap().configure();
|
|
||||||
}
|
}
|
||||||
"oauth2" => {
|
"oauth2" => {
|
||||||
if let Some(addr) = ctx.read().unwrap().get_config(config::Config::Addr) {
|
if let Some(addr) = ctx.get_config(config::Config::Addr).await {
|
||||||
let oauth2_url = dc_get_oauth2_url(
|
let oauth2_url =
|
||||||
&ctx.read().unwrap(),
|
dc_get_oauth2_url(&ctx, &addr, "chat.delta:/com.b44t.messenger").await;
|
||||||
&addr,
|
|
||||||
"chat.delta:/com.b44t.messenger",
|
|
||||||
);
|
|
||||||
if oauth2_url.is_none() {
|
if oauth2_url.is_none() {
|
||||||
println!("OAuth2 not available for {}.", &addr);
|
println!("OAuth2 not available for {}.", &addr);
|
||||||
} else {
|
} else {
|
||||||
@@ -485,11 +371,10 @@ fn handle_cmd(line: &str, ctx: Arc<RwLock<Context>>) -> Result<ExitResult, failu
|
|||||||
print!("\x1b[1;1H\x1b[2J");
|
print!("\x1b[1;1H\x1b[2J");
|
||||||
}
|
}
|
||||||
"getqr" | "getbadqr" => {
|
"getqr" | "getbadqr" => {
|
||||||
start_threads(ctx.clone());
|
ctx.run().await;
|
||||||
if let Some(mut qr) = dc_get_securejoin_qr(
|
if let Some(mut qr) =
|
||||||
&ctx.read().unwrap(),
|
dc_get_securejoin_qr(&ctx, ChatId::new(arg1.parse().unwrap_or_default())).await
|
||||||
ChatId::new(arg1.parse().unwrap_or_default()),
|
{
|
||||||
) {
|
|
||||||
if !qr.is_empty() {
|
if !qr.is_empty() {
|
||||||
if arg0 == "getbadqr" && qr.len() > 40 {
|
if arg0 == "getbadqr" && qr.len() > 40 {
|
||||||
qr.replace_range(12..22, "0000000000")
|
qr.replace_range(12..22, "0000000000")
|
||||||
@@ -505,23 +390,23 @@ fn handle_cmd(line: &str, ctx: Arc<RwLock<Context>>) -> Result<ExitResult, failu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
"joinqr" => {
|
"joinqr" => {
|
||||||
start_threads(ctx.clone());
|
ctx.run().await;
|
||||||
if !arg0.is_empty() {
|
if !arg0.is_empty() {
|
||||||
dc_join_securejoin(&ctx.read().unwrap(), arg1);
|
dc_join_securejoin(&ctx, arg1).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"exit" | "quit" => return Ok(ExitResult::Exit),
|
"exit" | "quit" => return Ok(ExitResult::Exit),
|
||||||
_ => dc_cmdline(&ctx.read().unwrap(), line)?,
|
_ => cmdline(ctx.clone(), line, selected_chat).await?,
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(ExitResult::Continue)
|
Ok(ExitResult::Continue)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn main() -> Result<(), failure::Error> {
|
fn main() -> Result<(), failure::Error> {
|
||||||
let _ = pretty_env_logger::try_init();
|
let _ = pretty_env_logger::try_init();
|
||||||
|
|
||||||
let args: Vec<String> = std::env::args().collect();
|
let args = std::env::args().collect();
|
||||||
main_0(args)?;
|
async_std::task::block_on(async move { start(args).await })?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -674,7 +674,7 @@ impl Contact {
|
|||||||
let mut ret = String::new();
|
let mut ret = String::new();
|
||||||
|
|
||||||
if let Ok(contact) = Contact::load_from_db(context, contact_id).await {
|
if let Ok(contact) = Contact::load_from_db(context, contact_id).await {
|
||||||
let peerstate = Peerstate::from_addr(context, &context.sql, &contact.addr).await;
|
let peerstate = Peerstate::from_addr(context, &contact.addr).await;
|
||||||
let loginparam = LoginParam::from_database(context, "configured_").await;
|
let loginparam = LoginParam::from_database(context, "configured_").await;
|
||||||
|
|
||||||
let mut self_key = Key::from_self_public(context, &loginparam.addr, &context.sql).await;
|
let mut self_key = Key::from_self_public(context, &loginparam.addr, &context.sql).await;
|
||||||
@@ -940,7 +940,7 @@ impl Contact {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let peerstate = Peerstate::from_addr(context, &context.sql, &self.addr).await;
|
let peerstate = Peerstate::from_addr(context, &self.addr).await;
|
||||||
if let Some(ps) = peerstate {
|
if let Some(ps) = peerstate {
|
||||||
if ps.verified_key.is_some() {
|
if ps.verified_key.is_some() {
|
||||||
return VerifiedStatus::BidirectVerified;
|
return VerifiedStatus::BidirectVerified;
|
||||||
|
|||||||
@@ -136,10 +136,22 @@ impl Context {
|
|||||||
l.run(self.clone());
|
l.run(self.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn is_running(&self) -> bool {
|
||||||
|
self.inner.scheduler.read().await.is_running()
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn stop(&self) {
|
pub async fn stop(&self) {
|
||||||
self.inner.stop().await;
|
self.inner.stop().await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a reference to the underlying SQL instance.
|
||||||
|
///
|
||||||
|
/// Warning: this is only here for testing, not part of the public API.
|
||||||
|
#[cfg(feature = "internals")]
|
||||||
|
pub fn sql(&self) -> &Sql {
|
||||||
|
&self.inner.sql
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns database file path.
|
/// Returns database file path.
|
||||||
pub fn get_dbfile(&self) -> &Path {
|
pub fn get_dbfile(&self) -> &Path {
|
||||||
self.dbfile.as_path()
|
self.dbfile.as_path()
|
||||||
|
|||||||
@@ -1434,7 +1434,7 @@ async fn check_verified_properties(
|
|||||||
// this check is skipped for SELF as there is no proper SELF-peerstate
|
// this check is skipped for SELF as there is no proper SELF-peerstate
|
||||||
// and results in group-splits otherwise.
|
// and results in group-splits otherwise.
|
||||||
if from_id != DC_CONTACT_ID_SELF {
|
if from_id != DC_CONTACT_ID_SELF {
|
||||||
let peerstate = Peerstate::from_addr(context, &context.sql, contact.get_addr()).await;
|
let peerstate = Peerstate::from_addr(context, contact.get_addr()).await;
|
||||||
|
|
||||||
if peerstate.is_none()
|
if peerstate.is_none()
|
||||||
|| contact.is_verified_ex(context, peerstate.as_ref()).await
|
|| contact.is_verified_ex(context, peerstate.as_ref()).await
|
||||||
@@ -1488,7 +1488,7 @@ async fn check_verified_properties(
|
|||||||
context.is_self_addr(&to_addr).await
|
context.is_self_addr(&to_addr).await
|
||||||
);
|
);
|
||||||
let mut is_verified = _is_verified != 0;
|
let mut is_verified = _is_verified != 0;
|
||||||
let peerstate = Peerstate::from_addr(context, &context.sql, &to_addr).await;
|
let peerstate = Peerstate::from_addr(context, &to_addr).await;
|
||||||
|
|
||||||
// mark gossiped keys (if any) as verified
|
// mark gossiped keys (if any) as verified
|
||||||
if mimeparser.gossipped_addr.contains(&to_addr) {
|
if mimeparser.gossipped_addr.contains(&to_addr) {
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ pub async fn try_decrypt(
|
|||||||
let autocryptheader = Aheader::from_headers(context, &from, &mail.headers);
|
let autocryptheader = Aheader::from_headers(context, &from, &mail.headers);
|
||||||
|
|
||||||
if message_time > 0 {
|
if message_time > 0 {
|
||||||
peerstate = Peerstate::from_addr(context, &context.sql, &from).await;
|
peerstate = Peerstate::from_addr(context, &from).await;
|
||||||
|
|
||||||
if let Some(ref mut peerstate) = peerstate {
|
if let Some(ref mut peerstate) = peerstate {
|
||||||
if let Some(ref header) = autocryptheader {
|
if let Some(ref header) = autocryptheader {
|
||||||
@@ -167,7 +167,7 @@ pub async fn try_decrypt(
|
|||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
if peerstate.as_ref().map(|p| p.last_seen).unwrap_or_else(|| 0) == 0 {
|
if peerstate.as_ref().map(|p| p.last_seen).unwrap_or_else(|| 0) == 0 {
|
||||||
peerstate = Peerstate::from_addr(&context, &context.sql, &from).await;
|
peerstate = Peerstate::from_addr(&context, &from).await;
|
||||||
}
|
}
|
||||||
if let Some(ref peerstate) = peerstate {
|
if let Some(ref peerstate) = peerstate {
|
||||||
if peerstate.degrade_event.is_some() {
|
if peerstate.degrade_event.is_some() {
|
||||||
|
|||||||
17
src/lib.rs
17
src/lib.rs
@@ -20,20 +20,18 @@ pub trait ToSql: rusqlite::ToSql + Send + Sync {}
|
|||||||
|
|
||||||
impl<T: rusqlite::ToSql + Send + Sync> ToSql for T {}
|
impl<T: rusqlite::ToSql + Send + Sync> ToSql for T {}
|
||||||
|
|
||||||
macro_rules! paramsv {
|
|
||||||
() => {
|
|
||||||
Vec::new()
|
|
||||||
};
|
|
||||||
($($param:expr),+ $(,)?) => {
|
|
||||||
vec![$(&$param as &dyn $crate::ToSql),+]
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod log;
|
pub mod log;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
|
||||||
|
#[cfg(feature = "internals")]
|
||||||
|
#[macro_use]
|
||||||
|
pub mod sql;
|
||||||
|
#[cfg(not(feature = "internals"))]
|
||||||
|
#[macro_use]
|
||||||
|
mod sql;
|
||||||
|
|
||||||
pub mod headerdef;
|
pub mod headerdef;
|
||||||
|
|
||||||
pub(crate) mod events;
|
pub(crate) mod events;
|
||||||
@@ -71,7 +69,6 @@ pub mod qr;
|
|||||||
pub mod securejoin;
|
pub mod securejoin;
|
||||||
mod simplify;
|
mod simplify;
|
||||||
mod smtp;
|
mod smtp;
|
||||||
mod sql;
|
|
||||||
pub mod stock;
|
pub mod stock;
|
||||||
mod token;
|
mod token;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
|||||||
@@ -7,9 +7,7 @@ macro_rules! info {
|
|||||||
};
|
};
|
||||||
($ctx:expr, $msg:expr, $($args:expr),* $(,)?) => {{
|
($ctx:expr, $msg:expr, $($args:expr),* $(,)?) => {{
|
||||||
let formatted = format!($msg, $($args),*);
|
let formatted = format!($msg, $($args),*);
|
||||||
let thread = ::std::thread::current();
|
let full = format!("{file}:{line}: {msg}",
|
||||||
let full = format!("{thid:?} {file}:{line}: {msg}",
|
|
||||||
thid = thread.id(),
|
|
||||||
file = file!(),
|
file = file!(),
|
||||||
line = line!(),
|
line = line!(),
|
||||||
msg = &formatted);
|
msg = &formatted);
|
||||||
@@ -24,9 +22,7 @@ macro_rules! warn {
|
|||||||
};
|
};
|
||||||
($ctx:expr, $msg:expr, $($args:expr),* $(,)?) => {{
|
($ctx:expr, $msg:expr, $($args:expr),* $(,)?) => {{
|
||||||
let formatted = format!($msg, $($args),*);
|
let formatted = format!($msg, $($args),*);
|
||||||
let thread = ::std::thread::current();
|
let full = format!("{file}:{line}: {msg}",
|
||||||
let full = format!("{thid:?} {file}:{line}: {msg}",
|
|
||||||
thid = thread.id(),
|
|
||||||
file = file!(),
|
file = file!(),
|
||||||
line = line!(),
|
line = line!(),
|
||||||
msg = &formatted);
|
msg = &formatted);
|
||||||
|
|||||||
@@ -240,7 +240,7 @@ impl<'a, 'b> MimeFactory<'a, 'b> {
|
|||||||
.filter(|(_, addr)| addr != &self_addr)
|
.filter(|(_, addr)| addr != &self_addr)
|
||||||
{
|
{
|
||||||
res.push((
|
res.push((
|
||||||
Peerstate::from_addr(self.context, &self.context.sql, addr).await,
|
Peerstate::from_addr(self.context, addr).await,
|
||||||
addr.as_str(),
|
addr.as_str(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -886,7 +886,7 @@ async fn update_gossip_peerstates(
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.contains(&header.addr.to_lowercase())
|
.contains(&header.addr.to_lowercase())
|
||||||
{
|
{
|
||||||
let mut peerstate = Peerstate::from_addr(context, &context.sql, &header.addr).await;
|
let mut peerstate = Peerstate::from_addr(context, &header.addr).await;
|
||||||
if let Some(ref mut peerstate) = peerstate {
|
if let Some(ref mut peerstate) = peerstate {
|
||||||
peerstate.apply_gossip(header, message_time);
|
peerstate.apply_gossip(header, message_time);
|
||||||
peerstate.save_to_db(&context.sql, false).await?;
|
peerstate.save_to_db(&context.sql, false).await?;
|
||||||
|
|||||||
@@ -144,7 +144,7 @@ impl<'a> Peerstate<'a> {
|
|||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn from_addr(context: &'a Context, _sql: &Sql, addr: &str) -> Option<Peerstate<'a>> {
|
pub async fn from_addr(context: &'a Context, addr: &str) -> Option<Peerstate<'a>> {
|
||||||
let query = "SELECT addr, last_seen, last_seen_autocrypt, prefer_encrypted, public_key, gossip_timestamp, gossip_key, public_key_fingerprint, gossip_key_fingerprint, verified_key, verified_key_fingerprint FROM acpeerstates WHERE addr=? COLLATE NOCASE;";
|
let query = "SELECT addr, last_seen, last_seen_autocrypt, prefer_encrypted, public_key, gossip_timestamp, gossip_key, public_key_fingerprint, gossip_key_fingerprint, verified_key, verified_key_fingerprint FROM acpeerstates WHERE addr=? COLLATE NOCASE;";
|
||||||
Self::from_stmt(context, query, paramsv![addr]).await
|
Self::from_stmt(context, query, paramsv![addr]).await
|
||||||
}
|
}
|
||||||
@@ -510,7 +510,7 @@ mod tests {
|
|||||||
"failed to save to db"
|
"failed to save to db"
|
||||||
);
|
);
|
||||||
|
|
||||||
let peerstate_new = Peerstate::from_addr(&ctx.ctx, &ctx.ctx.sql, addr)
|
let peerstate_new = Peerstate::from_addr(&ctx.ctx, addr)
|
||||||
.await
|
.await
|
||||||
.expect("failed to load peerstate from db");
|
.expect("failed to load peerstate from db");
|
||||||
|
|
||||||
@@ -586,7 +586,7 @@ mod tests {
|
|||||||
"failed to save"
|
"failed to save"
|
||||||
);
|
);
|
||||||
|
|
||||||
let peerstate_new = Peerstate::from_addr(&ctx.ctx, &ctx.ctx.sql, addr)
|
let peerstate_new = Peerstate::from_addr(&ctx.ctx, addr)
|
||||||
.await
|
.await
|
||||||
.expect("failed to load peerstate from db");
|
.expect("failed to load peerstate from db");
|
||||||
|
|
||||||
|
|||||||
@@ -217,7 +217,6 @@ impl Scheduler {
|
|||||||
task::spawn(async move { smtp_loop(ctx1, smtp_handlers).await });
|
task::spawn(async move { smtp_loop(ctx1, smtp_handlers).await });
|
||||||
|
|
||||||
info!(ctx, "scheduler is running");
|
info!(ctx, "scheduler is running");
|
||||||
println!("RUN DONE");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_probe_network(&mut self, val: bool) {
|
fn set_probe_network(&mut self, val: bool) {
|
||||||
|
|||||||
@@ -349,9 +349,7 @@ async fn fingerprint_equals_sender(
|
|||||||
|
|
||||||
if contacts.len() == 1 {
|
if contacts.len() == 1 {
|
||||||
if let Ok(contact) = Contact::load_from_db(context, contacts[0]).await {
|
if let Ok(contact) = Contact::load_from_db(context, contacts[0]).await {
|
||||||
if let Some(peerstate) =
|
if let Some(peerstate) = Peerstate::from_addr(context, contact.get_addr()).await {
|
||||||
Peerstate::from_addr(context, &context.sql, contact.get_addr()).await
|
|
||||||
{
|
|
||||||
let fingerprint_normalized = dc_normalize_fingerprint(fingerprint.as_ref());
|
let fingerprint_normalized = dc_normalize_fingerprint(fingerprint.as_ref());
|
||||||
if peerstate.public_key_fingerprint.is_some()
|
if peerstate.public_key_fingerprint.is_some()
|
||||||
&& &fingerprint_normalized == peerstate.public_key_fingerprint.as_ref().unwrap()
|
&& &fingerprint_normalized == peerstate.public_key_fingerprint.as_ref().unwrap()
|
||||||
|
|||||||
12
src/sql.rs
12
src/sql.rs
@@ -17,6 +17,16 @@ use crate::dc_tools::*;
|
|||||||
use crate::param::*;
|
use crate::param::*;
|
||||||
use crate::peerstate::*;
|
use crate::peerstate::*;
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! paramsv {
|
||||||
|
() => {
|
||||||
|
Vec::new()
|
||||||
|
};
|
||||||
|
($($param:expr),+ $(,)?) => {
|
||||||
|
vec![$(&$param as &dyn $crate::ToSql),+]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Fail)]
|
#[derive(Debug, Fail)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[fail(display = "Sqlite Error: {:?}", _0)]
|
#[fail(display = "Sqlite Error: {:?}", _0)]
|
||||||
@@ -1295,7 +1305,7 @@ async fn open(
|
|||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
for addr in &addrs {
|
for addr in &addrs {
|
||||||
if let Some(ref mut peerstate) = Peerstate::from_addr(context, sql, addr).await {
|
if let Some(ref mut peerstate) = Peerstate::from_addr(context, addr).await {
|
||||||
peerstate.recalc_fingerprint();
|
peerstate.recalc_fingerprint();
|
||||||
peerstate.save_to_db(sql, false).await?;
|
peerstate.save_to_db(sql, false).await?;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user