Compare commits

..

44 Commits

Author SHA1 Message Date
jikstra
42b56cc53e cargo fmt 2019-08-13 00:19:49 +02:00
jikstra
80c727ee9f dc_get_chat_contacts should always return an array and never a null
pointer otherwise we break the ffi interface
2019-08-13 00:17:41 +02:00
Friedel Ziegelmayer
16f891c290 Merge pull request #337 from deltachat/fix-cmdline
fix 'chats' command in cmdline tool
2019-08-12 10:39:11 +02:00
holger krekel
650bddd54b try fix upload failure with / branches 2019-08-12 08:38:15 +02:00
B. Petersen
5554df29fd show full chatlist by just entering 'chats' in cmdline 2019-08-12 01:40:04 +02:00
B. Petersen
adb67d1910 off by one: show chats cnt-1..0 instead of cnt-1..1 2019-08-12 01:28:36 +02:00
Jikstra
ce3b815bd8 Merge pull request #319 from deltachat/fix_utf8_text_msg_load_from_db
Fix having a msg object without a text in it because of invalid utf8
2019-08-12 01:16:23 +02:00
holger krekel
b94f9ef496 address @flub comments 2019-08-11 23:09:48 +02:00
holger krekel
77db475663 - rework running of liveconfig tests
- better README reflecting how to use things, don't advertise
  run-integration-tests to only have one documented way
  and use less tools for rust-devs that just want to run
  python tests

- fix test skipping and get circle-ci to play along

- update docker related docs as well
2019-08-11 23:09:48 +02:00
jikstra
a3683be047 cargo fmt 2019-08-11 18:55:23 +02:00
Jikstra
9dca19d6c9 Merge pull request #302 from deltachat/rm_goto_dc_imex
Remove goto in dc imex
2019-08-11 18:52:17 +02:00
jikstra
3ba847ece2 Apply requested changes 2019-08-11 16:57:49 +02:00
Simon Laux
91bf948d1e chat magic to const 2019-08-11 10:45:17 +02:00
Simon Laux
91fec77f4b fix msg info: message-id 2019-08-11 09:05:56 +02:00
Simon Laux
8fb25a6340 Cargo fmt: removed two empty llines 2019-08-11 09:04:47 +02:00
Simon Laux
cf49acff67 part 2 2019-08-11 02:07:51 +02:00
Simon Laux
4f1a25e1bf cargo fmt 2019-08-11 02:07:51 +02:00
Simon Laux
8608daa7dc remove goto 2019-08-11 02:07:51 +02:00
Alexander Krotov
828e6e3fd0 Merge pull request #320 from link2xt/dc_tools_files
dc_tools: rustify interfaces of file-related functions
2019-08-10 23:10:24 +00:00
Alexander Krotov
ff021fed1f dc_tools: rustify interfaces of file-related functions 2019-08-10 21:15:48 +03:00
jikstra
b7ff996b15 Cargo fmt + refactoring 2019-08-10 17:57:53 +02:00
jikstra
faf53fe11e Manually get a lossy utf8 string from the database if other fails 2019-08-10 17:53:05 +02:00
jikstra
b23c4b4da6 Remove debug printlns, refactor a bit 2019-08-10 16:51:57 +02:00
jikstra
966bb2271a Put something into the msg object if we fail to get a valid string out of the db 2019-08-10 16:47:38 +02:00
Floris Bruynooghe
5438be891b Remove dc_context_unref from Rust API
This removes the dc_context_unref function from the Rust API which was
just an alias for dc_close.  It still exists on the C API where it
makes sure to free the memory.

It also implements Drop for the context which just calls dc_close to
make sure all the memory is freed.  Since you can call dc_close as
many times as you like this ensures that at the Rust level you can't
Drop the struct without releasing the memory.

Finally since memory is now freed by dropping the struct this removes
the #[repr(C)] for the struct.  This struct is fully opaque to the C
API.
2019-08-10 12:04:11 +02:00
Floris Bruynooghe
f31f603c8b Turn dc_ensure_secret_key_existy into something more rusty
This marks the function safe and returns Result, it also now returns
the ConfiguredAddr since it has to look this up anyway and it makes
testing more easy.  Turns out it reduces some duplicate SQL query in
some callers too.

More test code has been moved from dc_imex to test_utils as it's
more genrally applicable.
2019-08-10 11:14:40 +02:00
Dmitry Bogatov
ff39fa0fed Remove useless cast of format! argument
Both `c_int' and `u32' format is same way by default formatter `{}'.
2019-08-10 03:00:43 +02:00
Dmitry Bogatov
cdf3809634 Set type of dc_msg_t.server_folder to Option<String> 2019-08-10 03:00:43 +02:00
Simon Laux
b2a2791f6f cargo fmt 2019-08-09 23:49:54 +02:00
Simon Laux
125df968d2 replace goto with ok_to_continue 2019-08-09 23:49:54 +02:00
Dmitry Bogatov
1c5d07a29f Reimplement dc_str_replace() with standard Rust functions
This change removes one more use of unstable `wrapping_offset_of'.
2019-08-09 23:40:44 +02:00
Dmitry Bogatov
24b025f573 Replace DC_MOVE_* constants with enum 2019-08-09 21:51:33 +02:00
jikstra
d323bd3593 Write tests and docs for dc_strdup and dc_strdup_keep_null 2019-08-09 19:30:36 +02:00
Alexander Krotov
b7174783f1 Pass is_html to Simplify.simplify() as bool 2019-08-09 16:57:14 +02:00
Alexander Krotov
e3269616bd Use bool for Simplify members 2019-08-09 16:57:14 +02:00
Alexander Krotov
64051fca10 Rename dc_simplify_t into Simplify 2019-08-09 16:57:14 +02:00
Alexander Krotov
14ce55b1a8 Remove #[repr(C)] from dc_simplify_t 2019-08-09 16:57:14 +02:00
holger krekel
be605d8ea5 fix(peerstate): encryption-not-available
Add a test for failing e2e encryption and some info statement to hunt where the e2e encryption failure comes from, as well as fix the issue.


Closes #233
2019-08-09 13:28:48 +02:00
Friedel Ziegelmayer
4d8d5f4e1e Fix broken string allocations in message handling (#306)
Fix broken string allocations in message handling
2019-08-09 11:32:42 +02:00
holger krekel
750d6e99a8 fix some longer standing nonsense code that sent to misleading MSG_READ events instead of one correct one 2019-08-09 11:32:24 +02:00
holger krekel
a67892d414 (jikstra, hpk) fix a logic bug introduced with the stock-string merge which set the better message only if it was empty 2019-08-09 11:32:24 +02:00
holger krekel
1cd2a62caf fix a failure which blocked correctly sending out messages (dc_job_add_smtp mis-set filename) 2019-08-09 11:32:24 +02:00
dignifiedquire
6772d6f66c fix: improve some string handling in the message recieve path 2019-08-09 11:32:24 +02:00
Simon Laux
89531dfb62 fix(dc_lot): correct test2 2019-08-09 11:31:11 +02:00
37 changed files with 857 additions and 841 deletions

View File

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

View File

@@ -15,6 +15,7 @@ export BRANCH=${CIRCLE_BRANCH:?specify branch for uploading purposes}
# python docs to py.delta.chat
ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null delta@py.delta.chat mkdir -p build/${BRANCH}
rsync -avz \
-e "ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null" \
"$PYDOCDIR/html/" \
@@ -37,11 +38,13 @@ pip install devpi-client
devpi use https://m.devpi.net
devpi login dc --password $DEVPI_LOGIN
devpi use dc/$BRANCH || {
devpi index -c $BRANCH
devpi use dc/$BRANCH
N_BRANCH=${BRANCH//[\/]}
devpi use dc/$N_BRANCH || {
devpi index -c $N_BRANCH
devpi use dc/$N_BRANCH
}
devpi index $BRANCH bases=/root/pypi
devpi index $N_BRANCH bases=/root/pypi
devpi upload deltachat*.whl
popd

View File

@@ -3,9 +3,9 @@
set -e -x
# Install Rust
curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain nightly-2019-04-19 -y
curl https://sh.rustup.rs -sSf | sh -s -- --default-toolchain nightly-2019-07-10 -y
export PATH=/root/.cargo/bin:$PATH
rustc --version
# remove some 300-400 MB that we don't need for automated builds
rm -rf /root/.rustup/toolchains/nightly-2019-04-19-x86_64-unknown-linux-gnu/share/
rm -rf /root/.rustup/toolchains/nightly-2019-07-10-x86_64-unknown-linux-gnu/share/

View File

@@ -37,6 +37,10 @@ if [ -n "$TESTS" ]; then
export PYTHONDONTWRITEBYTECODE=1
# run tox
# XXX we don't run liveconfig tests because they hang sometimes
# see https://github.com/deltachat/deltachat-core-rust/issues/331
unset DCC_PY_LIVECONFIG
tox --workdir "$TOXWORKDIR" -e lint,py27,py35,py36,py37,auditwheels
popd
fi

View File

@@ -44,11 +44,14 @@ pub unsafe extern "C" fn dc_context_new(
Box::into_raw(Box::new(ctx))
}
/// Release the context structure.
///
/// This function releases the memory of the `dc_context_t` structure.
#[no_mangle]
pub unsafe extern "C" fn dc_context_unref(context: *mut dc_context_t) {
assert!(!context.is_null());
let context = &mut *context;
context::dc_context_unref(context);
context::dc_close(context);
Box::from_raw(context);
}
@@ -861,7 +864,12 @@ pub unsafe extern "C" fn dc_get_contact_encrinfo(
assert!(!context.is_null());
let context = &*context;
Contact::get_encrinfo(context, contact_id).strdup()
Contact::get_encrinfo(context, contact_id)
.map(|s| s.strdup())
.unwrap_or_else(|e| {
error!(context, 0, "{}", e);
std::ptr::null_mut()
})
}
#[no_mangle]

View File

@@ -604,9 +604,13 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
}
"listchats" | "listarchived" | "chats" => {
let listflags = if arg0 == "listarchived" { 0x01 } else { 0 };
let chatlist = Chatlist::try_load(context, listflags, Some(arg1), None)?;
let chatlist = Chatlist::try_load(
context,
listflags,
if arg1.is_empty() { None } else { Some(arg1) },
None,
)?;
let mut i: usize;
let cnt = chatlist.len();
if cnt > 0 {
info!(
@@ -614,9 +618,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
"================================================================================"
);
i = cnt - 1;
while i > 0 {
for i in (0..cnt).rev() {
let chat = dc_get_chat(context, chatlist.get_chat_id(i));
let temp_subtitle = dc_chat_get_subtitle(chat);
let temp_name = dc_chat_get_name(chat);
@@ -670,8 +672,6 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
context, 0,
"================================================================================"
);
i -= 1
}
}
if dc_is_sending_locations_to_chat(context, 0 as uint32_t) {
@@ -1091,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

@@ -456,12 +456,6 @@ fn main_0(args: Vec<String>) -> Result<(), failure::Error> {
println!("history saved");
{
stop_threads(&ctx.read().unwrap());
unsafe {
let mut ctx = ctx.write().unwrap();
dc_close(&mut ctx);
dc_context_unref(&mut ctx);
}
}
Ok(())

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 -p python3 venv
virtualenv venv # or: python -m venv
source venv/bin/activate
Afterwards, invoking ``python`` or ``pip install`` will only
@@ -39,6 +39,12 @@ and push them to a python package index. To install the latest github ``master``
pip install -i https://m.devpi.net/dc/master deltachat
.. note::
If you can help to automate the building of wheels for Mac or Windows,
that'd be much appreciated! please then get
`in contact with us <https://delta.chat/en/contribute>`_.
Installing bindings from source
===============================
@@ -48,34 +54,55 @@ to core deltachat library::
git clone https://github.com/deltachat/deltachat-core-rust
cd deltachat-core-rust
cargo build -p deltachat_ffi --release
This will result in a ``libdeltachat.so`` and ``libdeltachat.a`` files
in the ``target/release`` directory. These files are needed for
creating the python bindings for deltachat::
cd python
DCC_RS_DEV=`pwd`/.. pip install -e .
Now test if the bindings find the correct library::
If you don't have one active, create and activate a python "virtualenv":
python -c 'import deltachat ; print(deltachat.__version__)'
python virtualenv venv # or python -m venv
source venv/bin/activate
This should print your deltachat bindings version.
Afterwards ``which python`` tells you that it comes out of the "venv"
directory that contains all python install artifacts. Let's first
install test tools::
pip install pytest pytest-timeout requests
then cargo-build and install the deltachat bindings::
python install_python_bindings.py
The bindings will be installed in release mode but with debug symbols.
The release mode is neccessary because some tests generate RSA keys
which is prohibitively slow in debug mode.
After succcessul binding installation you can finally run the tests::
pytest -v tests
.. note::
If you can help to automate the building of wheels for Mac or Windows,
that'd be much appreciated! please then get
`in contact with us <https://delta.chat/en/contribute>`_.
Some tests are sometimes failing/hanging because of
https://github.com/deltachat/deltachat-core-rust/issues/331
and
https://github.com/deltachat/deltachat-core-rust/issues/326
Using a system-installed deltachat-core-rust
--------------------------------------------
When calling ``pip`` without specifying the ``DCC_RS_DEV`` environment
variable cffi will try to use a ``deltachat.h`` from a system location
like ``/usr/local/include`` and will try to dynamically link against a
``libdeltachat.so`` in a similar location (e.g. ``/usr/local/lib``).
running "live" tests (experimental)
-----------------------------------
If you want to run "liveconfig" functional tests you can set
``DCC_PY_LIVECONFIG`` to:
- a particular https-url that you can ask for from the delta
chat devs.
- or the path of a file that contains two lines, each describing
via "addr=... mail_pwd=..." a test account login that will
be used for the live tests.
With ``DCC_PY_LIVECONFIG`` set pytest invocations will use real
e-mail accounts and run through all functional "liveconfig" tests.
Code examples
@@ -84,68 +111,34 @@ Code examples
You may look at `examples <https://py.delta.chat/examples.html>`_.
Running tests
=============
Get a checkout of the `deltachat-core-rust github repository`_ and type::
pip install tox
./run-integration-tests.sh
If you want to run functional tests with real
e-mail test accounts, generate a "liveconfig" file where each
lines contains test account settings, for example::
# 'liveconfig' file specifying imap/smtp accounts
addr=some-email@example.org mail_pw=password
addr=other-email@example.org mail_pw=otherpassword
The "keyword=value" style allows to specify any
`deltachat account config setting <https://c.delta.chat/classdc__context__t.html#aff3b894f6cfca46cab5248fdffdf083d>`_ so you can also specify smtp or imap servers, ports, ssl modes etc.
Typically DC's automatic configuration allows to not specify these settings.
The ``run-integration-tests.sh`` script will automatically use
``python/liveconfig`` if it exists, to manually run tests with this
``liveconfig`` file use::
tox -- --liveconfig liveconfig
.. _`deltachat-core-rust github repository`: https://github.com/deltachat/deltachat-core-rust
.. _`deltachat-core`: https://github.com/deltachat/deltachat-core-rust
Running test using a debug build
--------------------------------
If you need to examine e.g. a coredump you may want to run the tests
using a debug build::
DCC_RS_TARGET=debug ./run-integration-tests.sh -e py37 -- -x -v -k failing_test
Building manylinux1 wheels
==========================
.. note::
This section may not fully work.
Building portable manylinux1 wheels which come with libdeltachat.so
and all it's dependencies is easy using the provided docker tooling.
using docker pull / premade images
------------------------------------
We publish a build environment under the ``deltachat/wheel`` tag so
We publish a build environment under the ``deltachat/coredeps`` tag so
that you can pull it from the ``hub.docker.com`` site's "deltachat"
organization::
$ docker pull deltachat/wheel
$ docker pull deltachat/coredeps
The ``deltachat/wheel`` image can be used to build both libdeltachat.so
and the Python wheels::
This docker image can be used to run tests and build Python wheels for all interpreters::
$ docker run --rm -it -v $(pwd):/io/ deltachat/wheel /io/python/wheelbuilder/build-wheels.sh
$ bash ci_scripts/ci_run.sh
This command runs a script within the image, after mounting ``$(pwd)`` as ``/io`` within
the docker image. The script is specified as a path within the docker image's filesystem.
The resulting wheel files will be in ``python/wheelhouse``.
This command runs tests and build-wheel scripts in a docker container.
Optionally build your own docker image
@@ -154,10 +147,10 @@ Optionally build your own docker image
If you want to build your own custom docker image you can do this::
$ cd deltachat-core # cd to deltachat-core checkout directory
$ docker build -t deltachat/wheel python/wheelbuilder/
$ docker build -t deltachat/coredeps ci_scripts/docker_coredeps
This will use the ``python/wheelbuilder/Dockerfile`` to build
up docker image called ``deltachat/wheel``. You can afterwards
This will use the ``ci_scripts/docker_coredeps/Dockerfile`` to build
up docker image called ``deltachat/coredeps``. You can afterwards
find it with::
$ docker images

View File

@@ -6,29 +6,18 @@
import os
import subprocess
import os
if __name__ == "__main__":
os.environ["DCC_RS_TARGET"] = target = "release"
if "DCC_RS_DEV" not in os.environ:
dn = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
os.environ["DCC_RS_DEV"] = dn
toml = os.path.join(os.getcwd(), "..", "Cargo.toml")
assert os.path.exists(toml)
with open(toml) as f:
s = orig = f.read()
s += "\n"
s += "[profile.release]\n"
s += "debug = true\n"
with open(toml, "w") as f:
f.write(s)
print("temporarily modifying Cargo.toml to provide release build with debug symbols ")
try:
subprocess.check_call([
"cargo", "build", "-p", "deltachat_ffi", "--" + target
])
finally:
with open(toml, "w") as f:
f.write(orig)
print("\nreseted Cargo.toml to previous original state")
os.environ["RUSTFLAGS"] = "-g"
subprocess.check_call([
"cargo", "build", "-p", "deltachat_ffi", "--" + target
])
subprocess.check_call("rm -rf build/ src/deltachat/*.so" , shell=True)
subprocess.check_call([

View File

@@ -6,10 +6,15 @@ import platform
import os
import cffi
import shutil
from os.path import dirname as dn
from os.path import abspath
def ffibuilder():
projdir = os.environ.get('DCC_RS_DEV')
if not projdir:
p = dn(dn(dn(dn(abspath(__file__)))))
projdir = os.environ["DCC_RS_DEV"] = p
target = os.environ.get('DCC_RS_TARGET', 'release')
if projdir:
if platform.system() == 'Darwin':

View File

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

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,6 +36,8 @@ def pytest_runtest_call(item):
def pytest_report_header(config, startdir):
summary = []
t = tempfile.mktemp()
try:
ac = Account(t, eventlogging=False)
@@ -43,13 +45,18 @@ def pytest_report_header(config, startdir):
ac.shutdown()
finally:
os.remove(t)
summary = ['Deltachat core={} sqlite={}'.format(
summary.extend(['Deltachat core={} sqlite={}'.format(
info['deltachat_core_version'],
info['sqlite_version'],
)]
cfg = config.getoption('--liveconfig')
)])
cfg = config.option.liveconfig
if cfg:
summary.append('Liveconfig: {}'.format(os.path.abspath(cfg)))
if "#" in cfg:
url, token = cfg.split("#", 1)
summary.append('Liveconfig provider: {}#<token ommitted>'.format(url))
else:
summary.append('Liveconfig file: {}'.format(cfg))
return summary
@@ -66,9 +73,56 @@ def data():
return Data()
class SessionLiveConfigFromFile:
def __init__(self, fn):
self.fn = fn
self.configlist = []
for line in open(fn):
if line.strip() and not line.strip().startswith('#'):
d = {}
for part in line.split():
name, value = part.split("=")
d[name] = value
self.configlist.append(d)
def get(self, index):
return self.configlist[index]
def exists(self):
return bool(self.configlist)
class SessionLiveConfigFromURL:
def __init__(self, url, create_token):
self.configlist = []
for i in range(2):
res = requests.post(url, json={"token_create_user": int(create_token)})
if res.status_code != 200:
pytest.skip("creating newtmpuser failed {!r}".format(res))
d = res.json()
config = dict(addr=d["email"], mail_pw=d["password"])
self.configlist.append(config)
def get(self, index):
return self.configlist[index]
def exists(self):
return bool(self.configlist)
@pytest.fixture(scope="session")
def session_liveconfig(request):
liveconfig_opt = request.config.option.liveconfig
if liveconfig_opt:
if liveconfig_opt.startswith("http"):
url, create_token = liveconfig_opt.split("#", 1)
return SessionLiveConfigFromURL(url, create_token)
else:
return SessionLiveConfigFromFile(liveconfig_opt)
@pytest.fixture
def acfactory(pytestconfig, tmpdir, request):
fn = pytestconfig.getoption("--liveconfig")
def acfactory(pytestconfig, tmpdir, request, session_liveconfig):
class AccountMaker:
def __init__(self):
@@ -82,18 +136,6 @@ def acfactory(pytestconfig, tmpdir, request):
fin = self._finalizers.pop()
fin()
@props.cached
def configlist(self):
configlist = []
for line in open(fn):
if line.strip() and not line.strip().startswith('#'):
d = {}
for part in line.split():
name, value = part.split("=")
d[name] = value
configlist.append(d)
return configlist
def get_unconfigured_account(self):
self.offline_count += 1
tmpdb = tmpdir.join("offlinedb%d" % self.offline_count)
@@ -116,10 +158,12 @@ def acfactory(pytestconfig, tmpdir, request):
return ac
def get_online_configuring_account(self):
if not fn:
pytest.skip("specify a --liveconfig file to run tests with real accounts")
if not session_liveconfig:
pytest.skip("specify DCC_PY_LIVECONFIG or --liveconfig")
configdict = session_liveconfig.get(self.live_count)
self.live_count += 1
configdict = self.configlist.pop(0)
if "e2ee_enabled" not in configdict:
configdict["e2ee_enabled"] = "1"
tmpdb = tmpdir.join("livedb%d" % self.live_count)
ac = Account(tmpdb.strpath, logid="ac{}".format(self.live_count))
ac._evlogger.init_time = self.init_time

View File

@@ -427,6 +427,37 @@ class TestOnlineAccount:
lp.step("2")
assert msg_out.is_out_mdn_received()
def test_send_and_receive_will_encrypt_decrypt(self, acfactory, lp):
lp.sec("starting accounts, waiting for configuration")
ac1 = acfactory.get_online_configuring_account()
ac2 = acfactory.get_online_configuring_account()
c2 = ac1.create_contact(email=ac2.get_config("addr"))
chat = ac1.create_chat_by_contact(c2)
assert chat.id >= const.DC_CHAT_ID_LAST_SPECIAL
wait_configuration_progress(ac1, 1000)
wait_configuration_progress(ac2, 1000)
lp.sec("sending text message from ac1 to ac2")
msg_out = chat.send_text("message1")
lp.sec("wait for ac2 to receive message")
ev = ac2._evlogger.get_matching("DC_EVENT_MSGS_CHANGED")
assert ev[2] == msg_out.id
msg_in = ac2.get_message_by_id(msg_out.id)
assert msg_in.text == "message1"
lp.sec("create new chat with contact and send back (encrypted) message")
chat2b = ac2.create_chat_by_message(msg_in)
chat2b.send_text("message-back")
lp.sec("wait for ac1 to receive message")
ev = ac1._evlogger.get_matching("DC_EVENT_INCOMING_MSG")
assert ev[1] == chat.id
assert ev[2] > msg_out.id
msg_back = ac1.get_message_by_id(ev[2])
assert msg_back.text == "message-back"
def test_saved_mime_on_received_message(self, acfactory, lp):
lp.sec("starting accounts, waiting for configuration")
ac1 = acfactory.get_online_configuring_account()

View File

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

View File

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

View File

@@ -6,10 +6,29 @@ use rusqlite::types::*;
pub const DC_VERSION_STR: &'static [u8; 14] = b"1.0.0-alpha.3\x00";
pub const DC_MOVE_STATE_MOVING: u32 = 3;
pub const DC_MOVE_STATE_STAY: u32 = 2;
pub const DC_MOVE_STATE_PENDING: u32 = 1;
pub const DC_MOVE_STATE_UNDEFINED: u32 = 0;
#[repr(u8)]
#[derive(Debug, Display, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive)]
pub enum MoveState {
Undefined = 0,
Pending = 1,
Stay = 2,
Moving = 3,
}
impl ToSql for MoveState {
fn to_sql(&self) -> sql::Result<ToSqlOutput> {
let num = *self as i64;
Ok(ToSqlOutput::Owned(Value::Integer(num)))
}
}
impl FromSql for MoveState {
fn column_result(col: ValueRef) -> FromSqlResult<Self> {
let inner = FromSql::column_result(col)?;
FromPrimitive::from_i64(inner).ok_or(FromSqlError::InvalidType)
}
}
pub const DC_GCL_ARCHIVED_ONLY: usize = 0x01;
pub const DC_GCL_NO_SPECIALS: usize = 0x02;
@@ -68,6 +87,8 @@ pub const DC_CHAT_TYPE_SINGLE: i32 = 100;
pub const DC_CHAT_TYPE_GROUP: i32 = 120;
pub const DC_CHAT_TYPE_VERIFIED_GROUP: i32 = 130;
pub const DC_CHAT_MAGIC: u32 = 0xc4a7c4a7;
pub const DC_MSG_ID_MARKER1: usize = 1;
pub const DC_MSG_ID_DAYMARKER: usize = 9;
pub const DC_MSG_ID_LAST_SPECIAL: usize = 9;

View File

@@ -584,7 +584,12 @@ impl<'a> Contact<'a> {
.unwrap_or_else(|_| std::ptr::null_mut())
}
pub fn get_encrinfo(context: &Context, contact_id: u32) -> String {
/// Returns a textual summary of the encryption state for the contact.
///
/// This function returns a string explaining the encryption state
/// of the contact and if the connection is encrypted the
/// fingerprints of the keys involved.
pub fn get_encrinfo(context: &Context, contact_id: u32) -> Result<String> {
let mut ret = String::new();
if let Ok(contact) = Contact::load_from_db(context, contact_id) {
@@ -603,7 +608,7 @@ impl<'a> Contact<'a> {
});
ret += &p;
if self_key.is_none() {
unsafe { dc_ensure_secret_key_exists(context) };
dc_ensure_secret_key_exists(context)?;
self_key = Key::from_self_public(context, &loginparam.addr, &context.sql);
}
let p = context.stock_str(StockMessage::FingerPrints);
@@ -646,7 +651,7 @@ impl<'a> Contact<'a> {
}
}
ret
Ok(ret)
}
/// Delete a contact. The contact is deleted from the local device. It may happen that this is not

View File

@@ -20,7 +20,6 @@ use crate::sql::Sql;
use crate::types::*;
use crate::x::*;
#[repr(C)]
pub struct Context {
pub userdata: *mut libc::c_void,
pub dbfile: Arc<RwLock<*mut libc::c_char>>,
@@ -77,6 +76,14 @@ impl Context {
}
}
impl Drop for Context {
fn drop(&mut self) {
unsafe {
dc_close(&self);
}
}
}
impl Default for RunningState {
fn default() -> Self {
RunningState {
@@ -165,16 +172,6 @@ pub fn dc_context_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) };
}
}
unsafe fn cb_receive_imf(
context: &Context,
imf_raw_not_terminated: *const libc::c_char,
@@ -229,7 +226,7 @@ unsafe fn cb_precheck_imf(
"[move] detected moved message {}",
as_str(rfc724_mid),
);
dc_update_msg_move_state(context, rfc724_mid, DC_MOVE_STATE_STAY);
dc_update_msg_move_state(context, rfc724_mid, MoveState::Stay);
}
if as_str(old_server_folder) != server_folder || old_server_uid != server_uid {
dc_update_server_uid(context, rfc724_mid, server_folder, server_uid);
@@ -258,12 +255,6 @@ fn cb_get_config(context: &Context, key: &str) -> Option<String> {
context.sql.get_config(context, key)
}
pub unsafe fn dc_context_unref(context: &mut Context) {
if 0 != dc_is_open(context) {
dc_close(context);
}
}
pub unsafe fn dc_close(context: &Context) {
info!(context, 0, "disconnecting INBOX-watch",);
context.inbox.read().unwrap().disconnect(context);
@@ -315,9 +306,9 @@ pub unsafe fn dc_open(context: &Context, dbfile: &str, blobdir: Option<&str>) ->
let dir = dc_ensure_no_slash_safe(blobdir.unwrap()).strdup();
*context.blobdir.write().unwrap() = dir;
} else {
let dir = (dbfile.to_string() + "-blobs").strdup();
dc_create_folder(context, dir);
*context.blobdir.write().unwrap() = dir;
let dir = dbfile.to_string() + "-blobs";
dc_create_folder(context, &dir);
*context.blobdir.write().unwrap() = dir.strdup();
}
// Create/open sqlite database, this may already use the blobdir
let dbfile_path = std::path::Path::new(dbfile);
@@ -591,3 +582,24 @@ pub fn dc_is_mvbox(context: &Context, folder_name: impl AsRef<str>) -> bool {
false
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn no_crashes_on_context_deref() {
let ctx = dc_context_new(None, std::ptr::null_mut(), Some("Test OS".into()));
std::mem::drop(ctx);
}
#[test]
fn test_context_double_close() {
let ctx = dc_context_new(None, std::ptr::null_mut(), None);
unsafe {
dc_close(&ctx);
dc_close(&ctx);
}
std::mem::drop(ctx);
}
}

View File

@@ -437,5 +437,4 @@ mod tests {
dc_array_unref(arr);
}
}
}

View File

@@ -24,7 +24,7 @@ use crate::x::*;
*/
#[derive(Clone)]
pub struct Chat<'a> {
magic: uint32_t,
magic: u32,
pub id: uint32_t,
pub type_0: libc::c_int,
pub name: *mut libc::c_char,
@@ -65,7 +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,
magic: DC_CHAT_MAGIC,
id: 0,
type_0: 0,
name: std::ptr::null_mut(),
@@ -82,7 +82,7 @@ pub unsafe fn dc_chat_new<'a>(context: &'a Context) -> *mut Chat<'a> {
}
pub unsafe fn dc_chat_unref(mut chat: *mut Chat) {
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
if chat.is_null() || (*chat).magic != DC_CHAT_MAGIC {
return;
}
dc_chat_empty(chat);
@@ -91,7 +91,7 @@ pub unsafe fn dc_chat_unref(mut chat: *mut Chat) {
}
pub unsafe fn dc_chat_empty(mut chat: *mut Chat) {
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
if chat.is_null() || (*chat).magic != DC_CHAT_MAGIC {
return;
}
free((*chat).name as *mut libc::c_void);
@@ -120,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() || unsafe { (*chat).magic != 0xc4a7c4a7u32 } {
if chat.is_null() || unsafe { (*chat).magic != DC_CHAT_MAGIC } {
return false;
}
unsafe { dc_chat_empty(chat) };
@@ -810,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() || (*chat).magic != 0xc4a7c4a7u32 {
if chat.is_null() || (*chat).magic != DC_CHAT_MAGIC {
return 0;
}
(*chat).param.exists(Param::Selftalk) as libc::c_int
@@ -1410,32 +1410,38 @@ 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 std::ptr::null_mut();
let ret = if chat_id != 1 {
// we could also create a list for all contacts in the deaddrop by searching contacts belonging to chats with
// chats.blocked=2, however, currently this is not needed
context
.sql
.query_map(
"SELECT cc.contact_id FROM chats_contacts cc \
LEFT JOIN contacts c ON c.id=cc.contact_id WHERE cc.chat_id=? \
ORDER BY c.id=1, LOWER(c.name||c.addr), c.id;",
params![chat_id as i32],
|row| row.get::<_, i32>(0),
|ids| {
let mut ret = dc_array_t::new(100);
for id in ids {
ret.add_id(id? as u32);
}
Ok(ret.into_raw())
},
)
.ok()
} else {
None
};
if let Some(chat_contacts) = ret {
chat_contacts
} else {
dc_array_t::new(0).into_raw()
}
// we could also create a list for all contacts in the deaddrop by searching contacts belonging to chats with
// chats.blocked=2, however, currently this is not needed
context
.sql
.query_map(
"SELECT cc.contact_id FROM chats_contacts cc \
LEFT JOIN contacts c ON c.id=cc.contact_id WHERE cc.chat_id=? \
ORDER BY c.id=1, LOWER(c.name||c.addr), c.id;",
params![chat_id as i32],
|row| row.get::<_, i32>(0),
|ids| {
let mut ret = dc_array_t::new(100);
for id in ids {
ret.add_id(id? as u32);
}
Ok(ret.into_raw())
},
)
.unwrap_or_else(|_| std::ptr::null_mut())
}
pub unsafe fn dc_get_chat(context: &Context, chat_id: uint32_t) -> *mut Chat {
@@ -2020,21 +2026,21 @@ pub unsafe fn dc_forward_msgs(
}
pub unsafe fn dc_chat_get_id(chat: *const Chat) -> uint32_t {
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
if chat.is_null() || (*chat).magic != DC_CHAT_MAGIC {
return 0i32 as uint32_t;
}
(*chat).id
}
pub unsafe fn dc_chat_get_type(chat: *const Chat) -> libc::c_int {
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
if chat.is_null() || (*chat).magic != DC_CHAT_MAGIC {
return 0i32;
}
(*chat).type_0
}
pub unsafe fn dc_chat_get_name(chat: *const Chat) -> *mut libc::c_char {
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
if chat.is_null() || (*chat).magic != DC_CHAT_MAGIC {
return dc_strdup(b"Err\x00" as *const u8 as *const libc::c_char);
}
dc_strdup((*chat).name)
@@ -2042,7 +2048,7 @@ pub unsafe fn dc_chat_get_name(chat: *const Chat) -> *mut libc::c_char {
pub unsafe fn dc_chat_get_subtitle(chat: *const Chat) -> *mut libc::c_char {
/* returns either the address or the number of chat members */
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
if chat.is_null() || (*chat).magic != DC_CHAT_MAGIC {
return dc_strdup(b"Err\x00" as *const u8 as *const libc::c_char);
}
@@ -2101,7 +2107,7 @@ pub unsafe fn dc_chat_get_profile_image(chat: *const Chat) -> *mut libc::c_char
let mut image_abs: *mut libc::c_char = 0 as *mut libc::c_char;
let mut contacts: *mut dc_array_t = 0 as *mut dc_array_t;
if !(chat.is_null() || (*chat).magic != 0xc4a7c4a7u32) {
if !(chat.is_null() || (*chat).magic != DC_CHAT_MAGIC) {
image_rel = (*chat)
.param
.get(Param::ProfileImage)
@@ -2109,7 +2115,7 @@ pub unsafe fn dc_chat_get_profile_image(chat: *const Chat) -> *mut libc::c_char
.strdup();
if !image_rel.is_null() && 0 != *image_rel.offset(0isize) as libc::c_int {
image_abs = dc_get_abs_path((*chat).context, image_rel)
} else if (*chat).type_0 == 100i32 {
} else if (*chat).type_0 == DC_CHAT_TYPE_SINGLE {
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)) {
@@ -2131,8 +2137,8 @@ pub unsafe fn dc_chat_get_color(chat: *const Chat) -> uint32_t {
let mut color: uint32_t = 0i32 as uint32_t;
let mut contacts: *mut dc_array_t = 0 as *mut dc_array_t;
if !(chat.is_null() || (*chat).magic != 0xc4a7c4a7u32) {
if (*chat).type_0 == 100i32 {
if !(chat.is_null() || (*chat).magic != DC_CHAT_MAGIC) {
if (*chat).type_0 == DC_CHAT_TYPE_SINGLE {
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)) {
@@ -2151,7 +2157,7 @@ pub unsafe fn dc_chat_get_color(chat: *const Chat) -> uint32_t {
// TODO should return bool /rtn
pub unsafe fn dc_chat_get_archived(chat: *const Chat) -> libc::c_int {
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
if chat.is_null() || (*chat).magic != DC_CHAT_MAGIC {
return 0i32;
}
(*chat).archived
@@ -2159,7 +2165,7 @@ pub unsafe fn dc_chat_get_archived(chat: *const Chat) -> libc::c_int {
// TODO should return bool /rtn
pub unsafe fn dc_chat_is_unpromoted(chat: *const Chat) -> libc::c_int {
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
if chat.is_null() || (*chat).magic != DC_CHAT_MAGIC {
return 0;
}
(*chat).param.get_int(Param::Unpromoted).unwrap_or_default() as libc::c_int
@@ -2167,7 +2173,7 @@ pub unsafe fn dc_chat_is_unpromoted(chat: *const Chat) -> libc::c_int {
// TODO should return bool /rtn
pub unsafe fn dc_chat_is_verified(chat: *const Chat) -> libc::c_int {
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
if chat.is_null() || (*chat).magic != DC_CHAT_MAGIC {
return 0i32;
}
((*chat).type_0 == 130i32) as libc::c_int
@@ -2175,7 +2181,7 @@ pub unsafe fn dc_chat_is_verified(chat: *const Chat) -> libc::c_int {
// TODO should return bool /rtn
pub unsafe fn dc_chat_is_sending_locations(chat: *const Chat) -> libc::c_int {
if chat.is_null() || (*chat).magic != 0xc4a7c4a7u32 {
if chat.is_null() || (*chat).magic != DC_CHAT_MAGIC {
return 0i32;
}
(*chat).is_sending_locations

View File

@@ -101,7 +101,7 @@ pub fn dc_stop_ongoing_process(context: &Context) {
}
// the other dc_job_do_DC_JOB_*() functions are declared static in the c-file
#[allow(non_snake_case)]
#[allow(non_snake_case, unused_must_use)]
pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context, _job: *mut dc_job_t) {
let flags: libc::c_int;
let mut current_block: u64;

View File

@@ -16,10 +16,12 @@ use mmime::mmapstring::*;
use mmime::{mailmime_substitute, MAILIMF_NO_ERROR, MAIL_NO_ERROR};
use crate::aheader::*;
use crate::config::Config;
use crate::context::Context;
use crate::dc_mimeparser::*;
use crate::dc_securejoin::*;
use crate::dc_tools::*;
use crate::error::*;
use crate::key::*;
use crate::keyring::*;
use crate::peerstate::*;
@@ -115,11 +117,22 @@ pub unsafe fn dc_e2ee_encrypt(
|| 0 != e2ee_guaranteed)
{
let peerstate = peerstate.unwrap();
info!(
context,
0, "dc_e2ee_encrypt {} has peerstate", recipient_addr
);
if let Some(key) = peerstate.peek_key(min_verified as usize) {
keyring.add_owned(key.clone());
peerstates.push(peerstate);
}
} else {
info!(
context,
0,
"dc_e2ee_encrypt {} HAS NO peerstate {}",
recipient_addr,
peerstate.is_some()
);
do_encrypt = 0i32;
/* if we cannot encrypt to a single recipient, we cannot encrypt the message at all */
break;
@@ -574,7 +587,7 @@ pub unsafe fn dc_e2ee_decrypt(
}
} else if let Some(ref header) = autocryptheader {
let p = Peerstate::from_header(context, header, message_time);
p.save_to_db(&context.sql, true);
assert!(p.save_to_db(&context.sql, true));
peerstate = Some(p);
}
}
@@ -812,7 +825,7 @@ unsafe fn decrypt_recursive(
}
unsafe fn decrypt_part(
context: &Context,
_context: &Context,
mime: *mut mailmime,
private_keyring: &Keyring,
public_keyring_for_validate: &Keyring,
@@ -1034,33 +1047,53 @@ pub unsafe fn dc_e2ee_thanks(helper: &mut dc_e2ee_helper_t) {
helper.cdata_to_free = 0 as *mut libc::c_void;
}
/* makes sure, the private key exists, needed only for exporting keys and the case no message was sent before */
// TODO should return bool /rtn
pub unsafe fn dc_ensure_secret_key_exists(context: &Context) -> libc::c_int {
/* normally, the key is generated as soon as the first mail is send
(this is to gain some extra-random-seed by the message content and the timespan between program start and message sending) */
let mut success: libc::c_int = 0i32;
let self_addr = context.sql.get_config(context, "configured_addr");
if self_addr.is_none() {
warn!(
context,
0, "Cannot ensure secret key if context is not configured.",
);
} else if load_or_generate_self_public_key(context, self_addr.unwrap(), 0 as *mut mailmime)
.is_some()
{
/*no random text data for seeding available*/
success = 1;
/// Ensures a private key exists for the configured user.
///
/// Normally the private key is generated when the first message is
/// sent (allowing the use of some extra random seed from the message
/// content) 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."
)))?;
unsafe {
load_or_generate_self_public_key(context, &self_addr, 0 as *mut mailmime)
.ok_or(format_err!("Failed to generate private key."))?;
}
success
Ok(self_addr)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_utils::*;
mod ensure_secret_key_exists {
use super::*;
#[test]
fn test_prexisting() {
let t = dummy_context();
let test_addr = configure_alice_keypair(&t.ctx);
assert_eq!(dc_ensure_secret_key_exists(&t.ctx).unwrap(), test_addr);
}
#[test]
fn test_not_configured() {
let t = dummy_context();
assert!(dc_ensure_secret_key_exists(&t.ctx).is_err());
}
}
#[test]
fn test_mailmime_parse() {
let plain = b"Chat-Disposition-Notification-To: holger@deltachat.de

View File

@@ -194,20 +194,15 @@ pub unsafe fn dc_initiate_key_transfer(context: &Context) -> *mut libc::c_char {
setup_code.strdup()
}
/// Renders HTML body of a setup file message.
///
/// The `passphrase` must be at least 2 characters long.
pub fn dc_render_setup_file(context: &Context, passphrase: &str) -> Result<String> {
ensure!(
passphrase.len() >= 2,
"Passphrase must be at least 2 chars long."
);
unsafe {
ensure!(
!(dc_ensure_secret_key_exists(context) == 0),
"No secret key available."
);
}
let self_addr = context
.get_config(Config::ConfiguredAddr)
.ok_or(format_err!("Failed to get self address."))?;
let self_addr = dc_ensure_secret_key_exists(context)?;
let private_key = Key::from_self_private(context, self_addr, &context.sql)
.ok_or(format_err!("Failed to get private key."))?;
let ac_headers = match context
@@ -513,7 +508,7 @@ pub unsafe fn dc_normalize_setup_code(
#[allow(non_snake_case)]
pub unsafe fn dc_job_do_DC_JOB_IMEX_IMAP(context: &Context, job: *mut dc_job_t) {
let mut current_block: u64;
let mut ok_to_continue = true;
let mut success: libc::c_int = 0;
let mut ongoing_allocated_here: libc::c_int = 0;
let what: libc::c_int;
@@ -521,7 +516,8 @@ pub unsafe fn dc_job_do_DC_JOB_IMEX_IMAP(context: &Context, job: *mut dc_job_t)
if !(0 == dc_alloc_ongoing(context)) {
ongoing_allocated_here = 1;
what = (*job).param.get_int(Param::Cmd).unwrap_or_default();
let param1 = CString::yolo((*job).param.get(Param::Arg).unwrap_or_default());
let param1_s = (*job).param.get(Param::Arg).unwrap_or_default();
let param1 = CString::yolo(param1_s);
let _param2 = CString::yolo((*job).param.get(Param::Arg2).unwrap_or_default());
if strlen(param1.as_ptr()) == 0 {
@@ -534,185 +530,45 @@ pub unsafe fn dc_job_do_DC_JOB_IMEX_IMAP(context: &Context, job: *mut dc_job_t)
} else {
if what == 1 || what == 11 {
/* before we export anything, make sure the private key exists */
if 0 == dc_ensure_secret_key_exists(context) {
if dc_ensure_secret_key_exists(context).is_err() {
error!(
context,
0,
"Import/export: Cannot create private key or private key not available.",
);
current_block = 3568988166330621280;
ok_to_continue = false;
} else {
dc_create_folder(context, param1.as_ptr());
current_block = 4495394744059808450;
dc_create_folder(context, &param1_s);
}
} else {
current_block = 4495394744059808450;
}
match current_block {
3568988166330621280 => {}
_ => match what {
if ok_to_continue {
match what {
1 => {
current_block = 10991094515395304355;
match current_block {
2973387206439775448 => {
if 0 == import_backup(context, param1.as_ptr()) {
current_block = 3568988166330621280;
} else {
current_block = 1118134448028020070;
}
}
11250025114629486028 => {
if 0 == import_self_keys(context, param1.as_ptr()) {
current_block = 3568988166330621280;
} else {
current_block = 1118134448028020070;
}
}
12669919903773909120 => {
if 0 == export_backup(context, param1.as_ptr()) {
current_block = 3568988166330621280;
} else {
current_block = 1118134448028020070;
}
}
_ => {
if 0 == export_self_keys(context, param1.as_ptr()) {
current_block = 3568988166330621280;
} else {
current_block = 1118134448028020070;
}
}
}
match current_block {
3568988166330621280 => {}
_ => {
info!(context, 0, "Import/export completed.",);
success = 1
}
if 0 != export_self_keys(context, param1.as_ptr()) {
info!(context, 0, "Import/export completed.",);
success = 1
}
}
2 => {
current_block = 11250025114629486028;
match current_block {
2973387206439775448 => {
if 0 == import_backup(context, param1.as_ptr()) {
current_block = 3568988166330621280;
} else {
current_block = 1118134448028020070;
}
}
11250025114629486028 => {
if 0 == import_self_keys(context, param1.as_ptr()) {
current_block = 3568988166330621280;
} else {
current_block = 1118134448028020070;
}
}
12669919903773909120 => {
if 0 == export_backup(context, param1.as_ptr()) {
current_block = 3568988166330621280;
} else {
current_block = 1118134448028020070;
}
}
_ => {
if 0 == export_self_keys(context, param1.as_ptr()) {
current_block = 3568988166330621280;
} else {
current_block = 1118134448028020070;
}
}
}
match current_block {
3568988166330621280 => {}
_ => {
info!(context, 0, "Import/export completed.",);
success = 1
}
if 0 != import_self_keys(context, param1.as_ptr()) {
info!(context, 0, "Import/export completed.",);
success = 1
}
}
11 => {
current_block = 12669919903773909120;
match current_block {
2973387206439775448 => {
if 0 == import_backup(context, param1.as_ptr()) {
current_block = 3568988166330621280;
} else {
current_block = 1118134448028020070;
}
}
11250025114629486028 => {
if 0 == import_self_keys(context, param1.as_ptr()) {
current_block = 3568988166330621280;
} else {
current_block = 1118134448028020070;
}
}
12669919903773909120 => {
if 0 == export_backup(context, param1.as_ptr()) {
current_block = 3568988166330621280;
} else {
current_block = 1118134448028020070;
}
}
_ => {
if 0 == export_self_keys(context, param1.as_ptr()) {
current_block = 3568988166330621280;
} else {
current_block = 1118134448028020070;
}
}
}
match current_block {
3568988166330621280 => {}
_ => {
info!(context, 0, "Import/export completed.",);
success = 1
}
if 0 != export_backup(context, param1.as_ptr()) {
info!(context, 0, "Import/export completed.",);
success = 1
}
}
12 => {
current_block = 2973387206439775448;
match current_block {
2973387206439775448 => {
if 0 == import_backup(context, param1.as_ptr()) {
current_block = 3568988166330621280;
} else {
current_block = 1118134448028020070;
}
}
11250025114629486028 => {
if 0 == import_self_keys(context, param1.as_ptr()) {
current_block = 3568988166330621280;
} else {
current_block = 1118134448028020070;
}
}
12669919903773909120 => {
if 0 == export_backup(context, param1.as_ptr()) {
current_block = 3568988166330621280;
} else {
current_block = 1118134448028020070;
}
}
_ => {
if 0 == export_self_keys(context, param1.as_ptr()) {
current_block = 3568988166330621280;
} else {
current_block = 1118134448028020070;
}
}
}
match current_block {
3568988166330621280 => {}
_ => {
info!(context, 0, "Import/export completed.",);
success = 1
}
if 0 != import_backup(context, param1.as_ptr()) {
info!(context, 0, "Import/export completed.",);
success = 1
}
}
_ => {}
},
}
}
}
}
@@ -748,8 +604,8 @@ unsafe fn import_backup(context: &Context, backup_to_import: *const libc::c_char
return 0;
}
&context.sql.close(&context);
dc_delete_file(context, context.get_dbfile());
if 0 != dc_file_exist(context, context.get_dbfile()) {
dc_delete_file(context, as_path(context.get_dbfile()));
if dc_file_exist(context, as_path(context.get_dbfile())) {
error!(
context,
0, "Cannot import backups: Cannot delete the old file.",
@@ -757,7 +613,11 @@ unsafe fn import_backup(context: &Context, backup_to_import: *const libc::c_char
return 0;
}
if 0 == dc_copy_file(context, backup_to_import, context.get_dbfile()) {
if !dc_copy_file(
context,
as_path(backup_to_import),
as_path(context.get_dbfile()),
) {
return 0;
}
/* error already logged */
@@ -884,7 +744,11 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> libc::c_
as_str(context.get_dbfile()),
as_str(dest_pathNfilename),
);
if !(0 == dc_copy_file(context, context.get_dbfile(), dest_pathNfilename)) {
if dc_copy_file(
context,
as_path(context.get_dbfile()),
as_path(dest_pathNfilename),
) {
context.sql.open(&context, as_path(context.get_dbfile()), 0);
closed = false;
/* add all files as blobs to the database copy (this does not require the source to be locked, neigher the destination as it is used only here) */
@@ -1044,7 +908,7 @@ unsafe fn export_backup(context: &Context, dir: *const libc::c_char) -> libc::c_
context.sql.open(&context, as_path(context.get_dbfile()), 0);
}
if 0 != delete_dest_file {
dc_delete_file(context, dest_pathNfilename);
dc_delete_file(context, as_path(dest_pathNfilename));
}
free(dest_pathNfilename as *mut libc::c_void);
@@ -1264,7 +1128,7 @@ unsafe fn export_key_to_asc_file(
)
}
info!(context, 0, "Exporting key {}", as_str(file_name),);
dc_delete_file(context, file_name);
dc_delete_file(context, as_path(file_name));
if !key.write_asc_to_file(file_name, context) {
error!(context, 0, "Cannot write key to {}", as_str(file_name),);
} else {
@@ -1284,147 +1148,15 @@ unsafe fn export_key_to_asc_file(
mod tests {
use super::*;
use std::ffi::CStr;
use num_traits::ToPrimitive;
use crate::config::Config;
use crate::key;
use crate::test_utils::*;
unsafe extern "C" fn logging_cb(
_ctx: &Context,
evt: Event,
_d1: uintptr_t,
d2: uintptr_t,
) -> uintptr_t {
let to_str = |x| CStr::from_ptr(x as *const libc::c_char).to_str().unwrap();
match evt {
Event::INFO => println!("I: {}", to_str(d2)),
Event::WARNING => println!("W: {}", to_str(d2)),
Event::ERROR => println!("E: {}", to_str(d2)),
_ => (),
}
0
}
/// Create Alice with a pre-generated keypair.
fn create_alice_keypair(ctx: &Context) {
ctx.set_config(Config::ConfiguredAddr, Some("alice@example.org"))
.unwrap();
// The keypair was created using:
// let (public, private) = crate::pgp::dc_pgp_create_keypair("alice@example.com")
// .unwrap();
// println!("{}", public.to_base64(64));
// println!("{}", private.to_base64(64));
let public = key::Key::from_base64(
concat!(
"xsBNBF086ewBCACmJKuoxIO6T87yi4Q3MyNpMch3Y8KrtHDQyUszU36eqM3Pmd1l",
"FrbcCd8ZWo2pq6OJSwsM/jjRGn1zo2YOaQeJRRrC+KrKGqSUtRSYQBPrPjE2YjSX",
"AMbu8jBI6VVUhHeghriBkK79PY9O/oRhIJC0p14IJe6CQ6OI2fTmTUHF9i/nJ3G4",
"Wb3/K1bU3yVfyPZjTZQPYPvvh03vxHULKurtYkX5DTEMSWsF4qzLMps+l87VuLV9",
"iQnbN7YMRLHHx2KkX5Ivi7JCefhCa54M0K3bDCCxuVWAM5wjQwNZjzR+WL+dYchw",
"oFvuF8NrlzjM9dSv+2rn+J7f99ijSXarzPC7ABEBAAHNEzxhbGljZUBleGFtcGxl",
"LmNvbT7CwIkEEAEIADMCGQEFAl086fgCGwMECwkIBwYVCAkKCwIDFgIBFiEE+iai",
"x4d0doj87Q0ek6DcNkbrcegACgkQk6DcNkbrcei3ogf/cruUmQ+th52TFHTHdkw9",
"OHUl3MrXtZ7QmHyOAFvbXE/6n5Eeh+eZoF8MWWV72m14Wbs+vTcNQkFVTdOPptkK",
"A8e4cJqwDOHsyAnvQXZ7WNje9+BMzcoipIUawHP4ORFaPDsKLZQ0b4wBbKn8ziea",
"6zjGF0/qljTdoxTtsYpv5wXYuhwbYklrLOqgSa5M7LXUe7E3g9mbg+9iX1GuB8m6",
"GkquJN814Y+xny4xhZzGOfue6SeP12jJMNSjSP7416dRq7794VGnkkW9V/7oFEUK",
"u5wO9FFbgDySOSlEjByGejSGuBmho0iJSjcPjZ7EY/j3M3orq4dpza5C82OeSvxD",
"Fc7ATQRdPOnsAQgA5oLxXRLnyugzOmNCy7dxV3JrDZscA6JNlJlDWIShT0YSs+zG",
"9JzDeQql+sYXgUSxOoIayItuXtnFn7tstwGoOnYvadm/e5/7V5fKAQRtCtdN51av",
"62n18Venlm0yNKpROPcZ6M/sc4m6uU6YRZ/a1idal8VGY0wLKlghjIBuIiBoVQ/R",
"noW+/fhmwIg08dQ5m8hQe3GEOZEeLrTWL/9awPlXK7Y+DmJOoR4qbHWEcRfbzS6q",
"4zW8vk2ztB8ngwbnqYy8zrN1DCICN1gYdlU++uVw6Bb1XfY8Cdldh1VLKpF35mAm",
"jxLZfVDcoObFH3Cv2GB7BEYxv86KC2Y6T74Q/wARAQABwsB2BBgBCAAgBQJdPOn4",
"AhsMFiEE+iaix4d0doj87Q0ek6DcNkbrcegACgkQk6DcNkbrcegLxwf/dXshJnoW",
"qEnRsf6rVb9/Mc66ti+NVQLfNd275dybh/QIJdK3NmSxdnTPIEJRVspJywJoupwX",
"FNrnHG2Ff6QPvHqI+/oNu986r9d7Z1oQibbLHKt8t6kpOfg/xGxotagJuiCQvR9m",
"MjD1DqsdB37SjDxGupZOOJSXWi6KX60IE+uM+QOBfeOZziQwuFmA5wV6RDXIeYJf",
"qrcbeXeR1d0nfNpPHQR1gBiqmxNb6KBbdXD2+EXW60axC7D2b1APmzMlammDliPw",
"sK9U1rc9nuquEBvGDOJf4K+Dzn+mDCqRpP6uAuQ7RKHyim4uyN0wwKObzPqgJCGw",
"jTglkixw+aSTXw=="
),
KeyType::Public,
)
.unwrap();
let private = key::Key::from_base64(
concat!(
"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",
"zPqgJCGwjTglkixw+aSTXw=="
),
KeyType::Private,
)
.unwrap();
let saved = key::dc_key_save_self_keypair(
&ctx,
&public,
&private,
"alice@example.org",
1,
&ctx.sql,
);
assert_eq!(saved, true, "Failed to save Alice's key");
}
#[test]
fn test_render_setup_file() {
let t = test_context(Some(logging_cb));
create_alice_keypair(&t.ctx); // Trick things to think we're configured.
configure_alice_keypair(&t.ctx);
let msg = dc_render_setup_file(&t.ctx, "hello").unwrap();
println!("{}", &msg);
// Check some substrings, indicating things got substituted.
@@ -1456,7 +1188,7 @@ mod tests {
#[test]
fn test_render_setup_file_newline_replace() {
let t = test_context(Some(ac_setup_msg_cb));
create_alice_keypair(&t.ctx);
configure_alice_keypair(&t.ctx);
let msg = dc_render_setup_file(&t.ctx, "pw").unwrap();
println!("{}", &msg);
assert!(msg.contains("<p>hello<br>there</p>"));

View File

@@ -313,7 +313,8 @@ unsafe fn dc_job_do_DC_JOB_SEND(context: &Context, job: &mut dc_job_t) {
}
match current_block {
13109137661213826276 => {
filename = job.param.get(Param::File).unwrap_or_default().strdup();
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)) {
@@ -369,7 +370,7 @@ unsafe fn dc_job_do_DC_JOB_SEND(context: &Context, job: &mut dc_job_t) {
(*&mut context.smtp.clone().lock().unwrap()).error,
);
} else {
dc_delete_file(context, filename);
dc_delete_file(context, filename_s);
if 0 != job.foreign_id {
dc_update_msg_state(
context,
@@ -447,7 +448,7 @@ unsafe fn dc_job_do_DC_JOB_MOVE_MSG(context: &Context, job: &mut dc_job_t) {
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);
let server_folder = (*msg).server_folder.as_ref().unwrap();
match inbox.mv(
context,
@@ -582,7 +583,7 @@ unsafe fn dc_job_do_DC_JOB_MARKSEEN_MSG_ON_IMAP(context: &Context, job: &mut dc_
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();
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 => {
@@ -598,8 +599,7 @@ unsafe fn dc_job_do_DC_JOB_MARKSEEN_MSG_ON_IMAP(context: &Context, job: &mut dc_
.get_config_int(context, "mdns_enabled")
.unwrap_or_else(|| 1)
{
let folder =
CStr::from_ptr((*msg).server_folder).to_str().unwrap();
let folder = (*msg).server_folder.as_ref().unwrap();
match inbox.set_mdnsent(context, folder, (*msg).server_uid)
as libc::c_uint
{
@@ -652,8 +652,7 @@ unsafe fn dc_job_do_DC_JOB_MARKSEEN_MSG_ON_IMAP(context: &Context, job: &mut dc_
.get_config_int(context, "mdns_enabled")
.unwrap_or_else(|| 1)
{
let folder =
CStr::from_ptr((*msg).server_folder).to_str().unwrap();
let folder = (*msg).server_folder.as_ref().unwrap();
match inbox.set_mdnsent(context, folder, (*msg).server_uid)
as libc::c_uint
@@ -898,7 +897,7 @@ unsafe fn dc_job_do_DC_JOB_DELETE_MSG_ON_IMAP(context: &Context, job: &mut dc_jo
8913536887710889399 => {}
_ => {
let mid = CStr::from_ptr((*msg).rfc724_mid).to_str().unwrap();
let server_folder = CStr::from_ptr((*msg).server_folder).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);
current_block = 8913536887710889399;

View File

@@ -6,8 +6,6 @@ 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)]
@@ -171,14 +169,15 @@ pub unsafe fn dc_lot_fill(
}
}
let msgtext_c = (*msg)
.text
.as_ref()
.map(|s| CString::yolo(String::as_str(s)));
let msgtext_ptr = msgtext_c.map_or(ptr::null(), |s| s.as_ptr());
let message_text = (*msg).text.as_ref().unwrap();
(*lot).text2 =
dc_msg_get_summarytext_by_raw((*msg).type_0, msgtext_ptr, &mut (*msg).param, 160, context);
(*lot).text2 = dc_msg_get_summarytext_by_raw(
(*msg).type_0,
message_text.strdup(),
&mut (*msg).param,
160,
context,
);
(*lot).timestamp = dc_msg_get_timestamp(msg);
(*lot).state = (*msg).state;

View File

@@ -1311,16 +1311,14 @@ unsafe fn build_body_file(
/*******************************************************************************
* Render
******************************************************************************/
#[allow(non_snake_case)]
unsafe fn is_file_size_okay(msg: *const dc_msg_t) -> bool {
let mut file_size_okay = true;
let pathNfilename = (*msg).param.get(Param::File).unwrap_or_default().strdup();
let bytes = dc_get_filebytes((*msg).context, pathNfilename);
let path = (*msg).param.get(Param::File).unwrap_or_default();
let bytes = dc_get_filebytes((*msg).context, &path);
if bytes > (49 * 1024 * 1024 / 4 * 3) {
file_size_okay = false;
}
free(pathNfilename as *mut _);
file_size_okay
}

View File

@@ -1112,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<dc_simplify_t> = None;
let mut simplifier: Option<Simplify> = None;
if !(mime.is_null() || (*mime).mm_data.mm_single.is_null()) {
mime_type = mailmime_get_mime_type(mime, &mut msg_type, &mut raw_mime);
mime_data = (*mime).mm_data.mm_single;
@@ -1134,7 +1134,7 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
match mime_type {
60 | 70 => {
if simplifier.is_none() {
simplifier = Some(dc_simplify_t::new());
simplifier = Some(Simplify::new());
}
/* get from `Content-Type: text/...; charset=utf-8`; must not be free()'d */
let charset = mailmime_content_charset_get((*mime).mm_content_type);
@@ -1192,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,
if mime_type == 70i32 { 1i32 } else { 0i32 },
mime_type == 70i32,
is_msgrmsg,
);
if !simplified_txt.is_null()
@@ -1208,7 +1208,7 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
} else {
free(simplified_txt as *mut libc::c_void);
}
if 0 != simplifier.unwrap().is_forwarded {
if simplifier.unwrap().is_forwarded {
mimeparser.is_forwarded = 1i32
}
current_block = 10261677128829721533;

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, DC_MOVE_STATE_STAY);
dc_update_msg_move_state(context, (*msg).rfc724_mid, MoveState::Stay);
}
// 1 = dc message, 2 = reply to dc message
if 0 != (*msg).is_dc_message {
dc_job_add(context, 200, (*msg).id as libc::c_int, Params::new(), 0);
dc_update_msg_move_state(context, (*msg).rfc724_mid, DC_MOVE_STATE_MOVING);
dc_update_msg_move_state(context, (*msg).rfc724_mid, MoveState::Moving);
}
dc_msg_unref(msg);

View File

@@ -25,7 +25,7 @@ pub struct dc_msg_t<'a> {
pub from_id: uint32_t,
pub to_id: uint32_t,
pub chat_id: uint32_t,
pub move_state: dc_move_state_t,
pub move_state: MoveState,
pub type_0: Viewtype,
pub state: libc::c_int,
pub hidden: libc::c_int,
@@ -36,7 +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: *mut libc::c_char,
pub server_folder: Option<String>,
pub server_uid: uint32_t,
pub is_dc_message: libc::c_int,
pub starred: libc::c_int,
@@ -168,7 +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, p) as libc::c_int,
dc_get_filebytes(context, as_path(p)) as libc::c_int,
);
}
free(p as *mut libc::c_void);
@@ -194,14 +194,12 @@ pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_ch
ret += &format!("\n{}\n", rawtxt);
}
if !(*msg).rfc724_mid.is_null() && 0 != *(*msg).rfc724_mid.offset(0) as libc::c_int {
ret += &format!("\nMessage-ID: {}", (*msg).rfc724_mid as libc::c_int);
ret += &format!("\nMessage-ID: {}", as_str((*msg).rfc724_mid));
}
if !(*msg).server_folder.is_null() && 0 != *(*msg).server_folder.offset(0) as libc::c_int {
ret += &format!(
"\nLast seen as: {}/{}",
to_string((*msg).server_folder),
(*msg).server_uid as libc::c_int,
);
if let Some(ref server_folder) = (*msg).server_folder {
if server_folder != "" {
ret += &format!("\nLast seen as: {}/{}", server_folder, (*msg).server_uid);
}
}
dc_msg_unref(msg);
@@ -229,7 +227,7 @@ pub unsafe fn dc_msg_new<'a>(context: &'a Context, viewtype: Viewtype) -> *mut d
from_id: 0,
to_id: 0,
chat_id: 0,
move_state: 0,
move_state: MoveState::Undefined,
type_0: viewtype,
state: 0,
hidden: 0,
@@ -240,7 +238,7 @@ pub unsafe fn dc_msg_new<'a>(context: &'a Context, viewtype: Viewtype) -> *mut d
context,
rfc724_mid: std::ptr::null_mut(),
in_reply_to: std::ptr::null_mut(),
server_folder: std::ptr::null_mut(),
server_folder: None,
server_uid: 0,
is_dc_message: 0,
starred: 0,
@@ -269,8 +267,6 @@ pub unsafe fn dc_msg_empty(mut msg: *mut dc_msg_t) {
(*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;
}
@@ -460,7 +456,7 @@ pub fn dc_msg_load_from_db<'a>(msg: *mut dc_msg_t<'a>, context: &'a Context, id:
Some(s) => s.strdup(),
None => std::ptr::null_mut(),
};
(*msg).server_folder = row.get::<_, String>(3)?.strdup();
(*msg).server_folder = row.get::<_, Option<String>>(3)?;
(*msg).server_uid = row.get(4)?;
(*msg).move_state = row.get(5)?;
(*msg).chat_id = row.get(6)?;
@@ -472,7 +468,21 @@ pub fn dc_msg_load_from_db<'a>(msg: *mut dc_msg_t<'a>, context: &'a Context, id:
(*msg).type_0 = row.get(12)?;
(*msg).state = row.get(13)?;
(*msg).is_dc_message = row.get(14)?;
(*msg).text = row.get::<_, Option<String>>(15)?;
let text;
if let rusqlite::types::ValueRef::Text(buf) = row.get_raw(15) {
if let Ok(t) = String::from_utf8(buf.to_vec()) {
text = t;
} else {
warn!(context, 0, "dc_msg_load_from_db: could not get text column as non-lossy utf8 id {}", id);
text = String::from_utf8_lossy(buf).into_owned();
}
} else {
warn!(context, 0, "dc_msg_load_from_db: could not get text column for id {}", id);
text = "[ Could not read from db ]".to_string();
}
(*msg).text = Some(text);
(*msg).param = row.get::<_, String>(16)?.parse().unwrap_or_default();
(*msg).starred = row.get(17)?;
(*msg).hidden = row.get(18)?;
@@ -488,11 +498,18 @@ pub fn dc_msg_load_from_db<'a>(msg: *mut dc_msg_t<'a>, context: &'a Context, id:
free(ptr.cast());
}
};
Ok(())
Ok(())
}
});
res.is_ok()
if let Err(e) = res {
warn!(
context,
0, "Error in msg_load_from_db for id {} because of {}", id, e
);
return false;
}
true
}
pub unsafe fn dc_get_mime_headers(context: &Context, msg_id: uint32_t) -> *mut libc::c_char {
@@ -628,12 +645,13 @@ pub fn dc_star_msgs(
}
pub unsafe fn dc_get_msg<'a>(context: &'a Context, msg_id: uint32_t) -> *mut dc_msg_t<'a> {
let mut success: libc::c_int = 0i32;
let mut success = false;
let obj: *mut dc_msg_t = dc_msg_new_untyped(context);
if dc_msg_load_from_db(obj, context, msg_id) {
success = 1i32
success = true
}
if 0 != success {
if success {
obj
} else {
dc_msg_unref(obj);
@@ -729,16 +747,13 @@ pub unsafe fn dc_msg_get_filename(msg: *const dc_msg_t) -> *mut libc::c_char {
}
pub unsafe fn dc_msg_get_filebytes(msg: *const dc_msg_t) -> uint64_t {
let mut ret = 0;
if !(msg.is_null() || (*msg).magic != 0x11561156i32 as libc::c_uint) {
if let Some(file) = (*msg).param.get(Param::File) {
let file_c = CString::yolo(file);
ret = dc_get_filebytes((*msg).context, file_c.as_ptr());
return dc_get_filebytes((*msg).context, &file);
}
}
ret
0
}
pub unsafe fn dc_msg_get_width(msg: *const dc_msg_t) -> libc::c_int {
@@ -786,7 +801,7 @@ pub unsafe fn dc_msg_get_summary<'a>(
msg: *mut dc_msg_t<'a>,
mut chat: *const Chat<'a>,
) -> *mut dc_lot_t {
let current_block: u64;
let mut ok_to_continue = true;
let ret: *mut dc_lot_t = dc_lot_new();
let mut chat_to_delete: *mut Chat = 0 as *mut Chat;
@@ -794,27 +809,21 @@ pub unsafe fn dc_msg_get_summary<'a>(
if chat.is_null() {
chat_to_delete = dc_get_chat((*msg).context, (*msg).chat_id);
if chat_to_delete.is_null() {
current_block = 15204159476013091401;
ok_to_continue = false;
} else {
chat = chat_to_delete;
current_block = 7815301370352969686;
}
} else {
current_block = 7815301370352969686;
}
match current_block {
15204159476013091401 => {}
_ => {
let contact = if (*msg).from_id != DC_CONTACT_ID_SELF as libc::c_uint
&& ((*chat).type_0 == 120 || (*chat).type_0 == 130)
{
Contact::get_by_id((*chat).context, (*msg).from_id).ok()
} else {
None
};
if ok_to_continue {
let contact = if (*msg).from_id != DC_CONTACT_ID_SELF as libc::c_uint
&& ((*chat).type_0 == 120 || (*chat).type_0 == 130)
{
Contact::get_by_id((*chat).context, (*msg).from_id).ok()
} else {
None
};
dc_lot_fill(ret, msg, chat, contact.as_ref(), (*msg).context);
}
dc_lot_fill(ret, msg, chat, contact.as_ref(), (*msg).context);
}
}
@@ -1187,7 +1196,7 @@ pub unsafe fn dc_msg_exists(context: &Context, msg_id: uint32_t) -> libc::c_int
pub fn dc_update_msg_move_state(
context: &Context,
rfc724_mid: *const libc::c_char,
state: dc_move_state_t,
state: MoveState,
) -> bool {
// we update the move_state for all messages belonging to a given Message-ID
// so that the state stay intact when parts are deleted

View File

@@ -42,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);
dc_ensure_secret_key_exists(context).ok();
invitenumber = dc_token_lookup(context, DC_TOKEN_INVITENUMBER, group_chat_id);
if invitenumber.is_null() {
invitenumber = dc_create_id().strdup();
@@ -149,7 +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);
dc_ensure_secret_key_exists(context).ok();
ongoing_allocated = dc_alloc_ongoing(context);
if !(ongoing_allocated == 0i32) {
qr_scan = dc_check_qr(context, qr);

View File

@@ -3,19 +3,18 @@ use crate::dc_tools::*;
use crate::x::*;
#[derive(Copy, Clone)]
#[repr(C)]
pub struct dc_simplify_t {
pub is_forwarded: libc::c_int,
pub is_cut_at_begin: libc::c_int,
pub is_cut_at_end: libc::c_int,
pub struct Simplify {
pub is_forwarded: bool,
pub is_cut_at_begin: bool,
pub is_cut_at_end: bool,
}
impl dc_simplify_t {
impl Simplify {
pub fn new() -> Self {
dc_simplify_t {
is_forwarded: 0,
is_cut_at_begin: 0,
is_cut_at_end: 0,
Simplify {
is_forwarded: false,
is_cut_at_begin: false,
is_cut_at_end: false,
}
}
@@ -26,7 +25,7 @@ impl dc_simplify_t {
&mut self,
in_unterminated: *const libc::c_char,
in_bytes: libc::c_int,
is_html: libc::c_int,
is_html: bool,
is_msgrmsg: libc::c_int,
) -> *mut libc::c_char {
if in_bytes <= 0 {
@@ -36,9 +35,9 @@ impl dc_simplify_t {
/* create a copy of the given buffer */
let mut out: *mut libc::c_char;
let mut temp: *mut libc::c_char;
self.is_forwarded = 0i32;
self.is_cut_at_begin = 0i32;
self.is_cut_at_end = 0i32;
self.is_forwarded = false;
self.is_cut_at_begin = false;
self.is_cut_at_end = false;
out = strndup(
in_unterminated as *mut libc::c_char,
in_bytes as libc::c_ulong,
@@ -46,7 +45,7 @@ impl dc_simplify_t {
if out.is_null() {
return dc_strdup(b"\x00" as *const u8 as *const libc::c_char);
}
if 0 != is_html {
if is_html {
temp = dc_dehtml(out);
if !temp.is_null() {
free(out as *mut libc::c_void);
@@ -96,7 +95,7 @@ impl dc_simplify_t {
|| strcmp(line, b"----\x00" as *const u8 as *const libc::c_char) == 0i32
{
footer_mark = 1i32;
self.is_cut_at_end = 1i32
self.is_cut_at_end = true
}
if 0 != footer_mark {
l_last = l;
@@ -115,7 +114,7 @@ impl dc_simplify_t {
&& strncmp(line1, b"From: \x00" as *const u8 as *const libc::c_char, 6) == 0i32
&& *line2.offset(0isize) as libc::c_int == 0i32
{
self.is_forwarded = 1i32;
self.is_forwarded = true;
l_first += 3
}
}
@@ -128,7 +127,7 @@ impl dc_simplify_t {
|| strncmp(line, b"~~~~~\x00" as *const u8 as *const libc::c_char, 5) == 0i32
{
l_last = l;
self.is_cut_at_end = 1i32;
self.is_cut_at_end = true;
/* done */
break;
}
@@ -145,7 +144,7 @@ impl dc_simplify_t {
}
if l_lastQuotedLine.is_some() {
l_last = l_lastQuotedLine.unwrap();
self.is_cut_at_end = 1i32;
self.is_cut_at_end = true;
if l_last > 1 {
if is_empty_line(lines[l_last - 1]) {
l_last -= 1
@@ -180,12 +179,12 @@ impl dc_simplify_t {
}
if l_lastQuotedLine_0.is_some() {
l_first = l_lastQuotedLine_0.unwrap() + 1;
self.is_cut_at_begin = 1i32
self.is_cut_at_begin = true
}
}
/* re-create buffer from the remaining lines */
let mut ret = String::new();
if 0 != self.is_cut_at_begin {
if self.is_cut_at_begin {
ret += "[...]";
}
/* we write empty lines only in case and non-empty line follows */
@@ -211,7 +210,7 @@ impl dc_simplify_t {
pending_linebreaks = 1i32
}
}
if 0 != self.is_cut_at_end && (0 == self.is_cut_at_begin || 0 != content_lines_added) {
if self.is_cut_at_end && (!self.is_cut_at_begin || 0 != content_lines_added) {
ret += " [...]";
}
dc_free_splitted_lines(lines);
@@ -268,11 +267,11 @@ mod tests {
#[test]
fn test_simplify_trim() {
unsafe {
let mut simplify = dc_simplify_t::new();
let mut simplify = Simplify::new();
let html: *const libc::c_char =
b"\r\r\nline1<br>\r\n\r\n\r\rline2\n\r\x00" as *const u8 as *const libc::c_char;
let plain: *mut libc::c_char =
simplify.simplify(html, strlen(html) as libc::c_int, 1, 0);
simplify.simplify(html, strlen(html) as libc::c_int, true, 0);
assert_eq!(
CStr::from_ptr(plain as *const libc::c_char)
@@ -288,11 +287,11 @@ mod tests {
#[test]
fn test_simplify_parse_href() {
unsafe {
let mut simplify = dc_simplify_t::new();
let mut simplify = Simplify::new();
let html: *const libc::c_char =
b"<a href=url>text</a\x00" as *const u8 as *const libc::c_char;
let plain: *mut libc::c_char =
simplify.simplify(html, strlen(html) as libc::c_int, 1, 0);
simplify.simplify(html, strlen(html) as libc::c_int, true, 0);
assert_eq!(
CStr::from_ptr(plain as *const libc::c_char)
@@ -308,12 +307,12 @@ mod tests {
#[test]
fn test_simplify_bold_text() {
unsafe {
let mut simplify = dc_simplify_t::new();
let mut simplify = Simplify::new();
let html: *const libc::c_char =
b"<!DOCTYPE name [<!DOCTYPE ...>]><!-- comment -->text <b><?php echo ... ?>bold</b><![CDATA[<>]]>\x00"
as *const u8 as *const libc::c_char;
let plain: *mut libc::c_char =
simplify.simplify(html, strlen(html) as libc::c_int, 1, 0);
simplify.simplify(html, strlen(html) as libc::c_int, true, 0);
assert_eq!(
CStr::from_ptr(plain as *const libc::c_char)
@@ -329,12 +328,12 @@ mod tests {
#[test]
fn test_simplify_html_encoded() {
unsafe {
let mut simplify = dc_simplify_t::new();
let mut simplify = Simplify::new();
let html: *const libc::c_char =
b"&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, 1, 0);
simplify.simplify(html, strlen(html) as libc::c_int, true, 0);
assert_eq!(
strcmp(plain,

View File

@@ -23,8 +23,21 @@ pub fn dc_exactly_one_bit_set(v: libc::c_int) -> bool {
0 != v && 0 == v & v - 1i32
}
/* string tools */
/* dc_strdup() returns empty string if NULL is given, never returns NULL (exits on errors) */
/// Duplicates a string
///
/// returns an empty string if NULL is given, never returns NULL (exits on errors)
///
/// # Examples
///
/// ```
/// use deltachat::dc_tools::{dc_strdup, to_string};
/// unsafe {
/// let str_a = b"foobar\x00" as *const u8 as *const libc::c_char;
/// let str_a_copy = dc_strdup(str_a);
/// assert_eq!(to_string(str_a_copy), "foobar");
/// assert_ne!(str_a, str_a_copy);
/// }
/// ```
pub unsafe fn dc_strdup(s: *const libc::c_char) -> *mut libc::c_char {
let ret: *mut libc::c_char;
if !s.is_null() {
@@ -38,7 +51,21 @@ pub unsafe fn dc_strdup(s: *const libc::c_char) -> *mut libc::c_char {
ret
}
/* strdup(NULL) is undefined, safe_strdup_keep_null(NULL) returns NULL in this case */
/// Duplicates a string, returns null if given string is null
///
/// # Examples
///
/// ```
/// use deltachat::dc_tools::{dc_strdup_keep_null, to_string};
/// use std::ffi::{CStr};
///
/// unsafe {
/// let str_a = b"foobar\x00" as *const u8 as *const libc::c_char;
/// let str_a_copy = dc_strdup_keep_null(str_a);
/// assert_eq!(to_string(str_a_copy), "foobar");
/// assert_ne!(str_a, str_a_copy);
/// }
/// ```
pub unsafe fn dc_strdup_keep_null(s: *const libc::c_char) -> *mut libc::c_char {
return if !s.is_null() {
dc_strdup(s)
@@ -67,50 +94,14 @@ pub unsafe fn dc_str_replace(
haystack: *mut *mut libc::c_char,
needle: *const libc::c_char,
replacement: *const libc::c_char,
) -> libc::c_int {
let mut replacements: libc::c_int = 0i32;
let mut start_search_pos: libc::c_int = 0i32;
let needle_len: libc::c_int;
let replacement_len: libc::c_int;
if haystack.is_null()
|| (*haystack).is_null()
|| needle.is_null()
|| *needle.offset(0isize) as libc::c_int == 0i32
{
return 0i32;
}
needle_len = strlen(needle) as libc::c_int;
replacement_len = (if !replacement.is_null() {
strlen(replacement)
} else {
0
}) as libc::c_int;
loop {
let mut p2: *mut libc::c_char =
strstr((*haystack).offset(start_search_pos as isize), needle);
if p2.is_null() {
break;
}
start_search_pos =
(p2.wrapping_offset_from(*haystack) + replacement_len as isize) as libc::c_int;
*p2 = 0i32 as libc::c_char;
p2 = p2.offset(needle_len as isize);
let new_string: *mut libc::c_char = dc_mprintf(
b"%s%s%s\x00" as *const u8 as *const libc::c_char,
*haystack,
if !replacement.is_null() {
replacement
} else {
b"\x00" as *const u8 as *const libc::c_char
},
p2,
);
free(*haystack as *mut libc::c_void);
*haystack = new_string;
replacements += 1
}
) {
let haystack_s = to_string(*haystack);
let needle_s = to_string(needle);
let replacement_s = to_string(replacement);
replacements
free(*haystack as *mut libc::c_void);
*haystack = haystack_s.replace(&needle_s, &replacement_s).strdup();
}
pub unsafe fn dc_ftoa(f: libc::c_double) -> *mut libc::c_char {
@@ -1086,21 +1077,20 @@ pub unsafe fn dc_get_abs_path(
pathNfilename_abs
}
pub fn dc_file_exist(context: &Context, path: *const libc::c_char) -> libc::c_int {
dc_get_abs_path_safe(context, as_path(path)).exists() as libc::c_int
pub fn dc_file_exist(context: &Context, path: impl AsRef<std::path::Path>) -> bool {
dc_get_abs_path_safe(context, &path).exists()
}
pub fn dc_get_filebytes(context: &Context, path: *const libc::c_char) -> uint64_t {
let path_abs = dc_get_abs_path_safe(context, as_path(path));
pub fn dc_get_filebytes(context: &Context, path: impl AsRef<std::path::Path>) -> uint64_t {
let path_abs = dc_get_abs_path_safe(context, &path);
match fs::metadata(&path_abs) {
Ok(meta) => meta.len() as uint64_t,
Err(_err) => 0,
}
}
pub fn dc_delete_file(context: &Context, path: *const libc::c_char) -> libc::c_int {
let path = as_path(path);
let path_abs = dc_get_abs_path_safe(context, path);
pub fn dc_delete_file(context: &Context, path: impl AsRef<std::path::Path>) -> bool {
let path_abs = dc_get_abs_path_safe(context, &path);
let res = if path_abs.is_file() {
fs::remove_file(path_abs)
} else {
@@ -1108,56 +1098,53 @@ pub fn dc_delete_file(context: &Context, path: *const libc::c_char) -> libc::c_i
};
match res {
Ok(_) => 1,
Ok(_) => true,
Err(_err) => {
warn!(context, 0, "Cannot delete \"{}\".", path.display());
0
warn!(context, 0, "Cannot delete \"{}\".", path.as_ref().display());
false
}
}
}
pub fn dc_copy_file(
context: &Context,
src: *const libc::c_char,
dest: *const libc::c_char,
) -> libc::c_int {
let src = as_path(src);
let dest = as_path(dest);
let src_abs = dc_get_abs_path_safe(context, src);
let dest_abs = dc_get_abs_path_safe(context, dest);
src: impl AsRef<std::path::Path>,
dest: impl AsRef<std::path::Path>,
) -> bool {
let src_abs = dc_get_abs_path_safe(context, &src);
let dest_abs = dc_get_abs_path_safe(context, &dest);
match fs::copy(&src_abs, &dest_abs) {
Ok(_) => 1,
Ok(_) => true,
Err(_) => {
error!(
context,
0,
"Cannot copy \"{}\" to \"{}\".",
src.display(),
dest.display(),
src.as_ref().display(),
dest.as_ref().display(),
);
0
false
}
}
}
pub fn dc_create_folder(context: &Context, path: *const libc::c_char) -> libc::c_int {
let path = as_path(path);
let path_abs = dc_get_abs_path_safe(context, path);
pub fn dc_create_folder(context: &Context, path: impl AsRef<std::path::Path>) -> bool {
let path_abs = dc_get_abs_path_safe(context, &path);
if !path_abs.exists() {
match fs::create_dir_all(path_abs) {
Ok(_) => 1,
Ok(_) => true,
Err(_err) => {
warn!(
context,
0,
"Cannot create directory \"{}\".",
path.display(),
path.as_ref().display(),
);
0
false
}
}
} else {
1
true
}
}
@@ -1266,7 +1253,7 @@ pub unsafe fn dc_get_fine_pathNfilename(
dotNSuffix,
)
}
if 0 == dc_file_exist(context, ret) {
if !dc_file_exist(context, as_path(ret)) {
/* fine filename found */
break;
} else {
@@ -1320,7 +1307,7 @@ pub unsafe fn dc_make_rel_and_copy(context: &Context, path: *mut *mut libc::c_ch
);
blobdir_path.is_null()
}
|| 0 == dc_copy_file(context, *path, blobdir_path))
|| !dc_copy_file(context, as_path(*path), as_path(blobdir_path)))
{
free(*path as *mut libc::c_void);
*path = blobdir_path;
@@ -1462,9 +1449,9 @@ pub trait StrExt {
///
/// This allocates a new raw C string which must be freed using
/// `free`. It takes care of some common pitfalls with using
/// [CString::as_ptr].
/// [CString.as_ptr].
///
/// [CString::as_ptr]: std::ffi::CString::as_ptr
/// [CString.as_ptr]: std::ffi::CString.as_ptr
///
/// # Panics
///
@@ -1573,6 +1560,49 @@ mod tests {
use super::*;
use std::ffi::CStr;
#[test]
fn test_dc_strdup() {
unsafe {
let str_a = b"foobar\x00" as *const u8 as *const libc::c_char;
let str_a_copy = dc_strdup(str_a);
// Value of str_a_copy should equal foobar
assert_eq!(
CStr::from_ptr(str_a_copy),
CString::new("foobar").unwrap().as_c_str()
);
// Address of str_a should be different from str_a_copy
assert_ne!(str_a, str_a_copy);
let str_a = std::ptr::null() as *const libc::c_char;
let str_a_copy = dc_strdup(str_a);
// Value of str_a_copy should equal ""
assert_eq!(
CStr::from_ptr(str_a_copy),
CString::new("").unwrap().as_c_str()
);
assert_ne!(str_a, str_a_copy);
}
}
#[test]
fn test_dc_strdup_keep_null() {
unsafe {
let str_a = b"foobar\x00" as *const u8 as *const libc::c_char;
let str_a_copy = dc_strdup_keep_null(str_a);
assert_eq!(
CStr::from_ptr(str_a_copy),
CString::new("foobar").unwrap().as_c_str()
);
assert_ne!(str_a, str_a_copy);
let str_a = 0 as *const u8 as *const libc::c_char;
let str_a_copy = dc_strdup_keep_null(str_a);
assert_eq!(str_a.is_null(), true);
assert_eq!(str_a_copy.is_null(), true);
}
}
#[test]
fn test_dc_ltrim() {
unsafe {
@@ -1647,7 +1677,7 @@ mod tests {
fn test_dc_str_replace() {
unsafe {
let mut str: *mut libc::c_char = strdup(b"aaa\x00" as *const u8 as *const libc::c_char);
let replacements: libc::c_int = dc_str_replace(
dc_str_replace(
&mut str,
b"a\x00" as *const u8 as *const libc::c_char,
b"ab\x00" as *const u8 as *const libc::c_char,
@@ -1656,7 +1686,6 @@ mod tests {
CStr::from_ptr(str as *const libc::c_char).to_str().unwrap(),
"ababab"
);
assert_eq!(replacements, 3);
free(str as *mut libc::c_void);
}
}
@@ -2085,5 +2114,4 @@ mod tests {
let grpid = dc_extract_grpid_from_rfc724_mid(mid);
assert_eq!(grpid, Some("1234567890123456"));
}
}

View File

@@ -166,7 +166,6 @@ impl<'a> Peerstate<'a> {
pub fn from_addr(context: &'a Context, _sql: &Sql, addr: &str) -> Option<Self> {
let query = "SELECT addr, last_seen, last_seen_autocrypt, prefer_encrypted, public_key, gossip_timestamp, gossip_key, public_key_fingerprint, gossip_key_fingerprint, verified_key, verified_key_fingerprint FROM acpeerstates WHERE addr=? COLLATE NOCASE;";
Self::from_stmt(context, query, &[addr])
}
@@ -191,6 +190,11 @@ impl<'a> Peerstate<'a> {
context
.sql
.query_row(query, params, |row| {
/* all the above queries start with this: SELECT
addr, last_seen, last_seen_autocrypt, prefer_encrypted,
public_key, gossip_timestamp, gossip_key, public_key_fingerprint,
gossip_key_fingerprint, verified_key, verified_key_fingerprint
*/
let mut res = Self::new(context);
res.addr = Some(row.get(0)?);
@@ -198,13 +202,34 @@ impl<'a> Peerstate<'a> {
res.last_seen_autocrypt = row.get(2)?;
res.prefer_encrypt = EncryptPreference::from_i32(row.get(3)?).unwrap_or_default();
res.gossip_timestamp = row.get(5)?;
let pkf: String = row.get(7)?;
res.public_key_fingerprint = if pkf.is_empty() { None } else { Some(pkf) };
let gkf: String = row.get(8)?;
res.gossip_key_fingerprint = if gkf.is_empty() { None } else { Some(gkf) };
let vkf: String = row.get(10)?;
res.verified_key_fingerprint = if vkf.is_empty() { None } else { Some(vkf) };
res.public_key_fingerprint = row.get(7)?;
if res
.public_key_fingerprint
.as_ref()
.map(|s| s.is_empty())
.unwrap_or_default()
{
res.public_key_fingerprint = None;
}
res.gossip_key_fingerprint = row.get(8)?;
if res
.gossip_key_fingerprint
.as_ref()
.map(|s| s.is_empty())
.unwrap_or_default()
{
res.gossip_key_fingerprint = None;
}
res.verified_key_fingerprint = row.get(10)?;
if res
.verified_key_fingerprint
.as_ref()
.map(|s| s.is_empty())
.unwrap_or_default()
{
res.verified_key_fingerprint = None;
}
res.public_key = row
.get(4)
.ok()
@@ -217,7 +242,8 @@ impl<'a> Peerstate<'a> {
.get(9)
.ok()
.and_then(|blob: Vec<u8>| Key::from_slice(&blob, KeyType::Public));
res.verified_key = if vk == res.gossip_key {
res.verified_key = if vk == res.gossip_key && res.gossip_key.is_some() {
VerifiedKey::Gossip
} else if vk == res.public_key {
VerifiedKey::Public
@@ -422,6 +448,7 @@ impl<'a> Peerstate<'a> {
&self.addr,
],
).is_ok();
assert_eq!(success, true);
} else if self.to_save == Some(ToSave::Timestamps) {
success = sql::execute(
self.context,
@@ -498,6 +525,40 @@ mod tests {
assert_eq!(peerstate, peerstate_new);
}
#[test]
fn test_peerstate_with_empty_gossip_key_save_to_db() {
let ctx = crate::test_utils::dummy_context();
let addr = "hello@mail.com";
let pub_key = crate::key::Key::from_base64("xsBNBFztUVkBCADYaQl/UOUpRPd32nLRzx8eU0eI+jQEnG+g5anjYA+3oct1rROGl5SygjMULDKdaUy27O3o9Srsti0YjA7uxZnavIqhSopJhFidqY1M1wA9JZa/duucZdNwUGbjGIRsS/4Cjr5+3svscK24hVYub1dvDWXpwUTnj3K6xOEnJdoM+MhCqtSD5+zcJhFc9vyZm9ZTGWUxAhKh0iJTcCD8V6CQ3XZ2z9GruwzZT/FTFovWrz7m3TUI2OdSSHh0eZLRGEoxMCT/vzflAFGAr8ijCaRsEIfqP6FW8uQWnFTqkjxEUCZG6XkeFHB84aj5jqYG/1KCLjL5vEKwfl1tz/WnPhY7ABEBAAHNEDxoZWxsb0BtYWlsLmNvbT7CwIkEEAEIADMCGQEFAlztUVoCGwMECwkIBwYVCAkKCwIDFgIBFiEEgMjHGVbvLXe6ioRROg8oKCvye7gACgkQOg8oKCvye7ijAwf+PTsuawUax9cNPn1bN90H+g9qyHZJMEwKXtUnNaXJxPW3iB7ThhpCiCzsZwP7+l7ArS8tmLeNDw2bENtcf1XCv4wovP2fdXOP3QOUUFX/GdakcTwv7DzC7CO0grB1HtaPhGw/6UX2o2cx2i9xiUf4Givq2MfCbgAW5zloH6WXGPb6yLQYJXxqDIphr4+uZDb+bMAyWHN/DUkAjHrV8nnVki7PMHqzzZpwglalxMX8RGeiGZE39ALJKL/Og87DMFah87/yoxQWGoS7Wqv0XDcCPKoTCPrpk8pOe2KEsq/lz215nefHd4aRpfUX5YCYa8HPvvfPQbGF73uvyQw5w7qjis7ATQRc7VFZAQgAt8ONdnX6KEEQ5Jw6ilJ+LBtY44SP5t0I3eK+goKepgIiKhjGDa+Mntyi4jdhH+HO6kvK5SHMh2sPp4rRO/WKHJwWFySyM1OdyiywhyH0J9R5rBY4vPHsJjf6vSKJdWLWT+ho1fNet2IIC+jVCYli91MAMbRvk6EKVj1nCc+67giOahXEkHt6xxkeCGlOvbw8hxGj1A8+AC1BLms/OR3oc4JMi9O3kq6uG0z9tlUEerac9HVwcjoO1XLe+hJhoT5H+TbnGjPuhuURP3pFiIKHpbRYgUfdSAY0dTObO7t4I5y/drPOrCTnWrBUg2wXAECUhpRKow9/ai2YemLv9KqhhwARAQABwsB2BBgBCAAgBQJc7VFaAhsMFiEEgMjHGVbvLXe6ioRROg8oKCvye7gACgkQOg8oKCvye7jmyggAhs4QzCzIbT2OsAReBxkxtm0AI+g1HZ1KFKof5NDHfgv9C/Qu1I8mKEjlZzA4qFyPmLqntgwJ0RuFy6gLbljZBNCFO7vB478AhYtnWjuKZmA40HUPwcB1hEJ31c42akzfUbioY1TLLepngdsJg7Cm8O+rhI9+1WRA66haJDgFs793SVUDyJh8f9NX50l5zR87/bsV30CFSw0q4OSSy9VI/z+2g5khn1LnuuOrCfFnYIPYtJED1BfkXkosxGlgbzy79VvGmI9d23x4atDK7oBPCzIj+lP8sytJ0u3HOguXi9OgDitKy+Pt1r8gH8frdktMJr5Ts6DW+tIn2vR23KR8aA==", KeyType::Public).unwrap();
let mut peerstate = Peerstate {
context: &ctx.ctx,
addr: Some(addr.into()),
last_seen: 10,
last_seen_autocrypt: 11,
prefer_encrypt: EncryptPreference::Mutual,
public_key: Some(pub_key.clone()),
public_key_fingerprint: Some(pub_key.fingerprint()),
gossip_key: None,
gossip_timestamp: 12,
gossip_key_fingerprint: None,
verified_key: VerifiedKey::None,
verified_key_fingerprint: None,
to_save: Some(ToSave::All),
degrade_event: None,
};
assert!(peerstate.save_to_db(&ctx.ctx.sql, true), "failed to save");
let peerstate_new = Peerstate::from_addr(&ctx.ctx, &ctx.ctx.sql, addr.into())
.expect("failed to load peerstate from db");
// clear to_save, as that is not persissted
peerstate.to_save = None;
assert_eq!(peerstate, peerstate_new);
}
// TODO: don't copy this from stress.rs
#[allow(dead_code)]
struct TestContext {

View File

@@ -4,7 +4,6 @@ use std::sync::{Arc, RwLock};
use rusqlite::{Connection, OpenFlags, Statement, NO_PARAMS};
use thread_local_object::ThreadLocal;
use crate::constants::*;
use crate::context::Context;
use crate::dc_tools::*;
use crate::error::{Error, Result};
@@ -689,10 +688,6 @@ fn open(
"ALTER TABLE msgs ADD COLUMN move_state INTEGER DEFAULT 1;",
params![],
)?;
assert_eq!(DC_MOVE_STATE_UNDEFINED as libc::c_int, 0);
assert_eq!(DC_MOVE_STATE_PENDING as libc::c_int, 1);
assert_eq!(DC_MOVE_STATE_STAY as libc::c_int, 2);
assert_eq!(DC_MOVE_STATE_MOVING as libc::c_int, 3);
dbversion = 48;
sql.set_config_int(context, "dbversion", 48)?;
@@ -1047,8 +1042,8 @@ pub fn housekeeping(context: &Context) {
unreferenced_count,
entry.file_name()
);
let path = entry.path().to_c_string().unwrap();
dc_delete_file(context, path.as_ptr());
let path = entry.path();
dc_delete_file(context, path);
}
}
Err(err) => {

View File

@@ -2,9 +2,15 @@
//!
//! This module is only compiled for test runs.
use std::ffi::CStr;
use libc::uintptr_t;
use tempfile::{tempdir, TempDir};
use crate::config::Config;
use crate::constants::{Event, KeyType};
use crate::context::{dc_context_new, dc_open, Context};
use crate::key;
use crate::types::dc_callback_t;
/// A Context and temporary directory.
@@ -44,3 +50,127 @@ pub fn test_context(cb: Option<dc_callback_t>) -> TestContext {
pub fn dummy_context() -> TestContext {
test_context(None)
}
pub unsafe extern "C" fn logging_cb(
_ctx: &Context,
evt: Event,
_d1: uintptr_t,
d2: uintptr_t,
) -> uintptr_t {
let to_str = |x| CStr::from_ptr(x as *const libc::c_char).to_str().unwrap();
match evt {
Event::INFO => println!("I: {}", to_str(d2)),
Event::WARNING => println!("W: {}", to_str(d2)),
Event::ERROR => println!("E: {}", to_str(d2)),
_ => (),
}
0
}
/// Creates Alice with a pre-generated keypair.
///
/// Returns the address of the keypair created (alice@example.org).
pub fn configure_alice_keypair(ctx: &Context) -> String {
let addr = String::from("alice@example.org");
ctx.set_config(Config::ConfiguredAddr, Some(&addr)).unwrap();
// The keypair was created using:
// let (public, private) = crate::pgp::dc_pgp_create_keypair("alice@example.com")
// .unwrap();
// println!("{}", public.to_base64(64));
// println!("{}", private.to_base64(64));
let public = key::Key::from_base64(
concat!(
"xsBNBF086ewBCACmJKuoxIO6T87yi4Q3MyNpMch3Y8KrtHDQyUszU36eqM3Pmd1l",
"FrbcCd8ZWo2pq6OJSwsM/jjRGn1zo2YOaQeJRRrC+KrKGqSUtRSYQBPrPjE2YjSX",
"AMbu8jBI6VVUhHeghriBkK79PY9O/oRhIJC0p14IJe6CQ6OI2fTmTUHF9i/nJ3G4",
"Wb3/K1bU3yVfyPZjTZQPYPvvh03vxHULKurtYkX5DTEMSWsF4qzLMps+l87VuLV9",
"iQnbN7YMRLHHx2KkX5Ivi7JCefhCa54M0K3bDCCxuVWAM5wjQwNZjzR+WL+dYchw",
"oFvuF8NrlzjM9dSv+2rn+J7f99ijSXarzPC7ABEBAAHNEzxhbGljZUBleGFtcGxl",
"LmNvbT7CwIkEEAEIADMCGQEFAl086fgCGwMECwkIBwYVCAkKCwIDFgIBFiEE+iai",
"x4d0doj87Q0ek6DcNkbrcegACgkQk6DcNkbrcei3ogf/cruUmQ+th52TFHTHdkw9",
"OHUl3MrXtZ7QmHyOAFvbXE/6n5Eeh+eZoF8MWWV72m14Wbs+vTcNQkFVTdOPptkK",
"A8e4cJqwDOHsyAnvQXZ7WNje9+BMzcoipIUawHP4ORFaPDsKLZQ0b4wBbKn8ziea",
"6zjGF0/qljTdoxTtsYpv5wXYuhwbYklrLOqgSa5M7LXUe7E3g9mbg+9iX1GuB8m6",
"GkquJN814Y+xny4xhZzGOfue6SeP12jJMNSjSP7416dRq7794VGnkkW9V/7oFEUK",
"u5wO9FFbgDySOSlEjByGejSGuBmho0iJSjcPjZ7EY/j3M3orq4dpza5C82OeSvxD",
"Fc7ATQRdPOnsAQgA5oLxXRLnyugzOmNCy7dxV3JrDZscA6JNlJlDWIShT0YSs+zG",
"9JzDeQql+sYXgUSxOoIayItuXtnFn7tstwGoOnYvadm/e5/7V5fKAQRtCtdN51av",
"62n18Venlm0yNKpROPcZ6M/sc4m6uU6YRZ/a1idal8VGY0wLKlghjIBuIiBoVQ/R",
"noW+/fhmwIg08dQ5m8hQe3GEOZEeLrTWL/9awPlXK7Y+DmJOoR4qbHWEcRfbzS6q",
"4zW8vk2ztB8ngwbnqYy8zrN1DCICN1gYdlU++uVw6Bb1XfY8Cdldh1VLKpF35mAm",
"jxLZfVDcoObFH3Cv2GB7BEYxv86KC2Y6T74Q/wARAQABwsB2BBgBCAAgBQJdPOn4",
"AhsMFiEE+iaix4d0doj87Q0ek6DcNkbrcegACgkQk6DcNkbrcegLxwf/dXshJnoW",
"qEnRsf6rVb9/Mc66ti+NVQLfNd275dybh/QIJdK3NmSxdnTPIEJRVspJywJoupwX",
"FNrnHG2Ff6QPvHqI+/oNu986r9d7Z1oQibbLHKt8t6kpOfg/xGxotagJuiCQvR9m",
"MjD1DqsdB37SjDxGupZOOJSXWi6KX60IE+uM+QOBfeOZziQwuFmA5wV6RDXIeYJf",
"qrcbeXeR1d0nfNpPHQR1gBiqmxNb6KBbdXD2+EXW60axC7D2b1APmzMlammDliPw",
"sK9U1rc9nuquEBvGDOJf4K+Dzn+mDCqRpP6uAuQ7RKHyim4uyN0wwKObzPqgJCGw",
"jTglkixw+aSTXw=="
),
KeyType::Public,
)
.unwrap();
let private = key::Key::from_base64(
concat!(
"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",
"zPqgJCGwjTglkixw+aSTXw=="
),
KeyType::Private,
)
.unwrap();
let saved = key::dc_key_save_self_keypair(&ctx, &public, &private, &addr, 1, &ctx.sql);
assert_eq!(saved, true, "Failed to save Alice's key");
addr
}

View File

@@ -16,8 +16,6 @@ pub use rusqlite::ffi::*;
pub type dc_callback_t =
unsafe extern "C" fn(_: &Context, _: Event, _: uintptr_t, _: uintptr_t) -> uintptr_t;
pub type dc_move_state_t = u32;
pub type dc_receive_imf_t = unsafe fn(
_: &Context,
_: *const libc::c_char,

View File

@@ -57,39 +57,15 @@ unsafe fn stress_functions(context: &Context) {
);
if 0 != dc_is_open(context) {
if 0 != dc_file_exist(
context,
b"$BLOBDIR/foobar\x00" as *const u8 as *const libc::c_char,
) || 0
!= dc_file_exist(
context,
b"$BLOBDIR/dada\x00" as *const u8 as *const libc::c_char,
)
|| 0 != dc_file_exist(
context,
b"$BLOBDIR/foobar.dadada\x00" as *const u8 as *const libc::c_char,
)
|| 0 != dc_file_exist(
context,
b"$BLOBDIR/foobar-folder\x00" as *const u8 as *const libc::c_char,
)
if dc_file_exist(context, "$BLOBDIR/foobar")
|| dc_file_exist(context, "$BLOBDIR/dada")
|| dc_file_exist(context, "$BLOBDIR/foobar.dadada")
|| dc_file_exist(context, "$BLOBDIR/foobar-folder")
{
dc_delete_file(
context,
b"$BLOBDIR/foobar\x00" as *const u8 as *const libc::c_char,
);
dc_delete_file(
context,
b"$BLOBDIR/dada\x00" as *const u8 as *const libc::c_char,
);
dc_delete_file(
context,
b"$BLOBDIR/foobar.dadada\x00" as *const u8 as *const libc::c_char,
);
dc_delete_file(
context,
b"$BLOBDIR/foobar-folder\x00" as *const u8 as *const libc::c_char,
);
dc_delete_file(context, "$BLOBDIR/foobar");
dc_delete_file(context, "$BLOBDIR/dada");
dc_delete_file(context, "$BLOBDIR/foobar.dadada");
dc_delete_file(context, "$BLOBDIR/foobar-folder");
}
dc_write_file(
context,
@@ -97,25 +73,10 @@ unsafe fn stress_functions(context: &Context) {
b"content\x00" as *const u8 as *const libc::c_char as *const libc::c_void,
7i32 as size_t,
);
assert_ne!(
0,
dc_file_exist(
context,
b"$BLOBDIR/foobar\x00" as *const u8 as *const libc::c_char,
)
);
assert!(dc_file_exist(context, "$BLOBDIR/foobar",));
assert!(!dc_file_exist(context, "$BLOBDIR/foobarx"));
assert_eq!(
0,
dc_file_exist(
context,
b"$BLOBDIR/foobarx\x00" as *const u8 as *const libc::c_char,
)
);
assert_eq!(
dc_get_filebytes(
context,
b"$BLOBDIR/foobar\x00" as *const u8 as *const libc::c_char,
),
dc_get_filebytes(context, "$BLOBDIR/foobar",),
7i32 as libc::c_ulonglong
);
@@ -133,23 +94,10 @@ unsafe fn stress_functions(context: &Context) {
context,
b"/BLOBDIR/fofo\x00" as *const u8 as *const libc::c_char,
));
assert_ne!(0, dc_file_exist(context, abs_path));
assert!(dc_file_exist(context, as_path(abs_path)));
free(abs_path as *mut libc::c_void);
assert_ne!(
0,
dc_copy_file(
context,
b"$BLOBDIR/foobar\x00" as *const u8 as *const libc::c_char,
b"$BLOBDIR/dada\x00" as *const u8 as *const libc::c_char,
)
);
assert_eq!(
dc_get_filebytes(
context,
b"$BLOBDIR/dada\x00" as *const u8 as *const libc::c_char,
),
7
);
assert!(dc_copy_file(context, "$BLOBDIR/foobar", "$BLOBDIR/dada",));
assert_eq!(dc_get_filebytes(context, "$BLOBDIR/dada",), 7);
let mut buf: *mut libc::c_void = 0 as *mut libc::c_void;
let mut buf_bytes: size_t = 0;
@@ -170,41 +118,11 @@ unsafe fn stress_functions(context: &Context) {
);
free(buf as *mut _);
assert_ne!(
0,
dc_delete_file(
context,
b"$BLOBDIR/foobar\x00" as *const u8 as *const libc::c_char,
)
);
assert_ne!(
0,
dc_delete_file(
context,
b"$BLOBDIR/dada\x00" as *const u8 as *const libc::c_char,
)
);
assert_ne!(
0,
dc_create_folder(
context,
b"$BLOBDIR/foobar-folder\x00" as *const u8 as *const libc::c_char,
)
);
assert_ne!(
0,
dc_file_exist(
context,
b"$BLOBDIR/foobar-folder\x00" as *const u8 as *const libc::c_char,
)
);
assert_ne!(
0,
dc_delete_file(
context,
b"$BLOBDIR/foobar-folder\x00" as *const u8 as *const libc::c_char,
)
);
assert!(dc_delete_file(context, "$BLOBDIR/foobar"));
assert!(dc_delete_file(context, "$BLOBDIR/dada"));
assert!(dc_create_folder(context, "$BLOBDIR/foobar-folder"));
assert!(dc_file_exist(context, "$BLOBDIR/foobar-folder",));
assert!(dc_delete_file(context, "$BLOBDIR/foobar-folder"));
let fn0: *mut libc::c_char = dc_get_fine_pathNfilename(
context,
b"$BLOBDIR\x00" as *const u8 as *const libc::c_char,
@@ -237,7 +155,7 @@ unsafe fn stress_functions(context: &Context) {
),
0
);
assert_ne!(0, dc_delete_file(context, fn0));
assert!(dc_delete_file(context, as_path(fn0)));
free(fn0 as *mut libc::c_void);
free(fn1 as *mut libc::c_void);
}