Compare commits

..

4 Commits

43 changed files with 3689 additions and 3331 deletions

9
Cargo.lock generated
View File

@@ -467,7 +467,6 @@ 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)",
@@ -502,14 +501,6 @@ 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"

View File

@@ -10,7 +10,6 @@ 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"
@@ -54,8 +53,7 @@ pretty_env_logger = "0.3.0"
[workspace]
members = [
"deltachat-ffi",
"deltachat_derive",
"deltachat-ffi"
]
[[example]]

View File

@@ -89,14 +89,6 @@ $ 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.

View File

@@ -16,7 +16,7 @@ export BRANCH=${CIRCLE_BRANCH:-test7}
#fi
# run everything else inside docker (TESTS, DOCS, WHEELS)
docker run -e DCC_PY_LIVECONFIG -e BRANCH -e TESTS -e DOCS \
docker run -e BRANCH -e TESTS -e DOCS \
--rm -it -v $(pwd):/mnt -w /mnt \
deltachat/coredeps ci_scripts/run_all.sh

View File

@@ -15,7 +15,6 @@ 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/" \
@@ -38,13 +37,11 @@ pip install devpi-client
devpi use https://m.devpi.net
devpi login dc --password $DEVPI_LOGIN
N_BRANCH=${BRANCH//[\/]}
devpi use dc/$N_BRANCH || {
devpi index -c $N_BRANCH
devpi use dc/$N_BRANCH
devpi use dc/$BRANCH || {
devpi index -c $BRANCH
devpi use dc/$BRANCH
}
devpi index $N_BRANCH bases=/root/pypi
devpi index $BRANCH bases=/root/pypi
devpi upload deltachat*.whl
popd

View File

@@ -3,9 +3,9 @@
set -e -x
# Install Rust
curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain nightly-2019-07-10 -y
curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain nightly-2019-04-19 -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-07-10-x86_64-unknown-linux-gnu/share/
rm -rf /root/.rustup/toolchains/nightly-2019-04-19-x86_64-unknown-linux-gnu/share/

View File

@@ -37,10 +37,6 @@ 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

View File

@@ -44,14 +44,11 @@ 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_close(context);
context::dc_context_unref(context);
Box::from_raw(context);
}
@@ -545,7 +542,7 @@ pub unsafe extern "C" fn dc_get_chat_contacts(
assert!(!context.is_null());
let context = &*context;
dc_array_t::from(dc_chat::dc_get_chat_contacts(context, chat_id)).into_raw()
dc_chat::dc_get_chat_contacts(context, chat_id)
}
#[no_mangle]
@@ -817,7 +814,7 @@ pub unsafe extern "C" fn dc_get_contacts(
};
match Contact::get_all(context, flags, query) {
Ok(contacts) => dc_array_t::from(contacts).into_raw(),
Ok(contacts) => contacts,
Err(_) => std::ptr::null_mut(),
}
}
@@ -864,12 +861,7 @@ pub unsafe extern "C" fn dc_get_contact_encrinfo(
assert!(!context.is_null());
let context = &*context;
Contact::get_encrinfo(context, contact_id)
.map(|s| s.strdup())
.unwrap_or_else(|e| {
error!(context, 0, "{}", e);
std::ptr::null_mut()
})
Contact::get_encrinfo(context, contact_id).strdup()
}
#[no_mangle]

View File

@@ -1,12 +0,0 @@
[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"

View File

@@ -1,45 +0,0 @@
#![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()
}

View File

@@ -125,7 +125,7 @@ unsafe fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int
return 0;
}
let ok_to_continue;
let mut current_block: u64;
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,71 +138,77 @@ 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();
ok_to_continue = true;
current_block = 7149356873433890176;
} else {
let rs = context.sql.get_config(context, "import_spec");
if rs.is_none() {
error!(context, 0, "Import: No file or folder given.");
ok_to_continue = false;
current_block = 8522321847195001863;
} else {
ok_to_continue = true;
current_block = 7149356873433890176;
}
real_spec = rs.unwrap_or_default().strdup();
}
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;
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;
} 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
/* 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
}
}
}
current_block = 1622411330066726685;
}
ok_to_continue2 = true;
}
}
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);
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
}
}
success = 1
}
}
@@ -295,12 +301,13 @@ unsafe fn log_msglist(context: &Context, msglist: *mut dc_array_t) {
}
}
unsafe fn log_contactlist(context: &Context, contacts: &Vec<u32>) {
let mut contacts = contacts.clone();
if !contacts.contains(&1) {
contacts.push(1);
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);
}
for contact_id in contacts {
let cnt = dc_array_get_cnt(contacts);
for i in 0..cnt {
let contact_id = dc_array_get_id(contacts, i as size_t);
let line;
let mut line2 = "".to_string();
if let Ok(contact) = Contact::get_by_id(context, contact_id) {
@@ -464,7 +471,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 or quit\n\
exit\n\
============================================="
),
},
@@ -597,13 +604,9 @@ 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,
if arg1.is_empty() { None } else { Some(arg1) },
None,
)?;
let chatlist = Chatlist::try_load(context, listflags, Some(arg1), None)?;
let mut i: usize;
let cnt = chatlist.len();
if cnt > 0 {
info!(
@@ -611,7 +614,9 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
"================================================================================"
);
for i in (0..cnt).rev() {
i = cnt - 1;
while i > 0 {
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);
@@ -665,6 +670,8 @@ 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) {
@@ -828,14 +835,16 @@ 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: {}",
contacts.len(),
dc_array_get_cnt(contacts),
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();
@@ -1055,8 +1064,13 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
},
Some(arg1),
)?;
log_contactlist(context, &contacts);
println!("{} contacts.", contacts.len());
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!("");
}
}
"addcontact" => {
ensure!(!arg1.is_empty(), "Arguments [<name>] <addr> expected.");
@@ -1077,7 +1091,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();

View File

@@ -335,8 +335,8 @@ const CONTACT_COMMANDS: [&'static str; 6] = [
"delcontact",
"cleanupcontacts",
];
const MISC_COMMANDS: [&'static str; 9] = [
"getqr", "getbadqr", "checkqr", "event", "fileinfo", "clear", "exit", "quit", "help",
const MISC_COMMANDS: [&'static str; 8] = [
"getqr", "getbadqr", "checkqr", "event", "fileinfo", "clear", "exit", "help",
];
impl Hinter for DcHelper {
@@ -456,6 +456,12 @@ 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(())
@@ -550,7 +556,7 @@ unsafe fn handle_cmd(line: &str, ctx: Arc<RwLock<Context>>) -> Result<ExitResult
dc_join_securejoin(&ctx.read().unwrap(), arg1_c);
}
}
"exit" | "quit" => return Ok(ExitResult::Exit),
"exit" => return Ok(ExitResult::Exit),
_ => dc_cmdline(&ctx.read().unwrap(), line)?,
}

View File

@@ -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 venv # or: python -m venv
virtualenv -p python3 venv
source venv/bin/activate
Afterwards, invoking ``python`` or ``pip install`` will only
@@ -39,12 +39,6 @@ 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
===============================
@@ -54,55 +48,34 @@ 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 .
If you don't have one active, create and activate a python "virtualenv":
Now test if the bindings find the correct library::
python virtualenv venv # or python -m venv
source venv/bin/activate
python -c 'import deltachat ; print(deltachat.__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
This should print your deltachat bindings version.
.. note::
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
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>`_.
Using a system-installed deltachat-core-rust
--------------------------------------------
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.
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``).
Code examples
@@ -111,34 +84,68 @@ 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/coredeps`` tag so
We publish a build environment under the ``deltachat/wheel`` tag so
that you can pull it from the ``hub.docker.com`` site's "deltachat"
organization::
$ docker pull deltachat/coredeps
$ docker pull deltachat/wheel
This docker image can be used to run tests and build Python wheels for all interpreters::
The ``deltachat/wheel`` image can be used to build both libdeltachat.so
and the Python wheels::
$ bash ci_scripts/ci_run.sh
$ docker run --rm -it -v $(pwd):/io/ deltachat/wheel /io/python/wheelbuilder/build-wheels.sh
This command runs tests and build-wheel scripts in a docker container.
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``.
Optionally build your own docker image
@@ -147,10 +154,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/coredeps ci_scripts/docker_coredeps
$ docker build -t deltachat/wheel python/wheelbuilder/
This will use the ``ci_scripts/docker_coredeps/Dockerfile`` to build
up docker image called ``deltachat/coredeps``. You can afterwards
This will use the ``python/wheelbuilder/Dockerfile`` to build
up docker image called ``deltachat/wheel``. You can afterwards
find it with::
$ docker images

View File

@@ -6,18 +6,29 @@
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
os.environ["RUSTFLAGS"] = "-g"
subprocess.check_call([
"cargo", "build", "-p", "deltachat_ffi", "--" + target
])
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")
subprocess.check_call("rm -rf build/ src/deltachat/*.so" , shell=True)
subprocess.check_call([

View File

@@ -6,15 +6,10 @@ 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':

View File

@@ -50,9 +50,8 @@ class Account(object):
self._configkeys = self.get_config("sys.config_keys").split()
self._imex_completed = threading.Event()
# XXX this can cause "illegal instructions" at test ends so we omit it for now
# def __del__(self):
# self.shutdown()
def __del__(self):
self.shutdown()
def _check_config_key(self, name):
if name not in self._configkeys:

View File

@@ -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,8 +36,6 @@ def pytest_runtest_call(item):
def pytest_report_header(config, startdir):
summary = []
t = tempfile.mktemp()
try:
ac = Account(t, eventlogging=False)
@@ -45,18 +43,13 @@ def pytest_report_header(config, startdir):
ac.shutdown()
finally:
os.remove(t)
summary.extend(['Deltachat core={} sqlite={}'.format(
summary = ['Deltachat core={} sqlite={}'.format(
info['deltachat_core_version'],
info['sqlite_version'],
)])
cfg = config.option.liveconfig
)]
cfg = config.getoption('--liveconfig')
if cfg:
if "#" in cfg:
url, token = cfg.split("#", 1)
summary.append('Liveconfig provider: {}#<token ommitted>'.format(url))
else:
summary.append('Liveconfig file: {}'.format(cfg))
summary.append('Liveconfig: {}'.format(os.path.abspath(cfg)))
return summary
@@ -73,56 +66,9 @@ 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, session_liveconfig):
def acfactory(pytestconfig, tmpdir, request):
fn = pytestconfig.getoption("--liveconfig")
class AccountMaker:
def __init__(self):
@@ -136,6 +82,18 @@ def acfactory(pytestconfig, tmpdir, request, session_liveconfig):
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)
@@ -158,12 +116,10 @@ def acfactory(pytestconfig, tmpdir, request, session_liveconfig):
return ac
def get_online_configuring_account(self):
if not session_liveconfig:
pytest.skip("specify DCC_PY_LIVECONFIG or --liveconfig")
configdict = session_liveconfig.get(self.live_count)
if not fn:
pytest.skip("specify a --liveconfig file to run tests with real accounts")
self.live_count += 1
if "e2ee_enabled" not in configdict:
configdict["e2ee_enabled"] = "1"
configdict = self.configlist.pop(0)
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

View File

@@ -427,37 +427,6 @@ 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()

View File

@@ -19,7 +19,6 @@ deps =
pytest
pytest-faulthandler
pdbpp
requests
[testenv:auditwheels]
skipsdist = True
@@ -52,7 +51,6 @@ commands =
[pytest]
addopts = -v -rs
python_files = tests/test_*.py
norecursedirs = .tox
xfail_strict=true

View File

@@ -23,7 +23,7 @@ if [ $? != 0 ]; then
fi
pushd python
if [ -e "./liveconfig" && -z "$DCC_PY_LIVECONFIG" ]; then
if [ -e "./liveconfig" ]; then
export DCC_PY_LIVECONFIG=liveconfig
fi
tox "$@"

View File

@@ -1,35 +1,15 @@
//! Constants
#![allow(non_camel_case_types)]
use deltachat_derive::*;
use num_traits::{FromPrimitive, ToPrimitive};
use rusqlite as sql;
use rusqlite::types::*;
pub const DC_VERSION_STR: &'static [u8; 14] = b"1.0.0-alpha.3\x00";
#[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_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;
pub const DC_GCL_ARCHIVED_ONLY: usize = 0x01;
pub const DC_GCL_NO_SPECIALS: usize = 0x02;
@@ -167,7 +147,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, FromSql, ToSql)]
#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)]
#[repr(i32)]
pub enum Viewtype {
Unknown = 0,
@@ -222,6 +202,23 @@ 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,

View File

@@ -472,13 +472,13 @@ impl<'a> Contact<'a> {
context: &Context,
listflags: u32,
query: Option<impl AsRef<str>>,
) -> Result<Vec<u32>> {
) -> Result<*mut dc_array_t> {
let self_addr = context
.get_config(Config::ConfiguredAddr)
.unwrap_or_default();
let mut add_self = false;
let mut ret = Vec::new();
let mut ret = dc_array_t::new(100);
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.push(id? as u32);
ret.add_id(id? as u32);
}
Ok(())
},
@@ -537,7 +537,7 @@ impl<'a> Contact<'a> {
|row| row.get::<_, i32>(0),
|ids| {
for id in ids {
ret.push(id? as u32);
ret.add_id(id? as u32);
}
Ok(())
}
@@ -545,10 +545,10 @@ impl<'a> Contact<'a> {
}
if 0 != listflags & DC_GCL_ADD_SELF as u32 && add_self {
ret.push(DC_CONTACT_ID_SELF as u32);
ret.add_id(DC_CONTACT_ID_SELF as u32);
}
Ok(ret)
Ok(ret.into_raw())
}
pub fn get_blocked_cnt(context: &Context) -> usize {
@@ -572,24 +572,19 @@ impl<'a> Contact<'a> {
params![DC_CONTACT_ID_LAST_SPECIAL as i32],
|row| row.get::<_, i32>(0),
|ids| {
let mut ret = Vec::new();
let mut ret = dc_array_t::new(100);
for id in ids {
ret.push(id? as u32);
ret.add_id(id? as u32);
}
Ok(dc_array_t::from(ret).into_raw())
Ok(ret.into_raw())
},
)
.unwrap_or_else(|_| std::ptr::null_mut())
}
/// 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> {
pub fn get_encrinfo(context: &Context, contact_id: u32) -> String {
let mut ret = String::new();
if let Ok(contact) = Contact::load_from_db(context, contact_id) {
@@ -608,7 +603,7 @@ impl<'a> Contact<'a> {
});
ret += &p;
if self_key.is_none() {
dc_ensure_secret_key_exists(context)?;
unsafe { dc_ensure_secret_key_exists(context) };
self_key = Key::from_self_public(context, &loginparam.addr, &context.sql);
}
let p = context.stock_str(StockMessage::FingerPrints);
@@ -651,7 +646,7 @@ impl<'a> Contact<'a> {
}
}
Ok(ret)
ret
}
/// Delete a contact. The contact is deleted from the local device. It may happen that this is not

View File

@@ -20,6 +20,7 @@ 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>>,
@@ -39,8 +40,6 @@ 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 {}
@@ -78,14 +77,6 @@ impl Context {
}
}
impl Drop for Context {
fn drop(&mut self) {
unsafe {
dc_close(&self);
}
}
}
impl Default for RunningState {
fn default() -> Self {
RunningState {
@@ -171,7 +162,16 @@ pub fn dc_context_new(
))),
probe_imap_network: Arc::new(RwLock::new(false)),
perform_inbox_jobs_needed: Arc::new(RwLock::new(false)),
generating_key_mutex: Mutex::new(()),
}
}
#[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) };
}
}
@@ -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, MoveState::Stay);
dc_update_msg_move_state(context, rfc724_mid, DC_MOVE_STATE_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,6 +258,12 @@ 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);
@@ -309,9 +315,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";
dc_create_folder(context, &dir);
*context.blobdir.write().unwrap() = dir.strdup();
let dir = (dbfile.to_string() + "-blobs").strdup();
dc_create_folder(context, dir);
*context.blobdir.write().unwrap() = dir;
}
// Create/open sqlite database, this may already use the blobdir
let dbfile_path = std::path::Path::new(dbfile);
@@ -499,12 +505,13 @@ 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 = Vec::new();
let mut ret = dc_array_t::new(128);
for row in rows {
let id: u32 = row?;
ret.push(id);
let id = row?;
ret.add_id(id);
}
Ok(dc_array_t::from(ret).into_raw())
Ok(ret.into_raw())
},
)
.unwrap()
@@ -538,7 +545,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 = Vec::new();
let mut ret = dc_array_t::new(100);
let success = context
.sql
@@ -548,7 +555,7 @@ pub fn dc_search_msgs(
|row| row.get::<_, i32>(0),
|rows| {
for id in rows {
ret.push(id? as u32);
ret.add_id(id? as u32);
}
Ok(())
},
@@ -556,7 +563,7 @@ pub fn dc_search_msgs(
.is_ok();
if success {
return dc_array_t::from(ret).into_raw();
return ret.into_raw();
}
std::ptr::null_mut()
@@ -584,24 +591,3 @@ 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);
}
}

View File

@@ -147,12 +147,6 @@ 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)
@@ -160,18 +154,22 @@ impl From<Vec<dc_location>> for dc_array_t {
}
pub unsafe fn dc_array_unref(array: *mut dc_array_t) {
assert!(!array.is_null());
if array.is_null() {
return;
}
Box::from_raw(array);
}
pub unsafe fn dc_array_add_uint(array: *mut dc_array_t, item: uintptr_t) {
assert!(!array.is_null());
(*array).add_uint(item);
if !array.is_null() {
(*array).add_uint(item);
}
}
pub unsafe fn dc_array_add_id(array: *mut dc_array_t, item: uint32_t) {
assert!(!array.is_null());
(*array).add_id(item);
if !array.is_null() {
(*array).add_id(item);
}
}
pub unsafe fn dc_array_add_ptr(array: *mut dc_array_t, item: *mut libc::c_void) {
@@ -179,62 +177,97 @@ 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 {
assert!(!array.is_null());
(*array).len()
if array.is_null() {
0
} else {
(*array).len()
}
}
pub unsafe fn dc_array_get_uint(array: *const dc_array_t, index: size_t) -> uintptr_t {
assert!(!array.is_null());
(*array).get_uint(index)
if array.is_null() || index >= (*array).len() {
0
} else {
(*array).get_uint(index)
}
}
pub unsafe fn dc_array_get_id(array: *const dc_array_t, index: size_t) -> uint32_t {
assert!(!array.is_null());
(*array).get_id(index)
if array.is_null() || index >= (*array).len() {
0
} else {
(*array).get_id(index)
}
}
pub unsafe fn dc_array_get_ptr(array: *const dc_array_t, index: size_t) -> *mut libc::c_void {
assert!(!array.is_null());
(*array).get_ptr(index)
if array.is_null() || index >= (*array).len() {
std::ptr::null_mut()
} else {
(*array).get_ptr(index)
}
}
pub unsafe fn dc_array_get_latitude(array: *const dc_array_t, index: size_t) -> libc::c_double {
assert!(!array.is_null());
(*array).get_latitude(index)
if array.is_null() || index >= (*array).len() {
0.0
} else {
(*array).get_latitude(index)
}
}
pub unsafe fn dc_array_get_longitude(array: *const dc_array_t, index: size_t) -> libc::c_double {
assert!(!array.is_null());
(*array).get_longitude(index)
if array.is_null() || index >= (*array).len() {
0.0
} else {
(*array).get_longitude(index)
}
}
pub unsafe fn dc_array_get_accuracy(array: *const dc_array_t, index: size_t) -> libc::c_double {
assert!(!array.is_null());
(*array).get_accuracy(index)
if array.is_null() || index >= (*array).len() {
0.0
} else {
(*array).get_accuracy(index)
}
}
pub unsafe fn dc_array_get_timestamp(array: *const dc_array_t, index: size_t) -> i64 {
assert!(!array.is_null());
(*array).get_timestamp(index)
if array.is_null() || index >= (*array).len() {
0
} else {
(*array).get_timestamp(index)
}
}
pub unsafe fn dc_array_get_chat_id(array: *const dc_array_t, index: size_t) -> uint32_t {
assert!(!array.is_null());
(*array).get_chat_id(index)
if array.is_null() || index >= (*array).len() {
0
} else {
(*array).get_chat_id(index)
}
}
pub unsafe fn dc_array_get_contact_id(array: *const dc_array_t, index: size_t) -> uint32_t {
assert!(!array.is_null());
(*array).get_contact_id(index)
if array.is_null() || index >= (*array).len() {
0
} else {
(*array).get_contact_id(index)
}
}
pub unsafe fn dc_array_get_msg_id(array: *const dc_array_t, index: size_t) -> uint32_t {
assert!(!array.is_null());
(*array).get_msg_id(index)
if array.is_null() || index >= (*array).len() {
0
} else {
(*array).get_msg_id(index)
}
}
pub unsafe fn dc_array_get_marker(array: *const dc_array_t, index: size_t) -> *mut libc::c_char {
assert!(!array.is_null());
if array.is_null() || index >= (*array).len() {
return std::ptr::null_mut();
}
if let dc_array_t::Locations(v) = &*array {
if let Some(s) = &v[index].marker {
@@ -243,7 +276,7 @@ pub unsafe fn dc_array_get_marker(array: *const dc_array_t, index: size_t) -> *m
std::ptr::null_mut()
}
} else {
panic!("Not an array of locations");
std::ptr::null_mut()
}
}
@@ -258,7 +291,9 @@ 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 {
assert!(!array.is_null());
if array.is_null() || index >= (*array).len() {
return 0;
}
if let dc_array_t::Locations(v) = &*array {
v[index].independent as libc::c_int
@@ -272,8 +307,9 @@ pub unsafe fn dc_array_search_id(
needle: uint32_t,
ret_index: *mut size_t,
) -> bool {
assert!(!array.is_null());
if array.is_null() {
return false;
}
if let Some(i) = (*array).search_id(needle as uintptr_t) {
if !ret_index.is_null() {
*ret_index = i
@@ -285,8 +321,9 @@ pub unsafe fn dc_array_search_id(
}
pub unsafe fn dc_array_get_raw(array: *const dc_array_t) -> *const uintptr_t {
assert!(!array.is_null());
if array.is_null() {
return 0 as *const uintptr_t;
}
if let dc_array_t::Uint(v) = &*array {
v.as_ptr()
} else {
@@ -303,24 +340,27 @@ pub fn dc_array_new_locations(initsize: size_t) -> *mut dc_array_t {
}
pub unsafe fn dc_array_empty(array: *mut dc_array_t) {
assert!(!array.is_null());
if array.is_null() {
return;
}
(*array).clear()
}
pub unsafe fn dc_array_duplicate(array: *const dc_array_t) -> *mut dc_array_t {
assert!(!array.is_null());
(*array).clone().into_raw()
if array.is_null() {
std::ptr::null_mut()
} else {
(*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 {
assert!(!array.is_null());
assert!(!sep.is_null());
if array.is_null() || sep.is_null() {
return dc_strdup(b"\x00" as *const u8 as *const libc::c_char);
}
if let dc_array_t::Uint(v) = &*array {
let cnt = v.len();
let sep = as_str(sep);
@@ -366,6 +406,10 @@ 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);
@@ -394,14 +438,4 @@ 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) };
}
}

View File

@@ -24,6 +24,7 @@ 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,
@@ -64,6 +65,7 @@ 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(),
@@ -79,16 +81,17 @@ 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(chat: *mut Chat) {
if chat.is_null() {
pub unsafe fn dc_chat_unref(mut chat: *mut Chat) {
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
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() {
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
return;
}
free((*chat).name as *mut libc::c_void);
@@ -117,7 +120,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() {
if chat.is_null() || unsafe { (*chat).magic != 0xc4a7c4a7u32 } {
return false;
}
unsafe { dc_chat_empty(chat) };
@@ -807,7 +810,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() {
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
return 0;
}
(*chat).param.exists(Param::Selftalk) as libc::c_int
@@ -1069,7 +1072,7 @@ pub fn dc_get_chat_msgs(
flags: uint32_t,
marker1before: uint32_t,
) -> *mut dc_array_t {
let mut ret = Vec::new();
let mut ret = dc_array_t::new(512);
let mut last_day = 0;
let cnv_to_local = dc_gm2local_offset();
@@ -1079,17 +1082,17 @@ pub fn dc_get_chat_msgs(
for row in rows {
let (curr_id, ts) = row?;
if curr_id as u32 == marker1before {
ret.push(DC_MSG_ID_MARKER1 as u32);
ret.add_id(1);
}
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.push(DC_MSG_ID_LAST_SPECIAL as u32);
ret.add_id(9);
last_day = curr_day;
}
}
ret.push(curr_id as u32);
ret.add_id(curr_id as u32);
}
Ok(())
};
@@ -1137,7 +1140,7 @@ pub fn dc_get_chat_msgs(
};
if success.is_ok() {
dc_array_t::from(ret).into_raw()
ret.into_raw()
} else {
0 as *mut dc_array_t
}
@@ -1250,11 +1253,11 @@ pub fn dc_get_chat_media(
],
|row| row.get::<_, i32>(0),
|ids| {
let mut ret = Vec::new();
let mut ret = dc_array_t::new(100);
for id in ids {
ret.push(id? as u32);
ret.add_id(id? as u32);
}
Ok(dc_array_t::from(ret).into_raw())
Ok(ret.into_raw())
}
).unwrap_or_else(|_| std::ptr::null_mut())
}
@@ -1403,12 +1406,12 @@ pub fn dc_delete_chat(context: &Context, chat_id: u32) -> bool {
true
}
pub fn dc_get_chat_contacts(context: &Context, chat_id: u32) -> Vec<u32> {
pub fn dc_get_chat_contacts(context: &Context, chat_id: u32) -> *mut dc_array_t {
/* 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 Vec::new();
return std::ptr::null_mut();
}
// we could also create a list for all contacts in the deaddrop by searching contacts belonging to chats with
@@ -1420,11 +1423,19 @@ pub fn dc_get_chat_contacts(context: &Context, chat_id: u32) -> Vec<u32> {
"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],
|row| row.get::<_, u32>(0),
|ids| ids.collect::<Result<Vec<_>, _>>().map_err(Into::into),
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())
},
)
.unwrap_or_default()
.unwrap_or_else(|_| std::ptr::null_mut())
}
pub unsafe fn dc_get_chat(context: &Context, chat_id: uint32_t) -> *mut Chat {
@@ -2009,21 +2020,21 @@ pub unsafe fn dc_forward_msgs(
}
pub unsafe fn dc_chat_get_id(chat: *const Chat) -> uint32_t {
if chat.is_null() {
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
return 0i32 as uint32_t;
}
(*chat).id
}
pub unsafe fn dc_chat_get_type(chat: *const Chat) -> libc::c_int {
if chat.is_null() {
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
return 0i32;
}
(*chat).type_0
}
pub unsafe fn dc_chat_get_name(chat: *const Chat) -> *mut libc::c_char {
if chat.is_null() {
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
return dc_strdup(b"Err\x00" as *const u8 as *const libc::c_char);
}
dc_strdup((*chat).name)
@@ -2031,7 +2042,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() {
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
return dc_strdup(b"Err\x00" as *const u8 as *const libc::c_char);
}
@@ -2088,8 +2099,9 @@ 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() {
if !(chat.is_null() || (*chat).magic != 0xc4a7c4a7u32) {
image_rel = (*chat)
.param
.get(Param::ProfileImage)
@@ -2097,10 +2109,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 == 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]) {
} 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)) {
if let Some(img) = contact.get_profile_image() {
image_abs = img.strdup();
}
@@ -2110,18 +2122,20 @@ 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() {
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 !(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)) {
color = contact.get_color();
}
}
@@ -2130,12 +2144,14 @@ 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() {
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
return 0i32;
}
(*chat).archived
@@ -2143,7 +2159,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() {
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
return 0;
}
(*chat).param.get_int(Param::Unpromoted).unwrap_or_default() as libc::c_int
@@ -2151,7 +2167,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() {
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
return 0i32;
}
((*chat).type_0 == 130i32) as libc::c_int
@@ -2159,7 +2175,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() {
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
return 0i32;
}
(*chat).is_sending_locations

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,3 @@
//! End-to-end encryption support.
use std::collections::HashSet;
use std::ffi::CStr;
use std::str::FromStr;
@@ -18,12 +16,10 @@ 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::*;
@@ -100,11 +96,9 @@ pub unsafe fn dc_e2ee_encrypt(
let addr = context.sql.get_config(context, "configured_addr");
if let Some(addr) = addr {
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 {
if let Some(public_key) =
load_or_generate_self_public_key(context, &addr, in_out_message)
{
/*only for random-seed*/
if prefer_encrypt == EncryptPreference::Mutual || 0 != e2ee_guaranteed {
do_encrypt = 1i32;
@@ -121,22 +115,11 @@ 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;
@@ -479,52 +462,65 @@ unsafe fn new_data_part(
return 0 as *mut mailmime;
}
/// 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();
/*******************************************************************************
* 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;
// 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);
let mut key = Key::from_self_public(context, &self_addr, &context.sql);
if key.is_some() {
return key;
}
let start = std::time::Instant::now();
/* 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();
info!(
context,
0, "Generating keypair with {} bits, e={} ...", 2048, 65537,
);
match dc_pgp_create_keypair(&self_addr) {
Some((public_key, private_key)) => {
match dc_key_save_self_keypair(
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!(
context,
&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")),
}
0,
"Keypair generated in {:.3}s.",
clock().wrapping_sub(start) as libc::c_double / 1000000 as libc::c_double,
);
}
None => Err(format_err!("Failed to generate keypair")),
key = Some(public_key);
} else {
warn!(context, 0, "Cannot create keypair.");
}
if 0 != key_creation_here {
S_IN_KEY_CREATION = 0;
}
key
}
/* returns 1 if sth. was decrypted, 0 in other cases */
@@ -544,18 +540,20 @@ 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()) {
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()
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()
}
}
}
}
@@ -576,7 +574,7 @@ pub unsafe fn dc_e2ee_decrypt(
}
} else if let Some(ref header) = autocryptheader {
let p = Peerstate::from_header(context, header, message_time);
assert!(p.save_to_db(&context.sql, true));
p.save_to_db(&context.sql, true);
peerstate = Some(p);
}
}
@@ -814,7 +812,7 @@ unsafe fn decrypt_recursive(
}
unsafe fn decrypt_part(
_context: &Context,
context: &Context,
mime: *mut mailmime,
private_keyring: &Keyring,
public_keyring_for_validate: &Keyring,
@@ -1036,49 +1034,33 @@ pub unsafe fn dc_e2ee_thanks(helper: &mut dc_e2ee_helper_t) {
helper.cdata_to_free = 0 as *mut libc::c_void;
}
/// 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)
/* 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
}
#[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
@@ -1139,47 +1121,4 @@ 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());
}
}
}

View File

@@ -194,15 +194,20 @@ 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."
);
let self_addr = dc_ensure_secret_key_exists(context)?;
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 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
@@ -508,7 +513,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 ok_to_continue = true;
let mut current_block: u64;
let mut success: libc::c_int = 0;
let mut ongoing_allocated_here: libc::c_int = 0;
let what: libc::c_int;
@@ -516,8 +521,7 @@ 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_s = (*job).param.get(Param::Arg).unwrap_or_default();
let param1 = CString::yolo(param1_s);
let param1 = CString::yolo((*job).param.get(Param::Arg).unwrap_or_default());
let _param2 = CString::yolo((*job).param.get(Param::Arg2).unwrap_or_default());
if strlen(param1.as_ptr()) == 0 {
@@ -530,45 +534,185 @@ 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 dc_ensure_secret_key_exists(context).is_err() {
if 0 == dc_ensure_secret_key_exists(context) {
error!(
context,
0,
"Import/export: Cannot create private key or private key not available.",
);
ok_to_continue = false;
current_block = 3568988166330621280;
} else {
dc_create_folder(context, &param1_s);
dc_create_folder(context, param1.as_ptr());
current_block = 4495394744059808450;
}
} else {
current_block = 4495394744059808450;
}
if ok_to_continue {
match what {
match current_block {
3568988166330621280 => {}
_ => match what {
1 => {
if 0 != export_self_keys(context, param1.as_ptr()) {
info!(context, 0, "Import/export completed.",);
success = 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
}
}
}
2 => {
if 0 != import_self_keys(context, param1.as_ptr()) {
info!(context, 0, "Import/export completed.",);
success = 1
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
}
}
}
11 => {
if 0 != export_backup(context, param1.as_ptr()) {
info!(context, 0, "Import/export completed.",);
success = 1
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
}
}
}
12 => {
if 0 != import_backup(context, param1.as_ptr()) {
info!(context, 0, "Import/export completed.",);
success = 1
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
}
}
}
_ => {}
}
},
}
}
}
@@ -604,8 +748,8 @@ unsafe fn import_backup(context: &Context, backup_to_import: *const libc::c_char
return 0;
}
&context.sql.close(&context);
dc_delete_file(context, as_path(context.get_dbfile()));
if dc_file_exist(context, as_path(context.get_dbfile())) {
dc_delete_file(context, context.get_dbfile());
if 0 != dc_file_exist(context, context.get_dbfile()) {
error!(
context,
0, "Cannot import backups: Cannot delete the old file.",
@@ -613,11 +757,7 @@ unsafe fn import_backup(context: &Context, backup_to_import: *const libc::c_char
return 0;
}
if !dc_copy_file(
context,
as_path(backup_to_import),
as_path(context.get_dbfile()),
) {
if 0 == dc_copy_file(context, backup_to_import, context.get_dbfile()) {
return 0;
}
/* error already logged */
@@ -744,11 +884,7 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> libc::c_
as_str(context.get_dbfile()),
as_str(dest_pathNfilename),
);
if dc_copy_file(
context,
as_path(context.get_dbfile()),
as_path(dest_pathNfilename),
) {
if !(0 == dc_copy_file(context, context.get_dbfile(), 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) */
@@ -908,7 +1044,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, as_path(dest_pathNfilename));
dc_delete_file(context, dest_pathNfilename);
}
free(dest_pathNfilename as *mut libc::c_void);
@@ -1128,7 +1264,7 @@ unsafe fn export_key_to_asc_file(
)
}
info!(context, 0, "Exporting key {}", as_str(file_name),);
dc_delete_file(context, as_path(file_name));
dc_delete_file(context, file_name);
if !key.write_asc_to_file(file_name, context) {
error!(context, 0, "Cannot write key to {}", as_str(file_name),);
} else {
@@ -1148,15 +1284,147 @@ 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));
configure_alice_keypair(&t.ctx);
create_alice_keypair(&t.ctx); // Trick things to think we're configured.
let msg = dc_render_setup_file(&t.ctx, "hello").unwrap();
println!("{}", &msg);
// Check some substrings, indicating things got substituted.
@@ -1188,7 +1456,7 @@ mod tests {
#[test]
fn test_render_setup_file_newline_replace() {
let t = test_context(Some(ac_setup_msg_cb));
configure_alice_keypair(&t.ctx);
create_alice_keypair(&t.ctx);
let msg = dc_render_setup_file(&t.ctx, "pw").unwrap();
println!("{}", &msg);
assert!(msg.contains("<p>hello<br>there</p>"));

View File

@@ -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 ok_to_continue;
let mut current_block: u64;
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,89 +304,100 @@ 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);
ok_to_continue = false;
current_block = 14216916617354591294;
} else {
ok_to_continue = true;
current_block = 13109137661213826276;
}
} else {
ok_to_continue = true;
current_block = 13109137661213826276;
}
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 {
ok_to_continue1 = 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 {
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()
let recipients_list = recipients
.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,
.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;
}
} else {
current_block = 11194104282611034094;
}
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,
);
}
}
}
}
}
}
}
_ => {}
}
free(buf);
free(filename as *mut libc::c_void);
@@ -405,7 +416,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 ok_to_continue;
let mut current_block: u64;
let msg = dc_msg_new_untyped(context);
let mut dest_uid: uint32_t = 0i32 as uint32_t;
@@ -415,46 +426,75 @@ 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);
ok_to_continue = false;
current_block = 2238328302157162973;
} else {
ok_to_continue = true;
current_block = 2473556513754201174;
}
} else {
ok_to_continue = true;
current_block = 2473556513754201174;
}
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
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
{
1 => {
dc_job_try_again_later(job, 3i32, 0 as *const libc::c_char);
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 | _ => {}
}
3 => {
dc_update_server_uid(context, (*msg).rfc724_mid, &dest_folder, dest_uid);
}
0 | 2 | _ => {}
}
}
}
_ => {}
}
dc_msg_unref(msg);
@@ -473,7 +513,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 ok_to_continue;
let current_block: u64;
let folder = job
.param
.get(Param::ServerFolder)
@@ -487,39 +527,44 @@ 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);
ok_to_continue = false;
current_block = 2670689566614003383;
} else {
ok_to_continue = true;
current_block = 11006700562992250127;
}
} else {
ok_to_continue = true;
current_block = 11006700562992250127;
}
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);
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);
}
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);
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);
}
}
}
}
_ => {}
}
}
#[allow(non_snake_case)]
unsafe fn dc_job_do_DC_JOB_MARKSEEN_MSG_ON_IMAP(context: &Context, job: &mut dc_job_t) {
let ok_to_continue;
let mut current_block: u64;
let msg: *mut dc_msg_t = dc_msg_new_untyped(context);
let inbox = context.inbox.read().unwrap();
@@ -527,44 +572,132 @@ 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);
ok_to_continue = false;
current_block = 17792648348530113339;
} else {
ok_to_continue = true;
current_block = 15240798224410183470;
}
} else {
ok_to_continue = true;
current_block = 15240798224410183470;
}
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 => {
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);
}
3 => {
dc_send_mdn(context, (*msg).id);
_ => {
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();
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 | _ => {}
}
}
}
0 | 2 | _ => {}
}
}
}
}
}
_ => {}
}
dc_msg_unref(msg);
}
@@ -731,6 +864,7 @@ 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();
@@ -739,7 +873,6 @@ 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!(
@@ -750,35 +883,38 @@ 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);
ok_to_continue = false;
current_block = 8913536887710889399;
} else {
ok_to_continue = true;
current_block = 5399440093318478209;
}
} else {
ok_to_continue = true;
current_block = 5399440093318478209;
}
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;
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;
}
}
} else {
ok_to_continue1 = false;
}
} else {
ok_to_continue1 = true;
current_block = 17407779659766490442;
}
if ok_to_continue1 {
dc_delete_msg_from_db(context, (*msg).id);
match current_block {
8913536887710889399 => {}
_ => {
dc_delete_msg_from_db(context, (*msg).id);
}
}
}
dc_msg_unref(msg);

View File

@@ -6,11 +6,14 @@ 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,
@@ -37,13 +40,14 @@ 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() {
if lot.is_null() || (*lot).magic != 0x107107i32 as libc::c_uint {
return;
}
free((*lot).text1 as *mut libc::c_void);
@@ -62,16 +66,17 @@ pub unsafe fn dc_lot_empty(mut lot: *mut dc_lot_t) {
(*lot).id = 0i32 as uint32_t;
}
pub unsafe fn dc_lot_unref(set: *mut dc_lot_t) {
if set.is_null() {
pub unsafe fn dc_lot_unref(mut set: *mut dc_lot_t) {
if set.is_null() || (*set).magic != 0x107107i32 as libc::c_uint {
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() {
if lot.is_null() || (*lot).magic != 0x107107i32 as libc::c_uint {
return 0 as *mut libc::c_char;
}
@@ -79,7 +84,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() {
if lot.is_null() || (*lot).magic != 0x107107i32 as libc::c_uint {
return 0 as *mut libc::c_char;
}
@@ -87,7 +92,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() {
if lot.is_null() || (*lot).magic != 0x107107i32 as libc::c_uint {
return 0i32;
}
@@ -95,7 +100,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() {
if lot.is_null() || (*lot).magic != 0x107107i32 as libc::c_uint {
return 0i32;
}
@@ -103,7 +108,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() {
if lot.is_null() || (*lot).magic != 0x107107i32 as libc::c_uint {
return 0i32 as uint32_t;
}
@@ -111,7 +116,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() {
if lot.is_null() || (*lot).magic != 0x107107i32 as libc::c_uint {
return 0;
}
@@ -127,7 +132,7 @@ pub unsafe fn dc_lot_fill(
contact: Option<&Contact>,
context: &Context,
) {
if lot.is_null() || msg.is_null() {
if lot.is_null() || (*lot).magic != 0x107107i32 as libc::c_uint || msg.is_null() {
return;
}
if (*msg).state == 19i32 {
@@ -166,15 +171,14 @@ pub unsafe fn dc_lot_fill(
}
}
let message_text = (*msg).text.as_ref().unwrap();
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());
(*lot).text2 = dc_msg_get_summarytext_by_raw(
(*msg).type_0,
message_text.strdup(),
&mut (*msg).param,
160,
context,
);
(*lot).text2 =
dc_msg_get_summarytext_by_raw((*msg).type_0, msgtext_ptr, &mut (*msg).param, 160, context);
(*lot).timestamp = dc_msg_get_timestamp(msg);
(*lot).state = (*msg).state;

View File

@@ -1311,14 +1311,16 @@ 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 path = (*msg).param.get(Param::File).unwrap_or_default();
let bytes = dc_get_filebytes((*msg).context, &path);
let pathNfilename = (*msg).param.get(Param::File).unwrap_or_default().strdup();
let bytes = dc_get_filebytes((*msg).context, pathNfilename);
if bytes > (49 * 1024 * 1024 / 4 * 3) {
file_size_okay = false;
}
free(pathNfilename as *mut _);
file_size_okay
}

View File

@@ -161,7 +161,12 @@ 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, "Chat-Version").is_null() {
if !dc_mimeparser_lookup_optional_field(
mimeparser,
b"Chat-Version\x00" as *const u8 as *const libc::c_char,
)
.is_null()
{
mimeparser.is_send_by_messenger = 1i32
}
if !dc_mimeparser_lookup_field(mimeparser, "Autocrypt-Setup-Message").is_null() {
@@ -196,7 +201,10 @@ pub unsafe fn dc_mimeparser_parse(
}
}
} else {
optional_field = dc_mimeparser_lookup_optional_field(mimeparser, "Chat-Content");
optional_field = dc_mimeparser_lookup_optional_field(
mimeparser,
b"Chat-Content\x00" as *const u8 as *const libc::c_char,
);
if !optional_field.is_null() && !(*optional_field).fld_value.is_null() {
if strcmp(
(*optional_field).fld_value,
@@ -304,7 +312,11 @@ 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, "Chat-Voice-Message").is_null()
if !dc_mimeparser_lookup_optional_field(
mimeparser,
b"Chat-Voice-Message\x00" as *const u8 as *const libc::c_char,
)
.is_null()
{
let part_mut = &mut mimeparser.parts[0];
part_mut.type_0 = 41i32
@@ -312,7 +324,10 @@ 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, "Chat-Duration");
let field_0 = dc_mimeparser_lookup_optional_field(
mimeparser,
b"Chat-Duration\x00" as *const u8 as *const libc::c_char,
);
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 {
@@ -323,8 +338,10 @@ pub unsafe fn dc_mimeparser_parse(
}
}
if 0 == mimeparser.decrypting_failed {
let dn_field: *const mailimf_optional_field =
dc_mimeparser_lookup_optional_field(mimeparser, "Chat-Disposition-Notification-To");
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,
);
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;
@@ -442,11 +459,11 @@ pub fn dc_mimeparser_lookup_field(
pub unsafe fn dc_mimeparser_lookup_optional_field(
mimeparser: &dc_mimeparser_t,
field_name: &str,
field_name: *const libc::c_char,
) -> *mut mailimf_optional_field {
let field = mimeparser
.header
.get(field_name)
.get(as_str(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 {
@@ -1095,7 +1112,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<Simplify> = None;
let mut simplifier: Option<dc_simplify_t> = 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;
@@ -1117,7 +1134,7 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
match mime_type {
60 | 70 => {
if simplifier.is_none() {
simplifier = Some(Simplify::new());
simplifier = Some(dc_simplify_t::new());
}
/* get from `Content-Type: text/...; charset=utf-8`; must not be free()'d */
let charset = mailmime_content_charset_get((*mime).mm_content_type);
@@ -1167,7 +1184,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,
"Chat-Version",
b"Chat-Version\x00" as *const u8 as *const libc::c_char,
)
.is_null())
as libc::c_int;
@@ -1175,7 +1192,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,
mime_type == 70i32,
if mime_type == 70i32 { 1i32 } else { 0i32 },
is_msgrmsg,
);
if !simplified_txt.is_null()
@@ -1191,7 +1208,7 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
} else {
free(simplified_txt as *mut libc::c_void);
}
if simplifier.unwrap().is_forwarded {
if 0 != simplifier.unwrap().is_forwarded {
mimeparser.is_forwarded = 1i32
}
current_block = 10261677128829721533;
@@ -1535,8 +1552,10 @@ 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, "Precedence");
let precedence: *mut mailimf_optional_field = dc_mimeparser_lookup_optional_field(
mimeparser,
b"Precedence\x00" as *const u8 as *const libc::c_char,
);
if !precedence.is_null() {
if strcasecmp(
(*precedence).fld_value,

View File

@@ -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, MoveState::Stay);
dc_update_msg_move_state(context, (*msg).rfc724_mid, DC_MOVE_STATE_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, MoveState::Moving);
dc_update_msg_move_state(context, (*msg).rfc724_mid, DC_MOVE_STATE_MOVING);
}
dc_msg_unref(msg);

View File

@@ -20,11 +20,12 @@ 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: MoveState,
pub move_state: dc_move_state_t,
pub type_0: Viewtype,
pub state: libc::c_int,
pub hidden: libc::c_int,
@@ -35,7 +36,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: Option<String>,
pub server_folder: *mut libc::c_char,
pub server_uid: uint32_t,
pub is_dc_message: libc::c_int,
pub starred: libc::c_int,
@@ -167,7 +168,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, as_path(p)) as libc::c_int,
dc_get_filebytes(context, p) as libc::c_int,
);
}
free(p as *mut libc::c_void);
@@ -193,12 +194,14 @@ 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: {}", as_str((*msg).rfc724_mid));
ret += &format!("\nMessage-ID: {}", (*msg).rfc724_mid 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);
}
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,
);
}
dc_msg_unref(msg);
@@ -221,11 +224,12 @@ 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: MoveState::Undefined,
move_state: 0,
type_0: viewtype,
state: 0,
hidden: 0,
@@ -236,7 +240,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: None,
server_folder: std::ptr::null_mut(),
server_uid: 0,
is_dc_message: 0,
starred: 0,
@@ -248,22 +252,25 @@ 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(msg: *mut dc_msg_t) {
if msg.is_null() {
pub unsafe fn dc_msg_unref(mut msg: *mut dc_msg_t) {
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
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() {
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
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;
}
@@ -271,7 +278,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() {
if !(msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint) {
match (*msg).param.get(Param::MimeType) {
Some(m) => {
ret = m.strdup();
@@ -355,7 +362,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() {
if !(msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint) {
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());
@@ -378,7 +385,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() {
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
return false;
}
@@ -407,7 +414,10 @@ pub unsafe fn dc_msg_set_location(
latitude: libc::c_double,
longitude: libc::c_double,
) {
if msg.is_null() || (latitude == 0.0 && longitude == 0.0) {
if msg.is_null()
|| (*msg).magic != 0x11561156i32 as libc::c_uint
|| (latitude == 0.0 && longitude == 0.0)
{
return;
}
@@ -416,7 +426,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() {
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
return 0;
}
return if 0 != (*msg).timestamp_sent {
@@ -450,7 +460,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::<_, Option<String>>(3)?;
(*msg).server_folder = row.get::<_, String>(3)?.strdup();
(*msg).server_uid = row.get(4)?;
(*msg).move_state = row.get(5)?;
(*msg).chat_id = row.get(6)?;
@@ -462,21 +472,7 @@ 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)?;
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).text = row.get::<_, Option<String>>(15)?;
(*msg).param = row.get::<_, String>(16)?.parse().unwrap_or_default();
(*msg).starred = row.get(17)?;
(*msg).hidden = row.get(18)?;
@@ -492,18 +488,11 @@ pub fn dc_msg_load_from_db<'a>(msg: *mut dc_msg_t<'a>, context: &'a Context, id:
free(ptr.cast());
}
};
Ok(())
Ok(())
}
});
if let Err(e) = res {
warn!(
context,
0, "Error in msg_load_from_db for id {} because of {}", id, e
);
return false;
}
true
res.is_ok()
}
pub unsafe fn dc_get_mime_headers(context: &Context, msg_id: uint32_t) -> *mut libc::c_char {
@@ -639,13 +628,12 @@ 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 = false;
let mut success: libc::c_int = 0i32;
let obj: *mut dc_msg_t = dc_msg_new_untyped(context);
if dc_msg_load_from_db(obj, context, msg_id) {
success = true
success = 1i32
}
if success {
if 0 != success {
obj
} else {
dc_msg_unref(obj);
@@ -654,7 +642,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() {
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
return 0i32 as uint32_t;
}
@@ -662,7 +650,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() {
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
return 0i32 as uint32_t;
}
@@ -670,7 +658,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() {
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
return 0i32 as uint32_t;
}
return if 0 != (*msg).chat_blocked {
@@ -681,7 +669,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() {
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
return Viewtype::Unknown;
}
@@ -689,7 +677,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() {
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
return 0i32;
}
@@ -697,7 +685,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() {
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
return 0;
}
@@ -705,7 +693,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() {
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
return 0;
}
@@ -713,7 +701,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() {
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
return dc_strdup(0 as *const libc::c_char);
}
if let Some(ref text) = (*msg).text {
@@ -727,7 +715,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() {
if !(msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint) {
if let Some(file) = (*msg).param.get(Param::File) {
let file_c = CString::yolo(file);
ret = dc_get_filename(file_c.as_ptr());
@@ -741,17 +729,20 @@ 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 {
if !msg.is_null() {
let mut ret = 0;
if !(msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint) {
if let Some(file) = (*msg).param.get(Param::File) {
return dc_get_filebytes((*msg).context, &file);
let file_c = CString::yolo(file);
ret = dc_get_filebytes((*msg).context, file_c.as_ptr());
}
}
0
ret
}
pub unsafe fn dc_msg_get_width(msg: *const dc_msg_t) -> libc::c_int {
if msg.is_null() {
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
return 0;
}
@@ -759,7 +750,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() {
if msg.is_null() || (*msg).magic != 0x11561156 as libc::c_uint {
return 0;
}
@@ -767,7 +758,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() {
if msg.is_null() || (*msg).magic != 0x11561156 as libc::c_uint {
return 0;
}
@@ -776,7 +767,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() {
if msg.is_null() || (*msg).magic != 0x11561156 as libc::c_uint {
return 0;
}
if (*msg)
@@ -795,29 +786,35 @@ pub unsafe fn dc_msg_get_summary<'a>(
msg: *mut dc_msg_t<'a>,
mut chat: *const Chat<'a>,
) -> *mut dc_lot_t {
let mut ok_to_continue = true;
let current_block: u64;
let ret: *mut dc_lot_t = dc_lot_new();
let mut chat_to_delete: *mut Chat = 0 as *mut Chat;
if !msg.is_null() {
if !(msg.is_null() || (*msg).magic != 0x11561156 as libc::c_uint) {
if chat.is_null() {
chat_to_delete = dc_get_chat((*msg).context, (*msg).chat_id);
if chat_to_delete.is_null() {
ok_to_continue = false;
current_block = 15204159476013091401;
} else {
chat = chat_to_delete;
current_block = 7815301370352969686;
}
} else {
current_block = 7815301370352969686;
}
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
};
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
};
dc_lot_fill(ret, msg, chat, contact.as_ref(), (*msg).context);
dc_lot_fill(ret, msg, chat, contact.as_ref(), (*msg).context);
}
}
}
@@ -830,7 +827,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() {
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
return dc_strdup(0 as *const libc::c_char);
}
@@ -941,7 +938,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() {
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
return 0;
}
if (*msg).state >= DC_STATE_OUT_DELIVERED {
@@ -952,7 +949,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() {
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
return false;
}
0 != (*msg).starred
@@ -960,7 +957,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() {
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
return 0;
}
if 0 != (*msg).param.get_int(Param::Forwarded).unwrap_or_default() {
@@ -972,7 +969,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() {
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
return 0;
}
let cmd = (*msg).param.get_int(Param::Cmd).unwrap_or_default();
@@ -988,7 +985,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() {
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
return 0;
}
@@ -1000,7 +997,10 @@ 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).type_0 != Viewtype::File {
if msg.is_null()
|| (*msg).magic != 0x11561156i32 as libc::c_uint
|| (*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() {
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
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() {
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
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() {
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
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() {
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
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() {
if !(msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint) {
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() {
if msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint {
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: MoveState,
state: dc_move_state_t,
) -> 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

View File

@@ -7,6 +7,7 @@ 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::*;
@@ -41,7 +42,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).ok();
dc_ensure_secret_key_exists(context);
invitenumber = dc_token_lookup(context, DC_TOKEN_INVITENUMBER, group_chat_id);
if invitenumber.is_null() {
invitenumber = dc_create_id().strdup();
@@ -148,7 +149,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).ok();
dc_ensure_secret_key_exists(context);
ongoing_allocated = dc_alloc_ongoing(context);
if !(ongoing_allocated == 0i32) {
qr_scan = dc_check_qr(context, qr);
@@ -295,12 +296,14 @@ unsafe fn send_handshake_msg(
}
unsafe fn chat_id_2_contact_id(context: &Context, contact_chat_id: uint32_t) -> uint32_t {
let contacts = dc_get_chat_contacts(context, contact_chat_id);
if contacts.len() == 1 {
contacts[0]
} else {
0
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)
}
dc_array_unref(contacts);
contact_id
}
unsafe fn fingerprint_equals_sender(
@@ -314,8 +317,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 contacts.len() == 1 {
if let Ok(contact) = Contact::load_from_db(context, contacts[0]) {
if !(dc_array_get_cnt(contacts) != 1) {
if let Ok(contact) = Contact::load_from_db(context, dc_array_get_id(contacts, 0)) {
if let Some(peerstate) = Peerstate::from_addr(context, &context.sql, contact.get_addr())
{
let fingerprint_normalized = dc_normalize_fingerprint(as_str(fingerprint));
@@ -329,6 +332,7 @@ unsafe fn fingerprint_equals_sender(
return 0;
}
}
dc_array_unref(contacts);
fingerprint_equal
}

View File

@@ -3,18 +3,19 @@ use crate::dc_tools::*;
use crate::x::*;
#[derive(Copy, Clone)]
pub struct Simplify {
pub is_forwarded: bool,
pub is_cut_at_begin: bool,
pub is_cut_at_end: bool,
#[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,
}
impl Simplify {
impl dc_simplify_t {
pub fn new() -> Self {
Simplify {
is_forwarded: false,
is_cut_at_begin: false,
is_cut_at_end: false,
dc_simplify_t {
is_forwarded: 0,
is_cut_at_begin: 0,
is_cut_at_end: 0,
}
}
@@ -25,7 +26,7 @@ impl Simplify {
&mut self,
in_unterminated: *const libc::c_char,
in_bytes: libc::c_int,
is_html: bool,
is_html: libc::c_int,
is_msgrmsg: libc::c_int,
) -> *mut libc::c_char {
if in_bytes <= 0 {
@@ -35,9 +36,9 @@ impl Simplify {
/* create a copy of the given buffer */
let mut out: *mut libc::c_char;
let mut temp: *mut libc::c_char;
self.is_forwarded = false;
self.is_cut_at_begin = false;
self.is_cut_at_end = false;
self.is_forwarded = 0i32;
self.is_cut_at_begin = 0i32;
self.is_cut_at_end = 0i32;
out = strndup(
in_unterminated as *mut libc::c_char,
in_bytes as libc::c_ulong,
@@ -45,7 +46,7 @@ impl Simplify {
if out.is_null() {
return dc_strdup(b"\x00" as *const u8 as *const libc::c_char);
}
if is_html {
if 0 != is_html {
temp = dc_dehtml(out);
if !temp.is_null() {
free(out as *mut libc::c_void);
@@ -95,7 +96,7 @@ impl Simplify {
|| strcmp(line, b"----\x00" as *const u8 as *const libc::c_char) == 0i32
{
footer_mark = 1i32;
self.is_cut_at_end = true
self.is_cut_at_end = 1i32
}
if 0 != footer_mark {
l_last = l;
@@ -114,7 +115,7 @@ impl Simplify {
&& 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 = true;
self.is_forwarded = 1i32;
l_first += 3
}
}
@@ -127,7 +128,7 @@ impl Simplify {
|| strncmp(line, b"~~~~~\x00" as *const u8 as *const libc::c_char, 5) == 0i32
{
l_last = l;
self.is_cut_at_end = true;
self.is_cut_at_end = 1i32;
/* done */
break;
}
@@ -144,7 +145,7 @@ impl Simplify {
}
if l_lastQuotedLine.is_some() {
l_last = l_lastQuotedLine.unwrap();
self.is_cut_at_end = true;
self.is_cut_at_end = 1i32;
if l_last > 1 {
if is_empty_line(lines[l_last - 1]) {
l_last -= 1
@@ -179,12 +180,12 @@ impl Simplify {
}
if l_lastQuotedLine_0.is_some() {
l_first = l_lastQuotedLine_0.unwrap() + 1;
self.is_cut_at_begin = true
self.is_cut_at_begin = 1i32
}
}
/* re-create buffer from the remaining lines */
let mut ret = String::new();
if self.is_cut_at_begin {
if 0 != self.is_cut_at_begin {
ret += "[...]";
}
/* we write empty lines only in case and non-empty line follows */
@@ -210,7 +211,7 @@ impl Simplify {
pending_linebreaks = 1i32
}
}
if self.is_cut_at_end && (!self.is_cut_at_begin || 0 != content_lines_added) {
if 0 != self.is_cut_at_end && (0 == self.is_cut_at_begin || 0 != content_lines_added) {
ret += " [...]";
}
dc_free_splitted_lines(lines);
@@ -267,11 +268,11 @@ mod tests {
#[test]
fn test_simplify_trim() {
unsafe {
let mut simplify = Simplify::new();
let mut simplify = dc_simplify_t::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, true, 0);
simplify.simplify(html, strlen(html) as libc::c_int, 1, 0);
assert_eq!(
CStr::from_ptr(plain as *const libc::c_char)
@@ -287,11 +288,11 @@ mod tests {
#[test]
fn test_simplify_parse_href() {
unsafe {
let mut simplify = Simplify::new();
let mut simplify = dc_simplify_t::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, true, 0);
simplify.simplify(html, strlen(html) as libc::c_int, 1, 0);
assert_eq!(
CStr::from_ptr(plain as *const libc::c_char)
@@ -307,12 +308,12 @@ mod tests {
#[test]
fn test_simplify_bold_text() {
unsafe {
let mut simplify = Simplify::new();
let mut simplify = dc_simplify_t::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, true, 0);
simplify.simplify(html, strlen(html) as libc::c_int, 1, 0);
assert_eq!(
CStr::from_ptr(plain as *const libc::c_char)
@@ -328,12 +329,12 @@ mod tests {
#[test]
fn test_simplify_html_encoded() {
unsafe {
let mut simplify = Simplify::new();
let mut simplify = dc_simplify_t::new();
let html: *const libc::c_char =
b"&lt;&gt;&quot;&apos;&amp; &auml;&Auml;&ouml;&Ouml;&uuml;&Uuml;&szlig; foo&AElig;&ccedil;&Ccedil; &diams;&noent;&lrm;&rlm;&zwnj;&zwj;\x00"
as *const u8 as *const libc::c_char;
let plain: *mut libc::c_char =
simplify.simplify(html, strlen(html) as libc::c_int, true, 0);
simplify.simplify(html, strlen(html) as libc::c_int, 1, 0);
assert_eq!(
strcmp(plain,

View File

@@ -23,21 +23,8 @@ pub fn dc_exactly_one_bit_set(v: libc::c_int) -> bool {
0 != v && 0 == v & v - 1i32
}
/// 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);
/// }
/// ```
/* string tools */
/* dc_strdup() returns empty string if NULL is given, never returns NULL (exits on errors) */
pub unsafe fn dc_strdup(s: *const libc::c_char) -> *mut libc::c_char {
let ret: *mut libc::c_char;
if !s.is_null() {
@@ -51,21 +38,7 @@ pub unsafe fn dc_strdup(s: *const libc::c_char) -> *mut libc::c_char {
ret
}
/// 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);
/// }
/// ```
/* strdup(NULL) is undefined, safe_strdup_keep_null(NULL) returns NULL in this case */
pub unsafe fn dc_strdup_keep_null(s: *const libc::c_char) -> *mut libc::c_char {
return if !s.is_null() {
dc_strdup(s)
@@ -94,14 +67,50 @@ pub unsafe fn dc_str_replace(
haystack: *mut *mut libc::c_char,
needle: *const libc::c_char,
replacement: *const libc::c_char,
) {
let haystack_s = to_string(*haystack);
let needle_s = to_string(needle);
let replacement_s = to_string(replacement);
) -> 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
}
free(*haystack as *mut libc::c_void);
*haystack = haystack_s.replace(&needle_s, &replacement_s).strdup();
replacements
}
pub unsafe fn dc_ftoa(f: libc::c_double) -> *mut libc::c_char {
@@ -1077,20 +1086,21 @@ pub unsafe fn dc_get_abs_path(
pathNfilename_abs
}
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_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_get_filebytes(context: &Context, path: impl AsRef<std::path::Path>) -> uint64_t {
let path_abs = dc_get_abs_path_safe(context, &path);
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));
match fs::metadata(&path_abs) {
Ok(meta) => meta.len() as uint64_t,
Err(_err) => 0,
}
}
pub fn dc_delete_file(context: &Context, path: impl AsRef<std::path::Path>) -> bool {
let path_abs = dc_get_abs_path_safe(context, &path);
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);
let res = if path_abs.is_file() {
fs::remove_file(path_abs)
} else {
@@ -1098,53 +1108,56 @@ pub fn dc_delete_file(context: &Context, path: impl AsRef<std::path::Path>) -> b
};
match res {
Ok(_) => true,
Ok(_) => 1,
Err(_err) => {
warn!(context, 0, "Cannot delete \"{}\".", path.as_ref().display());
false
warn!(context, 0, "Cannot delete \"{}\".", path.display());
0
}
}
}
pub fn dc_copy_file(
context: &Context,
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);
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);
match fs::copy(&src_abs, &dest_abs) {
Ok(_) => true,
Ok(_) => 1,
Err(_) => {
error!(
context,
0,
"Cannot copy \"{}\" to \"{}\".",
src.as_ref().display(),
dest.as_ref().display(),
src.display(),
dest.display(),
);
false
0
}
}
}
pub fn dc_create_folder(context: &Context, path: impl AsRef<std::path::Path>) -> bool {
let path_abs = dc_get_abs_path_safe(context, &path);
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);
if !path_abs.exists() {
match fs::create_dir_all(path_abs) {
Ok(_) => true,
Ok(_) => 1,
Err(_err) => {
warn!(
context,
0,
"Cannot create directory \"{}\".",
path.as_ref().display(),
path.display(),
);
false
0
}
}
} else {
true
1
}
}
@@ -1253,7 +1266,7 @@ pub unsafe fn dc_get_fine_pathNfilename(
dotNSuffix,
)
}
if !dc_file_exist(context, as_path(ret)) {
if 0 == dc_file_exist(context, ret) {
/* fine filename found */
break;
} else {
@@ -1307,7 +1320,7 @@ pub unsafe fn dc_make_rel_and_copy(context: &Context, path: *mut *mut libc::c_ch
);
blobdir_path.is_null()
}
|| !dc_copy_file(context, as_path(*path), as_path(blobdir_path)))
|| 0 == dc_copy_file(context, *path, blobdir_path))
{
free(*path as *mut libc::c_void);
*path = blobdir_path;
@@ -1449,9 +1462,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
///
@@ -1560,49 +1573,6 @@ 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 {
@@ -1677,7 +1647,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);
dc_str_replace(
let replacements: libc::c_int = 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,
@@ -1686,6 +1656,7 @@ 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);
}
}
@@ -2114,4 +2085,5 @@ mod tests {
let grpid = dc_extract_grpid_from_rfc724_mid(mid);
assert_eq!(grpid, Some("1234567890123456"));
}
}

View File

@@ -166,6 +166,7 @@ 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])
}
@@ -190,11 +191,6 @@ 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)?);
@@ -202,34 +198,13 @@ 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()
@@ -242,8 +217,7 @@ 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.gossip_key.is_some() {
res.verified_key = if vk == res.gossip_key {
VerifiedKey::Gossip
} else if vk == res.public_key {
VerifiedKey::Public
@@ -448,7 +422,6 @@ 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,
@@ -525,40 +498,6 @@ 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 {

View File

@@ -4,6 +4,7 @@ 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};
@@ -688,6 +689,10 @@ 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)?;
@@ -1042,8 +1047,8 @@ pub fn housekeeping(context: &Context) {
unreferenced_count,
entry.file_name()
);
let path = entry.path();
dc_delete_file(context, path);
let path = entry.path().to_c_string().unwrap();
dc_delete_file(context, path.as_ptr());
}
}
Err(err) => {

View File

@@ -2,15 +2,9 @@
//!
//! 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.
@@ -50,127 +44,3 @@ 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
}

View File

@@ -16,6 +16,8 @@ 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,

View File

@@ -10,6 +10,7 @@ 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::*;
@@ -56,15 +57,39 @@ unsafe fn stress_functions(context: &Context) {
);
if 0 != dc_is_open(context) {
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")
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,
)
{
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_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_write_file(
context,
@@ -72,10 +97,25 @@ 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!(dc_file_exist(context, "$BLOBDIR/foobar",));
assert!(!dc_file_exist(context, "$BLOBDIR/foobarx"));
assert_ne!(
0,
dc_file_exist(
context,
b"$BLOBDIR/foobar\x00" as *const u8 as *const libc::c_char,
)
);
assert_eq!(
dc_get_filebytes(context, "$BLOBDIR/foobar",),
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,
),
7i32 as libc::c_ulonglong
);
@@ -93,10 +133,23 @@ unsafe fn stress_functions(context: &Context) {
context,
b"/BLOBDIR/fofo\x00" as *const u8 as *const libc::c_char,
));
assert!(dc_file_exist(context, as_path(abs_path)));
assert_ne!(0, dc_file_exist(context, abs_path));
free(abs_path as *mut libc::c_void);
assert!(dc_copy_file(context, "$BLOBDIR/foobar", "$BLOBDIR/dada",));
assert_eq!(dc_get_filebytes(context, "$BLOBDIR/dada",), 7);
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
);
let mut buf: *mut libc::c_void = 0 as *mut libc::c_void;
let mut buf_bytes: size_t = 0;
@@ -117,11 +170,41 @@ unsafe fn stress_functions(context: &Context) {
);
free(buf as *mut _);
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"));
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,
)
);
let fn0: *mut libc::c_char = dc_get_fine_pathNfilename(
context,
b"$BLOBDIR\x00" as *const u8 as *const libc::c_char,
@@ -154,7 +237,7 @@ unsafe fn stress_functions(context: &Context) {
),
0
);
assert!(dc_delete_file(context, as_path(fn0)));
assert_ne!(0, dc_delete_file(context, fn0));
free(fn0 as *mut libc::c_void);
free(fn1 as *mut libc::c_void);
}
@@ -742,14 +825,22 @@ fn test_dc_mimeparser_with_context() {
"inner-subject",
);
let mut of: *mut mailimf_optional_field =
dc_mimeparser_lookup_optional_field(&mimeparser, "X-Special-A");
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,
);
assert_eq!(as_str((*of).fld_value as *const libc::c_char), "special-a",);
of = dc_mimeparser_lookup_optional_field(&mimeparser, "Foo");
of = dc_mimeparser_lookup_optional_field(
&mimeparser,
b"Foo\x00" as *const u8 as *const libc::c_char,
);
assert_eq!(as_str((*of).fld_value as *const libc::c_char), "Bar",);
of = dc_mimeparser_lookup_optional_field(&mimeparser, "Chat-Version");
of = dc_mimeparser_lookup_optional_field(
&mimeparser,
b"Chat-Version\x00" as *const u8 as *const libc::c_char,
);
assert_eq!(as_str((*of).fld_value as *const libc::c_char), "1.0",);
assert_eq!(mimeparser.parts.len(), 1);
@@ -800,16 +891,19 @@ fn test_get_contacts() {
unsafe {
let context = create_test_context();
let contacts = Contact::get_all(&context.ctx, 0, Some("some2")).unwrap();
assert_eq!(contacts.len(), 0);
assert_eq!(dc_array_get_cnt(contacts), 0);
dc_array_unref(contacts);
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!(contacts.len(), 1);
assert_eq!(dc_array_get_cnt(contacts), 1);
dc_array_unref(contacts);
let contacts = Contact::get_all(&context.ctx, 0, Some("alice")).unwrap();
assert_eq!(contacts.len(), 0);
assert_eq!(dc_array_get_cnt(contacts), 0);
dc_array_unref(contacts);
}
}