mirror of
https://github.com/chatmail/core.git
synced 2026-04-02 13:32:11 +03:00
Compare commits
71 Commits
fix/str-de
...
fix_progre
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d13427cc84 | ||
|
|
ed237c8d25 | ||
|
|
d46a5345d2 | ||
|
|
6067160582 | ||
|
|
3175c4f7ba | ||
|
|
a29f06a730 | ||
|
|
c713474d1f | ||
|
|
89c874d4a9 | ||
|
|
5e3cba9b70 | ||
|
|
a7894fd785 | ||
|
|
c638a770f9 | ||
|
|
6ced6ac23b | ||
|
|
d0b77b61eb | ||
|
|
b440c3636b | ||
|
|
dfd58961f7 | ||
|
|
139c9f37b1 | ||
|
|
2445b12898 | ||
|
|
4d402f3a06 | ||
|
|
ab022ccc33 | ||
|
|
fb7bbac524 | ||
|
|
39fbff5fb6 | ||
|
|
3ac1eaf7d2 | ||
|
|
6c95d008e0 | ||
|
|
16f891c290 | ||
|
|
650bddd54b | ||
|
|
9e30df4b43 | ||
|
|
50c592e41f | ||
|
|
bdf8cd2dd5 | ||
|
|
5554df29fd | ||
|
|
2dd3088f50 | ||
|
|
b9bd128c7a | ||
|
|
adb67d1910 | ||
|
|
ce3b815bd8 | ||
|
|
b94f9ef496 | ||
|
|
77db475663 | ||
|
|
a3683be047 | ||
|
|
9dca19d6c9 | ||
|
|
3ba847ece2 | ||
|
|
91bf948d1e | ||
|
|
91fec77f4b | ||
|
|
8fb25a6340 | ||
|
|
cf49acff67 | ||
|
|
4f1a25e1bf | ||
|
|
8608daa7dc | ||
|
|
828e6e3fd0 | ||
|
|
ff021fed1f | ||
|
|
ed66f36cb5 | ||
|
|
b7ff996b15 | ||
|
|
faf53fe11e | ||
|
|
b23c4b4da6 | ||
|
|
966bb2271a | ||
|
|
5438be891b | ||
|
|
f31f603c8b | ||
|
|
ff39fa0fed | ||
|
|
cdf3809634 | ||
|
|
b2a2791f6f | ||
|
|
125df968d2 | ||
|
|
1c5d07a29f | ||
|
|
24b025f573 | ||
|
|
d323bd3593 | ||
|
|
b7174783f1 | ||
|
|
e3269616bd | ||
|
|
64051fca10 | ||
|
|
14ce55b1a8 | ||
|
|
be605d8ea5 | ||
|
|
4d8d5f4e1e | ||
|
|
750d6e99a8 | ||
|
|
a67892d414 | ||
|
|
1cd2a62caf | ||
|
|
6772d6f66c | ||
|
|
89531dfb62 |
9
Cargo.lock
generated
9
Cargo.lock
generated
@@ -467,6 +467,7 @@ dependencies = [
|
||||
"cc 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"charset 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"deltachat_derive 0.1.0",
|
||||
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
@@ -501,6 +502,14 @@ dependencies = [
|
||||
"thread-local-object 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deltachat_derive"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "deltachat_ffi"
|
||||
version = "1.0.0-alpha.3"
|
||||
|
||||
@@ -10,6 +10,7 @@ cc = "1.0.35"
|
||||
pkg-config = "0.3"
|
||||
|
||||
[dependencies]
|
||||
deltachat_derive = { path = "./deltachat_derive" }
|
||||
libc = "0.2.51"
|
||||
pgp = { version = "0.2", default-features = false }
|
||||
hex = "0.3.2"
|
||||
@@ -53,7 +54,8 @@ pretty_env_logger = "0.3.0"
|
||||
|
||||
[workspace]
|
||||
members = [
|
||||
"deltachat-ffi"
|
||||
"deltachat-ffi",
|
||||
"deltachat_derive",
|
||||
]
|
||||
|
||||
[[example]]
|
||||
|
||||
@@ -89,6 +89,14 @@ $ cargo test --all
|
||||
$ cargo build -p deltachat_ffi --release
|
||||
```
|
||||
|
||||
### Expensive tests
|
||||
|
||||
Some tests are expensive and marked with `#[ignore]`, to run these
|
||||
use the `--ignored` argument to the test binary (not to cargo itself):
|
||||
```sh
|
||||
$ cargo test -- --ignored
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
- `vendored`: When using Openssl for TLS, this bundles a vendored version.
|
||||
|
||||
@@ -16,7 +16,7 @@ export BRANCH=${CIRCLE_BRANCH:-test7}
|
||||
#fi
|
||||
|
||||
# run everything else inside docker (TESTS, DOCS, WHEELS)
|
||||
docker run -e BRANCH -e TESTS -e DOCS \
|
||||
docker run -e DCC_PY_LIVECONFIG -e BRANCH -e TESTS -e DOCS \
|
||||
--rm -it -v $(pwd):/mnt -w /mnt \
|
||||
deltachat/coredeps ci_scripts/run_all.sh
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ export BRANCH=${CIRCLE_BRANCH:?specify branch for uploading purposes}
|
||||
|
||||
|
||||
# python docs to py.delta.chat
|
||||
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null delta@py.delta.chat mkdir -p build/${BRANCH}
|
||||
rsync -avz \
|
||||
-e "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" \
|
||||
"$PYDOCDIR/html/" \
|
||||
@@ -37,11 +38,13 @@ pip install devpi-client
|
||||
devpi use https://m.devpi.net
|
||||
devpi login dc --password $DEVPI_LOGIN
|
||||
|
||||
devpi use dc/$BRANCH || {
|
||||
devpi index -c $BRANCH
|
||||
devpi use dc/$BRANCH
|
||||
N_BRANCH=${BRANCH//[\/]}
|
||||
|
||||
devpi use dc/$N_BRANCH || {
|
||||
devpi index -c $N_BRANCH
|
||||
devpi use dc/$N_BRANCH
|
||||
}
|
||||
devpi index $BRANCH bases=/root/pypi
|
||||
devpi index $N_BRANCH bases=/root/pypi
|
||||
devpi upload deltachat*.whl
|
||||
|
||||
popd
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
set -e -x
|
||||
|
||||
# Install Rust
|
||||
curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain nightly-2019-04-19 -y
|
||||
curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain nightly-2019-07-10 -y
|
||||
export PATH=/root/.cargo/bin:$PATH
|
||||
rustc --version
|
||||
|
||||
# remove some 300-400 MB that we don't need for automated builds
|
||||
rm -rf /root/.rustup/toolchains/nightly-2019-04-19-x86_64-unknown-linux-gnu/share/
|
||||
rm -rf /root/.rustup/toolchains/nightly-2019-07-10-x86_64-unknown-linux-gnu/share/
|
||||
|
||||
@@ -37,6 +37,10 @@ if [ -n "$TESTS" ]; then
|
||||
export PYTHONDONTWRITEBYTECODE=1
|
||||
|
||||
# run tox
|
||||
# XXX we don't run liveconfig tests because they hang sometimes
|
||||
# see https://github.com/deltachat/deltachat-core-rust/issues/331
|
||||
unset DCC_PY_LIVECONFIG
|
||||
|
||||
tox --workdir "$TOXWORKDIR" -e lint,py27,py35,py36,py37,auditwheels
|
||||
popd
|
||||
fi
|
||||
|
||||
@@ -44,11 +44,14 @@ pub unsafe extern "C" fn dc_context_new(
|
||||
Box::into_raw(Box::new(ctx))
|
||||
}
|
||||
|
||||
/// Release the context structure.
|
||||
///
|
||||
/// This function releases the memory of the `dc_context_t` structure.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn dc_context_unref(context: *mut dc_context_t) {
|
||||
assert!(!context.is_null());
|
||||
let context = &mut *context;
|
||||
context::dc_context_unref(context);
|
||||
context::dc_close(context);
|
||||
Box::from_raw(context);
|
||||
}
|
||||
|
||||
@@ -542,7 +545,7 @@ pub unsafe extern "C" fn dc_get_chat_contacts(
|
||||
assert!(!context.is_null());
|
||||
let context = &*context;
|
||||
|
||||
dc_chat::dc_get_chat_contacts(context, chat_id)
|
||||
dc_array_t::from(dc_chat::dc_get_chat_contacts(context, chat_id)).into_raw()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
@@ -814,7 +817,7 @@ pub unsafe extern "C" fn dc_get_contacts(
|
||||
};
|
||||
|
||||
match Contact::get_all(context, flags, query) {
|
||||
Ok(contacts) => contacts,
|
||||
Ok(contacts) => dc_array_t::from(contacts).into_raw(),
|
||||
Err(_) => std::ptr::null_mut(),
|
||||
}
|
||||
}
|
||||
@@ -861,7 +864,12 @@ pub unsafe extern "C" fn dc_get_contact_encrinfo(
|
||||
assert!(!context.is_null());
|
||||
let context = &*context;
|
||||
|
||||
Contact::get_encrinfo(context, contact_id).strdup()
|
||||
Contact::get_encrinfo(context, contact_id)
|
||||
.map(|s| s.strdup())
|
||||
.unwrap_or_else(|e| {
|
||||
error!(context, 0, "{}", e);
|
||||
std::ptr::null_mut()
|
||||
})
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
||||
12
deltachat_derive/Cargo.toml
Normal file
12
deltachat_derive/Cargo.toml
Normal file
@@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "deltachat_derive"
|
||||
version = "0.1.0"
|
||||
authors = ["Dmitry Bogatov <KAction@debian.org>"]
|
||||
edition = "2018"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
syn = "0.14.4"
|
||||
quote = "0.6.3"
|
||||
45
deltachat_derive/src/lib.rs
Normal file
45
deltachat_derive/src/lib.rs
Normal file
@@ -0,0 +1,45 @@
|
||||
#![recursion_limit = "128"]
|
||||
extern crate proc_macro;
|
||||
|
||||
use crate::proc_macro::TokenStream;
|
||||
use quote::quote;
|
||||
use syn;
|
||||
|
||||
// For now, assume (not check) that these macroses are applied to enum without
|
||||
// data. If this assumption is violated, compiler error will point to
|
||||
// generated code, which is not very user-friendly.
|
||||
|
||||
#[proc_macro_derive(ToSql)]
|
||||
pub fn to_sql_derive(input: TokenStream) -> TokenStream {
|
||||
let ast: syn::DeriveInput = syn::parse(input).unwrap();
|
||||
let name = &ast.ident;
|
||||
|
||||
let gen = quote! {
|
||||
impl rusqlite::types::ToSql for #name {
|
||||
fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput> {
|
||||
let num = *self as i64;
|
||||
let value = rusqlite::types::Value::Integer(num);
|
||||
let output = rusqlite::types::ToSqlOutput::Owned(value);
|
||||
|
||||
std::result::Result::Ok(output)
|
||||
}
|
||||
}
|
||||
};
|
||||
gen.into()
|
||||
}
|
||||
|
||||
#[proc_macro_derive(FromSql)]
|
||||
pub fn from_sql_derive(input: TokenStream) -> TokenStream {
|
||||
let ast: syn::DeriveInput = syn::parse(input).unwrap();
|
||||
let name = &ast.ident;
|
||||
|
||||
let gen = quote! {
|
||||
impl rusqlite::types::FromSql for #name {
|
||||
fn column_result(col: rusqlite::types::ValueRef) -> rusqlite::types::FromSqlResult<Self> {
|
||||
let inner = rusqlite::types::FromSql::column_result(col)?;
|
||||
num_traits::FromPrimitive::from_i64(inner).ok_or(rusqlite::types::FromSqlError::InvalidType)
|
||||
}
|
||||
}
|
||||
};
|
||||
gen.into()
|
||||
}
|
||||
@@ -125,7 +125,7 @@ unsafe fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int
|
||||
return 0;
|
||||
}
|
||||
|
||||
let mut current_block: u64;
|
||||
let ok_to_continue;
|
||||
let mut success: libc::c_int = 0;
|
||||
let real_spec: *mut libc::c_char;
|
||||
let mut suffix: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
@@ -138,77 +138,71 @@ unsafe fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int
|
||||
.sql
|
||||
.set_config(context, "import_spec", Some(as_str(real_spec)))
|
||||
.unwrap();
|
||||
current_block = 7149356873433890176;
|
||||
ok_to_continue = true;
|
||||
} else {
|
||||
let rs = context.sql.get_config(context, "import_spec");
|
||||
if rs.is_none() {
|
||||
error!(context, 0, "Import: No file or folder given.");
|
||||
current_block = 8522321847195001863;
|
||||
ok_to_continue = false;
|
||||
} else {
|
||||
current_block = 7149356873433890176;
|
||||
ok_to_continue = true;
|
||||
}
|
||||
real_spec = rs.unwrap_or_default().strdup();
|
||||
}
|
||||
match current_block {
|
||||
8522321847195001863 => {}
|
||||
_ => {
|
||||
suffix = dc_get_filesuffix_lc(real_spec);
|
||||
if !suffix.is_null()
|
||||
&& strcmp(suffix, b"eml\x00" as *const u8 as *const libc::c_char) == 0
|
||||
{
|
||||
if 0 != dc_poke_eml_file(context, real_spec) {
|
||||
read_cnt += 1
|
||||
}
|
||||
current_block = 1622411330066726685;
|
||||
if ok_to_continue {
|
||||
let ok_to_continue2;
|
||||
suffix = dc_get_filesuffix_lc(real_spec);
|
||||
if !suffix.is_null() && strcmp(suffix, b"eml\x00" as *const u8 as *const libc::c_char) == 0
|
||||
{
|
||||
if 0 != dc_poke_eml_file(context, real_spec) {
|
||||
read_cnt += 1
|
||||
}
|
||||
ok_to_continue2 = true;
|
||||
} else {
|
||||
/* import a directory */
|
||||
let dir_name = std::path::Path::new(as_str(real_spec));
|
||||
let dir = std::fs::read_dir(dir_name);
|
||||
if dir.is_err() {
|
||||
error!(
|
||||
context,
|
||||
0,
|
||||
"Import: Cannot open directory \"{}\".",
|
||||
as_str(real_spec),
|
||||
);
|
||||
ok_to_continue2 = false;
|
||||
} else {
|
||||
/* import a directory */
|
||||
let dir_name = std::path::Path::new(as_str(real_spec));
|
||||
let dir = std::fs::read_dir(dir_name);
|
||||
if dir.is_err() {
|
||||
error!(
|
||||
context,
|
||||
0,
|
||||
"Import: Cannot open directory \"{}\".",
|
||||
as_str(real_spec),
|
||||
);
|
||||
current_block = 8522321847195001863;
|
||||
} else {
|
||||
let dir = dir.unwrap();
|
||||
for entry in dir {
|
||||
if entry.is_err() {
|
||||
break;
|
||||
}
|
||||
let entry = entry.unwrap();
|
||||
let name_f = entry.file_name();
|
||||
let name = name_f.to_string_lossy();
|
||||
if name.ends_with(".eml") {
|
||||
let path_plus_name = format!("{}/{}", as_str(real_spec), name);
|
||||
info!(context, 0, "Import: {}", path_plus_name);
|
||||
let path_plus_name_c = CString::yolo(path_plus_name);
|
||||
if 0 != dc_poke_eml_file(context, path_plus_name_c.as_ptr()) {
|
||||
read_cnt += 1
|
||||
}
|
||||
let dir = dir.unwrap();
|
||||
for entry in dir {
|
||||
if entry.is_err() {
|
||||
break;
|
||||
}
|
||||
let entry = entry.unwrap();
|
||||
let name_f = entry.file_name();
|
||||
let name = name_f.to_string_lossy();
|
||||
if name.ends_with(".eml") {
|
||||
let path_plus_name = format!("{}/{}", as_str(real_spec), name);
|
||||
info!(context, 0, "Import: {}", path_plus_name);
|
||||
let path_plus_name_c = CString::yolo(path_plus_name);
|
||||
if 0 != dc_poke_eml_file(context, path_plus_name_c.as_ptr()) {
|
||||
read_cnt += 1
|
||||
}
|
||||
}
|
||||
current_block = 1622411330066726685;
|
||||
}
|
||||
ok_to_continue2 = true;
|
||||
}
|
||||
match current_block {
|
||||
8522321847195001863 => {}
|
||||
_ => {
|
||||
info!(
|
||||
context,
|
||||
0,
|
||||
"Import: {} items read from \"{}\".",
|
||||
read_cnt,
|
||||
as_str(real_spec)
|
||||
);
|
||||
if read_cnt > 0 {
|
||||
context.call_cb(Event::MSGS_CHANGED, 0 as uintptr_t, 0 as uintptr_t);
|
||||
}
|
||||
success = 1
|
||||
}
|
||||
}
|
||||
if ok_to_continue2 {
|
||||
info!(
|
||||
context,
|
||||
0,
|
||||
"Import: {} items read from \"{}\".",
|
||||
read_cnt,
|
||||
as_str(real_spec)
|
||||
);
|
||||
if read_cnt > 0 {
|
||||
context.call_cb(Event::MSGS_CHANGED, 0 as uintptr_t, 0 as uintptr_t);
|
||||
}
|
||||
success = 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -301,13 +295,12 @@ unsafe fn log_msglist(context: &Context, msglist: *mut dc_array_t) {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn log_contactlist(context: &Context, contacts: *mut dc_array_t) {
|
||||
if !dc_array_search_id(contacts, 1 as uint32_t, 0 as *mut size_t) {
|
||||
dc_array_add_id(contacts, 1 as uint32_t);
|
||||
unsafe fn log_contactlist(context: &Context, contacts: &Vec<u32>) {
|
||||
let mut contacts = contacts.clone();
|
||||
if !contacts.contains(&1) {
|
||||
contacts.push(1);
|
||||
}
|
||||
let cnt = dc_array_get_cnt(contacts);
|
||||
for i in 0..cnt {
|
||||
let contact_id = dc_array_get_id(contacts, i as size_t);
|
||||
for contact_id in contacts {
|
||||
let line;
|
||||
let mut line2 = "".to_string();
|
||||
if let Ok(contact) = Contact::get_by_id(context, contact_id) {
|
||||
@@ -471,7 +464,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
event <event-id to test>\n\
|
||||
fileinfo <file>\n\
|
||||
clear -- clear screen\n\
|
||||
exit\n\
|
||||
exit or quit\n\
|
||||
============================================="
|
||||
),
|
||||
},
|
||||
@@ -604,9 +597,13 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
}
|
||||
"listchats" | "listarchived" | "chats" => {
|
||||
let listflags = if arg0 == "listarchived" { 0x01 } else { 0 };
|
||||
let chatlist = Chatlist::try_load(context, listflags, Some(arg1), None)?;
|
||||
let chatlist = Chatlist::try_load(
|
||||
context,
|
||||
listflags,
|
||||
if arg1.is_empty() { None } else { Some(arg1) },
|
||||
None,
|
||||
)?;
|
||||
|
||||
let mut i: usize;
|
||||
let cnt = chatlist.len();
|
||||
if cnt > 0 {
|
||||
info!(
|
||||
@@ -614,9 +611,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
"================================================================================"
|
||||
);
|
||||
|
||||
i = cnt - 1;
|
||||
|
||||
while i > 0 {
|
||||
for i in (0..cnt).rev() {
|
||||
let chat = dc_get_chat(context, chatlist.get_chat_id(i));
|
||||
let temp_subtitle = dc_chat_get_subtitle(chat);
|
||||
let temp_name = dc_chat_get_name(chat);
|
||||
@@ -670,8 +665,6 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
context, 0,
|
||||
"================================================================================"
|
||||
);
|
||||
|
||||
i -= 1
|
||||
}
|
||||
}
|
||||
if dc_is_sending_locations_to_chat(context, 0 as uint32_t) {
|
||||
@@ -835,16 +828,14 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
ensure!(!sel_chat.is_null(), "No chat selected.");
|
||||
|
||||
let contacts = dc_get_chat_contacts(context, dc_chat_get_id(sel_chat));
|
||||
ensure!(!contacts.is_null(), "Failed to retreive contacts");
|
||||
info!(context, 0, "Memberlist:");
|
||||
|
||||
log_contactlist(context, contacts);
|
||||
log_contactlist(context, &contacts);
|
||||
println!(
|
||||
"{} contacts\nLocation streaming: {}",
|
||||
dc_array_get_cnt(contacts),
|
||||
contacts.len(),
|
||||
dc_is_sending_locations_to_chat(context, dc_chat_get_id(sel_chat)),
|
||||
);
|
||||
dc_array_unref(contacts);
|
||||
}
|
||||
"getlocations" => {
|
||||
let contact_id = arg1.parse().unwrap_or_default();
|
||||
@@ -1064,13 +1055,8 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
},
|
||||
Some(arg1),
|
||||
)?;
|
||||
if !contacts.is_null() {
|
||||
log_contactlist(context, contacts);
|
||||
println!("{} contacts.", dc_array_get_cnt(contacts) as libc::c_int,);
|
||||
dc_array_unref(contacts);
|
||||
} else {
|
||||
bail!("");
|
||||
}
|
||||
log_contactlist(context, &contacts);
|
||||
println!("{} contacts.", contacts.len());
|
||||
}
|
||||
"addcontact" => {
|
||||
ensure!(!arg1.is_empty(), "Arguments [<name>] <addr> expected.");
|
||||
@@ -1091,7 +1077,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
|
||||
|
||||
let mut res = format!("Contact info for: {}:\n\n", name_n_addr);
|
||||
|
||||
res += &Contact::get_encrinfo(context, contact_id);
|
||||
res += &Contact::get_encrinfo(context, contact_id)?;
|
||||
|
||||
let chatlist = Chatlist::try_load(context, 0, None, Some(contact_id))?;
|
||||
let chatlist_cnt = chatlist.len();
|
||||
|
||||
@@ -335,8 +335,8 @@ const CONTACT_COMMANDS: [&'static str; 6] = [
|
||||
"delcontact",
|
||||
"cleanupcontacts",
|
||||
];
|
||||
const MISC_COMMANDS: [&'static str; 8] = [
|
||||
"getqr", "getbadqr", "checkqr", "event", "fileinfo", "clear", "exit", "help",
|
||||
const MISC_COMMANDS: [&'static str; 9] = [
|
||||
"getqr", "getbadqr", "checkqr", "event", "fileinfo", "clear", "exit", "quit", "help",
|
||||
];
|
||||
|
||||
impl Hinter for DcHelper {
|
||||
@@ -456,12 +456,6 @@ fn main_0(args: Vec<String>) -> Result<(), failure::Error> {
|
||||
println!("history saved");
|
||||
{
|
||||
stop_threads(&ctx.read().unwrap());
|
||||
|
||||
unsafe {
|
||||
let mut ctx = ctx.write().unwrap();
|
||||
dc_close(&mut ctx);
|
||||
dc_context_unref(&mut ctx);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -556,7 +550,7 @@ unsafe fn handle_cmd(line: &str, ctx: Arc<RwLock<Context>>) -> Result<ExitResult
|
||||
dc_join_securejoin(&ctx.read().unwrap(), arg1_c);
|
||||
}
|
||||
}
|
||||
"exit" => return Ok(ExitResult::Exit),
|
||||
"exit" | "quit" => return Ok(ExitResult::Exit),
|
||||
_ => dc_cmdline(&ctx.read().unwrap(), line)?,
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ without any "build-from-source" steps.
|
||||
1. `Install virtualenv <https://virtualenv.pypa.io/en/stable/installation/>`_,
|
||||
then create a fresh python environment and activate it in your shell::
|
||||
|
||||
virtualenv -p python3 venv
|
||||
virtualenv venv # or: python -m venv
|
||||
source venv/bin/activate
|
||||
|
||||
Afterwards, invoking ``python`` or ``pip install`` will only
|
||||
@@ -39,6 +39,12 @@ and push them to a python package index. To install the latest github ``master``
|
||||
|
||||
pip install -i https://m.devpi.net/dc/master deltachat
|
||||
|
||||
.. note::
|
||||
|
||||
If you can help to automate the building of wheels for Mac or Windows,
|
||||
that'd be much appreciated! please then get
|
||||
`in contact with us <https://delta.chat/en/contribute>`_.
|
||||
|
||||
|
||||
Installing bindings from source
|
||||
===============================
|
||||
@@ -48,34 +54,55 @@ to core deltachat library::
|
||||
|
||||
git clone https://github.com/deltachat/deltachat-core-rust
|
||||
cd deltachat-core-rust
|
||||
cargo build -p deltachat_ffi --release
|
||||
|
||||
This will result in a ``libdeltachat.so`` and ``libdeltachat.a`` files
|
||||
in the ``target/release`` directory. These files are needed for
|
||||
creating the python bindings for deltachat::
|
||||
|
||||
cd python
|
||||
DCC_RS_DEV=`pwd`/.. pip install -e .
|
||||
|
||||
Now test if the bindings find the correct library::
|
||||
If you don't have one active, create and activate a python "virtualenv":
|
||||
|
||||
python -c 'import deltachat ; print(deltachat.__version__)'
|
||||
python virtualenv venv # or python -m venv
|
||||
source venv/bin/activate
|
||||
|
||||
This should print your deltachat bindings version.
|
||||
Afterwards ``which python`` tells you that it comes out of the "venv"
|
||||
directory that contains all python install artifacts. Let's first
|
||||
install test tools::
|
||||
|
||||
pip install pytest pytest-timeout requests
|
||||
|
||||
then cargo-build and install the deltachat bindings::
|
||||
|
||||
python install_python_bindings.py
|
||||
|
||||
The bindings will be installed in release mode but with debug symbols.
|
||||
The release mode is neccessary because some tests generate RSA keys
|
||||
which is prohibitively slow in debug mode.
|
||||
|
||||
After succcessul binding installation you can finally run the tests::
|
||||
|
||||
pytest -v tests
|
||||
|
||||
.. note::
|
||||
|
||||
If you can help to automate the building of wheels for Mac or Windows,
|
||||
that'd be much appreciated! please then get
|
||||
`in contact with us <https://delta.chat/en/contribute>`_.
|
||||
Some tests are sometimes failing/hanging because of
|
||||
https://github.com/deltachat/deltachat-core-rust/issues/331
|
||||
and
|
||||
https://github.com/deltachat/deltachat-core-rust/issues/326
|
||||
|
||||
Using a system-installed deltachat-core-rust
|
||||
--------------------------------------------
|
||||
|
||||
When calling ``pip`` without specifying the ``DCC_RS_DEV`` environment
|
||||
variable cffi will try to use a ``deltachat.h`` from a system location
|
||||
like ``/usr/local/include`` and will try to dynamically link against a
|
||||
``libdeltachat.so`` in a similar location (e.g. ``/usr/local/lib``).
|
||||
running "live" tests (experimental)
|
||||
-----------------------------------
|
||||
|
||||
If you want to run "liveconfig" functional tests you can set
|
||||
``DCC_PY_LIVECONFIG`` to:
|
||||
|
||||
- a particular https-url that you can ask for from the delta
|
||||
chat devs.
|
||||
|
||||
- or the path of a file that contains two lines, each describing
|
||||
via "addr=... mail_pwd=..." a test account login that will
|
||||
be used for the live tests.
|
||||
|
||||
With ``DCC_PY_LIVECONFIG`` set pytest invocations will use real
|
||||
e-mail accounts and run through all functional "liveconfig" tests.
|
||||
|
||||
|
||||
|
||||
Code examples
|
||||
@@ -84,68 +111,34 @@ Code examples
|
||||
You may look at `examples <https://py.delta.chat/examples.html>`_.
|
||||
|
||||
|
||||
Running tests
|
||||
=============
|
||||
|
||||
Get a checkout of the `deltachat-core-rust github repository`_ and type::
|
||||
|
||||
pip install tox
|
||||
./run-integration-tests.sh
|
||||
|
||||
If you want to run functional tests with real
|
||||
e-mail test accounts, generate a "liveconfig" file where each
|
||||
lines contains test account settings, for example::
|
||||
|
||||
# 'liveconfig' file specifying imap/smtp accounts
|
||||
addr=some-email@example.org mail_pw=password
|
||||
addr=other-email@example.org mail_pw=otherpassword
|
||||
|
||||
The "keyword=value" style allows to specify any
|
||||
`deltachat account config setting <https://c.delta.chat/classdc__context__t.html#aff3b894f6cfca46cab5248fdffdf083d>`_ so you can also specify smtp or imap servers, ports, ssl modes etc.
|
||||
Typically DC's automatic configuration allows to not specify these settings.
|
||||
|
||||
The ``run-integration-tests.sh`` script will automatically use
|
||||
``python/liveconfig`` if it exists, to manually run tests with this
|
||||
``liveconfig`` file use::
|
||||
|
||||
tox -- --liveconfig liveconfig
|
||||
|
||||
|
||||
.. _`deltachat-core-rust github repository`: https://github.com/deltachat/deltachat-core-rust
|
||||
.. _`deltachat-core`: https://github.com/deltachat/deltachat-core-rust
|
||||
|
||||
Running test using a debug build
|
||||
--------------------------------
|
||||
|
||||
If you need to examine e.g. a coredump you may want to run the tests
|
||||
using a debug build::
|
||||
|
||||
DCC_RS_TARGET=debug ./run-integration-tests.sh -e py37 -- -x -v -k failing_test
|
||||
|
||||
|
||||
Building manylinux1 wheels
|
||||
==========================
|
||||
|
||||
.. note::
|
||||
|
||||
This section may not fully work.
|
||||
|
||||
Building portable manylinux1 wheels which come with libdeltachat.so
|
||||
and all it's dependencies is easy using the provided docker tooling.
|
||||
|
||||
using docker pull / premade images
|
||||
------------------------------------
|
||||
|
||||
We publish a build environment under the ``deltachat/wheel`` tag so
|
||||
We publish a build environment under the ``deltachat/coredeps`` tag so
|
||||
that you can pull it from the ``hub.docker.com`` site's "deltachat"
|
||||
organization::
|
||||
|
||||
$ docker pull deltachat/wheel
|
||||
$ docker pull deltachat/coredeps
|
||||
|
||||
The ``deltachat/wheel`` image can be used to build both libdeltachat.so
|
||||
and the Python wheels::
|
||||
This docker image can be used to run tests and build Python wheels for all interpreters::
|
||||
|
||||
$ docker run --rm -it -v $(pwd):/io/ deltachat/wheel /io/python/wheelbuilder/build-wheels.sh
|
||||
$ bash ci_scripts/ci_run.sh
|
||||
|
||||
This command runs a script within the image, after mounting ``$(pwd)`` as ``/io`` within
|
||||
the docker image. The script is specified as a path within the docker image's filesystem.
|
||||
The resulting wheel files will be in ``python/wheelhouse``.
|
||||
This command runs tests and build-wheel scripts in a docker container.
|
||||
|
||||
|
||||
Optionally build your own docker image
|
||||
@@ -154,10 +147,10 @@ Optionally build your own docker image
|
||||
If you want to build your own custom docker image you can do this::
|
||||
|
||||
$ cd deltachat-core # cd to deltachat-core checkout directory
|
||||
$ docker build -t deltachat/wheel python/wheelbuilder/
|
||||
$ docker build -t deltachat/coredeps ci_scripts/docker_coredeps
|
||||
|
||||
This will use the ``python/wheelbuilder/Dockerfile`` to build
|
||||
up docker image called ``deltachat/wheel``. You can afterwards
|
||||
This will use the ``ci_scripts/docker_coredeps/Dockerfile`` to build
|
||||
up docker image called ``deltachat/coredeps``. You can afterwards
|
||||
find it with::
|
||||
|
||||
$ docker images
|
||||
|
||||
@@ -6,29 +6,18 @@
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import os
|
||||
|
||||
if __name__ == "__main__":
|
||||
os.environ["DCC_RS_TARGET"] = target = "release"
|
||||
if "DCC_RS_DEV" not in os.environ:
|
||||
dn = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
os.environ["DCC_RS_DEV"] = dn
|
||||
|
||||
toml = os.path.join(os.getcwd(), "..", "Cargo.toml")
|
||||
assert os.path.exists(toml)
|
||||
with open(toml) as f:
|
||||
s = orig = f.read()
|
||||
s += "\n"
|
||||
s += "[profile.release]\n"
|
||||
s += "debug = true\n"
|
||||
with open(toml, "w") as f:
|
||||
f.write(s)
|
||||
print("temporarily modifying Cargo.toml to provide release build with debug symbols ")
|
||||
try:
|
||||
subprocess.check_call([
|
||||
"cargo", "build", "-p", "deltachat_ffi", "--" + target
|
||||
])
|
||||
finally:
|
||||
with open(toml, "w") as f:
|
||||
f.write(orig)
|
||||
print("\nreseted Cargo.toml to previous original state")
|
||||
|
||||
os.environ["RUSTFLAGS"] = "-g"
|
||||
subprocess.check_call([
|
||||
"cargo", "build", "-p", "deltachat_ffi", "--" + target
|
||||
])
|
||||
subprocess.check_call("rm -rf build/ src/deltachat/*.so" , shell=True)
|
||||
|
||||
subprocess.check_call([
|
||||
|
||||
@@ -6,10 +6,15 @@ import platform
|
||||
import os
|
||||
import cffi
|
||||
import shutil
|
||||
from os.path import dirname as dn
|
||||
from os.path import abspath
|
||||
|
||||
|
||||
def ffibuilder():
|
||||
projdir = os.environ.get('DCC_RS_DEV')
|
||||
if not projdir:
|
||||
p = dn(dn(dn(dn(abspath(__file__)))))
|
||||
projdir = os.environ["DCC_RS_DEV"] = p
|
||||
target = os.environ.get('DCC_RS_TARGET', 'release')
|
||||
if projdir:
|
||||
if platform.system() == 'Darwin':
|
||||
|
||||
@@ -50,8 +50,9 @@ class Account(object):
|
||||
self._configkeys = self.get_config("sys.config_keys").split()
|
||||
self._imex_completed = threading.Event()
|
||||
|
||||
def __del__(self):
|
||||
self.shutdown()
|
||||
# XXX this can cause "illegal instructions" at test ends so we omit it for now
|
||||
# def __del__(self):
|
||||
# self.shutdown()
|
||||
|
||||
def _check_config_key(self, name):
|
||||
if name not in self._configkeys:
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
from __future__ import print_function
|
||||
import os
|
||||
import pytest
|
||||
import requests
|
||||
import time
|
||||
from deltachat import Account
|
||||
from deltachat import props
|
||||
from deltachat.capi import lib
|
||||
import tempfile
|
||||
|
||||
@@ -36,6 +36,8 @@ def pytest_runtest_call(item):
|
||||
|
||||
|
||||
def pytest_report_header(config, startdir):
|
||||
summary = []
|
||||
|
||||
t = tempfile.mktemp()
|
||||
try:
|
||||
ac = Account(t, eventlogging=False)
|
||||
@@ -43,13 +45,18 @@ def pytest_report_header(config, startdir):
|
||||
ac.shutdown()
|
||||
finally:
|
||||
os.remove(t)
|
||||
summary = ['Deltachat core={} sqlite={}'.format(
|
||||
summary.extend(['Deltachat core={} sqlite={}'.format(
|
||||
info['deltachat_core_version'],
|
||||
info['sqlite_version'],
|
||||
)]
|
||||
cfg = config.getoption('--liveconfig')
|
||||
)])
|
||||
|
||||
cfg = config.option.liveconfig
|
||||
if cfg:
|
||||
summary.append('Liveconfig: {}'.format(os.path.abspath(cfg)))
|
||||
if "#" in cfg:
|
||||
url, token = cfg.split("#", 1)
|
||||
summary.append('Liveconfig provider: {}#<token ommitted>'.format(url))
|
||||
else:
|
||||
summary.append('Liveconfig file: {}'.format(cfg))
|
||||
return summary
|
||||
|
||||
|
||||
@@ -66,9 +73,56 @@ def data():
|
||||
return Data()
|
||||
|
||||
|
||||
class SessionLiveConfigFromFile:
|
||||
def __init__(self, fn):
|
||||
self.fn = fn
|
||||
self.configlist = []
|
||||
for line in open(fn):
|
||||
if line.strip() and not line.strip().startswith('#'):
|
||||
d = {}
|
||||
for part in line.split():
|
||||
name, value = part.split("=")
|
||||
d[name] = value
|
||||
self.configlist.append(d)
|
||||
|
||||
def get(self, index):
|
||||
return self.configlist[index]
|
||||
|
||||
def exists(self):
|
||||
return bool(self.configlist)
|
||||
|
||||
|
||||
class SessionLiveConfigFromURL:
|
||||
def __init__(self, url, create_token):
|
||||
self.configlist = []
|
||||
for i in range(2):
|
||||
res = requests.post(url, json={"token_create_user": int(create_token)})
|
||||
if res.status_code != 200:
|
||||
pytest.skip("creating newtmpuser failed {!r}".format(res))
|
||||
d = res.json()
|
||||
config = dict(addr=d["email"], mail_pw=d["password"])
|
||||
self.configlist.append(config)
|
||||
|
||||
def get(self, index):
|
||||
return self.configlist[index]
|
||||
|
||||
def exists(self):
|
||||
return bool(self.configlist)
|
||||
|
||||
|
||||
@pytest.fixture(scope="session")
|
||||
def session_liveconfig(request):
|
||||
liveconfig_opt = request.config.option.liveconfig
|
||||
if liveconfig_opt:
|
||||
if liveconfig_opt.startswith("http"):
|
||||
url, create_token = liveconfig_opt.split("#", 1)
|
||||
return SessionLiveConfigFromURL(url, create_token)
|
||||
else:
|
||||
return SessionLiveConfigFromFile(liveconfig_opt)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def acfactory(pytestconfig, tmpdir, request):
|
||||
fn = pytestconfig.getoption("--liveconfig")
|
||||
def acfactory(pytestconfig, tmpdir, request, session_liveconfig):
|
||||
|
||||
class AccountMaker:
|
||||
def __init__(self):
|
||||
@@ -82,18 +136,6 @@ def acfactory(pytestconfig, tmpdir, request):
|
||||
fin = self._finalizers.pop()
|
||||
fin()
|
||||
|
||||
@props.cached
|
||||
def configlist(self):
|
||||
configlist = []
|
||||
for line in open(fn):
|
||||
if line.strip() and not line.strip().startswith('#'):
|
||||
d = {}
|
||||
for part in line.split():
|
||||
name, value = part.split("=")
|
||||
d[name] = value
|
||||
configlist.append(d)
|
||||
return configlist
|
||||
|
||||
def get_unconfigured_account(self):
|
||||
self.offline_count += 1
|
||||
tmpdb = tmpdir.join("offlinedb%d" % self.offline_count)
|
||||
@@ -116,10 +158,12 @@ def acfactory(pytestconfig, tmpdir, request):
|
||||
return ac
|
||||
|
||||
def get_online_configuring_account(self):
|
||||
if not fn:
|
||||
pytest.skip("specify a --liveconfig file to run tests with real accounts")
|
||||
if not session_liveconfig:
|
||||
pytest.skip("specify DCC_PY_LIVECONFIG or --liveconfig")
|
||||
configdict = session_liveconfig.get(self.live_count)
|
||||
self.live_count += 1
|
||||
configdict = self.configlist.pop(0)
|
||||
if "e2ee_enabled" not in configdict:
|
||||
configdict["e2ee_enabled"] = "1"
|
||||
tmpdb = tmpdir.join("livedb%d" % self.live_count)
|
||||
ac = Account(tmpdb.strpath, logid="ac{}".format(self.live_count))
|
||||
ac._evlogger.init_time = self.init_time
|
||||
|
||||
@@ -427,6 +427,37 @@ class TestOnlineAccount:
|
||||
lp.step("2")
|
||||
assert msg_out.is_out_mdn_received()
|
||||
|
||||
def test_send_and_receive_will_encrypt_decrypt(self, acfactory, lp):
|
||||
lp.sec("starting accounts, waiting for configuration")
|
||||
ac1 = acfactory.get_online_configuring_account()
|
||||
ac2 = acfactory.get_online_configuring_account()
|
||||
c2 = ac1.create_contact(email=ac2.get_config("addr"))
|
||||
chat = ac1.create_chat_by_contact(c2)
|
||||
assert chat.id >= const.DC_CHAT_ID_LAST_SPECIAL
|
||||
|
||||
wait_configuration_progress(ac1, 1000)
|
||||
wait_configuration_progress(ac2, 1000)
|
||||
|
||||
lp.sec("sending text message from ac1 to ac2")
|
||||
msg_out = chat.send_text("message1")
|
||||
|
||||
lp.sec("wait for ac2 to receive message")
|
||||
ev = ac2._evlogger.get_matching("DC_EVENT_MSGS_CHANGED")
|
||||
assert ev[2] == msg_out.id
|
||||
msg_in = ac2.get_message_by_id(msg_out.id)
|
||||
assert msg_in.text == "message1"
|
||||
|
||||
lp.sec("create new chat with contact and send back (encrypted) message")
|
||||
chat2b = ac2.create_chat_by_message(msg_in)
|
||||
chat2b.send_text("message-back")
|
||||
|
||||
lp.sec("wait for ac1 to receive message")
|
||||
ev = ac1._evlogger.get_matching("DC_EVENT_INCOMING_MSG")
|
||||
assert ev[1] == chat.id
|
||||
assert ev[2] > msg_out.id
|
||||
msg_back = ac1.get_message_by_id(ev[2])
|
||||
assert msg_back.text == "message-back"
|
||||
|
||||
def test_saved_mime_on_received_message(self, acfactory, lp):
|
||||
lp.sec("starting accounts, waiting for configuration")
|
||||
ac1 = acfactory.get_online_configuring_account()
|
||||
|
||||
@@ -19,6 +19,7 @@ deps =
|
||||
pytest
|
||||
pytest-faulthandler
|
||||
pdbpp
|
||||
requests
|
||||
|
||||
[testenv:auditwheels]
|
||||
skipsdist = True
|
||||
@@ -51,6 +52,7 @@ commands =
|
||||
|
||||
|
||||
[pytest]
|
||||
addopts = -v -rs
|
||||
python_files = tests/test_*.py
|
||||
norecursedirs = .tox
|
||||
xfail_strict=true
|
||||
|
||||
@@ -23,7 +23,7 @@ if [ $? != 0 ]; then
|
||||
fi
|
||||
|
||||
pushd python
|
||||
if [ -e "./liveconfig" ]; then
|
||||
if [ -e "./liveconfig" && -z "$DCC_PY_LIVECONFIG" ]; then
|
||||
export DCC_PY_LIVECONFIG=liveconfig
|
||||
fi
|
||||
tox "$@"
|
||||
|
||||
@@ -1,15 +1,35 @@
|
||||
//! Constants
|
||||
#![allow(non_camel_case_types)]
|
||||
use num_traits::{FromPrimitive, ToPrimitive};
|
||||
use rusqlite as sql;
|
||||
use rusqlite::types::*;
|
||||
use deltachat_derive::*;
|
||||
|
||||
pub const DC_VERSION_STR: &'static [u8; 14] = b"1.0.0-alpha.3\x00";
|
||||
|
||||
pub const DC_MOVE_STATE_MOVING: u32 = 3;
|
||||
pub const DC_MOVE_STATE_STAY: u32 = 2;
|
||||
pub const DC_MOVE_STATE_PENDING: u32 = 1;
|
||||
pub const DC_MOVE_STATE_UNDEFINED: u32 = 0;
|
||||
#[repr(u8)]
|
||||
#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive, ToSql, FromSql)]
|
||||
pub enum MoveState {
|
||||
Undefined = 0,
|
||||
Pending = 1,
|
||||
Stay = 2,
|
||||
Moving = 3,
|
||||
}
|
||||
|
||||
// some defaults
|
||||
pub const DC_E2EE_DEFAULT_ENABLED: i32 = 1;
|
||||
pub const DC_MDNS_DEFAULT_ENABLED: i32 = 1;
|
||||
pub const DC_INBOX_WATCH_DEFAULT: i32 = 1;
|
||||
pub const DC_SENTBOX_WATCH_DEFAULT: i32 = 1;
|
||||
pub const DC_MVBOX_WATCH_DEFAULT: i32 = 1;
|
||||
pub const DC_MVBOX_MOVE_DEFAULT: i32 = 1;
|
||||
|
||||
pub const DC_CHAT_NOT_BLOCKED: i32 = 0;
|
||||
pub const DC_CHAT_MANUALLY_BLOCKED: i32 = 1;
|
||||
pub const DC_CHAT_DEADDROP_BLOCKED: i32 = 2;
|
||||
|
||||
pub const DC_IMAP_SEEN: u32 = 0x1;
|
||||
|
||||
pub const DC_HANDSHAKE_CONTINUE_NORMAL_PROCESSING: i32 = 0x01;
|
||||
pub const DC_HANDSHAKE_STOP_NORMAL_PROCESSING: i32 = 0x02;
|
||||
pub const DC_HANDSHAKE_ADD_DELETE_JOB: i32 = 0x04;
|
||||
|
||||
pub const DC_GCL_ARCHIVED_ONLY: usize = 0x01;
|
||||
pub const DC_GCL_NO_SPECIALS: usize = 0x02;
|
||||
@@ -147,7 +167,7 @@ pub const DC_LP_IMAP_SOCKET_FLAGS: usize =
|
||||
pub const DC_LP_SMTP_SOCKET_FLAGS: usize =
|
||||
(DC_LP_SMTP_SOCKET_STARTTLS | DC_LP_SMTP_SOCKET_SSL | DC_LP_SMTP_SOCKET_PLAIN);
|
||||
|
||||
#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)]
|
||||
#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive, FromSql, ToSql)]
|
||||
#[repr(i32)]
|
||||
pub enum Viewtype {
|
||||
Unknown = 0,
|
||||
@@ -202,23 +222,6 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
impl ToSql for Viewtype {
|
||||
fn to_sql(&self) -> sql::Result<ToSqlOutput> {
|
||||
let num: i64 = self
|
||||
.to_i64()
|
||||
.expect("impossible: Viewtype -> i64 conversion failed");
|
||||
|
||||
Ok(ToSqlOutput::Owned(Value::Integer(num)))
|
||||
}
|
||||
}
|
||||
|
||||
impl FromSql for Viewtype {
|
||||
fn column_result(col: ValueRef) -> FromSqlResult<Self> {
|
||||
let inner = FromSql::column_result(col)?;
|
||||
FromPrimitive::from_i64(inner).ok_or(FromSqlError::InvalidType)
|
||||
}
|
||||
}
|
||||
|
||||
// These constants are used as events
|
||||
// reported to the callback given to dc_context_new().
|
||||
// If you do not want to handle an event, it is always safe to return 0,
|
||||
|
||||
@@ -472,13 +472,13 @@ impl<'a> Contact<'a> {
|
||||
context: &Context,
|
||||
listflags: u32,
|
||||
query: Option<impl AsRef<str>>,
|
||||
) -> Result<*mut dc_array_t> {
|
||||
) -> Result<Vec<u32>> {
|
||||
let self_addr = context
|
||||
.get_config(Config::ConfiguredAddr)
|
||||
.unwrap_or_default();
|
||||
|
||||
let mut add_self = false;
|
||||
let mut ret = dc_array_t::new(100);
|
||||
let mut ret = Vec::new();
|
||||
|
||||
if (listflags & DC_GCL_VERIFIED_ONLY) > 0 || query.is_some() {
|
||||
let s3str_like_cmd = format!(
|
||||
@@ -509,7 +509,7 @@ impl<'a> Contact<'a> {
|
||||
|row| row.get::<_, i32>(0),
|
||||
|ids| {
|
||||
for id in ids {
|
||||
ret.add_id(id? as u32);
|
||||
ret.push(id? as u32);
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
@@ -537,7 +537,7 @@ impl<'a> Contact<'a> {
|
||||
|row| row.get::<_, i32>(0),
|
||||
|ids| {
|
||||
for id in ids {
|
||||
ret.add_id(id? as u32);
|
||||
ret.push(id? as u32);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -545,10 +545,10 @@ impl<'a> Contact<'a> {
|
||||
}
|
||||
|
||||
if 0 != listflags & DC_GCL_ADD_SELF as u32 && add_self {
|
||||
ret.add_id(DC_CONTACT_ID_SELF as u32);
|
||||
ret.push(DC_CONTACT_ID_SELF as u32);
|
||||
}
|
||||
|
||||
Ok(ret.into_raw())
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
pub fn get_blocked_cnt(context: &Context) -> usize {
|
||||
@@ -572,19 +572,24 @@ impl<'a> Contact<'a> {
|
||||
params![DC_CONTACT_ID_LAST_SPECIAL as i32],
|
||||
|row| row.get::<_, i32>(0),
|
||||
|ids| {
|
||||
let mut ret = dc_array_t::new(100);
|
||||
let mut ret = Vec::new();
|
||||
|
||||
for id in ids {
|
||||
ret.add_id(id? as u32);
|
||||
ret.push(id? as u32);
|
||||
}
|
||||
|
||||
Ok(ret.into_raw())
|
||||
Ok(dc_array_t::from(ret).into_raw())
|
||||
},
|
||||
)
|
||||
.unwrap_or_else(|_| std::ptr::null_mut())
|
||||
}
|
||||
|
||||
pub fn get_encrinfo(context: &Context, contact_id: u32) -> String {
|
||||
/// Returns a textual summary of the encryption state for the contact.
|
||||
///
|
||||
/// This function returns a string explaining the encryption state
|
||||
/// of the contact and if the connection is encrypted the
|
||||
/// fingerprints of the keys involved.
|
||||
pub fn get_encrinfo(context: &Context, contact_id: u32) -> Result<String> {
|
||||
let mut ret = String::new();
|
||||
|
||||
if let Ok(contact) = Contact::load_from_db(context, contact_id) {
|
||||
@@ -603,7 +608,7 @@ impl<'a> Contact<'a> {
|
||||
});
|
||||
ret += &p;
|
||||
if self_key.is_none() {
|
||||
unsafe { dc_ensure_secret_key_exists(context) };
|
||||
dc_ensure_secret_key_exists(context)?;
|
||||
self_key = Key::from_self_public(context, &loginparam.addr, &context.sql);
|
||||
}
|
||||
let p = context.stock_str(StockMessage::FingerPrints);
|
||||
@@ -646,7 +651,7 @@ impl<'a> Contact<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
ret
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
/// Delete a contact. The contact is deleted from the local device. It may happen that this is not
|
||||
|
||||
@@ -20,7 +20,6 @@ use crate::sql::Sql;
|
||||
use crate::types::*;
|
||||
use crate::x::*;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct Context {
|
||||
pub userdata: *mut libc::c_void,
|
||||
pub dbfile: Arc<RwLock<*mut libc::c_char>>,
|
||||
@@ -40,6 +39,8 @@ pub struct Context {
|
||||
pub bob: Arc<RwLock<BobStatus>>,
|
||||
pub last_smeared_timestamp: Arc<RwLock<i64>>,
|
||||
pub running_state: Arc<RwLock<RunningState>>,
|
||||
/// Mutex to avoid generating the key for the user more than once.
|
||||
pub generating_key_mutex: Mutex<()>,
|
||||
}
|
||||
|
||||
unsafe impl std::marker::Send for Context {}
|
||||
@@ -77,6 +78,14 @@ impl Context {
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Context {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
dc_close(&self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for RunningState {
|
||||
fn default() -> Self {
|
||||
RunningState {
|
||||
@@ -162,16 +171,7 @@ pub fn dc_context_new(
|
||||
))),
|
||||
probe_imap_network: Arc::new(RwLock::new(false)),
|
||||
perform_inbox_jobs_needed: Arc::new(RwLock::new(false)),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn no_crashes_on_context_deref() {
|
||||
let mut ctx = dc_context_new(None, std::ptr::null_mut(), Some("Test OS".into()));
|
||||
unsafe { dc_context_unref(&mut ctx) };
|
||||
generating_key_mutex: Mutex::new(()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,7 +229,7 @@ unsafe fn cb_precheck_imf(
|
||||
"[move] detected moved message {}",
|
||||
as_str(rfc724_mid),
|
||||
);
|
||||
dc_update_msg_move_state(context, rfc724_mid, DC_MOVE_STATE_STAY);
|
||||
dc_update_msg_move_state(context, rfc724_mid, MoveState::Stay);
|
||||
}
|
||||
if as_str(old_server_folder) != server_folder || old_server_uid != server_uid {
|
||||
dc_update_server_uid(context, rfc724_mid, server_folder, server_uid);
|
||||
@@ -258,12 +258,6 @@ fn cb_get_config(context: &Context, key: &str) -> Option<String> {
|
||||
context.sql.get_config(context, key)
|
||||
}
|
||||
|
||||
pub unsafe fn dc_context_unref(context: &mut Context) {
|
||||
if 0 != dc_is_open(context) {
|
||||
dc_close(context);
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn dc_close(context: &Context) {
|
||||
info!(context, 0, "disconnecting INBOX-watch",);
|
||||
context.inbox.read().unwrap().disconnect(context);
|
||||
@@ -315,9 +309,9 @@ pub unsafe fn dc_open(context: &Context, dbfile: &str, blobdir: Option<&str>) ->
|
||||
let dir = dc_ensure_no_slash_safe(blobdir.unwrap()).strdup();
|
||||
*context.blobdir.write().unwrap() = dir;
|
||||
} else {
|
||||
let dir = (dbfile.to_string() + "-blobs").strdup();
|
||||
dc_create_folder(context, dir);
|
||||
*context.blobdir.write().unwrap() = dir;
|
||||
let dir = dbfile.to_string() + "-blobs";
|
||||
dc_create_folder(context, &dir);
|
||||
*context.blobdir.write().unwrap() = dir.strdup();
|
||||
}
|
||||
// Create/open sqlite database, this may already use the blobdir
|
||||
let dbfile_path = std::path::Path::new(dbfile);
|
||||
@@ -505,13 +499,12 @@ pub fn dc_get_fresh_msgs(context: &Context) -> *mut dc_array_t {
|
||||
&[10, 9, if 0 != show_deaddrop { 2 } else { 0 }],
|
||||
|row| row.get(0),
|
||||
|rows| {
|
||||
let mut ret = dc_array_t::new(128);
|
||||
|
||||
let mut ret = Vec::new();
|
||||
for row in rows {
|
||||
let id = row?;
|
||||
ret.add_id(id);
|
||||
let id: u32 = row?;
|
||||
ret.push(id);
|
||||
}
|
||||
Ok(ret.into_raw())
|
||||
Ok(dc_array_t::from(ret).into_raw())
|
||||
},
|
||||
)
|
||||
.unwrap()
|
||||
@@ -545,7 +538,7 @@ pub fn dc_search_msgs(
|
||||
AND ct.blocked=0 AND (m.txt LIKE ? OR ct.name LIKE ?) ORDER BY m.timestamp DESC,m.id DESC;"
|
||||
};
|
||||
|
||||
let mut ret = dc_array_t::new(100);
|
||||
let mut ret = Vec::new();
|
||||
|
||||
let success = context
|
||||
.sql
|
||||
@@ -555,7 +548,7 @@ pub fn dc_search_msgs(
|
||||
|row| row.get::<_, i32>(0),
|
||||
|rows| {
|
||||
for id in rows {
|
||||
ret.add_id(id? as u32);
|
||||
ret.push(id? as u32);
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
@@ -563,7 +556,7 @@ pub fn dc_search_msgs(
|
||||
.is_ok();
|
||||
|
||||
if success {
|
||||
return ret.into_raw();
|
||||
return dc_array_t::from(ret).into_raw();
|
||||
}
|
||||
|
||||
std::ptr::null_mut()
|
||||
@@ -591,3 +584,24 @@ pub fn dc_is_mvbox(context: &Context, folder_name: impl AsRef<str>) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn no_crashes_on_context_deref() {
|
||||
let ctx = dc_context_new(None, std::ptr::null_mut(), Some("Test OS".into()));
|
||||
std::mem::drop(ctx);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_context_double_close() {
|
||||
let ctx = dc_context_new(None, std::ptr::null_mut(), None);
|
||||
unsafe {
|
||||
dc_close(&ctx);
|
||||
dc_close(&ctx);
|
||||
}
|
||||
std::mem::drop(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
150
src/dc_array.rs
150
src/dc_array.rs
@@ -147,6 +147,12 @@ impl dc_array_t {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<u32>> for dc_array_t {
|
||||
fn from(array: Vec<u32>) -> Self {
|
||||
dc_array_t::Uint(array.iter().map(|&x| x as uintptr_t).collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<dc_location>> for dc_array_t {
|
||||
fn from(array: Vec<dc_location>) -> Self {
|
||||
dc_array_t::Locations(array)
|
||||
@@ -154,22 +160,18 @@ impl From<Vec<dc_location>> for dc_array_t {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_unref(array: *mut dc_array_t) {
|
||||
if array.is_null() {
|
||||
return;
|
||||
}
|
||||
assert!(!array.is_null());
|
||||
Box::from_raw(array);
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_add_uint(array: *mut dc_array_t, item: uintptr_t) {
|
||||
if !array.is_null() {
|
||||
(*array).add_uint(item);
|
||||
}
|
||||
assert!(!array.is_null());
|
||||
(*array).add_uint(item);
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_add_id(array: *mut dc_array_t, item: uint32_t) {
|
||||
if !array.is_null() {
|
||||
(*array).add_id(item);
|
||||
}
|
||||
assert!(!array.is_null());
|
||||
(*array).add_id(item);
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_add_ptr(array: *mut dc_array_t, item: *mut libc::c_void) {
|
||||
@@ -177,97 +179,62 @@ pub unsafe fn dc_array_add_ptr(array: *mut dc_array_t, item: *mut libc::c_void)
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_get_cnt(array: *const dc_array_t) -> size_t {
|
||||
if array.is_null() {
|
||||
0
|
||||
} else {
|
||||
(*array).len()
|
||||
}
|
||||
assert!(!array.is_null());
|
||||
(*array).len()
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_get_uint(array: *const dc_array_t, index: size_t) -> uintptr_t {
|
||||
if array.is_null() || index >= (*array).len() {
|
||||
0
|
||||
} else {
|
||||
(*array).get_uint(index)
|
||||
}
|
||||
assert!(!array.is_null());
|
||||
(*array).get_uint(index)
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_get_id(array: *const dc_array_t, index: size_t) -> uint32_t {
|
||||
if array.is_null() || index >= (*array).len() {
|
||||
0
|
||||
} else {
|
||||
(*array).get_id(index)
|
||||
}
|
||||
assert!(!array.is_null());
|
||||
(*array).get_id(index)
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_get_ptr(array: *const dc_array_t, index: size_t) -> *mut libc::c_void {
|
||||
if array.is_null() || index >= (*array).len() {
|
||||
std::ptr::null_mut()
|
||||
} else {
|
||||
(*array).get_ptr(index)
|
||||
}
|
||||
assert!(!array.is_null());
|
||||
(*array).get_ptr(index)
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_get_latitude(array: *const dc_array_t, index: size_t) -> libc::c_double {
|
||||
if array.is_null() || index >= (*array).len() {
|
||||
0.0
|
||||
} else {
|
||||
(*array).get_latitude(index)
|
||||
}
|
||||
assert!(!array.is_null());
|
||||
(*array).get_latitude(index)
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_get_longitude(array: *const dc_array_t, index: size_t) -> libc::c_double {
|
||||
if array.is_null() || index >= (*array).len() {
|
||||
0.0
|
||||
} else {
|
||||
(*array).get_longitude(index)
|
||||
}
|
||||
assert!(!array.is_null());
|
||||
(*array).get_longitude(index)
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_get_accuracy(array: *const dc_array_t, index: size_t) -> libc::c_double {
|
||||
if array.is_null() || index >= (*array).len() {
|
||||
0.0
|
||||
} else {
|
||||
(*array).get_accuracy(index)
|
||||
}
|
||||
assert!(!array.is_null());
|
||||
(*array).get_accuracy(index)
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_get_timestamp(array: *const dc_array_t, index: size_t) -> i64 {
|
||||
if array.is_null() || index >= (*array).len() {
|
||||
0
|
||||
} else {
|
||||
(*array).get_timestamp(index)
|
||||
}
|
||||
assert!(!array.is_null());
|
||||
(*array).get_timestamp(index)
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_get_chat_id(array: *const dc_array_t, index: size_t) -> uint32_t {
|
||||
if array.is_null() || index >= (*array).len() {
|
||||
0
|
||||
} else {
|
||||
(*array).get_chat_id(index)
|
||||
}
|
||||
assert!(!array.is_null());
|
||||
(*array).get_chat_id(index)
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_get_contact_id(array: *const dc_array_t, index: size_t) -> uint32_t {
|
||||
if array.is_null() || index >= (*array).len() {
|
||||
0
|
||||
} else {
|
||||
(*array).get_contact_id(index)
|
||||
}
|
||||
assert!(!array.is_null());
|
||||
(*array).get_contact_id(index)
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_get_msg_id(array: *const dc_array_t, index: size_t) -> uint32_t {
|
||||
if array.is_null() || index >= (*array).len() {
|
||||
0
|
||||
} else {
|
||||
(*array).get_msg_id(index)
|
||||
}
|
||||
assert!(!array.is_null());
|
||||
(*array).get_msg_id(index)
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_get_marker(array: *const dc_array_t, index: size_t) -> *mut libc::c_char {
|
||||
if array.is_null() || index >= (*array).len() {
|
||||
return std::ptr::null_mut();
|
||||
}
|
||||
assert!(!array.is_null());
|
||||
|
||||
if let dc_array_t::Locations(v) = &*array {
|
||||
if let Some(s) = &v[index].marker {
|
||||
@@ -276,7 +243,7 @@ pub unsafe fn dc_array_get_marker(array: *const dc_array_t, index: size_t) -> *m
|
||||
std::ptr::null_mut()
|
||||
}
|
||||
} else {
|
||||
std::ptr::null_mut()
|
||||
panic!("Not an array of locations");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,9 +258,7 @@ pub unsafe fn dc_array_get_marker(array: *const dc_array_t, index: size_t) -> *m
|
||||
* 1=Location was reported independently.
|
||||
*/
|
||||
pub unsafe fn dc_array_is_independent(array: *const dc_array_t, index: size_t) -> libc::c_int {
|
||||
if array.is_null() || index >= (*array).len() {
|
||||
return 0;
|
||||
}
|
||||
assert!(!array.is_null());
|
||||
|
||||
if let dc_array_t::Locations(v) = &*array {
|
||||
v[index].independent as libc::c_int
|
||||
@@ -307,9 +272,8 @@ pub unsafe fn dc_array_search_id(
|
||||
needle: uint32_t,
|
||||
ret_index: *mut size_t,
|
||||
) -> bool {
|
||||
if array.is_null() {
|
||||
return false;
|
||||
}
|
||||
assert!(!array.is_null());
|
||||
|
||||
if let Some(i) = (*array).search_id(needle as uintptr_t) {
|
||||
if !ret_index.is_null() {
|
||||
*ret_index = i
|
||||
@@ -321,9 +285,8 @@ pub unsafe fn dc_array_search_id(
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_get_raw(array: *const dc_array_t) -> *const uintptr_t {
|
||||
if array.is_null() {
|
||||
return 0 as *const uintptr_t;
|
||||
}
|
||||
assert!(!array.is_null());
|
||||
|
||||
if let dc_array_t::Uint(v) = &*array {
|
||||
v.as_ptr()
|
||||
} else {
|
||||
@@ -340,27 +303,24 @@ pub fn dc_array_new_locations(initsize: size_t) -> *mut dc_array_t {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_empty(array: *mut dc_array_t) {
|
||||
if array.is_null() {
|
||||
return;
|
||||
}
|
||||
assert!(!array.is_null());
|
||||
|
||||
(*array).clear()
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_duplicate(array: *const dc_array_t) -> *mut dc_array_t {
|
||||
if array.is_null() {
|
||||
std::ptr::null_mut()
|
||||
} else {
|
||||
(*array).clone().into_raw()
|
||||
}
|
||||
assert!(!array.is_null());
|
||||
|
||||
(*array).clone().into_raw()
|
||||
}
|
||||
|
||||
pub unsafe fn dc_array_get_string(
|
||||
array: *const dc_array_t,
|
||||
sep: *const libc::c_char,
|
||||
) -> *mut libc::c_char {
|
||||
if array.is_null() || sep.is_null() {
|
||||
return dc_strdup(b"\x00" as *const u8 as *const libc::c_char);
|
||||
}
|
||||
assert!(!array.is_null());
|
||||
assert!(!sep.is_null());
|
||||
|
||||
if let dc_array_t::Uint(v) = &*array {
|
||||
let cnt = v.len();
|
||||
let sep = as_str(sep);
|
||||
@@ -406,10 +366,6 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
assert_eq!(dc_array_get_id(arr, -1i32 as size_t), 0);
|
||||
assert_eq!(dc_array_get_id(arr, 1000 as size_t), 0);
|
||||
assert_eq!(dc_array_get_id(arr, 1001 as size_t), 0);
|
||||
|
||||
dc_array_empty(arr);
|
||||
|
||||
assert_eq!(dc_array_get_cnt(arr), 0);
|
||||
@@ -438,4 +394,14 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_dc_array_out_of_bounds() {
|
||||
let arr = dc_array_new(7);
|
||||
for i in 0..1000 {
|
||||
unsafe { dc_array_add_id(arr, (i + 2) as uint32_t) };
|
||||
}
|
||||
unsafe { dc_array_get_id(arr, 1000) };
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ use crate::x::*;
|
||||
*/
|
||||
#[derive(Clone)]
|
||||
pub struct Chat<'a> {
|
||||
magic: uint32_t,
|
||||
pub id: uint32_t,
|
||||
pub type_0: libc::c_int,
|
||||
pub name: *mut libc::c_char,
|
||||
@@ -65,7 +64,6 @@ pub unsafe fn dc_create_chat_by_msg_id(context: &Context, msg_id: uint32_t) -> u
|
||||
|
||||
pub unsafe fn dc_chat_new<'a>(context: &'a Context) -> *mut Chat<'a> {
|
||||
let chat = Chat {
|
||||
magic: 0xc4a7c4a7,
|
||||
id: 0,
|
||||
type_0: 0,
|
||||
name: std::ptr::null_mut(),
|
||||
@@ -81,17 +79,16 @@ pub unsafe fn dc_chat_new<'a>(context: &'a Context) -> *mut Chat<'a> {
|
||||
Box::into_raw(Box::new(chat))
|
||||
}
|
||||
|
||||
pub unsafe fn dc_chat_unref(mut chat: *mut Chat) {
|
||||
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
|
||||
pub unsafe fn dc_chat_unref(chat: *mut Chat) {
|
||||
if chat.is_null() {
|
||||
return;
|
||||
}
|
||||
dc_chat_empty(chat);
|
||||
(*chat).magic = 0;
|
||||
Box::from_raw(chat);
|
||||
}
|
||||
|
||||
pub unsafe fn dc_chat_empty(mut chat: *mut Chat) {
|
||||
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
|
||||
if chat.is_null() {
|
||||
return;
|
||||
}
|
||||
free((*chat).name as *mut libc::c_void);
|
||||
@@ -120,7 +117,7 @@ pub fn dc_block_chat(context: &Context, chat_id: u32, new_blocking: libc::c_int)
|
||||
}
|
||||
|
||||
pub fn dc_chat_load_from_db(chat: *mut Chat, chat_id: u32) -> bool {
|
||||
if chat.is_null() || unsafe { (*chat).magic != 0xc4a7c4a7u32 } {
|
||||
if chat.is_null() {
|
||||
return false;
|
||||
}
|
||||
unsafe { dc_chat_empty(chat) };
|
||||
@@ -810,7 +807,7 @@ unsafe fn get_parent_mime_headers(
|
||||
}
|
||||
|
||||
pub unsafe fn dc_chat_is_self_talk(chat: *const Chat) -> libc::c_int {
|
||||
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
|
||||
if chat.is_null() {
|
||||
return 0;
|
||||
}
|
||||
(*chat).param.exists(Param::Selftalk) as libc::c_int
|
||||
@@ -1072,7 +1069,7 @@ pub fn dc_get_chat_msgs(
|
||||
flags: uint32_t,
|
||||
marker1before: uint32_t,
|
||||
) -> *mut dc_array_t {
|
||||
let mut ret = dc_array_t::new(512);
|
||||
let mut ret = Vec::new();
|
||||
|
||||
let mut last_day = 0;
|
||||
let cnv_to_local = dc_gm2local_offset();
|
||||
@@ -1082,17 +1079,17 @@ pub fn dc_get_chat_msgs(
|
||||
for row in rows {
|
||||
let (curr_id, ts) = row?;
|
||||
if curr_id as u32 == marker1before {
|
||||
ret.add_id(1);
|
||||
ret.push(DC_MSG_ID_MARKER1 as u32);
|
||||
}
|
||||
if 0 != flags & 0x1 {
|
||||
let curr_local_timestamp = ts + cnv_to_local;
|
||||
let curr_day = (curr_local_timestamp / 86400) as libc::c_int;
|
||||
if curr_day != last_day {
|
||||
ret.add_id(9);
|
||||
ret.push(DC_MSG_ID_LAST_SPECIAL as u32);
|
||||
last_day = curr_day;
|
||||
}
|
||||
}
|
||||
ret.add_id(curr_id as u32);
|
||||
ret.push(curr_id as u32);
|
||||
}
|
||||
Ok(())
|
||||
};
|
||||
@@ -1140,7 +1137,7 @@ pub fn dc_get_chat_msgs(
|
||||
};
|
||||
|
||||
if success.is_ok() {
|
||||
ret.into_raw()
|
||||
dc_array_t::from(ret).into_raw()
|
||||
} else {
|
||||
0 as *mut dc_array_t
|
||||
}
|
||||
@@ -1253,11 +1250,11 @@ pub fn dc_get_chat_media(
|
||||
],
|
||||
|row| row.get::<_, i32>(0),
|
||||
|ids| {
|
||||
let mut ret = dc_array_t::new(100);
|
||||
let mut ret = Vec::new();
|
||||
for id in ids {
|
||||
ret.add_id(id? as u32);
|
||||
ret.push(id? as u32);
|
||||
}
|
||||
Ok(ret.into_raw())
|
||||
Ok(dc_array_t::from(ret).into_raw())
|
||||
}
|
||||
).unwrap_or_else(|_| std::ptr::null_mut())
|
||||
}
|
||||
@@ -1406,12 +1403,12 @@ pub fn dc_delete_chat(context: &Context, chat_id: u32) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
pub fn dc_get_chat_contacts(context: &Context, chat_id: u32) -> *mut dc_array_t {
|
||||
pub fn dc_get_chat_contacts(context: &Context, chat_id: u32) -> Vec<u32> {
|
||||
/* Normal chats do not include SELF. Group chats do (as it may happen that one is deleted from a
|
||||
groupchat but the chats stays visible, moreover, this makes displaying lists easier) */
|
||||
|
||||
if chat_id == 1 {
|
||||
return std::ptr::null_mut();
|
||||
return Vec::new();
|
||||
}
|
||||
|
||||
// we could also create a list for all contacts in the deaddrop by searching contacts belonging to chats with
|
||||
@@ -1423,19 +1420,11 @@ pub fn dc_get_chat_contacts(context: &Context, chat_id: u32) -> *mut dc_array_t
|
||||
"SELECT cc.contact_id FROM chats_contacts cc \
|
||||
LEFT JOIN contacts c ON c.id=cc.contact_id WHERE cc.chat_id=? \
|
||||
ORDER BY c.id=1, LOWER(c.name||c.addr), c.id;",
|
||||
params![chat_id as i32],
|
||||
|row| row.get::<_, i32>(0),
|
||||
|ids| {
|
||||
let mut ret = dc_array_t::new(100);
|
||||
|
||||
for id in ids {
|
||||
ret.add_id(id? as u32);
|
||||
}
|
||||
|
||||
Ok(ret.into_raw())
|
||||
},
|
||||
params![chat_id],
|
||||
|row| row.get::<_, u32>(0),
|
||||
|ids| ids.collect::<Result<Vec<_>, _>>().map_err(Into::into),
|
||||
)
|
||||
.unwrap_or_else(|_| std::ptr::null_mut())
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
pub unsafe fn dc_get_chat(context: &Context, chat_id: uint32_t) -> *mut Chat {
|
||||
@@ -2020,21 +2009,21 @@ pub unsafe fn dc_forward_msgs(
|
||||
}
|
||||
|
||||
pub unsafe fn dc_chat_get_id(chat: *const Chat) -> uint32_t {
|
||||
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
|
||||
if chat.is_null() {
|
||||
return 0i32 as uint32_t;
|
||||
}
|
||||
(*chat).id
|
||||
}
|
||||
|
||||
pub unsafe fn dc_chat_get_type(chat: *const Chat) -> libc::c_int {
|
||||
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
|
||||
if chat.is_null() {
|
||||
return 0i32;
|
||||
}
|
||||
(*chat).type_0
|
||||
}
|
||||
|
||||
pub unsafe fn dc_chat_get_name(chat: *const Chat) -> *mut libc::c_char {
|
||||
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
|
||||
if chat.is_null() {
|
||||
return dc_strdup(b"Err\x00" as *const u8 as *const libc::c_char);
|
||||
}
|
||||
dc_strdup((*chat).name)
|
||||
@@ -2042,7 +2031,7 @@ pub unsafe fn dc_chat_get_name(chat: *const Chat) -> *mut libc::c_char {
|
||||
|
||||
pub unsafe fn dc_chat_get_subtitle(chat: *const Chat) -> *mut libc::c_char {
|
||||
/* returns either the address or the number of chat members */
|
||||
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
|
||||
if chat.is_null() {
|
||||
return dc_strdup(b"Err\x00" as *const u8 as *const libc::c_char);
|
||||
}
|
||||
|
||||
@@ -2099,9 +2088,8 @@ pub fn dc_get_chat_contact_cnt(context: &Context, chat_id: u32) -> libc::c_int {
|
||||
pub unsafe fn dc_chat_get_profile_image(chat: *const Chat) -> *mut libc::c_char {
|
||||
let mut image_rel: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut image_abs: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut contacts: *mut dc_array_t = 0 as *mut dc_array_t;
|
||||
|
||||
if !(chat.is_null() || (*chat).magic != 0xc4a7c4a7u32) {
|
||||
if !chat.is_null() {
|
||||
image_rel = (*chat)
|
||||
.param
|
||||
.get(Param::ProfileImage)
|
||||
@@ -2109,10 +2097,10 @@ pub unsafe fn dc_chat_get_profile_image(chat: *const Chat) -> *mut libc::c_char
|
||||
.strdup();
|
||||
if !image_rel.is_null() && 0 != *image_rel.offset(0isize) as libc::c_int {
|
||||
image_abs = dc_get_abs_path((*chat).context, image_rel)
|
||||
} else if (*chat).type_0 == 100i32 {
|
||||
contacts = dc_get_chat_contacts((*chat).context, (*chat).id);
|
||||
if !(*contacts).is_empty() {
|
||||
if let Ok(contact) = Contact::get_by_id((*chat).context, (*contacts).get_id(0)) {
|
||||
} else if (*chat).type_0 == DC_CHAT_TYPE_SINGLE {
|
||||
let contacts = dc_get_chat_contacts((*chat).context, (*chat).id);
|
||||
if !contacts.is_empty() {
|
||||
if let Ok(contact) = Contact::get_by_id((*chat).context, contacts[0]) {
|
||||
if let Some(img) = contact.get_profile_image() {
|
||||
image_abs = img.strdup();
|
||||
}
|
||||
@@ -2122,20 +2110,18 @@ pub unsafe fn dc_chat_get_profile_image(chat: *const Chat) -> *mut libc::c_char
|
||||
}
|
||||
|
||||
free(image_rel as *mut libc::c_void);
|
||||
dc_array_unref(contacts);
|
||||
|
||||
image_abs
|
||||
}
|
||||
|
||||
pub unsafe fn dc_chat_get_color(chat: *const Chat) -> uint32_t {
|
||||
let mut color: uint32_t = 0i32 as uint32_t;
|
||||
let mut contacts: *mut dc_array_t = 0 as *mut dc_array_t;
|
||||
|
||||
if !(chat.is_null() || (*chat).magic != 0xc4a7c4a7u32) {
|
||||
if (*chat).type_0 == 100i32 {
|
||||
contacts = dc_get_chat_contacts((*chat).context, (*chat).id);
|
||||
if !(*contacts).is_empty() {
|
||||
if let Ok(contact) = Contact::get_by_id((*chat).context, (*contacts).get_id(0)) {
|
||||
if !chat.is_null() {
|
||||
if (*chat).type_0 == DC_CHAT_TYPE_SINGLE {
|
||||
let contacts = dc_get_chat_contacts((*chat).context, (*chat).id);
|
||||
if !contacts.is_empty() {
|
||||
if let Ok(contact) = Contact::get_by_id((*chat).context, contacts[0]) {
|
||||
color = contact.get_color();
|
||||
}
|
||||
}
|
||||
@@ -2144,14 +2130,12 @@ pub unsafe fn dc_chat_get_color(chat: *const Chat) -> uint32_t {
|
||||
}
|
||||
}
|
||||
|
||||
dc_array_unref(contacts);
|
||||
|
||||
color
|
||||
}
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_chat_get_archived(chat: *const Chat) -> libc::c_int {
|
||||
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
|
||||
if chat.is_null() {
|
||||
return 0i32;
|
||||
}
|
||||
(*chat).archived
|
||||
@@ -2159,7 +2143,7 @@ pub unsafe fn dc_chat_get_archived(chat: *const Chat) -> libc::c_int {
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_chat_is_unpromoted(chat: *const Chat) -> libc::c_int {
|
||||
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
|
||||
if chat.is_null() {
|
||||
return 0;
|
||||
}
|
||||
(*chat).param.get_int(Param::Unpromoted).unwrap_or_default() as libc::c_int
|
||||
@@ -2167,7 +2151,7 @@ pub unsafe fn dc_chat_is_unpromoted(chat: *const Chat) -> libc::c_int {
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_chat_is_verified(chat: *const Chat) -> libc::c_int {
|
||||
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
|
||||
if chat.is_null() {
|
||||
return 0i32;
|
||||
}
|
||||
((*chat).type_0 == 130i32) as libc::c_int
|
||||
@@ -2175,7 +2159,7 @@ pub unsafe fn dc_chat_is_verified(chat: *const Chat) -> libc::c_int {
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_chat_is_sending_locations(chat: *const Chat) -> libc::c_int {
|
||||
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
|
||||
if chat.is_null() {
|
||||
return 0i32;
|
||||
}
|
||||
(*chat).is_sending_locations
|
||||
|
||||
1271
src/dc_configure.rs
1271
src/dc_configure.rs
File diff suppressed because it is too large
Load Diff
239
src/dc_e2ee.rs
239
src/dc_e2ee.rs
@@ -1,3 +1,5 @@
|
||||
//! End-to-end encryption support.
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::ffi::CStr;
|
||||
use std::str::FromStr;
|
||||
@@ -16,10 +18,12 @@ use mmime::mmapstring::*;
|
||||
use mmime::{mailmime_substitute, MAILIMF_NO_ERROR, MAIL_NO_ERROR};
|
||||
|
||||
use crate::aheader::*;
|
||||
use crate::config::Config;
|
||||
use crate::context::Context;
|
||||
use crate::dc_mimeparser::*;
|
||||
use crate::dc_securejoin::*;
|
||||
use crate::dc_tools::*;
|
||||
use crate::error::*;
|
||||
use crate::key::*;
|
||||
use crate::keyring::*;
|
||||
use crate::peerstate::*;
|
||||
@@ -96,9 +100,11 @@ pub unsafe fn dc_e2ee_encrypt(
|
||||
let addr = context.sql.get_config(context, "configured_addr");
|
||||
|
||||
if let Some(addr) = addr {
|
||||
if let Some(public_key) =
|
||||
load_or_generate_self_public_key(context, &addr, in_out_message)
|
||||
{
|
||||
let pubkey_ret = load_or_generate_self_public_key(context, &addr).map_err(|err| {
|
||||
error!(context, 0, "Failed to load public key: {}", err);
|
||||
err
|
||||
});
|
||||
if let Ok(public_key) = pubkey_ret {
|
||||
/*only for random-seed*/
|
||||
if prefer_encrypt == EncryptPreference::Mutual || 0 != e2ee_guaranteed {
|
||||
do_encrypt = 1i32;
|
||||
@@ -115,11 +121,22 @@ pub unsafe fn dc_e2ee_encrypt(
|
||||
|| 0 != e2ee_guaranteed)
|
||||
{
|
||||
let peerstate = peerstate.unwrap();
|
||||
info!(
|
||||
context,
|
||||
0, "dc_e2ee_encrypt {} has peerstate", recipient_addr
|
||||
);
|
||||
if let Some(key) = peerstate.peek_key(min_verified as usize) {
|
||||
keyring.add_owned(key.clone());
|
||||
peerstates.push(peerstate);
|
||||
}
|
||||
} else {
|
||||
info!(
|
||||
context,
|
||||
0,
|
||||
"dc_e2ee_encrypt {} HAS NO peerstate {}",
|
||||
recipient_addr,
|
||||
peerstate.is_some()
|
||||
);
|
||||
do_encrypt = 0i32;
|
||||
/* if we cannot encrypt to a single recipient, we cannot encrypt the message at all */
|
||||
break;
|
||||
@@ -462,65 +479,52 @@ unsafe fn new_data_part(
|
||||
return 0 as *mut mailmime;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* Generate Keypairs
|
||||
******************************************************************************/
|
||||
unsafe fn load_or_generate_self_public_key(
|
||||
context: &Context,
|
||||
self_addr: impl AsRef<str>,
|
||||
_random_data_mime: *mut mailmime,
|
||||
) -> Option<Key> {
|
||||
/* avoid double creation (we unlock the database during creation) */
|
||||
static mut S_IN_KEY_CREATION: libc::c_int = 0;
|
||||
/// Load public key from database or generate a new one.
|
||||
///
|
||||
/// This will load a public key from the database, generating and
|
||||
/// storing a new one when one doesn't exist yet. Care is taken to
|
||||
/// only generate one key per context even when multiple threads call
|
||||
/// this function concurrently.
|
||||
fn load_or_generate_self_public_key(context: &Context, self_addr: impl AsRef<str>) -> Result<Key> {
|
||||
if let Some(key) = Key::from_self_public(context, &self_addr, &context.sql) {
|
||||
return Ok(key);
|
||||
}
|
||||
let _guard = context.generating_key_mutex.lock().unwrap();
|
||||
|
||||
let mut key = Key::from_self_public(context, &self_addr, &context.sql);
|
||||
if key.is_some() {
|
||||
return key;
|
||||
// Check again in case the key was generated while we were waiting for the lock.
|
||||
if let Some(key) = Key::from_self_public(context, &self_addr, &context.sql) {
|
||||
return Ok(key);
|
||||
}
|
||||
|
||||
/* create the keypair - this may take a moment, however, as this is in a thread, this is no big deal */
|
||||
if 0 != S_IN_KEY_CREATION {
|
||||
return None;
|
||||
}
|
||||
let key_creation_here = 1;
|
||||
S_IN_KEY_CREATION = 1;
|
||||
|
||||
let start = clock();
|
||||
let start = std::time::Instant::now();
|
||||
info!(
|
||||
context,
|
||||
0, "Generating keypair with {} bits, e={} ...", 2048, 65537,
|
||||
);
|
||||
|
||||
if let Some((public_key, private_key)) = dc_pgp_create_keypair(&self_addr) {
|
||||
if !dc_key_save_self_keypair(
|
||||
context,
|
||||
&public_key,
|
||||
&private_key,
|
||||
&self_addr,
|
||||
1i32,
|
||||
&context.sql,
|
||||
) {
|
||||
/*set default*/
|
||||
warn!(context, 0, "Cannot save keypair.",);
|
||||
} else {
|
||||
info!(
|
||||
match dc_pgp_create_keypair(&self_addr) {
|
||||
Some((public_key, private_key)) => {
|
||||
match dc_key_save_self_keypair(
|
||||
context,
|
||||
0,
|
||||
"Keypair generated in {:.3}s.",
|
||||
clock().wrapping_sub(start) as libc::c_double / 1000000 as libc::c_double,
|
||||
);
|
||||
&public_key,
|
||||
&private_key,
|
||||
&self_addr,
|
||||
1,
|
||||
&context.sql,
|
||||
) {
|
||||
true => {
|
||||
info!(
|
||||
context,
|
||||
0,
|
||||
"Keypair generated in {:.3}s.",
|
||||
start.elapsed().as_secs()
|
||||
);
|
||||
Ok(public_key)
|
||||
}
|
||||
false => Err(format_err!("Failed to save keypair")),
|
||||
}
|
||||
}
|
||||
|
||||
key = Some(public_key);
|
||||
} else {
|
||||
warn!(context, 0, "Cannot create keypair.");
|
||||
None => Err(format_err!("Failed to generate keypair")),
|
||||
}
|
||||
|
||||
if 0 != key_creation_here {
|
||||
S_IN_KEY_CREATION = 0;
|
||||
}
|
||||
|
||||
key
|
||||
}
|
||||
|
||||
/* returns 1 if sth. was decrypted, 0 in other cases */
|
||||
@@ -540,20 +544,18 @@ pub unsafe fn dc_e2ee_decrypt(
|
||||
let mut public_keyring_for_validate = Keyring::default();
|
||||
let mut gossip_headers: *mut mailimf_fields = 0 as *mut mailimf_fields;
|
||||
if !(in_out_message.is_null() || imffields.is_null()) {
|
||||
if !imffields.is_null() {
|
||||
let mut field: *mut mailimf_field =
|
||||
mailimf_find_field(imffields, MAILIMF_FIELD_FROM as libc::c_int);
|
||||
if !field.is_null() && !(*field).fld_data.fld_from.is_null() {
|
||||
from = mailimf_find_first_addr((*(*field).fld_data.fld_from).frm_mb_list)
|
||||
}
|
||||
field = mailimf_find_field(imffields, MAILIMF_FIELD_ORIG_DATE as libc::c_int);
|
||||
if !field.is_null() && !(*field).fld_data.fld_orig_date.is_null() {
|
||||
let orig_date: *mut mailimf_orig_date = (*field).fld_data.fld_orig_date;
|
||||
if !orig_date.is_null() {
|
||||
message_time = dc_timestamp_from_date((*orig_date).dt_date_time);
|
||||
if message_time != 0 && message_time > time() {
|
||||
message_time = time()
|
||||
}
|
||||
let mut field: *mut mailimf_field =
|
||||
mailimf_find_field(imffields, MAILIMF_FIELD_FROM as libc::c_int);
|
||||
if !field.is_null() && !(*field).fld_data.fld_from.is_null() {
|
||||
from = mailimf_find_first_addr((*(*field).fld_data.fld_from).frm_mb_list)
|
||||
}
|
||||
field = mailimf_find_field(imffields, MAILIMF_FIELD_ORIG_DATE as libc::c_int);
|
||||
if !field.is_null() && !(*field).fld_data.fld_orig_date.is_null() {
|
||||
let orig_date: *mut mailimf_orig_date = (*field).fld_data.fld_orig_date;
|
||||
if !orig_date.is_null() {
|
||||
message_time = dc_timestamp_from_date((*orig_date).dt_date_time);
|
||||
if message_time != 0 && message_time > time() {
|
||||
message_time = time()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -574,7 +576,7 @@ pub unsafe fn dc_e2ee_decrypt(
|
||||
}
|
||||
} else if let Some(ref header) = autocryptheader {
|
||||
let p = Peerstate::from_header(context, header, message_time);
|
||||
p.save_to_db(&context.sql, true);
|
||||
assert!(p.save_to_db(&context.sql, true));
|
||||
peerstate = Some(p);
|
||||
}
|
||||
}
|
||||
@@ -812,7 +814,7 @@ unsafe fn decrypt_recursive(
|
||||
}
|
||||
|
||||
unsafe fn decrypt_part(
|
||||
context: &Context,
|
||||
_context: &Context,
|
||||
mime: *mut mailmime,
|
||||
private_keyring: &Keyring,
|
||||
public_keyring_for_validate: &Keyring,
|
||||
@@ -1034,33 +1036,49 @@ pub unsafe fn dc_e2ee_thanks(helper: &mut dc_e2ee_helper_t) {
|
||||
helper.cdata_to_free = 0 as *mut libc::c_void;
|
||||
}
|
||||
|
||||
/* makes sure, the private key exists, needed only for exporting keys and the case no message was sent before */
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_ensure_secret_key_exists(context: &Context) -> libc::c_int {
|
||||
/* normally, the key is generated as soon as the first mail is send
|
||||
(this is to gain some extra-random-seed by the message content and the timespan between program start and message sending) */
|
||||
let mut success: libc::c_int = 0i32;
|
||||
|
||||
let self_addr = context.sql.get_config(context, "configured_addr");
|
||||
if self_addr.is_none() {
|
||||
warn!(
|
||||
context,
|
||||
0, "Cannot ensure secret key if context is not configured.",
|
||||
);
|
||||
} else if load_or_generate_self_public_key(context, self_addr.unwrap(), 0 as *mut mailmime)
|
||||
.is_some()
|
||||
{
|
||||
/*no random text data for seeding available*/
|
||||
success = 1;
|
||||
}
|
||||
|
||||
success
|
||||
/// Ensures a private key exists for the configured user.
|
||||
///
|
||||
/// Normally the private key is generated when the first message is
|
||||
/// sent but in a few locations there are no such guarantees,
|
||||
/// e.g. when exporting keys, and calling this function ensures a
|
||||
/// private key will be present.
|
||||
///
|
||||
/// If this succeeds you are also guaranteed that the
|
||||
/// [Config::ConfiguredAddr] is configured, this address is returned.
|
||||
pub fn dc_ensure_secret_key_exists(context: &Context) -> Result<String> {
|
||||
let self_addr = context
|
||||
.get_config(Config::ConfiguredAddr)
|
||||
.ok_or(format_err!(concat!(
|
||||
"Failed to get self address, ",
|
||||
"cannot ensure secret key if not configured."
|
||||
)))?;
|
||||
load_or_generate_self_public_key(context, &self_addr)?;
|
||||
Ok(self_addr)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use crate::test_utils::*;
|
||||
|
||||
mod ensure_secret_key_exists {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_prexisting() {
|
||||
let t = dummy_context();
|
||||
let test_addr = configure_alice_keypair(&t.ctx);
|
||||
assert_eq!(dc_ensure_secret_key_exists(&t.ctx).unwrap(), test_addr);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_not_configured() {
|
||||
let t = dummy_context();
|
||||
assert!(dc_ensure_secret_key_exists(&t.ctx).is_err());
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mailmime_parse() {
|
||||
let plain = b"Chat-Disposition-Notification-To: holger@deltachat.de
|
||||
@@ -1121,4 +1139,47 @@ Sent with my Delta Chat Messenger: https://delta.chat";
|
||||
|
||||
unsafe { free(decrypted_mime as *mut _) };
|
||||
}
|
||||
|
||||
mod load_or_generate_self_public_key {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_existing() {
|
||||
let t = dummy_context();
|
||||
let addr = configure_alice_keypair(&t.ctx);
|
||||
let key = load_or_generate_self_public_key(&t.ctx, addr);
|
||||
assert!(key.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore] // generating keys is expensive
|
||||
fn test_generate() {
|
||||
let t = dummy_context();
|
||||
let addr = "alice@example.org";
|
||||
let key0 = load_or_generate_self_public_key(&t.ctx, addr);
|
||||
assert!(key0.is_ok());
|
||||
let key1 = load_or_generate_self_public_key(&t.ctx, addr);
|
||||
assert!(key1.is_ok());
|
||||
assert_eq!(key0.unwrap(), key1.unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_generate_concurrent() {
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
|
||||
let t = dummy_context();
|
||||
let ctx = Arc::new(t.ctx);
|
||||
let ctx0 = Arc::clone(&ctx);
|
||||
let thr0 =
|
||||
thread::spawn(move || load_or_generate_self_public_key(&ctx0, "alice@example.org"));
|
||||
let ctx1 = Arc::clone(&ctx);
|
||||
let thr1 =
|
||||
thread::spawn(move || load_or_generate_self_public_key(&ctx1, "alice@example.org"));
|
||||
let res0 = thr0.join().unwrap();
|
||||
let res1 = thr1.join().unwrap();
|
||||
assert_eq!(res0.unwrap(), res1.unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
350
src/dc_imex.rs
350
src/dc_imex.rs
@@ -194,20 +194,15 @@ pub unsafe fn dc_initiate_key_transfer(context: &Context) -> *mut libc::c_char {
|
||||
setup_code.strdup()
|
||||
}
|
||||
|
||||
/// Renders HTML body of a setup file message.
|
||||
///
|
||||
/// The `passphrase` must be at least 2 characters long.
|
||||
pub fn dc_render_setup_file(context: &Context, passphrase: &str) -> Result<String> {
|
||||
ensure!(
|
||||
passphrase.len() >= 2,
|
||||
"Passphrase must be at least 2 chars long."
|
||||
);
|
||||
unsafe {
|
||||
ensure!(
|
||||
!(dc_ensure_secret_key_exists(context) == 0),
|
||||
"No secret key available."
|
||||
);
|
||||
}
|
||||
let self_addr = context
|
||||
.get_config(Config::ConfiguredAddr)
|
||||
.ok_or(format_err!("Failed to get self address."))?;
|
||||
let self_addr = dc_ensure_secret_key_exists(context)?;
|
||||
let private_key = Key::from_self_private(context, self_addr, &context.sql)
|
||||
.ok_or(format_err!("Failed to get private key."))?;
|
||||
let ac_headers = match context
|
||||
@@ -513,7 +508,7 @@ pub unsafe fn dc_normalize_setup_code(
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe fn dc_job_do_DC_JOB_IMEX_IMAP(context: &Context, job: *mut dc_job_t) {
|
||||
let mut current_block: u64;
|
||||
let mut ok_to_continue = true;
|
||||
let mut success: libc::c_int = 0;
|
||||
let mut ongoing_allocated_here: libc::c_int = 0;
|
||||
let what: libc::c_int;
|
||||
@@ -521,7 +516,8 @@ pub unsafe fn dc_job_do_DC_JOB_IMEX_IMAP(context: &Context, job: *mut dc_job_t)
|
||||
if !(0 == dc_alloc_ongoing(context)) {
|
||||
ongoing_allocated_here = 1;
|
||||
what = (*job).param.get_int(Param::Cmd).unwrap_or_default();
|
||||
let param1 = CString::yolo((*job).param.get(Param::Arg).unwrap_or_default());
|
||||
let param1_s = (*job).param.get(Param::Arg).unwrap_or_default();
|
||||
let param1 = CString::yolo(param1_s);
|
||||
let _param2 = CString::yolo((*job).param.get(Param::Arg2).unwrap_or_default());
|
||||
|
||||
if strlen(param1.as_ptr()) == 0 {
|
||||
@@ -534,185 +530,45 @@ pub unsafe fn dc_job_do_DC_JOB_IMEX_IMAP(context: &Context, job: *mut dc_job_t)
|
||||
} else {
|
||||
if what == 1 || what == 11 {
|
||||
/* before we export anything, make sure the private key exists */
|
||||
if 0 == dc_ensure_secret_key_exists(context) {
|
||||
if dc_ensure_secret_key_exists(context).is_err() {
|
||||
error!(
|
||||
context,
|
||||
0,
|
||||
"Import/export: Cannot create private key or private key not available.",
|
||||
);
|
||||
current_block = 3568988166330621280;
|
||||
ok_to_continue = false;
|
||||
} else {
|
||||
dc_create_folder(context, param1.as_ptr());
|
||||
current_block = 4495394744059808450;
|
||||
dc_create_folder(context, ¶m1_s);
|
||||
}
|
||||
} else {
|
||||
current_block = 4495394744059808450;
|
||||
}
|
||||
match current_block {
|
||||
3568988166330621280 => {}
|
||||
_ => match what {
|
||||
if ok_to_continue {
|
||||
match what {
|
||||
1 => {
|
||||
current_block = 10991094515395304355;
|
||||
match current_block {
|
||||
2973387206439775448 => {
|
||||
if 0 == import_backup(context, param1.as_ptr()) {
|
||||
current_block = 3568988166330621280;
|
||||
} else {
|
||||
current_block = 1118134448028020070;
|
||||
}
|
||||
}
|
||||
11250025114629486028 => {
|
||||
if 0 == import_self_keys(context, param1.as_ptr()) {
|
||||
current_block = 3568988166330621280;
|
||||
} else {
|
||||
current_block = 1118134448028020070;
|
||||
}
|
||||
}
|
||||
12669919903773909120 => {
|
||||
if 0 == export_backup(context, param1.as_ptr()) {
|
||||
current_block = 3568988166330621280;
|
||||
} else {
|
||||
current_block = 1118134448028020070;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
if 0 == export_self_keys(context, param1.as_ptr()) {
|
||||
current_block = 3568988166330621280;
|
||||
} else {
|
||||
current_block = 1118134448028020070;
|
||||
}
|
||||
}
|
||||
}
|
||||
match current_block {
|
||||
3568988166330621280 => {}
|
||||
_ => {
|
||||
info!(context, 0, "Import/export completed.",);
|
||||
success = 1
|
||||
}
|
||||
if 0 != export_self_keys(context, param1.as_ptr()) {
|
||||
info!(context, 0, "Import/export completed.",);
|
||||
success = 1
|
||||
}
|
||||
}
|
||||
2 => {
|
||||
current_block = 11250025114629486028;
|
||||
match current_block {
|
||||
2973387206439775448 => {
|
||||
if 0 == import_backup(context, param1.as_ptr()) {
|
||||
current_block = 3568988166330621280;
|
||||
} else {
|
||||
current_block = 1118134448028020070;
|
||||
}
|
||||
}
|
||||
11250025114629486028 => {
|
||||
if 0 == import_self_keys(context, param1.as_ptr()) {
|
||||
current_block = 3568988166330621280;
|
||||
} else {
|
||||
current_block = 1118134448028020070;
|
||||
}
|
||||
}
|
||||
12669919903773909120 => {
|
||||
if 0 == export_backup(context, param1.as_ptr()) {
|
||||
current_block = 3568988166330621280;
|
||||
} else {
|
||||
current_block = 1118134448028020070;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
if 0 == export_self_keys(context, param1.as_ptr()) {
|
||||
current_block = 3568988166330621280;
|
||||
} else {
|
||||
current_block = 1118134448028020070;
|
||||
}
|
||||
}
|
||||
}
|
||||
match current_block {
|
||||
3568988166330621280 => {}
|
||||
_ => {
|
||||
info!(context, 0, "Import/export completed.",);
|
||||
success = 1
|
||||
}
|
||||
if 0 != import_self_keys(context, param1.as_ptr()) {
|
||||
info!(context, 0, "Import/export completed.",);
|
||||
success = 1
|
||||
}
|
||||
}
|
||||
11 => {
|
||||
current_block = 12669919903773909120;
|
||||
match current_block {
|
||||
2973387206439775448 => {
|
||||
if 0 == import_backup(context, param1.as_ptr()) {
|
||||
current_block = 3568988166330621280;
|
||||
} else {
|
||||
current_block = 1118134448028020070;
|
||||
}
|
||||
}
|
||||
11250025114629486028 => {
|
||||
if 0 == import_self_keys(context, param1.as_ptr()) {
|
||||
current_block = 3568988166330621280;
|
||||
} else {
|
||||
current_block = 1118134448028020070;
|
||||
}
|
||||
}
|
||||
12669919903773909120 => {
|
||||
if 0 == export_backup(context, param1.as_ptr()) {
|
||||
current_block = 3568988166330621280;
|
||||
} else {
|
||||
current_block = 1118134448028020070;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
if 0 == export_self_keys(context, param1.as_ptr()) {
|
||||
current_block = 3568988166330621280;
|
||||
} else {
|
||||
current_block = 1118134448028020070;
|
||||
}
|
||||
}
|
||||
}
|
||||
match current_block {
|
||||
3568988166330621280 => {}
|
||||
_ => {
|
||||
info!(context, 0, "Import/export completed.",);
|
||||
success = 1
|
||||
}
|
||||
if 0 != export_backup(context, param1.as_ptr()) {
|
||||
info!(context, 0, "Import/export completed.",);
|
||||
success = 1
|
||||
}
|
||||
}
|
||||
12 => {
|
||||
current_block = 2973387206439775448;
|
||||
match current_block {
|
||||
2973387206439775448 => {
|
||||
if 0 == import_backup(context, param1.as_ptr()) {
|
||||
current_block = 3568988166330621280;
|
||||
} else {
|
||||
current_block = 1118134448028020070;
|
||||
}
|
||||
}
|
||||
11250025114629486028 => {
|
||||
if 0 == import_self_keys(context, param1.as_ptr()) {
|
||||
current_block = 3568988166330621280;
|
||||
} else {
|
||||
current_block = 1118134448028020070;
|
||||
}
|
||||
}
|
||||
12669919903773909120 => {
|
||||
if 0 == export_backup(context, param1.as_ptr()) {
|
||||
current_block = 3568988166330621280;
|
||||
} else {
|
||||
current_block = 1118134448028020070;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
if 0 == export_self_keys(context, param1.as_ptr()) {
|
||||
current_block = 3568988166330621280;
|
||||
} else {
|
||||
current_block = 1118134448028020070;
|
||||
}
|
||||
}
|
||||
}
|
||||
match current_block {
|
||||
3568988166330621280 => {}
|
||||
_ => {
|
||||
info!(context, 0, "Import/export completed.",);
|
||||
success = 1
|
||||
}
|
||||
if 0 != import_backup(context, param1.as_ptr()) {
|
||||
info!(context, 0, "Import/export completed.",);
|
||||
success = 1
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -748,8 +604,8 @@ unsafe fn import_backup(context: &Context, backup_to_import: *const libc::c_char
|
||||
return 0;
|
||||
}
|
||||
&context.sql.close(&context);
|
||||
dc_delete_file(context, context.get_dbfile());
|
||||
if 0 != dc_file_exist(context, context.get_dbfile()) {
|
||||
dc_delete_file(context, as_path(context.get_dbfile()));
|
||||
if dc_file_exist(context, as_path(context.get_dbfile())) {
|
||||
error!(
|
||||
context,
|
||||
0, "Cannot import backups: Cannot delete the old file.",
|
||||
@@ -757,7 +613,11 @@ unsafe fn import_backup(context: &Context, backup_to_import: *const libc::c_char
|
||||
return 0;
|
||||
}
|
||||
|
||||
if 0 == dc_copy_file(context, backup_to_import, context.get_dbfile()) {
|
||||
if !dc_copy_file(
|
||||
context,
|
||||
as_path(backup_to_import),
|
||||
as_path(context.get_dbfile()),
|
||||
) {
|
||||
return 0;
|
||||
}
|
||||
/* error already logged */
|
||||
@@ -884,7 +744,11 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> libc::c_
|
||||
as_str(context.get_dbfile()),
|
||||
as_str(dest_pathNfilename),
|
||||
);
|
||||
if !(0 == dc_copy_file(context, context.get_dbfile(), dest_pathNfilename)) {
|
||||
if dc_copy_file(
|
||||
context,
|
||||
as_path(context.get_dbfile()),
|
||||
as_path(dest_pathNfilename),
|
||||
) {
|
||||
context.sql.open(&context, as_path(context.get_dbfile()), 0);
|
||||
closed = false;
|
||||
/* add all files as blobs to the database copy (this does not require the source to be locked, neigher the destination as it is used only here) */
|
||||
@@ -1044,7 +908,7 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> libc::c_
|
||||
context.sql.open(&context, as_path(context.get_dbfile()), 0);
|
||||
}
|
||||
if 0 != delete_dest_file {
|
||||
dc_delete_file(context, dest_pathNfilename);
|
||||
dc_delete_file(context, as_path(dest_pathNfilename));
|
||||
}
|
||||
free(dest_pathNfilename as *mut libc::c_void);
|
||||
|
||||
@@ -1264,7 +1128,7 @@ unsafe fn export_key_to_asc_file(
|
||||
)
|
||||
}
|
||||
info!(context, 0, "Exporting key {}", as_str(file_name),);
|
||||
dc_delete_file(context, file_name);
|
||||
dc_delete_file(context, as_path(file_name));
|
||||
if !key.write_asc_to_file(file_name, context) {
|
||||
error!(context, 0, "Cannot write key to {}", as_str(file_name),);
|
||||
} else {
|
||||
@@ -1284,147 +1148,15 @@ unsafe fn export_key_to_asc_file(
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
use std::ffi::CStr;
|
||||
|
||||
use num_traits::ToPrimitive;
|
||||
|
||||
use crate::config::Config;
|
||||
use crate::key;
|
||||
use crate::test_utils::*;
|
||||
|
||||
unsafe extern "C" fn logging_cb(
|
||||
_ctx: &Context,
|
||||
evt: Event,
|
||||
_d1: uintptr_t,
|
||||
d2: uintptr_t,
|
||||
) -> uintptr_t {
|
||||
let to_str = |x| CStr::from_ptr(x as *const libc::c_char).to_str().unwrap();
|
||||
match evt {
|
||||
Event::INFO => println!("I: {}", to_str(d2)),
|
||||
Event::WARNING => println!("W: {}", to_str(d2)),
|
||||
Event::ERROR => println!("E: {}", to_str(d2)),
|
||||
_ => (),
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
/// Create Alice with a pre-generated keypair.
|
||||
fn create_alice_keypair(ctx: &Context) {
|
||||
ctx.set_config(Config::ConfiguredAddr, Some("alice@example.org"))
|
||||
.unwrap();
|
||||
|
||||
// The keypair was created using:
|
||||
// let (public, private) = crate::pgp::dc_pgp_create_keypair("alice@example.com")
|
||||
// .unwrap();
|
||||
// println!("{}", public.to_base64(64));
|
||||
// println!("{}", private.to_base64(64));
|
||||
let public = key::Key::from_base64(
|
||||
concat!(
|
||||
"xsBNBF086ewBCACmJKuoxIO6T87yi4Q3MyNpMch3Y8KrtHDQyUszU36eqM3Pmd1l",
|
||||
"FrbcCd8ZWo2pq6OJSwsM/jjRGn1zo2YOaQeJRRrC+KrKGqSUtRSYQBPrPjE2YjSX",
|
||||
"AMbu8jBI6VVUhHeghriBkK79PY9O/oRhIJC0p14IJe6CQ6OI2fTmTUHF9i/nJ3G4",
|
||||
"Wb3/K1bU3yVfyPZjTZQPYPvvh03vxHULKurtYkX5DTEMSWsF4qzLMps+l87VuLV9",
|
||||
"iQnbN7YMRLHHx2KkX5Ivi7JCefhCa54M0K3bDCCxuVWAM5wjQwNZjzR+WL+dYchw",
|
||||
"oFvuF8NrlzjM9dSv+2rn+J7f99ijSXarzPC7ABEBAAHNEzxhbGljZUBleGFtcGxl",
|
||||
"LmNvbT7CwIkEEAEIADMCGQEFAl086fgCGwMECwkIBwYVCAkKCwIDFgIBFiEE+iai",
|
||||
"x4d0doj87Q0ek6DcNkbrcegACgkQk6DcNkbrcei3ogf/cruUmQ+th52TFHTHdkw9",
|
||||
"OHUl3MrXtZ7QmHyOAFvbXE/6n5Eeh+eZoF8MWWV72m14Wbs+vTcNQkFVTdOPptkK",
|
||||
"A8e4cJqwDOHsyAnvQXZ7WNje9+BMzcoipIUawHP4ORFaPDsKLZQ0b4wBbKn8ziea",
|
||||
"6zjGF0/qljTdoxTtsYpv5wXYuhwbYklrLOqgSa5M7LXUe7E3g9mbg+9iX1GuB8m6",
|
||||
"GkquJN814Y+xny4xhZzGOfue6SeP12jJMNSjSP7416dRq7794VGnkkW9V/7oFEUK",
|
||||
"u5wO9FFbgDySOSlEjByGejSGuBmho0iJSjcPjZ7EY/j3M3orq4dpza5C82OeSvxD",
|
||||
"Fc7ATQRdPOnsAQgA5oLxXRLnyugzOmNCy7dxV3JrDZscA6JNlJlDWIShT0YSs+zG",
|
||||
"9JzDeQql+sYXgUSxOoIayItuXtnFn7tstwGoOnYvadm/e5/7V5fKAQRtCtdN51av",
|
||||
"62n18Venlm0yNKpROPcZ6M/sc4m6uU6YRZ/a1idal8VGY0wLKlghjIBuIiBoVQ/R",
|
||||
"noW+/fhmwIg08dQ5m8hQe3GEOZEeLrTWL/9awPlXK7Y+DmJOoR4qbHWEcRfbzS6q",
|
||||
"4zW8vk2ztB8ngwbnqYy8zrN1DCICN1gYdlU++uVw6Bb1XfY8Cdldh1VLKpF35mAm",
|
||||
"jxLZfVDcoObFH3Cv2GB7BEYxv86KC2Y6T74Q/wARAQABwsB2BBgBCAAgBQJdPOn4",
|
||||
"AhsMFiEE+iaix4d0doj87Q0ek6DcNkbrcegACgkQk6DcNkbrcegLxwf/dXshJnoW",
|
||||
"qEnRsf6rVb9/Mc66ti+NVQLfNd275dybh/QIJdK3NmSxdnTPIEJRVspJywJoupwX",
|
||||
"FNrnHG2Ff6QPvHqI+/oNu986r9d7Z1oQibbLHKt8t6kpOfg/xGxotagJuiCQvR9m",
|
||||
"MjD1DqsdB37SjDxGupZOOJSXWi6KX60IE+uM+QOBfeOZziQwuFmA5wV6RDXIeYJf",
|
||||
"qrcbeXeR1d0nfNpPHQR1gBiqmxNb6KBbdXD2+EXW60axC7D2b1APmzMlammDliPw",
|
||||
"sK9U1rc9nuquEBvGDOJf4K+Dzn+mDCqRpP6uAuQ7RKHyim4uyN0wwKObzPqgJCGw",
|
||||
"jTglkixw+aSTXw=="
|
||||
),
|
||||
KeyType::Public,
|
||||
)
|
||||
.unwrap();
|
||||
let private = key::Key::from_base64(
|
||||
concat!(
|
||||
"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",
|
||||
"zPqgJCGwjTglkixw+aSTXw=="
|
||||
),
|
||||
KeyType::Private,
|
||||
)
|
||||
.unwrap();
|
||||
let saved = key::dc_key_save_self_keypair(
|
||||
&ctx,
|
||||
&public,
|
||||
&private,
|
||||
"alice@example.org",
|
||||
1,
|
||||
&ctx.sql,
|
||||
);
|
||||
assert_eq!(saved, true, "Failed to save Alice's key");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_render_setup_file() {
|
||||
let t = test_context(Some(logging_cb));
|
||||
|
||||
create_alice_keypair(&t.ctx); // Trick things to think we're configured.
|
||||
configure_alice_keypair(&t.ctx);
|
||||
let msg = dc_render_setup_file(&t.ctx, "hello").unwrap();
|
||||
println!("{}", &msg);
|
||||
// Check some substrings, indicating things got substituted.
|
||||
@@ -1456,7 +1188,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_render_setup_file_newline_replace() {
|
||||
let t = test_context(Some(ac_setup_msg_cb));
|
||||
create_alice_keypair(&t.ctx);
|
||||
configure_alice_keypair(&t.ctx);
|
||||
let msg = dc_render_setup_file(&t.ctx, "pw").unwrap();
|
||||
println!("{}", &msg);
|
||||
assert!(msg.contains("<p>hello<br>there</p>"));
|
||||
|
||||
476
src/dc_job.rs
476
src/dc_job.rs
@@ -292,7 +292,7 @@ unsafe fn dc_suspend_smtp_thread(context: &Context, suspend: bool) {
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
unsafe fn dc_job_do_DC_JOB_SEND(context: &Context, job: &mut dc_job_t) {
|
||||
let mut current_block: u64;
|
||||
let ok_to_continue;
|
||||
let mut filename: *mut libc::c_char = 0 as *mut libc::c_char;
|
||||
let mut buf: *mut libc::c_void = 0 as *mut libc::c_void;
|
||||
let mut buf_bytes: size_t = 0i32 as size_t;
|
||||
@@ -304,100 +304,89 @@ unsafe fn dc_job_do_DC_JOB_SEND(context: &Context, job: &mut dc_job_t) {
|
||||
|
||||
if !connected {
|
||||
dc_job_try_again_later(job, 3i32, 0 as *const libc::c_char);
|
||||
current_block = 14216916617354591294;
|
||||
ok_to_continue = false;
|
||||
} else {
|
||||
current_block = 13109137661213826276;
|
||||
ok_to_continue = true;
|
||||
}
|
||||
} else {
|
||||
current_block = 13109137661213826276;
|
||||
ok_to_continue = true;
|
||||
}
|
||||
match current_block {
|
||||
13109137661213826276 => {
|
||||
filename = job.param.get(Param::File).unwrap_or_default().strdup();
|
||||
if strlen(filename) == 0 {
|
||||
warn!(context, 0, "Missing file name for job {}", job.job_id,);
|
||||
} else if !(0 == dc_read_file(context, filename, &mut buf, &mut buf_bytes)) {
|
||||
let recipients = job.param.get(Param::Recipients);
|
||||
if recipients.is_none() {
|
||||
warn!(context, 0, "Missing recipients for job {}", job.job_id,);
|
||||
} else {
|
||||
let recipients_list = recipients
|
||||
.unwrap()
|
||||
.split("\x1e")
|
||||
.filter_map(|addr| match lettre::EmailAddress::new(addr.to_string()) {
|
||||
Ok(addr) => Some(addr),
|
||||
Err(err) => {
|
||||
eprintln!("WARNING: invalid recipient: {} {:?}", addr, err);
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
/* if there is a msg-id and it does not exist in the db, cancel sending.
|
||||
this happends if dc_delete_msgs() was called
|
||||
before the generated mime was sent out */
|
||||
if 0 != job.foreign_id {
|
||||
if 0 == dc_msg_exists(context, job.foreign_id) {
|
||||
warn!(
|
||||
context,
|
||||
0,
|
||||
"Message {} for job {} does not exist",
|
||||
job.foreign_id,
|
||||
job.job_id,
|
||||
);
|
||||
current_block = 14216916617354591294;
|
||||
} else {
|
||||
current_block = 11194104282611034094;
|
||||
if ok_to_continue {
|
||||
let filename_s = job.param.get(Param::File).unwrap_or_default();
|
||||
filename = filename_s.strdup();
|
||||
if strlen(filename) == 0 {
|
||||
warn!(context, 0, "Missing file name for job {}", job.job_id,);
|
||||
} else if !(0 == dc_read_file(context, filename, &mut buf, &mut buf_bytes)) {
|
||||
let recipients = job.param.get(Param::Recipients);
|
||||
if recipients.is_none() {
|
||||
warn!(context, 0, "Missing recipients for job {}", job.job_id,);
|
||||
} else {
|
||||
let recipients_list = recipients
|
||||
.unwrap()
|
||||
.split("\x1e")
|
||||
.filter_map(|addr| match lettre::EmailAddress::new(addr.to_string()) {
|
||||
Ok(addr) => Some(addr),
|
||||
Err(err) => {
|
||||
eprintln!("WARNING: invalid recipient: {} {:?}", addr, err);
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
/* if there is a msg-id and it does not exist in the db, cancel sending.
|
||||
this happends if dc_delete_msgs() was called
|
||||
before the generated mime was sent out */
|
||||
let ok_to_continue1;
|
||||
if 0 != job.foreign_id {
|
||||
if 0 == dc_msg_exists(context, job.foreign_id) {
|
||||
warn!(
|
||||
context,
|
||||
0, "Message {} for job {} does not exist", job.foreign_id, job.job_id,
|
||||
);
|
||||
ok_to_continue1 = false;
|
||||
} else {
|
||||
current_block = 11194104282611034094;
|
||||
ok_to_continue1 = true;
|
||||
}
|
||||
match current_block {
|
||||
14216916617354591294 => {}
|
||||
_ => {
|
||||
/* send message */
|
||||
let body =
|
||||
std::slice::from_raw_parts(buf as *const u8, buf_bytes).to_vec();
|
||||
if 0 == context.smtp.lock().unwrap().send(
|
||||
context,
|
||||
recipients_list,
|
||||
body,
|
||||
) {
|
||||
context.smtp.lock().unwrap().disconnect();
|
||||
dc_job_try_again_later(
|
||||
job,
|
||||
-1i32,
|
||||
(*&mut context.smtp.clone().lock().unwrap()).error,
|
||||
);
|
||||
} else {
|
||||
dc_delete_file(context, filename);
|
||||
if 0 != job.foreign_id {
|
||||
dc_update_msg_state(
|
||||
context,
|
||||
job.foreign_id,
|
||||
DC_STATE_OUT_DELIVERED,
|
||||
);
|
||||
let chat_id: i32 = context
|
||||
.sql
|
||||
.query_row_col(
|
||||
context,
|
||||
"SELECT chat_id FROM msgs WHERE id=?",
|
||||
params![job.foreign_id as i32],
|
||||
0,
|
||||
)
|
||||
.unwrap_or_default();
|
||||
context.call_cb(
|
||||
Event::MSG_DELIVERED,
|
||||
chat_id as uintptr_t,
|
||||
job.foreign_id as uintptr_t,
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ok_to_continue1 = true;
|
||||
}
|
||||
if ok_to_continue1 {
|
||||
/* send message */
|
||||
let body = std::slice::from_raw_parts(buf as *const u8, buf_bytes).to_vec();
|
||||
if 0 == context
|
||||
.smtp
|
||||
.lock()
|
||||
.unwrap()
|
||||
.send(context, recipients_list, body)
|
||||
{
|
||||
context.smtp.lock().unwrap().disconnect();
|
||||
dc_job_try_again_later(
|
||||
job,
|
||||
-1i32,
|
||||
(*&mut context.smtp.clone().lock().unwrap()).error,
|
||||
);
|
||||
} else {
|
||||
dc_delete_file(context, filename_s);
|
||||
if 0 != job.foreign_id {
|
||||
dc_update_msg_state(context, job.foreign_id, DC_STATE_OUT_DELIVERED);
|
||||
let chat_id: i32 = context
|
||||
.sql
|
||||
.query_row_col(
|
||||
context,
|
||||
"SELECT chat_id FROM msgs WHERE id=?",
|
||||
params![job.foreign_id as i32],
|
||||
0,
|
||||
)
|
||||
.unwrap_or_default();
|
||||
context.call_cb(
|
||||
Event::MSG_DELIVERED,
|
||||
chat_id as uintptr_t,
|
||||
job.foreign_id as uintptr_t,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
free(buf);
|
||||
free(filename as *mut libc::c_void);
|
||||
@@ -416,7 +405,7 @@ pub unsafe fn dc_job_try_again_later(
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
unsafe fn dc_job_do_DC_JOB_MOVE_MSG(context: &Context, job: &mut dc_job_t) {
|
||||
let mut current_block: u64;
|
||||
let ok_to_continue;
|
||||
let msg = dc_msg_new_untyped(context);
|
||||
let mut dest_uid: uint32_t = 0i32 as uint32_t;
|
||||
|
||||
@@ -426,75 +415,46 @@ unsafe fn dc_job_do_DC_JOB_MOVE_MSG(context: &Context, job: &mut dc_job_t) {
|
||||
connect_to_inbox(context, &inbox);
|
||||
if !inbox.is_connected() {
|
||||
dc_job_try_again_later(job, 3i32, 0 as *const libc::c_char);
|
||||
current_block = 2238328302157162973;
|
||||
ok_to_continue = false;
|
||||
} else {
|
||||
current_block = 2473556513754201174;
|
||||
ok_to_continue = true;
|
||||
}
|
||||
} else {
|
||||
current_block = 2473556513754201174;
|
||||
ok_to_continue = true;
|
||||
}
|
||||
match current_block {
|
||||
2473556513754201174 => {
|
||||
if dc_msg_load_from_db(msg, context, job.foreign_id) {
|
||||
if context
|
||||
.sql
|
||||
.get_config_int(context, "folders_configured")
|
||||
.unwrap_or_default()
|
||||
< 3
|
||||
if ok_to_continue {
|
||||
if dc_msg_load_from_db(msg, context, job.foreign_id) {
|
||||
if context
|
||||
.sql
|
||||
.get_config_int(context, "folders_configured")
|
||||
.unwrap_or_default()
|
||||
< 3
|
||||
{
|
||||
inbox.configure_folders(context, 0x1i32);
|
||||
}
|
||||
let dest_folder = context.sql.get_config(context, "configured_mvbox_folder");
|
||||
|
||||
if let Some(dest_folder) = dest_folder {
|
||||
let server_folder = (*msg).server_folder.as_ref().unwrap();
|
||||
|
||||
match inbox.mv(
|
||||
context,
|
||||
server_folder,
|
||||
(*msg).server_uid,
|
||||
&dest_folder,
|
||||
&mut dest_uid,
|
||||
) as libc::c_uint
|
||||
{
|
||||
inbox.configure_folders(context, 0x1i32);
|
||||
}
|
||||
let dest_folder = context.sql.get_config(context, "configured_mvbox_folder");
|
||||
|
||||
if let Some(dest_folder) = dest_folder {
|
||||
let server_folder = as_str((*msg).server_folder);
|
||||
|
||||
match inbox.mv(
|
||||
context,
|
||||
server_folder,
|
||||
(*msg).server_uid,
|
||||
&dest_folder,
|
||||
&mut dest_uid,
|
||||
) as libc::c_uint
|
||||
{
|
||||
1 => {
|
||||
current_block = 6379107252614456477;
|
||||
match current_block {
|
||||
12072121998757195963 => {
|
||||
dc_update_server_uid(
|
||||
context,
|
||||
(*msg).rfc724_mid,
|
||||
&dest_folder,
|
||||
dest_uid,
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
dc_job_try_again_later(job, 3i32, 0 as *const libc::c_char);
|
||||
}
|
||||
}
|
||||
}
|
||||
3 => {
|
||||
current_block = 12072121998757195963;
|
||||
match current_block {
|
||||
12072121998757195963 => {
|
||||
dc_update_server_uid(
|
||||
context,
|
||||
(*msg).rfc724_mid,
|
||||
&dest_folder,
|
||||
dest_uid,
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
dc_job_try_again_later(job, 3i32, 0 as *const libc::c_char);
|
||||
}
|
||||
}
|
||||
}
|
||||
0 | 2 | _ => {}
|
||||
1 => {
|
||||
dc_job_try_again_later(job, 3i32, 0 as *const libc::c_char);
|
||||
}
|
||||
3 => {
|
||||
dc_update_server_uid(context, (*msg).rfc724_mid, &dest_folder, dest_uid);
|
||||
}
|
||||
0 | 2 | _ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
dc_msg_unref(msg);
|
||||
@@ -513,7 +473,7 @@ fn connect_to_inbox(context: &Context, inbox: &Imap) -> libc::c_int {
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
unsafe fn dc_job_do_DC_JOB_MARKSEEN_MDN_ON_IMAP(context: &Context, job: &mut dc_job_t) {
|
||||
let current_block: u64;
|
||||
let ok_to_continue;
|
||||
let folder = job
|
||||
.param
|
||||
.get(Param::ServerFolder)
|
||||
@@ -527,44 +487,39 @@ unsafe fn dc_job_do_DC_JOB_MARKSEEN_MDN_ON_IMAP(context: &Context, job: &mut dc_
|
||||
connect_to_inbox(context, &inbox);
|
||||
if !inbox.is_connected() {
|
||||
dc_job_try_again_later(job, 3, 0 as *const libc::c_char);
|
||||
current_block = 2670689566614003383;
|
||||
ok_to_continue = false;
|
||||
} else {
|
||||
current_block = 11006700562992250127;
|
||||
ok_to_continue = true;
|
||||
}
|
||||
} else {
|
||||
current_block = 11006700562992250127;
|
||||
ok_to_continue = true;
|
||||
}
|
||||
match current_block {
|
||||
11006700562992250127 => {
|
||||
if inbox.set_seen(context, &folder, uid) == 0 {
|
||||
dc_job_try_again_later(job, 3i32, 0 as *const libc::c_char);
|
||||
if ok_to_continue {
|
||||
if inbox.set_seen(context, &folder, uid) == 0 {
|
||||
dc_job_try_again_later(job, 3i32, 0 as *const libc::c_char);
|
||||
}
|
||||
if 0 != job.param.get_int(Param::AlsoMove).unwrap_or_default() {
|
||||
if context
|
||||
.sql
|
||||
.get_config_int(context, "folders_configured")
|
||||
.unwrap_or_default()
|
||||
< 3
|
||||
{
|
||||
inbox.configure_folders(context, 0x1i32);
|
||||
}
|
||||
if 0 != job.param.get_int(Param::AlsoMove).unwrap_or_default() {
|
||||
if context
|
||||
.sql
|
||||
.get_config_int(context, "folders_configured")
|
||||
.unwrap_or_default()
|
||||
< 3
|
||||
{
|
||||
inbox.configure_folders(context, 0x1i32);
|
||||
}
|
||||
let dest_folder = context.sql.get_config(context, "configured_mvbox_folder");
|
||||
if let Some(dest_folder) = dest_folder {
|
||||
if 1 == inbox.mv(context, folder, uid, dest_folder, &mut dest_uid)
|
||||
as libc::c_uint
|
||||
{
|
||||
dc_job_try_again_later(job, 3, 0 as *const libc::c_char);
|
||||
}
|
||||
let dest_folder = context.sql.get_config(context, "configured_mvbox_folder");
|
||||
if let Some(dest_folder) = dest_folder {
|
||||
if 1 == inbox.mv(context, folder, uid, dest_folder, &mut dest_uid) as libc::c_uint {
|
||||
dc_job_try_again_later(job, 3, 0 as *const libc::c_char);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
unsafe fn dc_job_do_DC_JOB_MARKSEEN_MSG_ON_IMAP(context: &Context, job: &mut dc_job_t) {
|
||||
let mut current_block: u64;
|
||||
let ok_to_continue;
|
||||
let msg: *mut dc_msg_t = dc_msg_new_untyped(context);
|
||||
let inbox = context.inbox.read().unwrap();
|
||||
|
||||
@@ -572,132 +527,44 @@ unsafe fn dc_job_do_DC_JOB_MARKSEEN_MSG_ON_IMAP(context: &Context, job: &mut dc_
|
||||
connect_to_inbox(context, &inbox);
|
||||
if !inbox.is_connected() {
|
||||
dc_job_try_again_later(job, 3i32, 0 as *const libc::c_char);
|
||||
current_block = 17792648348530113339;
|
||||
ok_to_continue = false;
|
||||
} else {
|
||||
current_block = 15240798224410183470;
|
||||
ok_to_continue = true;
|
||||
}
|
||||
} else {
|
||||
current_block = 15240798224410183470;
|
||||
ok_to_continue = true;
|
||||
}
|
||||
match current_block {
|
||||
15240798224410183470 => {
|
||||
if dc_msg_load_from_db(msg, context, job.foreign_id) {
|
||||
let server_folder = CStr::from_ptr((*msg).server_folder).to_str().unwrap();
|
||||
match inbox.set_seen(context, server_folder, (*msg).server_uid) as libc::c_uint {
|
||||
0 => {}
|
||||
1 => {
|
||||
current_block = 12392248546350854223;
|
||||
match current_block {
|
||||
12392248546350854223 => {
|
||||
dc_job_try_again_later(job, 3i32, 0 as *const libc::c_char);
|
||||
}
|
||||
_ => {
|
||||
if 0 != (*msg).param.get_int(Param::WantsMdn).unwrap_or_default()
|
||||
&& 0 != context
|
||||
.sql
|
||||
.get_config_int(context, "mdns_enabled")
|
||||
.unwrap_or_else(|| 1)
|
||||
{
|
||||
let folder =
|
||||
CStr::from_ptr((*msg).server_folder).to_str().unwrap();
|
||||
match inbox.set_mdnsent(context, folder, (*msg).server_uid)
|
||||
as libc::c_uint
|
||||
{
|
||||
1 => {
|
||||
current_block = 4016212065805849280;
|
||||
match current_block {
|
||||
6186957421461061791 => {
|
||||
dc_send_mdn(context, (*msg).id);
|
||||
}
|
||||
_ => {
|
||||
dc_job_try_again_later(
|
||||
job,
|
||||
3i32,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
3 => {
|
||||
current_block = 6186957421461061791;
|
||||
match current_block {
|
||||
6186957421461061791 => {
|
||||
dc_send_mdn(context, (*msg).id);
|
||||
}
|
||||
_ => {
|
||||
dc_job_try_again_later(
|
||||
job,
|
||||
3i32,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
0 | 2 | _ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
current_block = 7746791466490516765;
|
||||
match current_block {
|
||||
12392248546350854223 => {
|
||||
dc_job_try_again_later(job, 3i32, 0 as *const libc::c_char);
|
||||
}
|
||||
_ => {
|
||||
if 0 != (*msg).param.get_int(Param::WantsMdn).unwrap_or_default()
|
||||
&& 0 != context
|
||||
.sql
|
||||
.get_config_int(context, "mdns_enabled")
|
||||
.unwrap_or_else(|| 1)
|
||||
{
|
||||
let folder =
|
||||
CStr::from_ptr((*msg).server_folder).to_str().unwrap();
|
||||
if ok_to_continue {
|
||||
if dc_msg_load_from_db(msg, context, job.foreign_id) {
|
||||
let server_folder = (*msg).server_folder.as_ref().unwrap();
|
||||
match inbox.set_seen(context, server_folder, (*msg).server_uid) as libc::c_uint {
|
||||
0 => {}
|
||||
1 => {
|
||||
dc_job_try_again_later(job, 3i32, 0 as *const libc::c_char);
|
||||
}
|
||||
_ => {
|
||||
if 0 != (*msg).param.get_int(Param::WantsMdn).unwrap_or_default()
|
||||
&& 0 != context
|
||||
.sql
|
||||
.get_config_int(context, "mdns_enabled")
|
||||
.unwrap_or_else(|| 1)
|
||||
{
|
||||
let folder = (*msg).server_folder.as_ref().unwrap();
|
||||
|
||||
match inbox.set_mdnsent(context, folder, (*msg).server_uid)
|
||||
as libc::c_uint
|
||||
{
|
||||
1 => {
|
||||
current_block = 4016212065805849280;
|
||||
match current_block {
|
||||
6186957421461061791 => {
|
||||
dc_send_mdn(context, (*msg).id);
|
||||
}
|
||||
_ => {
|
||||
dc_job_try_again_later(
|
||||
job,
|
||||
3i32,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
3 => {
|
||||
current_block = 6186957421461061791;
|
||||
match current_block {
|
||||
6186957421461061791 => {
|
||||
dc_send_mdn(context, (*msg).id);
|
||||
}
|
||||
_ => {
|
||||
dc_job_try_again_later(
|
||||
job,
|
||||
3i32,
|
||||
0 as *const libc::c_char,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
0 | 2 | _ => {}
|
||||
}
|
||||
}
|
||||
match inbox.set_mdnsent(context, folder, (*msg).server_uid) as libc::c_uint
|
||||
{
|
||||
1 => {
|
||||
dc_job_try_again_later(job, 3i32, 0 as *const libc::c_char);
|
||||
}
|
||||
3 => {
|
||||
dc_send_mdn(context, (*msg).id);
|
||||
}
|
||||
0 | 2 | _ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
dc_msg_unref(msg);
|
||||
}
|
||||
@@ -864,7 +731,6 @@ pub unsafe fn dc_interrupt_imap_idle(context: &Context) {
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
unsafe fn dc_job_do_DC_JOB_DELETE_MSG_ON_IMAP(context: &Context, job: &mut dc_job_t) {
|
||||
let mut current_block: u64;
|
||||
let mut delete_from_server: libc::c_int = 1i32;
|
||||
let msg: *mut dc_msg_t = dc_msg_new_untyped(context);
|
||||
let inbox = context.inbox.read().unwrap();
|
||||
@@ -873,6 +739,7 @@ unsafe fn dc_job_do_DC_JOB_DELETE_MSG_ON_IMAP(context: &Context, job: &mut dc_jo
|
||||
|| (*msg).rfc724_mid.is_null()
|
||||
|| *(*msg).rfc724_mid.offset(0isize) as libc::c_int == 0i32)
|
||||
{
|
||||
let ok_to_continue1;
|
||||
/* eg. device messages have no Message-ID */
|
||||
if dc_rfc724_mid_cnt(context, (*msg).rfc724_mid) != 1i32 {
|
||||
info!(
|
||||
@@ -883,38 +750,35 @@ unsafe fn dc_job_do_DC_JOB_DELETE_MSG_ON_IMAP(context: &Context, job: &mut dc_jo
|
||||
}
|
||||
/* if this is the last existing part of the message, we delete the message from the server */
|
||||
if 0 != delete_from_server {
|
||||
let ok_to_continue;
|
||||
if !inbox.is_connected() {
|
||||
connect_to_inbox(context, &inbox);
|
||||
if !inbox.is_connected() {
|
||||
dc_job_try_again_later(job, 3i32, 0 as *const libc::c_char);
|
||||
current_block = 8913536887710889399;
|
||||
ok_to_continue = false;
|
||||
} else {
|
||||
current_block = 5399440093318478209;
|
||||
ok_to_continue = true;
|
||||
}
|
||||
} else {
|
||||
current_block = 5399440093318478209;
|
||||
ok_to_continue = true;
|
||||
}
|
||||
match current_block {
|
||||
8913536887710889399 => {}
|
||||
_ => {
|
||||
let mid = CStr::from_ptr((*msg).rfc724_mid).to_str().unwrap();
|
||||
let server_folder = CStr::from_ptr((*msg).server_folder).to_str().unwrap();
|
||||
if 0 == inbox.delete_msg(context, mid, server_folder, &mut (*msg).server_uid) {
|
||||
dc_job_try_again_later(job, -1i32, 0 as *const libc::c_char);
|
||||
current_block = 8913536887710889399;
|
||||
} else {
|
||||
current_block = 17407779659766490442;
|
||||
}
|
||||
if ok_to_continue {
|
||||
let mid = CStr::from_ptr((*msg).rfc724_mid).to_str().unwrap();
|
||||
let server_folder = (*msg).server_folder.as_ref().unwrap();
|
||||
if 0 == inbox.delete_msg(context, mid, server_folder, &mut (*msg).server_uid) {
|
||||
dc_job_try_again_later(job, -1i32, 0 as *const libc::c_char);
|
||||
ok_to_continue1 = false;
|
||||
} else {
|
||||
ok_to_continue1 = true;
|
||||
}
|
||||
} else {
|
||||
ok_to_continue1 = false;
|
||||
}
|
||||
} else {
|
||||
current_block = 17407779659766490442;
|
||||
ok_to_continue1 = true;
|
||||
}
|
||||
match current_block {
|
||||
8913536887710889399 => {}
|
||||
_ => {
|
||||
dc_delete_msg_from_db(context, (*msg).id);
|
||||
}
|
||||
if ok_to_continue1 {
|
||||
dc_delete_msg_from_db(context, (*msg).id);
|
||||
}
|
||||
}
|
||||
dc_msg_unref(msg);
|
||||
|
||||
@@ -6,14 +6,11 @@ use crate::dc_tools::*;
|
||||
use crate::stock::StockMessage;
|
||||
use crate::types::*;
|
||||
use crate::x::*;
|
||||
use std::ffi::CString;
|
||||
use std::ptr;
|
||||
|
||||
/* * Structure behind dc_lot_t */
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct dc_lot_t {
|
||||
pub magic: uint32_t,
|
||||
pub text1_meaning: libc::c_int,
|
||||
pub text1: *mut libc::c_char,
|
||||
pub text2: *mut libc::c_char,
|
||||
@@ -40,14 +37,13 @@ pub unsafe fn dc_lot_new() -> *mut dc_lot_t {
|
||||
lot = calloc(1, ::std::mem::size_of::<dc_lot_t>()) as *mut dc_lot_t;
|
||||
assert!(!lot.is_null());
|
||||
|
||||
(*lot).magic = 0x107107i32 as uint32_t;
|
||||
(*lot).text1_meaning = 0i32;
|
||||
|
||||
lot
|
||||
}
|
||||
|
||||
pub unsafe fn dc_lot_empty(mut lot: *mut dc_lot_t) {
|
||||
if lot.is_null() || (*lot).magic != 0x107107i32 as libc::c_uint {
|
||||
if lot.is_null() {
|
||||
return;
|
||||
}
|
||||
free((*lot).text1 as *mut libc::c_void);
|
||||
@@ -66,17 +62,16 @@ pub unsafe fn dc_lot_empty(mut lot: *mut dc_lot_t) {
|
||||
(*lot).id = 0i32 as uint32_t;
|
||||
}
|
||||
|
||||
pub unsafe fn dc_lot_unref(mut set: *mut dc_lot_t) {
|
||||
if set.is_null() || (*set).magic != 0x107107i32 as libc::c_uint {
|
||||
pub unsafe fn dc_lot_unref(set: *mut dc_lot_t) {
|
||||
if set.is_null() {
|
||||
return;
|
||||
}
|
||||
dc_lot_empty(set);
|
||||
(*set).magic = 0i32 as uint32_t;
|
||||
free(set as *mut libc::c_void);
|
||||
}
|
||||
|
||||
pub unsafe fn dc_lot_get_text1(lot: *const dc_lot_t) -> *mut libc::c_char {
|
||||
if lot.is_null() || (*lot).magic != 0x107107i32 as libc::c_uint {
|
||||
if lot.is_null() {
|
||||
return 0 as *mut libc::c_char;
|
||||
}
|
||||
|
||||
@@ -84,7 +79,7 @@ pub unsafe fn dc_lot_get_text1(lot: *const dc_lot_t) -> *mut libc::c_char {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_lot_get_text2(lot: *const dc_lot_t) -> *mut libc::c_char {
|
||||
if lot.is_null() || (*lot).magic != 0x107107i32 as libc::c_uint {
|
||||
if lot.is_null() {
|
||||
return 0 as *mut libc::c_char;
|
||||
}
|
||||
|
||||
@@ -92,7 +87,7 @@ pub unsafe fn dc_lot_get_text2(lot: *const dc_lot_t) -> *mut libc::c_char {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_lot_get_text1_meaning(lot: *const dc_lot_t) -> libc::c_int {
|
||||
if lot.is_null() || (*lot).magic != 0x107107i32 as libc::c_uint {
|
||||
if lot.is_null() {
|
||||
return 0i32;
|
||||
}
|
||||
|
||||
@@ -100,7 +95,7 @@ pub unsafe fn dc_lot_get_text1_meaning(lot: *const dc_lot_t) -> libc::c_int {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_lot_get_state(lot: *const dc_lot_t) -> libc::c_int {
|
||||
if lot.is_null() || (*lot).magic != 0x107107i32 as libc::c_uint {
|
||||
if lot.is_null() {
|
||||
return 0i32;
|
||||
}
|
||||
|
||||
@@ -108,7 +103,7 @@ pub unsafe fn dc_lot_get_state(lot: *const dc_lot_t) -> libc::c_int {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_lot_get_id(lot: *const dc_lot_t) -> uint32_t {
|
||||
if lot.is_null() || (*lot).magic != 0x107107i32 as libc::c_uint {
|
||||
if lot.is_null() {
|
||||
return 0i32 as uint32_t;
|
||||
}
|
||||
|
||||
@@ -116,7 +111,7 @@ pub unsafe fn dc_lot_get_id(lot: *const dc_lot_t) -> uint32_t {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_lot_get_timestamp(lot: *const dc_lot_t) -> i64 {
|
||||
if lot.is_null() || (*lot).magic != 0x107107i32 as libc::c_uint {
|
||||
if lot.is_null() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -132,7 +127,7 @@ pub unsafe fn dc_lot_fill(
|
||||
contact: Option<&Contact>,
|
||||
context: &Context,
|
||||
) {
|
||||
if lot.is_null() || (*lot).magic != 0x107107i32 as libc::c_uint || msg.is_null() {
|
||||
if lot.is_null() || msg.is_null() {
|
||||
return;
|
||||
}
|
||||
if (*msg).state == 19i32 {
|
||||
@@ -171,14 +166,15 @@ pub unsafe fn dc_lot_fill(
|
||||
}
|
||||
}
|
||||
|
||||
let msgtext_c = (*msg)
|
||||
.text
|
||||
.as_ref()
|
||||
.map(|s| CString::yolo(String::as_str(s)));
|
||||
let msgtext_ptr = msgtext_c.map_or(ptr::null(), |s| s.as_ptr());
|
||||
let message_text = (*msg).text.as_ref().unwrap();
|
||||
|
||||
(*lot).text2 =
|
||||
dc_msg_get_summarytext_by_raw((*msg).type_0, msgtext_ptr, &mut (*msg).param, 160, context);
|
||||
(*lot).text2 = dc_msg_get_summarytext_by_raw(
|
||||
(*msg).type_0,
|
||||
message_text.strdup(),
|
||||
&mut (*msg).param,
|
||||
160,
|
||||
context,
|
||||
);
|
||||
|
||||
(*lot).timestamp = dc_msg_get_timestamp(msg);
|
||||
(*lot).state = (*msg).state;
|
||||
|
||||
@@ -1311,16 +1311,14 @@ unsafe fn build_body_file(
|
||||
/*******************************************************************************
|
||||
* Render
|
||||
******************************************************************************/
|
||||
#[allow(non_snake_case)]
|
||||
unsafe fn is_file_size_okay(msg: *const dc_msg_t) -> bool {
|
||||
let mut file_size_okay = true;
|
||||
let pathNfilename = (*msg).param.get(Param::File).unwrap_or_default().strdup();
|
||||
let bytes = dc_get_filebytes((*msg).context, pathNfilename);
|
||||
let path = (*msg).param.get(Param::File).unwrap_or_default();
|
||||
let bytes = dc_get_filebytes((*msg).context, &path);
|
||||
|
||||
if bytes > (49 * 1024 * 1024 / 4 * 3) {
|
||||
file_size_okay = false;
|
||||
}
|
||||
free(pathNfilename as *mut _);
|
||||
|
||||
file_size_okay
|
||||
}
|
||||
|
||||
@@ -161,12 +161,7 @@ pub unsafe fn dc_mimeparser_parse(
|
||||
if !field.is_null() && (*field).fld_type == MAILIMF_FIELD_SUBJECT as libc::c_int {
|
||||
mimeparser.subject = dc_decode_header_words((*(*field).fld_data.fld_subject).sbj_value)
|
||||
}
|
||||
if !dc_mimeparser_lookup_optional_field(
|
||||
mimeparser,
|
||||
b"Chat-Version\x00" as *const u8 as *const libc::c_char,
|
||||
)
|
||||
.is_null()
|
||||
{
|
||||
if !dc_mimeparser_lookup_optional_field(mimeparser, "Chat-Version").is_null() {
|
||||
mimeparser.is_send_by_messenger = 1i32
|
||||
}
|
||||
if !dc_mimeparser_lookup_field(mimeparser, "Autocrypt-Setup-Message").is_null() {
|
||||
@@ -201,10 +196,7 @@ pub unsafe fn dc_mimeparser_parse(
|
||||
}
|
||||
}
|
||||
} else {
|
||||
optional_field = dc_mimeparser_lookup_optional_field(
|
||||
mimeparser,
|
||||
b"Chat-Content\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
optional_field = dc_mimeparser_lookup_optional_field(mimeparser, "Chat-Content");
|
||||
if !optional_field.is_null() && !(*optional_field).fld_value.is_null() {
|
||||
if strcmp(
|
||||
(*optional_field).fld_value,
|
||||
@@ -312,11 +304,7 @@ pub unsafe fn dc_mimeparser_parse(
|
||||
}
|
||||
if mimeparser.parts.len() == 1 {
|
||||
if mimeparser.parts[0].type_0 == 40i32 {
|
||||
if !dc_mimeparser_lookup_optional_field(
|
||||
mimeparser,
|
||||
b"Chat-Voice-Message\x00" as *const u8 as *const libc::c_char,
|
||||
)
|
||||
.is_null()
|
||||
if !dc_mimeparser_lookup_optional_field(mimeparser, "Chat-Voice-Message").is_null()
|
||||
{
|
||||
let part_mut = &mut mimeparser.parts[0];
|
||||
part_mut.type_0 = 41i32
|
||||
@@ -324,10 +312,7 @@ pub unsafe fn dc_mimeparser_parse(
|
||||
}
|
||||
let part = &mimeparser.parts[0];
|
||||
if part.type_0 == 40i32 || part.type_0 == 41i32 || part.type_0 == 50i32 {
|
||||
let field_0 = dc_mimeparser_lookup_optional_field(
|
||||
mimeparser,
|
||||
b"Chat-Duration\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
let field_0 = dc_mimeparser_lookup_optional_field(mimeparser, "Chat-Duration");
|
||||
if !field_0.is_null() {
|
||||
let duration_ms: libc::c_int = dc_atoi_null_is_0((*field_0).fld_value);
|
||||
if duration_ms > 0i32 && duration_ms < 24i32 * 60i32 * 60i32 * 1000i32 {
|
||||
@@ -338,10 +323,8 @@ pub unsafe fn dc_mimeparser_parse(
|
||||
}
|
||||
}
|
||||
if 0 == mimeparser.decrypting_failed {
|
||||
let dn_field: *const mailimf_optional_field = dc_mimeparser_lookup_optional_field(
|
||||
mimeparser,
|
||||
b"Chat-Disposition-Notification-To\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
let dn_field: *const mailimf_optional_field =
|
||||
dc_mimeparser_lookup_optional_field(mimeparser, "Chat-Disposition-Notification-To");
|
||||
if !dn_field.is_null() && dc_mimeparser_get_last_nonmeta(mimeparser).is_some() {
|
||||
let mut mb_list: *mut mailimf_mailbox_list = 0 as *mut mailimf_mailbox_list;
|
||||
let mut index_0: size_t = 0i32 as size_t;
|
||||
@@ -459,11 +442,11 @@ pub fn dc_mimeparser_lookup_field(
|
||||
|
||||
pub unsafe fn dc_mimeparser_lookup_optional_field(
|
||||
mimeparser: &dc_mimeparser_t,
|
||||
field_name: *const libc::c_char,
|
||||
field_name: &str,
|
||||
) -> *mut mailimf_optional_field {
|
||||
let field = mimeparser
|
||||
.header
|
||||
.get(as_str(field_name))
|
||||
.get(field_name)
|
||||
.map(|v| *v)
|
||||
.unwrap_or_else(|| std::ptr::null_mut());
|
||||
if !field.is_null() && (*field).fld_type == MAILIMF_FIELD_OPTIONAL_FIELD as libc::c_int {
|
||||
@@ -1112,7 +1095,7 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
|
||||
/* must not be free()'d */
|
||||
let mut decoded_data: *const libc::c_char = 0 as *const libc::c_char;
|
||||
let mut decoded_data_bytes = 0;
|
||||
let mut simplifier: Option<dc_simplify_t> = None;
|
||||
let mut simplifier: Option<Simplify> = None;
|
||||
if !(mime.is_null() || (*mime).mm_data.mm_single.is_null()) {
|
||||
mime_type = mailmime_get_mime_type(mime, &mut msg_type, &mut raw_mime);
|
||||
mime_data = (*mime).mm_data.mm_single;
|
||||
@@ -1134,7 +1117,7 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
|
||||
match mime_type {
|
||||
60 | 70 => {
|
||||
if simplifier.is_none() {
|
||||
simplifier = Some(dc_simplify_t::new());
|
||||
simplifier = Some(Simplify::new());
|
||||
}
|
||||
/* get from `Content-Type: text/...; charset=utf-8`; must not be free()'d */
|
||||
let charset = mailmime_content_charset_get((*mime).mm_content_type);
|
||||
@@ -1184,7 +1167,7 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
|
||||
/* check header directly as is_send_by_messenger is not yet set up */
|
||||
let is_msgrmsg = (!dc_mimeparser_lookup_optional_field(
|
||||
&mimeparser,
|
||||
b"Chat-Version\x00" as *const u8 as *const libc::c_char,
|
||||
"Chat-Version",
|
||||
)
|
||||
.is_null())
|
||||
as libc::c_int;
|
||||
@@ -1192,7 +1175,7 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
|
||||
let simplified_txt = simplifier.unwrap().simplify(
|
||||
decoded_data,
|
||||
decoded_data_bytes as libc::c_int,
|
||||
if mime_type == 70i32 { 1i32 } else { 0i32 },
|
||||
mime_type == 70i32,
|
||||
is_msgrmsg,
|
||||
);
|
||||
if !simplified_txt.is_null()
|
||||
@@ -1208,7 +1191,7 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
|
||||
} else {
|
||||
free(simplified_txt as *mut libc::c_void);
|
||||
}
|
||||
if 0 != simplifier.unwrap().is_forwarded {
|
||||
if simplifier.unwrap().is_forwarded {
|
||||
mimeparser.is_forwarded = 1i32
|
||||
}
|
||||
current_block = 10261677128829721533;
|
||||
@@ -1552,10 +1535,8 @@ pub unsafe fn dc_mimeparser_is_mailinglist_message(mimeparser: &dc_mimeparser_t)
|
||||
if !dc_mimeparser_lookup_field(&mimeparser, "List-Id").is_null() {
|
||||
return 1i32;
|
||||
}
|
||||
let precedence: *mut mailimf_optional_field = dc_mimeparser_lookup_optional_field(
|
||||
mimeparser,
|
||||
b"Precedence\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
let precedence: *mut mailimf_optional_field =
|
||||
dc_mimeparser_lookup_optional_field(mimeparser, "Precedence");
|
||||
if !precedence.is_null() {
|
||||
if strcasecmp(
|
||||
(*precedence).fld_value,
|
||||
|
||||
@@ -27,13 +27,13 @@ pub unsafe fn dc_do_heuristics_moves(context: &Context, folder: &str, msg_id: u3
|
||||
}
|
||||
|
||||
if dc_is_mvbox(context, folder) {
|
||||
dc_update_msg_move_state(context, (*msg).rfc724_mid, DC_MOVE_STATE_STAY);
|
||||
dc_update_msg_move_state(context, (*msg).rfc724_mid, MoveState::Stay);
|
||||
}
|
||||
|
||||
// 1 = dc message, 2 = reply to dc message
|
||||
if 0 != (*msg).is_dc_message {
|
||||
dc_job_add(context, 200, (*msg).id as libc::c_int, Params::new(), 0);
|
||||
dc_update_msg_move_state(context, (*msg).rfc724_mid, DC_MOVE_STATE_MOVING);
|
||||
dc_update_msg_move_state(context, (*msg).rfc724_mid, MoveState::Moving);
|
||||
}
|
||||
|
||||
dc_msg_unref(msg);
|
||||
|
||||
178
src/dc_msg.rs
178
src/dc_msg.rs
@@ -20,12 +20,11 @@ use std::ptr;
|
||||
#[derive(Clone)]
|
||||
#[repr(C)]
|
||||
pub struct dc_msg_t<'a> {
|
||||
pub magic: uint32_t,
|
||||
pub id: uint32_t,
|
||||
pub from_id: uint32_t,
|
||||
pub to_id: uint32_t,
|
||||
pub chat_id: uint32_t,
|
||||
pub move_state: dc_move_state_t,
|
||||
pub move_state: MoveState,
|
||||
pub type_0: Viewtype,
|
||||
pub state: libc::c_int,
|
||||
pub hidden: libc::c_int,
|
||||
@@ -36,7 +35,7 @@ pub struct dc_msg_t<'a> {
|
||||
pub context: &'a Context,
|
||||
pub rfc724_mid: *mut libc::c_char,
|
||||
pub in_reply_to: *mut libc::c_char,
|
||||
pub server_folder: *mut libc::c_char,
|
||||
pub server_folder: Option<String>,
|
||||
pub server_uid: uint32_t,
|
||||
pub is_dc_message: libc::c_int,
|
||||
pub starred: libc::c_int,
|
||||
@@ -168,7 +167,7 @@ pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_ch
|
||||
ret += &format!(
|
||||
"\nFile: {}, {}, bytes\n",
|
||||
as_str(p),
|
||||
dc_get_filebytes(context, p) as libc::c_int,
|
||||
dc_get_filebytes(context, as_path(p)) as libc::c_int,
|
||||
);
|
||||
}
|
||||
free(p as *mut libc::c_void);
|
||||
@@ -194,14 +193,12 @@ pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_ch
|
||||
ret += &format!("\n{}\n", rawtxt);
|
||||
}
|
||||
if !(*msg).rfc724_mid.is_null() && 0 != *(*msg).rfc724_mid.offset(0) as libc::c_int {
|
||||
ret += &format!("\nMessage-ID: {}", (*msg).rfc724_mid as libc::c_int);
|
||||
ret += &format!("\nMessage-ID: {}", as_str((*msg).rfc724_mid));
|
||||
}
|
||||
if !(*msg).server_folder.is_null() && 0 != *(*msg).server_folder.offset(0) as libc::c_int {
|
||||
ret += &format!(
|
||||
"\nLast seen as: {}/{}",
|
||||
to_string((*msg).server_folder),
|
||||
(*msg).server_uid as libc::c_int,
|
||||
);
|
||||
if let Some(ref server_folder) = (*msg).server_folder {
|
||||
if server_folder != "" {
|
||||
ret += &format!("\nLast seen as: {}/{}", server_folder, (*msg).server_uid);
|
||||
}
|
||||
}
|
||||
|
||||
dc_msg_unref(msg);
|
||||
@@ -224,12 +221,11 @@ pub unsafe fn dc_msg_new_untyped<'a>(context: &'a Context) -> *mut dc_msg_t<'a>
|
||||
// approx. max. length returned by dc_get_msg_info()
|
||||
pub unsafe fn dc_msg_new<'a>(context: &'a Context, viewtype: Viewtype) -> *mut dc_msg_t<'a> {
|
||||
let msg = dc_msg_t {
|
||||
magic: 0x11561156,
|
||||
id: 0,
|
||||
from_id: 0,
|
||||
to_id: 0,
|
||||
chat_id: 0,
|
||||
move_state: 0,
|
||||
move_state: MoveState::Undefined,
|
||||
type_0: viewtype,
|
||||
state: 0,
|
||||
hidden: 0,
|
||||
@@ -240,7 +236,7 @@ pub unsafe fn dc_msg_new<'a>(context: &'a Context, viewtype: Viewtype) -> *mut d
|
||||
context,
|
||||
rfc724_mid: std::ptr::null_mut(),
|
||||
in_reply_to: std::ptr::null_mut(),
|
||||
server_folder: std::ptr::null_mut(),
|
||||
server_folder: None,
|
||||
server_uid: 0,
|
||||
is_dc_message: 0,
|
||||
starred: 0,
|
||||
@@ -252,25 +248,22 @@ pub unsafe fn dc_msg_new<'a>(context: &'a Context, viewtype: Viewtype) -> *mut d
|
||||
Box::into_raw(Box::new(msg))
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_unref(mut msg: *mut dc_msg_t) {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
pub unsafe fn dc_msg_unref(msg: *mut dc_msg_t) {
|
||||
if msg.is_null() {
|
||||
return;
|
||||
}
|
||||
dc_msg_empty(msg);
|
||||
(*msg).magic = 0i32 as uint32_t;
|
||||
Box::from_raw(msg);
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_empty(mut msg: *mut dc_msg_t) {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
if msg.is_null() {
|
||||
return;
|
||||
}
|
||||
free((*msg).rfc724_mid as *mut libc::c_void);
|
||||
(*msg).rfc724_mid = 0 as *mut libc::c_char;
|
||||
free((*msg).in_reply_to as *mut libc::c_void);
|
||||
(*msg).in_reply_to = 0 as *mut libc::c_char;
|
||||
free((*msg).server_folder as *mut libc::c_void);
|
||||
(*msg).server_folder = 0 as *mut libc::c_char;
|
||||
(*msg).param = Params::new();
|
||||
(*msg).hidden = 0i32;
|
||||
}
|
||||
@@ -278,7 +271,7 @@ pub unsafe fn dc_msg_empty(mut msg: *mut dc_msg_t) {
|
||||
pub unsafe fn dc_msg_get_filemime(msg: *const dc_msg_t) -> *mut libc::c_char {
|
||||
let mut ret = 0 as *mut libc::c_char;
|
||||
|
||||
if !(msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint) {
|
||||
if !msg.is_null() {
|
||||
match (*msg).param.get(Param::MimeType) {
|
||||
Some(m) => {
|
||||
ret = m.strdup();
|
||||
@@ -362,7 +355,7 @@ pub unsafe fn dc_msg_guess_msgtype_from_suffix(
|
||||
pub unsafe fn dc_msg_get_file(msg: *const dc_msg_t) -> *mut libc::c_char {
|
||||
let mut file_abs = 0 as *mut libc::c_char;
|
||||
|
||||
if !(msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint) {
|
||||
if !msg.is_null() {
|
||||
if let Some(file_rel) = (*msg).param.get(Param::File) {
|
||||
let file_rel_c = CString::yolo(file_rel);
|
||||
file_abs = dc_get_abs_path((*msg).context, file_rel_c.as_ptr());
|
||||
@@ -385,7 +378,7 @@ pub unsafe fn dc_msg_get_file(msg: *const dc_msg_t) -> *mut libc::c_char {
|
||||
* @return 1=Message has location bound to it, 0=No location bound to message.
|
||||
*/
|
||||
pub unsafe fn dc_msg_has_location(msg: *const dc_msg_t) -> bool {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
if msg.is_null() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -414,10 +407,7 @@ pub unsafe fn dc_msg_set_location(
|
||||
latitude: libc::c_double,
|
||||
longitude: libc::c_double,
|
||||
) {
|
||||
if msg.is_null()
|
||||
|| (*msg).magic != 0x11561156i32 as libc::c_uint
|
||||
|| (latitude == 0.0 && longitude == 0.0)
|
||||
{
|
||||
if msg.is_null() || (latitude == 0.0 && longitude == 0.0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -426,7 +416,7 @@ pub unsafe fn dc_msg_set_location(
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_get_timestamp(msg: *const dc_msg_t) -> i64 {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
if msg.is_null() {
|
||||
return 0;
|
||||
}
|
||||
return if 0 != (*msg).timestamp_sent {
|
||||
@@ -460,7 +450,7 @@ pub fn dc_msg_load_from_db<'a>(msg: *mut dc_msg_t<'a>, context: &'a Context, id:
|
||||
Some(s) => s.strdup(),
|
||||
None => std::ptr::null_mut(),
|
||||
};
|
||||
(*msg).server_folder = row.get::<_, String>(3)?.strdup();
|
||||
(*msg).server_folder = row.get::<_, Option<String>>(3)?;
|
||||
(*msg).server_uid = row.get(4)?;
|
||||
(*msg).move_state = row.get(5)?;
|
||||
(*msg).chat_id = row.get(6)?;
|
||||
@@ -472,7 +462,21 @@ pub fn dc_msg_load_from_db<'a>(msg: *mut dc_msg_t<'a>, context: &'a Context, id:
|
||||
(*msg).type_0 = row.get(12)?;
|
||||
(*msg).state = row.get(13)?;
|
||||
(*msg).is_dc_message = row.get(14)?;
|
||||
(*msg).text = row.get::<_, Option<String>>(15)?;
|
||||
|
||||
let text;
|
||||
if let rusqlite::types::ValueRef::Text(buf) = row.get_raw(15) {
|
||||
if let Ok(t) = String::from_utf8(buf.to_vec()) {
|
||||
text = t;
|
||||
} else {
|
||||
warn!(context, 0, "dc_msg_load_from_db: could not get text column as non-lossy utf8 id {}", id);
|
||||
text = String::from_utf8_lossy(buf).into_owned();
|
||||
}
|
||||
} else {
|
||||
warn!(context, 0, "dc_msg_load_from_db: could not get text column for id {}", id);
|
||||
text = "[ Could not read from db ]".to_string();
|
||||
}
|
||||
(*msg).text = Some(text);
|
||||
|
||||
(*msg).param = row.get::<_, String>(16)?.parse().unwrap_or_default();
|
||||
(*msg).starred = row.get(17)?;
|
||||
(*msg).hidden = row.get(18)?;
|
||||
@@ -488,11 +492,18 @@ pub fn dc_msg_load_from_db<'a>(msg: *mut dc_msg_t<'a>, context: &'a Context, id:
|
||||
free(ptr.cast());
|
||||
}
|
||||
};
|
||||
Ok(())
|
||||
Ok(())
|
||||
}
|
||||
});
|
||||
|
||||
res.is_ok()
|
||||
if let Err(e) = res {
|
||||
warn!(
|
||||
context,
|
||||
0, "Error in msg_load_from_db for id {} because of {}", id, e
|
||||
);
|
||||
return false;
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
pub unsafe fn dc_get_mime_headers(context: &Context, msg_id: uint32_t) -> *mut libc::c_char {
|
||||
@@ -628,12 +639,13 @@ pub fn dc_star_msgs(
|
||||
}
|
||||
|
||||
pub unsafe fn dc_get_msg<'a>(context: &'a Context, msg_id: uint32_t) -> *mut dc_msg_t<'a> {
|
||||
let mut success: libc::c_int = 0i32;
|
||||
let mut success = false;
|
||||
let obj: *mut dc_msg_t = dc_msg_new_untyped(context);
|
||||
if dc_msg_load_from_db(obj, context, msg_id) {
|
||||
success = 1i32
|
||||
success = true
|
||||
}
|
||||
if 0 != success {
|
||||
|
||||
if success {
|
||||
obj
|
||||
} else {
|
||||
dc_msg_unref(obj);
|
||||
@@ -642,7 +654,7 @@ pub unsafe fn dc_get_msg<'a>(context: &'a Context, msg_id: uint32_t) -> *mut dc_
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_get_id(msg: *const dc_msg_t) -> uint32_t {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
if msg.is_null() {
|
||||
return 0i32 as uint32_t;
|
||||
}
|
||||
|
||||
@@ -650,7 +662,7 @@ pub unsafe fn dc_msg_get_id(msg: *const dc_msg_t) -> uint32_t {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_get_from_id(msg: *const dc_msg_t) -> uint32_t {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
if msg.is_null() {
|
||||
return 0i32 as uint32_t;
|
||||
}
|
||||
|
||||
@@ -658,7 +670,7 @@ pub unsafe fn dc_msg_get_from_id(msg: *const dc_msg_t) -> uint32_t {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_get_chat_id(msg: *const dc_msg_t) -> uint32_t {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
if msg.is_null() {
|
||||
return 0i32 as uint32_t;
|
||||
}
|
||||
return if 0 != (*msg).chat_blocked {
|
||||
@@ -669,7 +681,7 @@ pub unsafe fn dc_msg_get_chat_id(msg: *const dc_msg_t) -> uint32_t {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_get_viewtype(msg: *const dc_msg_t) -> Viewtype {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
if msg.is_null() {
|
||||
return Viewtype::Unknown;
|
||||
}
|
||||
|
||||
@@ -677,7 +689,7 @@ pub unsafe fn dc_msg_get_viewtype(msg: *const dc_msg_t) -> Viewtype {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_get_state(msg: *const dc_msg_t) -> libc::c_int {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
if msg.is_null() {
|
||||
return 0i32;
|
||||
}
|
||||
|
||||
@@ -685,7 +697,7 @@ pub unsafe fn dc_msg_get_state(msg: *const dc_msg_t) -> libc::c_int {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_get_received_timestamp(msg: *const dc_msg_t) -> i64 {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
if msg.is_null() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -693,7 +705,7 @@ pub unsafe fn dc_msg_get_received_timestamp(msg: *const dc_msg_t) -> i64 {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_get_sort_timestamp(msg: *const dc_msg_t) -> i64 {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
if msg.is_null() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -701,7 +713,7 @@ pub unsafe fn dc_msg_get_sort_timestamp(msg: *const dc_msg_t) -> i64 {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_get_text(msg: *const dc_msg_t) -> *mut libc::c_char {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
if msg.is_null() {
|
||||
return dc_strdup(0 as *const libc::c_char);
|
||||
}
|
||||
if let Some(ref text) = (*msg).text {
|
||||
@@ -715,7 +727,7 @@ pub unsafe fn dc_msg_get_text(msg: *const dc_msg_t) -> *mut libc::c_char {
|
||||
pub unsafe fn dc_msg_get_filename(msg: *const dc_msg_t) -> *mut libc::c_char {
|
||||
let mut ret = 0 as *mut libc::c_char;
|
||||
|
||||
if !(msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint) {
|
||||
if !msg.is_null() {
|
||||
if let Some(file) = (*msg).param.get(Param::File) {
|
||||
let file_c = CString::yolo(file);
|
||||
ret = dc_get_filename(file_c.as_ptr());
|
||||
@@ -729,20 +741,17 @@ pub unsafe fn dc_msg_get_filename(msg: *const dc_msg_t) -> *mut libc::c_char {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_get_filebytes(msg: *const dc_msg_t) -> uint64_t {
|
||||
let mut ret = 0;
|
||||
|
||||
if !(msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint) {
|
||||
if !msg.is_null() {
|
||||
if let Some(file) = (*msg).param.get(Param::File) {
|
||||
let file_c = CString::yolo(file);
|
||||
ret = dc_get_filebytes((*msg).context, file_c.as_ptr());
|
||||
return dc_get_filebytes((*msg).context, &file);
|
||||
}
|
||||
}
|
||||
|
||||
ret
|
||||
0
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_get_width(msg: *const dc_msg_t) -> libc::c_int {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
if msg.is_null() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -750,7 +759,7 @@ pub unsafe fn dc_msg_get_width(msg: *const dc_msg_t) -> libc::c_int {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_get_height(msg: *const dc_msg_t) -> libc::c_int {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156 as libc::c_uint {
|
||||
if msg.is_null() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -758,7 +767,7 @@ pub unsafe fn dc_msg_get_height(msg: *const dc_msg_t) -> libc::c_int {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_get_duration(msg: *const dc_msg_t) -> libc::c_int {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156 as libc::c_uint {
|
||||
if msg.is_null() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -767,7 +776,7 @@ pub unsafe fn dc_msg_get_duration(msg: *const dc_msg_t) -> libc::c_int {
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_msg_get_showpadlock(msg: *const dc_msg_t) -> libc::c_int {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156 as libc::c_uint {
|
||||
if msg.is_null() {
|
||||
return 0;
|
||||
}
|
||||
if (*msg)
|
||||
@@ -786,35 +795,29 @@ pub unsafe fn dc_msg_get_summary<'a>(
|
||||
msg: *mut dc_msg_t<'a>,
|
||||
mut chat: *const Chat<'a>,
|
||||
) -> *mut dc_lot_t {
|
||||
let current_block: u64;
|
||||
let mut ok_to_continue = true;
|
||||
let ret: *mut dc_lot_t = dc_lot_new();
|
||||
let mut chat_to_delete: *mut Chat = 0 as *mut Chat;
|
||||
|
||||
if !(msg.is_null() || (*msg).magic != 0x11561156 as libc::c_uint) {
|
||||
if !msg.is_null() {
|
||||
if chat.is_null() {
|
||||
chat_to_delete = dc_get_chat((*msg).context, (*msg).chat_id);
|
||||
if chat_to_delete.is_null() {
|
||||
current_block = 15204159476013091401;
|
||||
ok_to_continue = false;
|
||||
} else {
|
||||
chat = chat_to_delete;
|
||||
current_block = 7815301370352969686;
|
||||
}
|
||||
} else {
|
||||
current_block = 7815301370352969686;
|
||||
}
|
||||
match current_block {
|
||||
15204159476013091401 => {}
|
||||
_ => {
|
||||
let contact = if (*msg).from_id != DC_CONTACT_ID_SELF as libc::c_uint
|
||||
&& ((*chat).type_0 == 120 || (*chat).type_0 == 130)
|
||||
{
|
||||
Contact::get_by_id((*chat).context, (*msg).from_id).ok()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
if ok_to_continue {
|
||||
let contact = if (*msg).from_id != DC_CONTACT_ID_SELF as libc::c_uint
|
||||
&& ((*chat).type_0 == 120 || (*chat).type_0 == 130)
|
||||
{
|
||||
Contact::get_by_id((*chat).context, (*msg).from_id).ok()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
dc_lot_fill(ret, msg, chat, contact.as_ref(), (*msg).context);
|
||||
}
|
||||
dc_lot_fill(ret, msg, chat, contact.as_ref(), (*msg).context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -827,7 +830,7 @@ pub unsafe fn dc_msg_get_summarytext(
|
||||
msg: *mut dc_msg_t,
|
||||
approx_characters: libc::c_int,
|
||||
) -> *mut libc::c_char {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
if msg.is_null() {
|
||||
return dc_strdup(0 as *const libc::c_char);
|
||||
}
|
||||
|
||||
@@ -938,7 +941,7 @@ pub unsafe fn dc_msg_has_deviating_timestamp(msg: *const dc_msg_t) -> libc::c_in
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_msg_is_sent(msg: *const dc_msg_t) -> libc::c_int {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
if msg.is_null() {
|
||||
return 0;
|
||||
}
|
||||
if (*msg).state >= DC_STATE_OUT_DELIVERED {
|
||||
@@ -949,7 +952,7 @@ pub unsafe fn dc_msg_is_sent(msg: *const dc_msg_t) -> libc::c_int {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_is_starred(msg: *const dc_msg_t) -> bool {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
if msg.is_null() {
|
||||
return false;
|
||||
}
|
||||
0 != (*msg).starred
|
||||
@@ -957,7 +960,7 @@ pub unsafe fn dc_msg_is_starred(msg: *const dc_msg_t) -> bool {
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_msg_is_forwarded(msg: *const dc_msg_t) -> libc::c_int {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
if msg.is_null() {
|
||||
return 0;
|
||||
}
|
||||
if 0 != (*msg).param.get_int(Param::Forwarded).unwrap_or_default() {
|
||||
@@ -969,7 +972,7 @@ pub unsafe fn dc_msg_is_forwarded(msg: *const dc_msg_t) -> libc::c_int {
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_msg_is_info(msg: *const dc_msg_t) -> libc::c_int {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
if msg.is_null() {
|
||||
return 0;
|
||||
}
|
||||
let cmd = (*msg).param.get_int(Param::Cmd).unwrap_or_default();
|
||||
@@ -985,7 +988,7 @@ pub unsafe fn dc_msg_is_info(msg: *const dc_msg_t) -> libc::c_int {
|
||||
|
||||
// TODO should return bool /rtn
|
||||
pub unsafe fn dc_msg_is_increation(msg: *const dc_msg_t) -> libc::c_int {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
if msg.is_null() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -997,10 +1000,7 @@ pub unsafe fn dc_msg_is_increation(msg: *const dc_msg_t) -> libc::c_int {
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_is_setupmessage(msg: *const dc_msg_t) -> bool {
|
||||
if msg.is_null()
|
||||
|| (*msg).magic != 0x11561156i32 as libc::c_uint
|
||||
|| (*msg).type_0 != Viewtype::File
|
||||
{
|
||||
if msg.is_null() || (*msg).type_0 != Viewtype::File {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1056,7 +1056,7 @@ pub unsafe fn dc_msg_get_setupcodebegin(msg: *const dc_msg_t) -> *mut libc::c_ch
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_set_text(mut msg: *mut dc_msg_t, text: *const libc::c_char) {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
if msg.is_null() {
|
||||
return;
|
||||
}
|
||||
(*msg).text = if text.is_null() {
|
||||
@@ -1071,7 +1071,7 @@ pub unsafe fn dc_msg_set_file(
|
||||
file: *const libc::c_char,
|
||||
filemime: *const libc::c_char,
|
||||
) {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
if msg.is_null() {
|
||||
return;
|
||||
}
|
||||
if !file.is_null() {
|
||||
@@ -1083,7 +1083,7 @@ pub unsafe fn dc_msg_set_file(
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_set_dimension(msg: *mut dc_msg_t, width: libc::c_int, height: libc::c_int) {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
if msg.is_null() {
|
||||
return;
|
||||
}
|
||||
(*msg).param.set_int(Param::Width, width);
|
||||
@@ -1091,7 +1091,7 @@ pub unsafe fn dc_msg_set_dimension(msg: *mut dc_msg_t, width: libc::c_int, heigh
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_set_duration(msg: *mut dc_msg_t, duration: libc::c_int) {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
if msg.is_null() {
|
||||
return;
|
||||
}
|
||||
(*msg).param.set_int(Param::Duration, duration);
|
||||
@@ -1103,7 +1103,7 @@ pub unsafe fn dc_msg_latefiling_mediasize(
|
||||
height: libc::c_int,
|
||||
duration: libc::c_int,
|
||||
) {
|
||||
if !(msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint) {
|
||||
if !msg.is_null() {
|
||||
if width > 0 && height > 0 {
|
||||
(*msg).param.set_int(Param::Width, width);
|
||||
(*msg).param.set_int(Param::Height, height);
|
||||
@@ -1116,7 +1116,7 @@ pub unsafe fn dc_msg_latefiling_mediasize(
|
||||
}
|
||||
|
||||
pub unsafe fn dc_msg_save_param_to_disk(msg: *mut dc_msg_t) -> bool {
|
||||
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
|
||||
if msg.is_null() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1187,7 +1187,7 @@ pub unsafe fn dc_msg_exists(context: &Context, msg_id: uint32_t) -> libc::c_int
|
||||
pub fn dc_update_msg_move_state(
|
||||
context: &Context,
|
||||
rfc724_mid: *const libc::c_char,
|
||||
state: dc_move_state_t,
|
||||
state: MoveState,
|
||||
) -> bool {
|
||||
// we update the move_state for all messages belonging to a given Message-ID
|
||||
// so that the state stay intact when parts are deleted
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,6 @@ use crate::aheader::EncryptPreference;
|
||||
use crate::constants::*;
|
||||
use crate::contact::*;
|
||||
use crate::context::Context;
|
||||
use crate::dc_array::*;
|
||||
use crate::dc_chat::*;
|
||||
use crate::dc_configure::*;
|
||||
use crate::dc_e2ee::*;
|
||||
@@ -42,7 +41,7 @@ pub unsafe fn dc_get_securejoin_qr(
|
||||
let mut group_name_urlencoded = 0 as *mut libc::c_char;
|
||||
let mut qr: Option<String> = None;
|
||||
|
||||
dc_ensure_secret_key_exists(context);
|
||||
dc_ensure_secret_key_exists(context).ok();
|
||||
invitenumber = dc_token_lookup(context, DC_TOKEN_INVITENUMBER, group_chat_id);
|
||||
if invitenumber.is_null() {
|
||||
invitenumber = dc_create_id().strdup();
|
||||
@@ -149,7 +148,7 @@ pub unsafe fn dc_join_securejoin(context: &Context, qr: *const libc::c_char) ->
|
||||
let mut join_vg: libc::c_int = 0i32;
|
||||
let mut qr_scan: *mut dc_lot_t = 0 as *mut dc_lot_t;
|
||||
info!(context, 0, "Requesting secure-join ...",);
|
||||
dc_ensure_secret_key_exists(context);
|
||||
dc_ensure_secret_key_exists(context).ok();
|
||||
ongoing_allocated = dc_alloc_ongoing(context);
|
||||
if !(ongoing_allocated == 0i32) {
|
||||
qr_scan = dc_check_qr(context, qr);
|
||||
@@ -296,14 +295,12 @@ unsafe fn send_handshake_msg(
|
||||
}
|
||||
|
||||
unsafe fn chat_id_2_contact_id(context: &Context, contact_chat_id: uint32_t) -> uint32_t {
|
||||
let mut contact_id: uint32_t = 0i32 as uint32_t;
|
||||
let contacts: *mut dc_array_t = dc_get_chat_contacts(context, contact_chat_id);
|
||||
if !(dc_array_get_cnt(contacts) != 1) {
|
||||
contact_id = dc_array_get_id(contacts, 0i32 as size_t)
|
||||
let contacts = dc_get_chat_contacts(context, contact_chat_id);
|
||||
if contacts.len() == 1 {
|
||||
contacts[0]
|
||||
} else {
|
||||
0
|
||||
}
|
||||
dc_array_unref(contacts);
|
||||
|
||||
contact_id
|
||||
}
|
||||
|
||||
unsafe fn fingerprint_equals_sender(
|
||||
@@ -317,8 +314,8 @@ unsafe fn fingerprint_equals_sender(
|
||||
let mut fingerprint_equal: libc::c_int = 0i32;
|
||||
let contacts = dc_get_chat_contacts(context, contact_chat_id);
|
||||
|
||||
if !(dc_array_get_cnt(contacts) != 1) {
|
||||
if let Ok(contact) = Contact::load_from_db(context, dc_array_get_id(contacts, 0)) {
|
||||
if contacts.len() == 1 {
|
||||
if let Ok(contact) = Contact::load_from_db(context, contacts[0]) {
|
||||
if let Some(peerstate) = Peerstate::from_addr(context, &context.sql, contact.get_addr())
|
||||
{
|
||||
let fingerprint_normalized = dc_normalize_fingerprint(as_str(fingerprint));
|
||||
@@ -332,7 +329,6 @@ unsafe fn fingerprint_equals_sender(
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
dc_array_unref(contacts);
|
||||
|
||||
fingerprint_equal
|
||||
}
|
||||
|
||||
@@ -3,19 +3,18 @@ use crate::dc_tools::*;
|
||||
use crate::x::*;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct dc_simplify_t {
|
||||
pub is_forwarded: libc::c_int,
|
||||
pub is_cut_at_begin: libc::c_int,
|
||||
pub is_cut_at_end: libc::c_int,
|
||||
pub struct Simplify {
|
||||
pub is_forwarded: bool,
|
||||
pub is_cut_at_begin: bool,
|
||||
pub is_cut_at_end: bool,
|
||||
}
|
||||
|
||||
impl dc_simplify_t {
|
||||
impl Simplify {
|
||||
pub fn new() -> Self {
|
||||
dc_simplify_t {
|
||||
is_forwarded: 0,
|
||||
is_cut_at_begin: 0,
|
||||
is_cut_at_end: 0,
|
||||
Simplify {
|
||||
is_forwarded: false,
|
||||
is_cut_at_begin: false,
|
||||
is_cut_at_end: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,7 +25,7 @@ impl dc_simplify_t {
|
||||
&mut self,
|
||||
in_unterminated: *const libc::c_char,
|
||||
in_bytes: libc::c_int,
|
||||
is_html: libc::c_int,
|
||||
is_html: bool,
|
||||
is_msgrmsg: libc::c_int,
|
||||
) -> *mut libc::c_char {
|
||||
if in_bytes <= 0 {
|
||||
@@ -36,9 +35,9 @@ impl dc_simplify_t {
|
||||
/* create a copy of the given buffer */
|
||||
let mut out: *mut libc::c_char;
|
||||
let mut temp: *mut libc::c_char;
|
||||
self.is_forwarded = 0i32;
|
||||
self.is_cut_at_begin = 0i32;
|
||||
self.is_cut_at_end = 0i32;
|
||||
self.is_forwarded = false;
|
||||
self.is_cut_at_begin = false;
|
||||
self.is_cut_at_end = false;
|
||||
out = strndup(
|
||||
in_unterminated as *mut libc::c_char,
|
||||
in_bytes as libc::c_ulong,
|
||||
@@ -46,7 +45,7 @@ impl dc_simplify_t {
|
||||
if out.is_null() {
|
||||
return dc_strdup(b"\x00" as *const u8 as *const libc::c_char);
|
||||
}
|
||||
if 0 != is_html {
|
||||
if is_html {
|
||||
temp = dc_dehtml(out);
|
||||
if !temp.is_null() {
|
||||
free(out as *mut libc::c_void);
|
||||
@@ -96,7 +95,7 @@ impl dc_simplify_t {
|
||||
|| strcmp(line, b"----\x00" as *const u8 as *const libc::c_char) == 0i32
|
||||
{
|
||||
footer_mark = 1i32;
|
||||
self.is_cut_at_end = 1i32
|
||||
self.is_cut_at_end = true
|
||||
}
|
||||
if 0 != footer_mark {
|
||||
l_last = l;
|
||||
@@ -115,7 +114,7 @@ impl dc_simplify_t {
|
||||
&& strncmp(line1, b"From: \x00" as *const u8 as *const libc::c_char, 6) == 0i32
|
||||
&& *line2.offset(0isize) as libc::c_int == 0i32
|
||||
{
|
||||
self.is_forwarded = 1i32;
|
||||
self.is_forwarded = true;
|
||||
l_first += 3
|
||||
}
|
||||
}
|
||||
@@ -128,7 +127,7 @@ impl dc_simplify_t {
|
||||
|| strncmp(line, b"~~~~~\x00" as *const u8 as *const libc::c_char, 5) == 0i32
|
||||
{
|
||||
l_last = l;
|
||||
self.is_cut_at_end = 1i32;
|
||||
self.is_cut_at_end = true;
|
||||
/* done */
|
||||
break;
|
||||
}
|
||||
@@ -145,7 +144,7 @@ impl dc_simplify_t {
|
||||
}
|
||||
if l_lastQuotedLine.is_some() {
|
||||
l_last = l_lastQuotedLine.unwrap();
|
||||
self.is_cut_at_end = 1i32;
|
||||
self.is_cut_at_end = true;
|
||||
if l_last > 1 {
|
||||
if is_empty_line(lines[l_last - 1]) {
|
||||
l_last -= 1
|
||||
@@ -180,12 +179,12 @@ impl dc_simplify_t {
|
||||
}
|
||||
if l_lastQuotedLine_0.is_some() {
|
||||
l_first = l_lastQuotedLine_0.unwrap() + 1;
|
||||
self.is_cut_at_begin = 1i32
|
||||
self.is_cut_at_begin = true
|
||||
}
|
||||
}
|
||||
/* re-create buffer from the remaining lines */
|
||||
let mut ret = String::new();
|
||||
if 0 != self.is_cut_at_begin {
|
||||
if self.is_cut_at_begin {
|
||||
ret += "[...]";
|
||||
}
|
||||
/* we write empty lines only in case and non-empty line follows */
|
||||
@@ -211,7 +210,7 @@ impl dc_simplify_t {
|
||||
pending_linebreaks = 1i32
|
||||
}
|
||||
}
|
||||
if 0 != self.is_cut_at_end && (0 == self.is_cut_at_begin || 0 != content_lines_added) {
|
||||
if self.is_cut_at_end && (!self.is_cut_at_begin || 0 != content_lines_added) {
|
||||
ret += " [...]";
|
||||
}
|
||||
dc_free_splitted_lines(lines);
|
||||
@@ -268,11 +267,11 @@ mod tests {
|
||||
#[test]
|
||||
fn test_simplify_trim() {
|
||||
unsafe {
|
||||
let mut simplify = dc_simplify_t::new();
|
||||
let mut simplify = Simplify::new();
|
||||
let html: *const libc::c_char =
|
||||
b"\r\r\nline1<br>\r\n\r\n\r\rline2\n\r\x00" as *const u8 as *const libc::c_char;
|
||||
let plain: *mut libc::c_char =
|
||||
simplify.simplify(html, strlen(html) as libc::c_int, 1, 0);
|
||||
simplify.simplify(html, strlen(html) as libc::c_int, true, 0);
|
||||
|
||||
assert_eq!(
|
||||
CStr::from_ptr(plain as *const libc::c_char)
|
||||
@@ -288,11 +287,11 @@ mod tests {
|
||||
#[test]
|
||||
fn test_simplify_parse_href() {
|
||||
unsafe {
|
||||
let mut simplify = dc_simplify_t::new();
|
||||
let mut simplify = Simplify::new();
|
||||
let html: *const libc::c_char =
|
||||
b"<a href=url>text</a\x00" as *const u8 as *const libc::c_char;
|
||||
let plain: *mut libc::c_char =
|
||||
simplify.simplify(html, strlen(html) as libc::c_int, 1, 0);
|
||||
simplify.simplify(html, strlen(html) as libc::c_int, true, 0);
|
||||
|
||||
assert_eq!(
|
||||
CStr::from_ptr(plain as *const libc::c_char)
|
||||
@@ -308,12 +307,12 @@ mod tests {
|
||||
#[test]
|
||||
fn test_simplify_bold_text() {
|
||||
unsafe {
|
||||
let mut simplify = dc_simplify_t::new();
|
||||
let mut simplify = Simplify::new();
|
||||
let html: *const libc::c_char =
|
||||
b"<!DOCTYPE name [<!DOCTYPE ...>]><!-- comment -->text <b><?php echo ... ?>bold</b><![CDATA[<>]]>\x00"
|
||||
as *const u8 as *const libc::c_char;
|
||||
let plain: *mut libc::c_char =
|
||||
simplify.simplify(html, strlen(html) as libc::c_int, 1, 0);
|
||||
simplify.simplify(html, strlen(html) as libc::c_int, true, 0);
|
||||
|
||||
assert_eq!(
|
||||
CStr::from_ptr(plain as *const libc::c_char)
|
||||
@@ -329,12 +328,12 @@ mod tests {
|
||||
#[test]
|
||||
fn test_simplify_html_encoded() {
|
||||
unsafe {
|
||||
let mut simplify = dc_simplify_t::new();
|
||||
let mut simplify = Simplify::new();
|
||||
let html: *const libc::c_char =
|
||||
b"<>"'& äÄöÖüÜß fooÆçÇ ♦&noent;‎‏‌‍\x00"
|
||||
as *const u8 as *const libc::c_char;
|
||||
let plain: *mut libc::c_char =
|
||||
simplify.simplify(html, strlen(html) as libc::c_int, 1, 0);
|
||||
simplify.simplify(html, strlen(html) as libc::c_int, true, 0);
|
||||
|
||||
assert_eq!(
|
||||
strcmp(plain,
|
||||
|
||||
190
src/dc_tools.rs
190
src/dc_tools.rs
@@ -23,8 +23,21 @@ pub fn dc_exactly_one_bit_set(v: libc::c_int) -> bool {
|
||||
0 != v && 0 == v & v - 1i32
|
||||
}
|
||||
|
||||
/* string tools */
|
||||
/* dc_strdup() returns empty string if NULL is given, never returns NULL (exits on errors) */
|
||||
/// Duplicates a string
|
||||
///
|
||||
/// returns an empty string if NULL is given, never returns NULL (exits on errors)
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use deltachat::dc_tools::{dc_strdup, to_string};
|
||||
/// unsafe {
|
||||
/// let str_a = b"foobar\x00" as *const u8 as *const libc::c_char;
|
||||
/// let str_a_copy = dc_strdup(str_a);
|
||||
/// assert_eq!(to_string(str_a_copy), "foobar");
|
||||
/// assert_ne!(str_a, str_a_copy);
|
||||
/// }
|
||||
/// ```
|
||||
pub unsafe fn dc_strdup(s: *const libc::c_char) -> *mut libc::c_char {
|
||||
let ret: *mut libc::c_char;
|
||||
if !s.is_null() {
|
||||
@@ -38,7 +51,21 @@ pub unsafe fn dc_strdup(s: *const libc::c_char) -> *mut libc::c_char {
|
||||
ret
|
||||
}
|
||||
|
||||
/* strdup(NULL) is undefined, safe_strdup_keep_null(NULL) returns NULL in this case */
|
||||
/// Duplicates a string, returns null if given string is null
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use deltachat::dc_tools::{dc_strdup_keep_null, to_string};
|
||||
/// use std::ffi::{CStr};
|
||||
///
|
||||
/// unsafe {
|
||||
/// let str_a = b"foobar\x00" as *const u8 as *const libc::c_char;
|
||||
/// let str_a_copy = dc_strdup_keep_null(str_a);
|
||||
/// assert_eq!(to_string(str_a_copy), "foobar");
|
||||
/// assert_ne!(str_a, str_a_copy);
|
||||
/// }
|
||||
/// ```
|
||||
pub unsafe fn dc_strdup_keep_null(s: *const libc::c_char) -> *mut libc::c_char {
|
||||
return if !s.is_null() {
|
||||
dc_strdup(s)
|
||||
@@ -67,50 +94,14 @@ pub unsafe fn dc_str_replace(
|
||||
haystack: *mut *mut libc::c_char,
|
||||
needle: *const libc::c_char,
|
||||
replacement: *const libc::c_char,
|
||||
) -> libc::c_int {
|
||||
let mut replacements: libc::c_int = 0i32;
|
||||
let mut start_search_pos: libc::c_int = 0i32;
|
||||
let needle_len: libc::c_int;
|
||||
let replacement_len: libc::c_int;
|
||||
if haystack.is_null()
|
||||
|| (*haystack).is_null()
|
||||
|| needle.is_null()
|
||||
|| *needle.offset(0isize) as libc::c_int == 0i32
|
||||
{
|
||||
return 0i32;
|
||||
}
|
||||
needle_len = strlen(needle) as libc::c_int;
|
||||
replacement_len = (if !replacement.is_null() {
|
||||
strlen(replacement)
|
||||
} else {
|
||||
0
|
||||
}) as libc::c_int;
|
||||
loop {
|
||||
let mut p2: *mut libc::c_char =
|
||||
strstr((*haystack).offset(start_search_pos as isize), needle);
|
||||
if p2.is_null() {
|
||||
break;
|
||||
}
|
||||
start_search_pos =
|
||||
(p2.wrapping_offset_from(*haystack) + replacement_len as isize) as libc::c_int;
|
||||
*p2 = 0i32 as libc::c_char;
|
||||
p2 = p2.offset(needle_len as isize);
|
||||
let new_string: *mut libc::c_char = dc_mprintf(
|
||||
b"%s%s%s\x00" as *const u8 as *const libc::c_char,
|
||||
*haystack,
|
||||
if !replacement.is_null() {
|
||||
replacement
|
||||
} else {
|
||||
b"\x00" as *const u8 as *const libc::c_char
|
||||
},
|
||||
p2,
|
||||
);
|
||||
free(*haystack as *mut libc::c_void);
|
||||
*haystack = new_string;
|
||||
replacements += 1
|
||||
}
|
||||
) {
|
||||
let haystack_s = to_string(*haystack);
|
||||
let needle_s = to_string(needle);
|
||||
let replacement_s = to_string(replacement);
|
||||
|
||||
replacements
|
||||
free(*haystack as *mut libc::c_void);
|
||||
|
||||
*haystack = haystack_s.replace(&needle_s, &replacement_s).strdup();
|
||||
}
|
||||
|
||||
pub unsafe fn dc_ftoa(f: libc::c_double) -> *mut libc::c_char {
|
||||
@@ -1086,21 +1077,20 @@ pub unsafe fn dc_get_abs_path(
|
||||
pathNfilename_abs
|
||||
}
|
||||
|
||||
pub fn dc_file_exist(context: &Context, path: *const libc::c_char) -> libc::c_int {
|
||||
dc_get_abs_path_safe(context, as_path(path)).exists() as libc::c_int
|
||||
pub fn dc_file_exist(context: &Context, path: impl AsRef<std::path::Path>) -> bool {
|
||||
dc_get_abs_path_safe(context, &path).exists()
|
||||
}
|
||||
|
||||
pub fn dc_get_filebytes(context: &Context, path: *const libc::c_char) -> uint64_t {
|
||||
let path_abs = dc_get_abs_path_safe(context, as_path(path));
|
||||
pub fn dc_get_filebytes(context: &Context, path: impl AsRef<std::path::Path>) -> uint64_t {
|
||||
let path_abs = dc_get_abs_path_safe(context, &path);
|
||||
match fs::metadata(&path_abs) {
|
||||
Ok(meta) => meta.len() as uint64_t,
|
||||
Err(_err) => 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dc_delete_file(context: &Context, path: *const libc::c_char) -> libc::c_int {
|
||||
let path = as_path(path);
|
||||
let path_abs = dc_get_abs_path_safe(context, path);
|
||||
pub fn dc_delete_file(context: &Context, path: impl AsRef<std::path::Path>) -> bool {
|
||||
let path_abs = dc_get_abs_path_safe(context, &path);
|
||||
let res = if path_abs.is_file() {
|
||||
fs::remove_file(path_abs)
|
||||
} else {
|
||||
@@ -1108,56 +1098,53 @@ pub fn dc_delete_file(context: &Context, path: *const libc::c_char) -> libc::c_i
|
||||
};
|
||||
|
||||
match res {
|
||||
Ok(_) => 1,
|
||||
Ok(_) => true,
|
||||
Err(_err) => {
|
||||
warn!(context, 0, "Cannot delete \"{}\".", path.display());
|
||||
0
|
||||
warn!(context, 0, "Cannot delete \"{}\".", path.as_ref().display());
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dc_copy_file(
|
||||
context: &Context,
|
||||
src: *const libc::c_char,
|
||||
dest: *const libc::c_char,
|
||||
) -> libc::c_int {
|
||||
let src = as_path(src);
|
||||
let dest = as_path(dest);
|
||||
let src_abs = dc_get_abs_path_safe(context, src);
|
||||
let dest_abs = dc_get_abs_path_safe(context, dest);
|
||||
src: impl AsRef<std::path::Path>,
|
||||
dest: impl AsRef<std::path::Path>,
|
||||
) -> bool {
|
||||
let src_abs = dc_get_abs_path_safe(context, &src);
|
||||
let dest_abs = dc_get_abs_path_safe(context, &dest);
|
||||
match fs::copy(&src_abs, &dest_abs) {
|
||||
Ok(_) => 1,
|
||||
Ok(_) => true,
|
||||
Err(_) => {
|
||||
error!(
|
||||
context,
|
||||
0,
|
||||
"Cannot copy \"{}\" to \"{}\".",
|
||||
src.display(),
|
||||
dest.display(),
|
||||
src.as_ref().display(),
|
||||
dest.as_ref().display(),
|
||||
);
|
||||
0
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dc_create_folder(context: &Context, path: *const libc::c_char) -> libc::c_int {
|
||||
let path = as_path(path);
|
||||
let path_abs = dc_get_abs_path_safe(context, path);
|
||||
pub fn dc_create_folder(context: &Context, path: impl AsRef<std::path::Path>) -> bool {
|
||||
let path_abs = dc_get_abs_path_safe(context, &path);
|
||||
if !path_abs.exists() {
|
||||
match fs::create_dir_all(path_abs) {
|
||||
Ok(_) => 1,
|
||||
Ok(_) => true,
|
||||
Err(_err) => {
|
||||
warn!(
|
||||
context,
|
||||
0,
|
||||
"Cannot create directory \"{}\".",
|
||||
path.display(),
|
||||
path.as_ref().display(),
|
||||
);
|
||||
0
|
||||
false
|
||||
}
|
||||
}
|
||||
} else {
|
||||
1
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1266,7 +1253,7 @@ pub unsafe fn dc_get_fine_pathNfilename(
|
||||
dotNSuffix,
|
||||
)
|
||||
}
|
||||
if 0 == dc_file_exist(context, ret) {
|
||||
if !dc_file_exist(context, as_path(ret)) {
|
||||
/* fine filename found */
|
||||
break;
|
||||
} else {
|
||||
@@ -1320,7 +1307,7 @@ pub unsafe fn dc_make_rel_and_copy(context: &Context, path: *mut *mut libc::c_ch
|
||||
);
|
||||
blobdir_path.is_null()
|
||||
}
|
||||
|| 0 == dc_copy_file(context, *path, blobdir_path))
|
||||
|| !dc_copy_file(context, as_path(*path), as_path(blobdir_path)))
|
||||
{
|
||||
free(*path as *mut libc::c_void);
|
||||
*path = blobdir_path;
|
||||
@@ -1462,9 +1449,9 @@ pub trait StrExt {
|
||||
///
|
||||
/// This allocates a new raw C string which must be freed using
|
||||
/// `free`. It takes care of some common pitfalls with using
|
||||
/// [CString::as_ptr].
|
||||
/// [CString.as_ptr].
|
||||
///
|
||||
/// [CString::as_ptr]: std::ffi::CString::as_ptr
|
||||
/// [CString.as_ptr]: std::ffi::CString.as_ptr
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
@@ -1573,6 +1560,49 @@ mod tests {
|
||||
use super::*;
|
||||
use std::ffi::CStr;
|
||||
|
||||
#[test]
|
||||
fn test_dc_strdup() {
|
||||
unsafe {
|
||||
let str_a = b"foobar\x00" as *const u8 as *const libc::c_char;
|
||||
let str_a_copy = dc_strdup(str_a);
|
||||
|
||||
// Value of str_a_copy should equal foobar
|
||||
assert_eq!(
|
||||
CStr::from_ptr(str_a_copy),
|
||||
CString::new("foobar").unwrap().as_c_str()
|
||||
);
|
||||
// Address of str_a should be different from str_a_copy
|
||||
assert_ne!(str_a, str_a_copy);
|
||||
|
||||
let str_a = std::ptr::null() as *const libc::c_char;
|
||||
let str_a_copy = dc_strdup(str_a);
|
||||
// Value of str_a_copy should equal ""
|
||||
assert_eq!(
|
||||
CStr::from_ptr(str_a_copy),
|
||||
CString::new("").unwrap().as_c_str()
|
||||
);
|
||||
assert_ne!(str_a, str_a_copy);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dc_strdup_keep_null() {
|
||||
unsafe {
|
||||
let str_a = b"foobar\x00" as *const u8 as *const libc::c_char;
|
||||
let str_a_copy = dc_strdup_keep_null(str_a);
|
||||
assert_eq!(
|
||||
CStr::from_ptr(str_a_copy),
|
||||
CString::new("foobar").unwrap().as_c_str()
|
||||
);
|
||||
assert_ne!(str_a, str_a_copy);
|
||||
|
||||
let str_a = 0 as *const u8 as *const libc::c_char;
|
||||
let str_a_copy = dc_strdup_keep_null(str_a);
|
||||
assert_eq!(str_a.is_null(), true);
|
||||
assert_eq!(str_a_copy.is_null(), true);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_dc_ltrim() {
|
||||
unsafe {
|
||||
@@ -1647,7 +1677,7 @@ mod tests {
|
||||
fn test_dc_str_replace() {
|
||||
unsafe {
|
||||
let mut str: *mut libc::c_char = strdup(b"aaa\x00" as *const u8 as *const libc::c_char);
|
||||
let replacements: libc::c_int = dc_str_replace(
|
||||
dc_str_replace(
|
||||
&mut str,
|
||||
b"a\x00" as *const u8 as *const libc::c_char,
|
||||
b"ab\x00" as *const u8 as *const libc::c_char,
|
||||
@@ -1656,7 +1686,6 @@ mod tests {
|
||||
CStr::from_ptr(str as *const libc::c_char).to_str().unwrap(),
|
||||
"ababab"
|
||||
);
|
||||
assert_eq!(replacements, 3);
|
||||
free(str as *mut libc::c_void);
|
||||
}
|
||||
}
|
||||
@@ -2085,5 +2114,4 @@ mod tests {
|
||||
let grpid = dc_extract_grpid_from_rfc724_mid(mid);
|
||||
assert_eq!(grpid, Some("1234567890123456"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -166,7 +166,6 @@ impl<'a> Peerstate<'a> {
|
||||
|
||||
pub fn from_addr(context: &'a Context, _sql: &Sql, addr: &str) -> Option<Self> {
|
||||
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, &[addr])
|
||||
}
|
||||
|
||||
@@ -191,6 +190,11 @@ impl<'a> Peerstate<'a> {
|
||||
context
|
||||
.sql
|
||||
.query_row(query, params, |row| {
|
||||
/* all the above queries start with this: 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
|
||||
*/
|
||||
let mut res = Self::new(context);
|
||||
|
||||
res.addr = Some(row.get(0)?);
|
||||
@@ -198,13 +202,34 @@ impl<'a> Peerstate<'a> {
|
||||
res.last_seen_autocrypt = row.get(2)?;
|
||||
res.prefer_encrypt = EncryptPreference::from_i32(row.get(3)?).unwrap_or_default();
|
||||
res.gossip_timestamp = row.get(5)?;
|
||||
let pkf: String = row.get(7)?;
|
||||
res.public_key_fingerprint = if pkf.is_empty() { None } else { Some(pkf) };
|
||||
let gkf: String = row.get(8)?;
|
||||
res.gossip_key_fingerprint = if gkf.is_empty() { None } else { Some(gkf) };
|
||||
let vkf: String = row.get(10)?;
|
||||
res.verified_key_fingerprint = if vkf.is_empty() { None } else { Some(vkf) };
|
||||
|
||||
res.public_key_fingerprint = row.get(7)?;
|
||||
if res
|
||||
.public_key_fingerprint
|
||||
.as_ref()
|
||||
.map(|s| s.is_empty())
|
||||
.unwrap_or_default()
|
||||
{
|
||||
res.public_key_fingerprint = None;
|
||||
}
|
||||
res.gossip_key_fingerprint = row.get(8)?;
|
||||
if res
|
||||
.gossip_key_fingerprint
|
||||
.as_ref()
|
||||
.map(|s| s.is_empty())
|
||||
.unwrap_or_default()
|
||||
{
|
||||
res.gossip_key_fingerprint = None;
|
||||
}
|
||||
res.verified_key_fingerprint = row.get(10)?;
|
||||
if res
|
||||
.verified_key_fingerprint
|
||||
.as_ref()
|
||||
.map(|s| s.is_empty())
|
||||
.unwrap_or_default()
|
||||
{
|
||||
res.verified_key_fingerprint = None;
|
||||
}
|
||||
res.public_key = row
|
||||
.get(4)
|
||||
.ok()
|
||||
@@ -217,7 +242,8 @@ impl<'a> Peerstate<'a> {
|
||||
.get(9)
|
||||
.ok()
|
||||
.and_then(|blob: Vec<u8>| Key::from_slice(&blob, KeyType::Public));
|
||||
res.verified_key = if vk == res.gossip_key {
|
||||
|
||||
res.verified_key = if vk == res.gossip_key && res.gossip_key.is_some() {
|
||||
VerifiedKey::Gossip
|
||||
} else if vk == res.public_key {
|
||||
VerifiedKey::Public
|
||||
@@ -422,6 +448,7 @@ impl<'a> Peerstate<'a> {
|
||||
&self.addr,
|
||||
],
|
||||
).is_ok();
|
||||
assert_eq!(success, true);
|
||||
} else if self.to_save == Some(ToSave::Timestamps) {
|
||||
success = sql::execute(
|
||||
self.context,
|
||||
@@ -498,6 +525,40 @@ mod tests {
|
||||
assert_eq!(peerstate, peerstate_new);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_peerstate_with_empty_gossip_key_save_to_db() {
|
||||
let ctx = crate::test_utils::dummy_context();
|
||||
let addr = "hello@mail.com";
|
||||
|
||||
let pub_key = crate::key::Key::from_base64("xsBNBFztUVkBCADYaQl/UOUpRPd32nLRzx8eU0eI+jQEnG+g5anjYA+3oct1rROGl5SygjMULDKdaUy27O3o9Srsti0YjA7uxZnavIqhSopJhFidqY1M1wA9JZa/duucZdNwUGbjGIRsS/4Cjr5+3svscK24hVYub1dvDWXpwUTnj3K6xOEnJdoM+MhCqtSD5+zcJhFc9vyZm9ZTGWUxAhKh0iJTcCD8V6CQ3XZ2z9GruwzZT/FTFovWrz7m3TUI2OdSSHh0eZLRGEoxMCT/vzflAFGAr8ijCaRsEIfqP6FW8uQWnFTqkjxEUCZG6XkeFHB84aj5jqYG/1KCLjL5vEKwfl1tz/WnPhY7ABEBAAHNEDxoZWxsb0BtYWlsLmNvbT7CwIkEEAEIADMCGQEFAlztUVoCGwMECwkIBwYVCAkKCwIDFgIBFiEEgMjHGVbvLXe6ioRROg8oKCvye7gACgkQOg8oKCvye7ijAwf+PTsuawUax9cNPn1bN90H+g9qyHZJMEwKXtUnNaXJxPW3iB7ThhpCiCzsZwP7+l7ArS8tmLeNDw2bENtcf1XCv4wovP2fdXOP3QOUUFX/GdakcTwv7DzC7CO0grB1HtaPhGw/6UX2o2cx2i9xiUf4Givq2MfCbgAW5zloH6WXGPb6yLQYJXxqDIphr4+uZDb+bMAyWHN/DUkAjHrV8nnVki7PMHqzzZpwglalxMX8RGeiGZE39ALJKL/Og87DMFah87/yoxQWGoS7Wqv0XDcCPKoTCPrpk8pOe2KEsq/lz215nefHd4aRpfUX5YCYa8HPvvfPQbGF73uvyQw5w7qjis7ATQRc7VFZAQgAt8ONdnX6KEEQ5Jw6ilJ+LBtY44SP5t0I3eK+goKepgIiKhjGDa+Mntyi4jdhH+HO6kvK5SHMh2sPp4rRO/WKHJwWFySyM1OdyiywhyH0J9R5rBY4vPHsJjf6vSKJdWLWT+ho1fNet2IIC+jVCYli91MAMbRvk6EKVj1nCc+67giOahXEkHt6xxkeCGlOvbw8hxGj1A8+AC1BLms/OR3oc4JMi9O3kq6uG0z9tlUEerac9HVwcjoO1XLe+hJhoT5H+TbnGjPuhuURP3pFiIKHpbRYgUfdSAY0dTObO7t4I5y/drPOrCTnWrBUg2wXAECUhpRKow9/ai2YemLv9KqhhwARAQABwsB2BBgBCAAgBQJc7VFaAhsMFiEEgMjHGVbvLXe6ioRROg8oKCvye7gACgkQOg8oKCvye7jmyggAhs4QzCzIbT2OsAReBxkxtm0AI+g1HZ1KFKof5NDHfgv9C/Qu1I8mKEjlZzA4qFyPmLqntgwJ0RuFy6gLbljZBNCFO7vB478AhYtnWjuKZmA40HUPwcB1hEJ31c42akzfUbioY1TLLepngdsJg7Cm8O+rhI9+1WRA66haJDgFs793SVUDyJh8f9NX50l5zR87/bsV30CFSw0q4OSSy9VI/z+2g5khn1LnuuOrCfFnYIPYtJED1BfkXkosxGlgbzy79VvGmI9d23x4atDK7oBPCzIj+lP8sytJ0u3HOguXi9OgDitKy+Pt1r8gH8frdktMJr5Ts6DW+tIn2vR23KR8aA==", KeyType::Public).unwrap();
|
||||
|
||||
let mut peerstate = Peerstate {
|
||||
context: &ctx.ctx,
|
||||
addr: Some(addr.into()),
|
||||
last_seen: 10,
|
||||
last_seen_autocrypt: 11,
|
||||
prefer_encrypt: EncryptPreference::Mutual,
|
||||
public_key: Some(pub_key.clone()),
|
||||
public_key_fingerprint: Some(pub_key.fingerprint()),
|
||||
gossip_key: None,
|
||||
gossip_timestamp: 12,
|
||||
gossip_key_fingerprint: None,
|
||||
verified_key: VerifiedKey::None,
|
||||
verified_key_fingerprint: None,
|
||||
to_save: Some(ToSave::All),
|
||||
degrade_event: None,
|
||||
};
|
||||
|
||||
assert!(peerstate.save_to_db(&ctx.ctx.sql, true), "failed to save");
|
||||
|
||||
let peerstate_new = Peerstate::from_addr(&ctx.ctx, &ctx.ctx.sql, addr.into())
|
||||
.expect("failed to load peerstate from db");
|
||||
|
||||
// clear to_save, as that is not persissted
|
||||
peerstate.to_save = None;
|
||||
assert_eq!(peerstate, peerstate_new);
|
||||
}
|
||||
|
||||
// TODO: don't copy this from stress.rs
|
||||
#[allow(dead_code)]
|
||||
struct TestContext {
|
||||
|
||||
@@ -4,7 +4,6 @@ use std::sync::{Arc, RwLock};
|
||||
use rusqlite::{Connection, OpenFlags, Statement, NO_PARAMS};
|
||||
use thread_local_object::ThreadLocal;
|
||||
|
||||
use crate::constants::*;
|
||||
use crate::context::Context;
|
||||
use crate::dc_tools::*;
|
||||
use crate::error::{Error, Result};
|
||||
@@ -689,10 +688,6 @@ fn open(
|
||||
"ALTER TABLE msgs ADD COLUMN move_state INTEGER DEFAULT 1;",
|
||||
params![],
|
||||
)?;
|
||||
assert_eq!(DC_MOVE_STATE_UNDEFINED as libc::c_int, 0);
|
||||
assert_eq!(DC_MOVE_STATE_PENDING as libc::c_int, 1);
|
||||
assert_eq!(DC_MOVE_STATE_STAY as libc::c_int, 2);
|
||||
assert_eq!(DC_MOVE_STATE_MOVING as libc::c_int, 3);
|
||||
|
||||
dbversion = 48;
|
||||
sql.set_config_int(context, "dbversion", 48)?;
|
||||
@@ -1047,8 +1042,8 @@ pub fn housekeeping(context: &Context) {
|
||||
unreferenced_count,
|
||||
entry.file_name()
|
||||
);
|
||||
let path = entry.path().to_c_string().unwrap();
|
||||
dc_delete_file(context, path.as_ptr());
|
||||
let path = entry.path();
|
||||
dc_delete_file(context, path);
|
||||
}
|
||||
}
|
||||
Err(err) => {
|
||||
|
||||
@@ -2,9 +2,15 @@
|
||||
//!
|
||||
//! This module is only compiled for test runs.
|
||||
|
||||
use std::ffi::CStr;
|
||||
|
||||
use libc::uintptr_t;
|
||||
use tempfile::{tempdir, TempDir};
|
||||
|
||||
use crate::config::Config;
|
||||
use crate::constants::{Event, KeyType};
|
||||
use crate::context::{dc_context_new, dc_open, Context};
|
||||
use crate::key;
|
||||
use crate::types::dc_callback_t;
|
||||
|
||||
/// A Context and temporary directory.
|
||||
@@ -44,3 +50,127 @@ pub fn test_context(cb: Option<dc_callback_t>) -> TestContext {
|
||||
pub fn dummy_context() -> TestContext {
|
||||
test_context(None)
|
||||
}
|
||||
|
||||
pub unsafe extern "C" fn logging_cb(
|
||||
_ctx: &Context,
|
||||
evt: Event,
|
||||
_d1: uintptr_t,
|
||||
d2: uintptr_t,
|
||||
) -> uintptr_t {
|
||||
let to_str = |x| CStr::from_ptr(x as *const libc::c_char).to_str().unwrap();
|
||||
match evt {
|
||||
Event::INFO => println!("I: {}", to_str(d2)),
|
||||
Event::WARNING => println!("W: {}", to_str(d2)),
|
||||
Event::ERROR => println!("E: {}", to_str(d2)),
|
||||
_ => (),
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
/// Creates Alice with a pre-generated keypair.
|
||||
///
|
||||
/// Returns the address of the keypair created (alice@example.org).
|
||||
pub fn configure_alice_keypair(ctx: &Context) -> String {
|
||||
let addr = String::from("alice@example.org");
|
||||
ctx.set_config(Config::ConfiguredAddr, Some(&addr)).unwrap();
|
||||
|
||||
// The keypair was created using:
|
||||
// let (public, private) = crate::pgp::dc_pgp_create_keypair("alice@example.com")
|
||||
// .unwrap();
|
||||
// println!("{}", public.to_base64(64));
|
||||
// println!("{}", private.to_base64(64));
|
||||
let public = key::Key::from_base64(
|
||||
concat!(
|
||||
"xsBNBF086ewBCACmJKuoxIO6T87yi4Q3MyNpMch3Y8KrtHDQyUszU36eqM3Pmd1l",
|
||||
"FrbcCd8ZWo2pq6OJSwsM/jjRGn1zo2YOaQeJRRrC+KrKGqSUtRSYQBPrPjE2YjSX",
|
||||
"AMbu8jBI6VVUhHeghriBkK79PY9O/oRhIJC0p14IJe6CQ6OI2fTmTUHF9i/nJ3G4",
|
||||
"Wb3/K1bU3yVfyPZjTZQPYPvvh03vxHULKurtYkX5DTEMSWsF4qzLMps+l87VuLV9",
|
||||
"iQnbN7YMRLHHx2KkX5Ivi7JCefhCa54M0K3bDCCxuVWAM5wjQwNZjzR+WL+dYchw",
|
||||
"oFvuF8NrlzjM9dSv+2rn+J7f99ijSXarzPC7ABEBAAHNEzxhbGljZUBleGFtcGxl",
|
||||
"LmNvbT7CwIkEEAEIADMCGQEFAl086fgCGwMECwkIBwYVCAkKCwIDFgIBFiEE+iai",
|
||||
"x4d0doj87Q0ek6DcNkbrcegACgkQk6DcNkbrcei3ogf/cruUmQ+th52TFHTHdkw9",
|
||||
"OHUl3MrXtZ7QmHyOAFvbXE/6n5Eeh+eZoF8MWWV72m14Wbs+vTcNQkFVTdOPptkK",
|
||||
"A8e4cJqwDOHsyAnvQXZ7WNje9+BMzcoipIUawHP4ORFaPDsKLZQ0b4wBbKn8ziea",
|
||||
"6zjGF0/qljTdoxTtsYpv5wXYuhwbYklrLOqgSa5M7LXUe7E3g9mbg+9iX1GuB8m6",
|
||||
"GkquJN814Y+xny4xhZzGOfue6SeP12jJMNSjSP7416dRq7794VGnkkW9V/7oFEUK",
|
||||
"u5wO9FFbgDySOSlEjByGejSGuBmho0iJSjcPjZ7EY/j3M3orq4dpza5C82OeSvxD",
|
||||
"Fc7ATQRdPOnsAQgA5oLxXRLnyugzOmNCy7dxV3JrDZscA6JNlJlDWIShT0YSs+zG",
|
||||
"9JzDeQql+sYXgUSxOoIayItuXtnFn7tstwGoOnYvadm/e5/7V5fKAQRtCtdN51av",
|
||||
"62n18Venlm0yNKpROPcZ6M/sc4m6uU6YRZ/a1idal8VGY0wLKlghjIBuIiBoVQ/R",
|
||||
"noW+/fhmwIg08dQ5m8hQe3GEOZEeLrTWL/9awPlXK7Y+DmJOoR4qbHWEcRfbzS6q",
|
||||
"4zW8vk2ztB8ngwbnqYy8zrN1DCICN1gYdlU++uVw6Bb1XfY8Cdldh1VLKpF35mAm",
|
||||
"jxLZfVDcoObFH3Cv2GB7BEYxv86KC2Y6T74Q/wARAQABwsB2BBgBCAAgBQJdPOn4",
|
||||
"AhsMFiEE+iaix4d0doj87Q0ek6DcNkbrcegACgkQk6DcNkbrcegLxwf/dXshJnoW",
|
||||
"qEnRsf6rVb9/Mc66ti+NVQLfNd275dybh/QIJdK3NmSxdnTPIEJRVspJywJoupwX",
|
||||
"FNrnHG2Ff6QPvHqI+/oNu986r9d7Z1oQibbLHKt8t6kpOfg/xGxotagJuiCQvR9m",
|
||||
"MjD1DqsdB37SjDxGupZOOJSXWi6KX60IE+uM+QOBfeOZziQwuFmA5wV6RDXIeYJf",
|
||||
"qrcbeXeR1d0nfNpPHQR1gBiqmxNb6KBbdXD2+EXW60axC7D2b1APmzMlammDliPw",
|
||||
"sK9U1rc9nuquEBvGDOJf4K+Dzn+mDCqRpP6uAuQ7RKHyim4uyN0wwKObzPqgJCGw",
|
||||
"jTglkixw+aSTXw=="
|
||||
),
|
||||
KeyType::Public,
|
||||
)
|
||||
.unwrap();
|
||||
let private = key::Key::from_base64(
|
||||
concat!(
|
||||
"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",
|
||||
"zPqgJCGwjTglkixw+aSTXw=="
|
||||
),
|
||||
KeyType::Private,
|
||||
)
|
||||
.unwrap();
|
||||
let saved = key::dc_key_save_self_keypair(&ctx, &public, &private, &addr, 1, &ctx.sql);
|
||||
assert_eq!(saved, true, "Failed to save Alice's key");
|
||||
addr
|
||||
}
|
||||
|
||||
@@ -16,8 +16,6 @@ pub use rusqlite::ffi::*;
|
||||
pub type dc_callback_t =
|
||||
unsafe extern "C" fn(_: &Context, _: Event, _: uintptr_t, _: uintptr_t) -> uintptr_t;
|
||||
|
||||
pub type dc_move_state_t = u32;
|
||||
|
||||
pub type dc_receive_imf_t = unsafe fn(
|
||||
_: &Context,
|
||||
_: *const libc::c_char,
|
||||
|
||||
148
tests/stress.rs
148
tests/stress.rs
@@ -10,7 +10,6 @@ use deltachat::config;
|
||||
use deltachat::constants::*;
|
||||
use deltachat::contact::*;
|
||||
use deltachat::context::*;
|
||||
use deltachat::dc_array::*;
|
||||
use deltachat::dc_chat::*;
|
||||
use deltachat::dc_configure::*;
|
||||
use deltachat::dc_imex::*;
|
||||
@@ -57,39 +56,15 @@ unsafe fn stress_functions(context: &Context) {
|
||||
);
|
||||
|
||||
if 0 != dc_is_open(context) {
|
||||
if 0 != dc_file_exist(
|
||||
context,
|
||||
b"$BLOBDIR/foobar\x00" as *const u8 as *const libc::c_char,
|
||||
) || 0
|
||||
!= dc_file_exist(
|
||||
context,
|
||||
b"$BLOBDIR/dada\x00" as *const u8 as *const libc::c_char,
|
||||
)
|
||||
|| 0 != dc_file_exist(
|
||||
context,
|
||||
b"$BLOBDIR/foobar.dadada\x00" as *const u8 as *const libc::c_char,
|
||||
)
|
||||
|| 0 != dc_file_exist(
|
||||
context,
|
||||
b"$BLOBDIR/foobar-folder\x00" as *const u8 as *const libc::c_char,
|
||||
)
|
||||
if dc_file_exist(context, "$BLOBDIR/foobar")
|
||||
|| dc_file_exist(context, "$BLOBDIR/dada")
|
||||
|| dc_file_exist(context, "$BLOBDIR/foobar.dadada")
|
||||
|| dc_file_exist(context, "$BLOBDIR/foobar-folder")
|
||||
{
|
||||
dc_delete_file(
|
||||
context,
|
||||
b"$BLOBDIR/foobar\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
dc_delete_file(
|
||||
context,
|
||||
b"$BLOBDIR/dada\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
dc_delete_file(
|
||||
context,
|
||||
b"$BLOBDIR/foobar.dadada\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
dc_delete_file(
|
||||
context,
|
||||
b"$BLOBDIR/foobar-folder\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
dc_delete_file(context, "$BLOBDIR/foobar");
|
||||
dc_delete_file(context, "$BLOBDIR/dada");
|
||||
dc_delete_file(context, "$BLOBDIR/foobar.dadada");
|
||||
dc_delete_file(context, "$BLOBDIR/foobar-folder");
|
||||
}
|
||||
dc_write_file(
|
||||
context,
|
||||
@@ -97,25 +72,10 @@ unsafe fn stress_functions(context: &Context) {
|
||||
b"content\x00" as *const u8 as *const libc::c_char as *const libc::c_void,
|
||||
7i32 as size_t,
|
||||
);
|
||||
assert_ne!(
|
||||
0,
|
||||
dc_file_exist(
|
||||
context,
|
||||
b"$BLOBDIR/foobar\x00" as *const u8 as *const libc::c_char,
|
||||
)
|
||||
);
|
||||
assert!(dc_file_exist(context, "$BLOBDIR/foobar",));
|
||||
assert!(!dc_file_exist(context, "$BLOBDIR/foobarx"));
|
||||
assert_eq!(
|
||||
0,
|
||||
dc_file_exist(
|
||||
context,
|
||||
b"$BLOBDIR/foobarx\x00" as *const u8 as *const libc::c_char,
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
dc_get_filebytes(
|
||||
context,
|
||||
b"$BLOBDIR/foobar\x00" as *const u8 as *const libc::c_char,
|
||||
),
|
||||
dc_get_filebytes(context, "$BLOBDIR/foobar",),
|
||||
7i32 as libc::c_ulonglong
|
||||
);
|
||||
|
||||
@@ -133,23 +93,10 @@ unsafe fn stress_functions(context: &Context) {
|
||||
context,
|
||||
b"/BLOBDIR/fofo\x00" as *const u8 as *const libc::c_char,
|
||||
));
|
||||
assert_ne!(0, dc_file_exist(context, abs_path));
|
||||
assert!(dc_file_exist(context, as_path(abs_path)));
|
||||
free(abs_path as *mut libc::c_void);
|
||||
assert_ne!(
|
||||
0,
|
||||
dc_copy_file(
|
||||
context,
|
||||
b"$BLOBDIR/foobar\x00" as *const u8 as *const libc::c_char,
|
||||
b"$BLOBDIR/dada\x00" as *const u8 as *const libc::c_char,
|
||||
)
|
||||
);
|
||||
assert_eq!(
|
||||
dc_get_filebytes(
|
||||
context,
|
||||
b"$BLOBDIR/dada\x00" as *const u8 as *const libc::c_char,
|
||||
),
|
||||
7
|
||||
);
|
||||
assert!(dc_copy_file(context, "$BLOBDIR/foobar", "$BLOBDIR/dada",));
|
||||
assert_eq!(dc_get_filebytes(context, "$BLOBDIR/dada",), 7);
|
||||
|
||||
let mut buf: *mut libc::c_void = 0 as *mut libc::c_void;
|
||||
let mut buf_bytes: size_t = 0;
|
||||
@@ -170,41 +117,11 @@ unsafe fn stress_functions(context: &Context) {
|
||||
);
|
||||
|
||||
free(buf as *mut _);
|
||||
assert_ne!(
|
||||
0,
|
||||
dc_delete_file(
|
||||
context,
|
||||
b"$BLOBDIR/foobar\x00" as *const u8 as *const libc::c_char,
|
||||
)
|
||||
);
|
||||
assert_ne!(
|
||||
0,
|
||||
dc_delete_file(
|
||||
context,
|
||||
b"$BLOBDIR/dada\x00" as *const u8 as *const libc::c_char,
|
||||
)
|
||||
);
|
||||
assert_ne!(
|
||||
0,
|
||||
dc_create_folder(
|
||||
context,
|
||||
b"$BLOBDIR/foobar-folder\x00" as *const u8 as *const libc::c_char,
|
||||
)
|
||||
);
|
||||
assert_ne!(
|
||||
0,
|
||||
dc_file_exist(
|
||||
context,
|
||||
b"$BLOBDIR/foobar-folder\x00" as *const u8 as *const libc::c_char,
|
||||
)
|
||||
);
|
||||
assert_ne!(
|
||||
0,
|
||||
dc_delete_file(
|
||||
context,
|
||||
b"$BLOBDIR/foobar-folder\x00" as *const u8 as *const libc::c_char,
|
||||
)
|
||||
);
|
||||
assert!(dc_delete_file(context, "$BLOBDIR/foobar"));
|
||||
assert!(dc_delete_file(context, "$BLOBDIR/dada"));
|
||||
assert!(dc_create_folder(context, "$BLOBDIR/foobar-folder"));
|
||||
assert!(dc_file_exist(context, "$BLOBDIR/foobar-folder",));
|
||||
assert!(dc_delete_file(context, "$BLOBDIR/foobar-folder"));
|
||||
let fn0: *mut libc::c_char = dc_get_fine_pathNfilename(
|
||||
context,
|
||||
b"$BLOBDIR\x00" as *const u8 as *const libc::c_char,
|
||||
@@ -237,7 +154,7 @@ unsafe fn stress_functions(context: &Context) {
|
||||
),
|
||||
0
|
||||
);
|
||||
assert_ne!(0, dc_delete_file(context, fn0));
|
||||
assert!(dc_delete_file(context, as_path(fn0)));
|
||||
free(fn0 as *mut libc::c_void);
|
||||
free(fn1 as *mut libc::c_void);
|
||||
}
|
||||
@@ -825,22 +742,14 @@ fn test_dc_mimeparser_with_context() {
|
||||
"inner-subject",
|
||||
);
|
||||
|
||||
let mut of: *mut mailimf_optional_field = dc_mimeparser_lookup_optional_field(
|
||||
&mimeparser,
|
||||
b"X-Special-A\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
let mut of: *mut mailimf_optional_field =
|
||||
dc_mimeparser_lookup_optional_field(&mimeparser, "X-Special-A");
|
||||
assert_eq!(as_str((*of).fld_value as *const libc::c_char), "special-a",);
|
||||
|
||||
of = dc_mimeparser_lookup_optional_field(
|
||||
&mimeparser,
|
||||
b"Foo\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
of = dc_mimeparser_lookup_optional_field(&mimeparser, "Foo");
|
||||
assert_eq!(as_str((*of).fld_value as *const libc::c_char), "Bar",);
|
||||
|
||||
of = dc_mimeparser_lookup_optional_field(
|
||||
&mimeparser,
|
||||
b"Chat-Version\x00" as *const u8 as *const libc::c_char,
|
||||
);
|
||||
of = dc_mimeparser_lookup_optional_field(&mimeparser, "Chat-Version");
|
||||
assert_eq!(as_str((*of).fld_value as *const libc::c_char), "1.0",);
|
||||
assert_eq!(mimeparser.parts.len(), 1);
|
||||
|
||||
@@ -891,19 +800,16 @@ fn test_get_contacts() {
|
||||
unsafe {
|
||||
let context = create_test_context();
|
||||
let contacts = Contact::get_all(&context.ctx, 0, Some("some2")).unwrap();
|
||||
assert_eq!(dc_array_get_cnt(contacts), 0);
|
||||
dc_array_unref(contacts);
|
||||
assert_eq!(contacts.len(), 0);
|
||||
|
||||
let id = Contact::create(&context.ctx, "bob", "bob@mail.de").unwrap();
|
||||
assert_ne!(id, 0);
|
||||
|
||||
let contacts = Contact::get_all(&context.ctx, 0, Some("bob")).unwrap();
|
||||
assert_eq!(dc_array_get_cnt(contacts), 1);
|
||||
dc_array_unref(contacts);
|
||||
assert_eq!(contacts.len(), 1);
|
||||
|
||||
let contacts = Contact::get_all(&context.ctx, 0, Some("alice")).unwrap();
|
||||
assert_eq!(dc_array_get_cnt(contacts), 0);
|
||||
dc_array_unref(contacts);
|
||||
assert_eq!(contacts.len(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user