Merge branch 'master' into eventlogging

This commit is contained in:
holger krekel
2019-07-18 09:59:44 +02:00
51 changed files with 10277 additions and 9595 deletions

View File

@@ -127,26 +127,26 @@ jobs:
machine: True
steps:
- checkout
# - run: docker pull deltachat/doxygen
# - run: docker pull deltachat/doxygen
- run: docker pull deltachat/coredeps
- run:
name: build docs, run tests and build wheels
- run:
name: build docs, run tests and build wheels
command: ci_scripts/ci_run.sh
environment:
TESTS: 1
DOCS: 1
- run:
name: copying docs and wheels to workspace
- run:
name: copying docs and wheels to workspace
command: |
mkdir -p workspace/python
# cp -av docs workspace/c-docs
cp -av python/.docker-tox/wheelhouse workspace/
cp -av python/doc/_build/ workspace/py-docs
- persist_to_workspace:
root: workspace
paths:
- persist_to_workspace:
root: workspace
paths:
# - c-docs
- py-docs
- wheelhouse
@@ -157,7 +157,7 @@ jobs:
- checkout
- attach_workspace:
at: workspace
- run: ls -laR workspace
- run: ls -laR workspace
- run: ci_scripts/ci_upload.sh workspace/py-docs workspace/wheelhouse
@@ -175,12 +175,17 @@ workflows:
requires:
- cargo_fetch
# Linux Desktop
# Linux Desktop 64bit
- test_x86_64-unknown-linux-gnu:
requires:
- cargo_fetch
# Linux Desktop
# Linux Desktop 32bit
# - test_i686-unknown-linux-gnu:
# requires:
# - cargo_fetch
# Android 64bit
# - test_aarch64-linux-android:
# requires:
# - cargo_fetch

3
.gitignore vendored
View File

@@ -1,6 +1,5 @@
/target
**/*.rs.bk
Cargo.lock
# ignore vi temporaries
*~
@@ -17,3 +16,5 @@ python/.tox
*.egg-info
__pycache__
python/src/deltachat/capi*.so
python/liveconfig*

2918
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
[package]
name = "deltachat"
version = "1.0.0-alpha.2"
version = "1.0.0-alpha.3"
authors = ["dignifiedquire <dignifiedquire@gmail.com>"]
edition = "2018"
license = "MPL"
@@ -16,7 +16,6 @@ hex = "0.3.2"
sha2 = "0.8.0"
rand = "0.6.5"
smallvec = "0.6.9"
libsqlite3-sys = { version = "0.14.0", features = ["bundled", "min_sqlite_version_3_7_16"] }
reqwest = "0.9.15"
num-derive = "0.2.5"
num-traits = "0.2.6"
@@ -36,6 +35,12 @@ failure_derive = "0.1.5"
rustyline = "4.1.0"
lazy_static = "1.3.0"
regex = "1.1.6"
rusqlite = { version = "0.19", features = ["bundled"] }
addr = "0.2.0"
r2d2_sqlite = "0.11.0"
r2d2 = "0.8.5"
strum = "0.15.0"
strum_macros = "0.15.0"
[dev-dependencies]
tempfile = "3.0"

View File

@@ -1,11 +1,10 @@
environment:
matrix:
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
TARGET: x86_64-pc-windows-msvc
install:
- appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe
- rustup-init -yv --default-host %target% --default-toolchain none
- rustup-init -yv --default-toolchain nightly-2019-07-10
- set PATH=%PATH%;%USERPROFILE%\.cargo\bin
- rustc -vV
- cargo -vV
@@ -14,7 +13,7 @@ install:
build: false
test_script:
- cargo test --release
- cargo test --release
cache:
- target

View File

@@ -1,6 +1,6 @@
[package]
name = "deltachat_ffi"
version = "1.0.0-alpha.1"
version = "1.0.0-alpha.3"
description = "Deltachat FFI"
authors = ["dignifiedquire <dignifiedquire@gmail.com>"]
edition = "2018"

View File

@@ -10,6 +10,8 @@
#[macro_use]
extern crate human_panic;
use std::str::FromStr;
use deltachat::*;
// TODO: constants
@@ -88,9 +90,13 @@ pub unsafe extern "C" fn dc_set_config(
value: *mut libc::c_char,
) -> libc::c_int {
assert!(!context.is_null());
assert!(!key.is_null(), "invalid key");
let context = &*context;
context::dc_set_config(context, key, value)
match config::Config::from_str(dc_tools::as_str(key)) {
Ok(key) => context.set_config(key, as_opt_str(value)).is_ok() as libc::c_int,
Err(_) => 0,
}
}
#[no_mangle]
@@ -99,9 +105,16 @@ pub unsafe extern "C" fn dc_get_config(
key: *mut libc::c_char,
) -> *mut libc::c_char {
assert!(!context.is_null());
assert!(!key.is_null(), "invalid key");
let context = &*context;
context::dc_get_config(context, key)
match config::Config::from_str(dc_tools::as_str(key)) {
Ok(key) => {
let value = context.get_config(key).unwrap_or_default();
into_cstring(value)
}
Err(_) => std::ptr::null_mut(),
}
}
#[no_mangle]
@@ -411,7 +424,7 @@ pub unsafe extern "C" fn dc_marknoticed_chat(context: *mut dc_context_t, chat_id
assert!(!context.is_null());
let context = &*context;
dc_chat::dc_marknoticed_chat(context, chat_id)
dc_chat::dc_marknoticed_chat(context, chat_id);
}
#[no_mangle]
@@ -419,7 +432,7 @@ pub unsafe extern "C" fn dc_marknoticed_all_chats(context: *mut dc_context_t) {
assert!(!context.is_null());
let context = &*context;
dc_chat::dc_marknoticed_all_chats(context)
dc_chat::dc_marknoticed_all_chats(context);
}
#[no_mangle]
@@ -460,7 +473,7 @@ pub unsafe extern "C" fn dc_archive_chat(
assert!(!context.is_null());
let context = &*context;
dc_chat::dc_archive_chat(context, chat_id, archive)
dc_chat::dc_archive_chat(context, chat_id, archive);
}
#[no_mangle]
@@ -468,7 +481,8 @@ pub unsafe extern "C" fn dc_delete_chat(context: *mut dc_context_t, chat_id: u32
assert!(!context.is_null());
let context = &*context;
dc_chat::dc_delete_chat(context, chat_id)
// TODO: update to indiciate public api success/failure of deletion
dc_chat::dc_delete_chat(context, chat_id);
}
#[no_mangle]
@@ -641,7 +655,7 @@ pub unsafe extern "C" fn dc_markseen_msgs(
assert!(!context.is_null());
let context = &*context;
dc_msg::dc_markseen_msgs(context, msg_ids, msg_cnt)
dc_msg::dc_markseen_msgs(context, msg_ids, msg_cnt as usize);
}
#[no_mangle]
@@ -654,7 +668,7 @@ pub unsafe extern "C" fn dc_star_msgs(
assert!(!context.is_null());
let context = &*context;
dc_msg::dc_star_msgs(context, msg_ids, msg_cnt, star)
dc_msg::dc_star_msgs(context, msg_ids, msg_cnt, star);
}
#[no_mangle]
@@ -887,7 +901,7 @@ pub unsafe extern "C" fn dc_is_sending_locations_to_chat(
assert!(!context.is_null());
let context = &*context;
dc_location::dc_is_sending_locations_to_chat(context, chat_id)
dc_location::dc_is_sending_locations_to_chat(context, chat_id) as libc::c_int
}
#[no_mangle]
@@ -928,7 +942,7 @@ pub unsafe extern "C" fn dc_delete_all_locations(context: *mut dc_context_t) {
assert!(!context.is_null());
let context = &*context;
dc_location::dc_delete_all_locations(context)
dc_location::dc_delete_all_locations(context);
}
// dc_array_t
@@ -1337,7 +1351,7 @@ pub unsafe extern "C" fn dc_msg_is_increation(msg: *mut dc_msg::dc_msg_t) -> lib
#[no_mangle]
pub unsafe extern "C" fn dc_msg_is_setupmessage(msg: *mut dc_msg::dc_msg_t) -> libc::c_int {
dc_msg::dc_msg_is_setupmessage(msg)
dc_msg::dc_msg_is_setupmessage(msg) as libc::c_int
}
#[no_mangle]
@@ -1524,3 +1538,15 @@ pub unsafe extern "C" fn dc_lot_get_timestamp(lot: *mut dc_lot::dc_lot_t) -> i64
pub unsafe extern "C" fn dc_str_unref(s: *mut libc::c_char) {
libc::free(s as *mut _)
}
fn as_opt_str<'a>(s: *const libc::c_char) -> Option<&'a str> {
if s.is_null() {
return None;
}
Some(dc_tools::as_str(s))
}
unsafe fn into_cstring(s: impl AsRef<str>) -> *mut libc::c_char {
dc_tools::dc_strdup(dc_tools::to_cstring(s).as_ptr())
}

View File

@@ -1,3 +1,6 @@
use std::str::FromStr;
use deltachat::config;
use deltachat::constants::*;
use deltachat::context::*;
use deltachat::dc_array::*;
@@ -12,9 +15,9 @@ use deltachat::dc_lot::*;
use deltachat::dc_msg::*;
use deltachat::dc_qr::*;
use deltachat::dc_receive_imf::*;
use deltachat::dc_sqlite3::*;
use deltachat::dc_tools::*;
use deltachat::peerstate::*;
use deltachat::sql;
use deltachat::types::*;
use deltachat::x::*;
use num_traits::FromPrimitive;
@@ -25,65 +28,58 @@ use num_traits::FromPrimitive;
pub unsafe fn dc_reset_tables(context: &Context, bits: i32) -> i32 {
info!(context, 0, "Resetting tables ({})...", bits);
if 0 != bits & 1 {
dc_sqlite3_execute(
context,
&context.sql,
b"DELETE FROM jobs;\x00" as *const u8 as *const libc::c_char,
);
sql::execute(context, &context.sql, "DELETE FROM jobs;", params![]);
info!(context, 0, "(1) Jobs reset.");
}
if 0 != bits & 2 {
dc_sqlite3_execute(
sql::execute(
context,
&context.sql,
b"DELETE FROM acpeerstates;\x00" as *const u8 as *const libc::c_char,
"DELETE FROM acpeerstates;",
params![],
);
info!(context, 0, "(2) Peerstates reset.");
}
if 0 != bits & 4 {
dc_sqlite3_execute(
context,
&context.sql,
b"DELETE FROM keypairs;\x00" as *const u8 as *const libc::c_char,
);
sql::execute(context, &context.sql, "DELETE FROM keypairs;", params![]);
info!(context, 0, "(4) Private keypairs reset.");
}
if 0 != bits & 8 {
dc_sqlite3_execute(
sql::execute(
context,
&context.sql,
b"DELETE FROM contacts WHERE id>9;\x00" as *const u8 as *const libc::c_char,
"DELETE FROM contacts WHERE id>9;",
params![],
);
dc_sqlite3_execute(
sql::execute(
context,
&context.sql,
b"DELETE FROM chats WHERE id>9;\x00" as *const u8 as *const libc::c_char,
"DELETE FROM chats WHERE id>9;",
params![],
);
dc_sqlite3_execute(
sql::execute(
context,
&context.sql,
b"DELETE FROM chats_contacts;\x00" as *const u8 as *const libc::c_char,
"DELETE FROM chats_contacts;",
params![],
);
dc_sqlite3_execute(
sql::execute(
context,
&context.sql,
b"DELETE FROM msgs WHERE id>9;\x00" as *const u8 as *const libc::c_char,
"DELETE FROM msgs WHERE id>9;",
params![],
);
dc_sqlite3_execute(
sql::execute(
context,
&context.sql,
b"DELETE FROM config WHERE keyname LIKE \'imap.%\' OR keyname LIKE \'configured%\';\x00"
as *const u8 as *const libc::c_char,
);
dc_sqlite3_execute(
context,
&context.sql,
b"DELETE FROM leftgrps;\x00" as *const u8 as *const libc::c_char,
"DELETE FROM config WHERE keyname LIKE 'imap.%' OR keyname LIKE 'configured%';",
params![],
);
sql::execute(context, &context.sql, "DELETE FROM leftgrps;", params![]);
info!(context, 0, "(8) Rest but server config reset.");
}
context.call_cb(Event::MSGS_CHANGED, 0 as uintptr_t, 0 as uintptr_t);
context.call_cb(Event::MSGS_CHANGED, 0, 0);
1
}
@@ -100,14 +96,7 @@ unsafe fn dc_poke_eml_file(context: &Context, filename: *const libc::c_char) ->
&mut data_bytes,
) == 0i32)
{
dc_receive_imf(
context,
data,
data_bytes,
b"import\x00" as *const u8 as *const libc::c_char,
0i32 as uint32_t,
0i32 as uint32_t,
);
dc_receive_imf(context, data, data_bytes, "import", 0, 0);
success = 1;
}
free(data as *mut libc::c_void);
@@ -138,26 +127,19 @@ unsafe fn poke_spec(context: &Context, spec: *const libc::c_char) -> libc::c_int
/* if `spec` is given, remember it for later usage; if it is not given, try to use the last one */
if !spec.is_null() {
real_spec = dc_strdup(spec);
dc_sqlite3_set_config(
context,
&context.sql,
b"import_spec\x00" as *const u8 as *const libc::c_char,
real_spec,
);
context
.sql
.set_config(context, "import_spec", Some(as_str(real_spec)));
current_block = 7149356873433890176;
} else {
real_spec = dc_sqlite3_get_config(
context,
&context.sql,
b"import_spec\x00" as *const u8 as *const libc::c_char,
0 as *const libc::c_char,
);
if real_spec.is_null() {
let rs = context.sql.get_config(context, "import_spec");
if rs.is_none() {
error!(context, 0, "Import: No file or folder given.");
current_block = 8522321847195001863;
} else {
current_block = 7149356873433890176;
}
real_spec = strdup(to_cstring(rs.unwrap_or_default()).as_ptr());
}
match current_block {
8522321847195001863 => {}
@@ -499,9 +481,10 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
},
"auth" => {
if 0 == S_IS_AUTH {
let is_pw =
dc_get_config(context, b"mail_pw\x00" as *const u8 as *const libc::c_char);
if arg1 == as_str(is_pw) {
let is_pw = context
.get_config(config::Config::MailPw)
.unwrap_or_default();
if arg1 == is_pw {
S_IS_AUTH = 1;
} else {
println!("Bad password.");
@@ -537,8 +520,8 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
ensure!(!arg1.is_empty(), "Argument <msg-id> missing.");
let msg_id: u32 = arg1.parse().unwrap();
let msg: *mut dc_msg_t = dc_get_msg(context, msg_id);
if 0 != dc_msg_is_setupmessage(msg) {
let setupcodebegin: *mut libc::c_char = dc_msg_get_setupcodebegin(msg);
if dc_msg_is_setupmessage(msg) {
let setupcodebegin = dc_msg_get_setupcodebegin(msg);
println!(
"The setup code for setup message Msg#{} starts with: {}",
msg_id,
@@ -620,16 +603,15 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
}
"set" => {
ensure!(!arg1.is_empty(), "Argument <key> missing.");
ensure!(
0 != dc_set_config(context, arg1_c_ptr, arg2_c_ptr),
"Set config failed"
);
let key = config::Config::from_str(&arg1)?;
let value = if arg2.is_empty() { None } else { Some(arg2) };
context.set_config(key, value)?;
}
"get" => {
ensure!(!arg1.is_empty(), "Argument <key> missing.");
let val = dc_get_config(context, arg1_c_ptr);
println!("{}={}", arg1, to_string(val));
free(val as *mut libc::c_void);
let key = config::Config::from_str(&arg1)?;
let val = context.get_config(key);
println!("{}={:?}", key, val);
}
"info" => {
println!("{}", to_string(dc_get_info(context)));
@@ -638,7 +620,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
dc_maybe_network(context);
}
"housekeeping" => {
dc_housekeeping(context);
sql::housekeeping(context);
}
"listchats" | "listarchived" | "chats" => {
let listflags = if arg0 == "listarchived" { 0x01 } else { 0 };
@@ -714,7 +696,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
i -= 1
}
}
if 0 != dc_is_sending_locations_to_chat(context, 0 as uint32_t) {
if dc_is_sending_locations_to_chat(context, 0 as uint32_t) {
info!(context, 0, "Location streaming enabled.");
}
println!("{} chats", cnt);
@@ -929,7 +911,7 @@ pub unsafe fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::E
let seconds = arg1.parse().unwrap();
dc_send_locations_to_chat(context, dc_chat_get_id(sel_chat), seconds);
println!("Locations will be sent to Chat#{} for {} seconds. Use \'setlocation <lat> <lng>\' to play around.", dc_chat_get_id(sel_chat), seconds);
println!("Locations will be sent to Chat#{} for {} seconds. Use 'setlocation <lat> <lng>' to play around.", dc_chat_get_id(sel_chat), seconds);
}
"setlocation" => {
ensure!(

View File

@@ -10,11 +10,14 @@ extern crate deltachat;
extern crate failure;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate rusqlite;
use std::borrow::Cow::{self, Borrowed, Owned};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex, RwLock};
use deltachat::config;
use deltachat::constants::*;
use deltachat::context::*;
use deltachat::dc_configure::*;
@@ -512,25 +515,20 @@ unsafe fn handle_cmd(line: &str, ctx: Arc<RwLock<Context>>) -> Result<ExitResult
dc_configure(&ctx.read().unwrap());
}
"oauth2" => {
let addr = dc_get_config(
&ctx.read().unwrap(),
b"addr\x00" as *const u8 as *const libc::c_char,
);
if addr.is_null() || *addr.offset(0isize) as libc::c_int == 0i32 {
println!("oauth2: set addr first.");
} else {
if let Some(addr) = ctx.read().unwrap().get_config(config::Config::Addr) {
let oauth2_url = dc_get_oauth2_url(
&ctx.read().unwrap(),
as_str(addr),
&addr,
"chat.delta:/com.b44t.messenger",
);
if oauth2_url.is_none() {
println!("OAuth2 not available for {}.", to_string(addr));
println!("OAuth2 not available for {}.", &addr);
} else {
println!("Open the following url, set mail_pw to the generated token and server_flags to 2:\n{}", oauth2_url.unwrap());
}
} else {
println!("oauth2: set addr first.");
}
free(addr as *mut libc::c_void);
}
"clear" => {
println!("\n\n\n");

View File

@@ -5,6 +5,7 @@ use std::sync::{Arc, RwLock};
use std::{thread, time};
use tempfile::tempdir;
use deltachat::config;
use deltachat::constants::Event;
use deltachat::context::*;
use deltachat::dc_chat::*;
@@ -79,20 +80,14 @@ fn main() {
println!("opening database {:?}", dbfile);
dc_open(&ctx, dbfile.as_ptr(), std::ptr::null());
assert_eq!(dc_open(&ctx, dbfile.as_ptr(), std::ptr::null()), 1);
println!("configuring");
let pw = std::env::args().collect::<Vec<String>>()[1].clone();
dc_set_config(
&ctx,
CString::new("addr").unwrap().as_ptr(),
CString::new("d@testrun.org").unwrap().as_ptr(),
);
dc_set_config(
&ctx,
CString::new("mail_pw").unwrap().as_ptr(),
CString::new(pw).unwrap().as_ptr(),
);
let args = std::env::args().collect::<Vec<String>>();
assert_eq!(args.len(), 2, "missing password");
let pw = args[1].clone();
ctx.set_config(config::Config::Addr, Some("d@testrun.org"));
ctx.set_config(config::Config::MailPw, Some(&pw));
dc_configure(&ctx);
thread::sleep(duration);
@@ -127,8 +122,8 @@ fn main() {
}
dc_chatlist_unref(chats);
*running.clone().write().unwrap() = false;
println!("stopping threads");
thread::sleep(duration);
// let msglist = dc_get_chat_msgs(&ctx, chat_id, 0, 0);
// for i in 0..dc_array_get_cnt(msglist) {
// let msg_id = dc_array_get_id(msglist, i);
@@ -139,6 +134,9 @@ fn main() {
// }
// dc_array_unref(msglist);
println!("stopping threads");
*running.clone().write().unwrap() = false;
deltachat::dc_job::dc_interrupt_imap_idle(&ctx);
deltachat::dc_job::dc_interrupt_smtp_idle(&ctx);

3
release.toml Normal file
View File

@@ -0,0 +1,3 @@
pre-release-commit-message = "chore({{crate_name}}): release {{version}}"
pro-release-commit-message = "chore({{crate_name}}): starting development cycle for {{next_version}}"
no-dev-version = true

View File

@@ -1 +1 @@
nightly-2019-06-16
nightly-2019-07-10

View File

@@ -1,5 +1,5 @@
use std::collections::BTreeMap;
use std::ffi::{CStr, CString};
use std::ffi::CStr;
use std::str::FromStr;
use std::{fmt, str};
@@ -7,6 +7,7 @@ use mmime::mailimf_types::*;
use crate::constants::*;
use crate::dc_contact::*;
use crate::dc_tools::as_str;
use crate::key::*;
/// Possible values for encryption preference
@@ -93,9 +94,7 @@ impl Aheader {
match Self::from_str(value) {
Ok(test) => {
// TODO: implement rust-safe version of dc_addr_cmp
let addr = CString::new(test.addr.clone()).unwrap();
if unsafe { dc_addr_cmp(addr.as_ptr(), wanted_from) } == 0 {
if dc_addr_cmp(&test.addr, as_str(wanted_from)) {
if fine_header.is_none() {
fine_header = Some(test);
} else {

177
src/config.rs Normal file
View File

@@ -0,0 +1,177 @@
use strum::{EnumProperty, IntoEnumIterator};
use strum_macros::{AsRefStr, Display, EnumIter, EnumProperty, EnumString};
use crate::constants::DC_VERSION_STR;
use crate::context::Context;
use crate::dc_job::*;
use crate::dc_stock::*;
use crate::dc_tools::*;
use crate::error::Error;
use crate::x::*;
/// The available configuration keys.
#[derive(
Debug, Clone, Copy, PartialEq, Eq, Display, EnumString, AsRefStr, EnumIter, EnumProperty,
)]
#[strum(serialize_all = "snake_case")]
pub enum Config {
Addr,
MailServer,
MailUser,
MailPw,
MailPort,
SendServer,
SendUser,
SendPw,
SendPort,
ServerFlags,
#[strum(props(default = "INBOX"))]
ImapFolder,
Displayname,
Selfstatus,
Selfavatar,
#[strum(props(default = "1"))]
E2eeEnabled,
#[strum(props(default = "1"))]
MdnsEnabled,
InboxWatch,
#[strum(props(default = "1"))]
SentboxWatch,
#[strum(props(default = "1"))]
MvboxWatch,
#[strum(props(default = "1"))]
MvboxMove,
#[strum(props(default = "0"))]
ShowEmails,
SaveMimeHeaders,
ConfiguredAddr,
ConfiguredMailServer,
ConfiguredMailUser,
ConfiguredMailPw,
ConfiguredMailPort,
ConfiguredSendServer,
ConfiguredSendUser,
ConfiguredSendPw,
ConfiguredSendPort,
ConfiguredServerFlags,
Configured,
// Deprecated
#[strum(serialize = "sys.version")]
SysVersion,
#[strum(serialize = "sys.msgsize_max_recommended")]
SysMsgsizeMaxRecommended,
#[strum(serialize = "sys.config_keys")]
SysConfigKeys,
}
impl Context {
/// Get a configuration key. Returns `None` if no value is set, and no default value found.
pub fn get_config(&self, key: Config) -> Option<String> {
let value = match key {
Config::Selfavatar => {
let rel_path = self.sql.get_config(self, key);
rel_path.map(|p| {
let v = unsafe { dc_get_abs_path(self, to_cstring(p).as_ptr()) };
let r = to_string(v);
unsafe { free(v as *mut _) };
r
})
}
Config::SysVersion => Some(std::str::from_utf8(DC_VERSION_STR).unwrap().into()),
Config::SysMsgsizeMaxRecommended => Some(format!("{}", 24 * 1024 * 1024 / 4 * 3)),
Config::SysConfigKeys => Some(get_config_keys_string()),
_ => self.sql.get_config(self, key),
};
if value.is_some() {
return value;
}
// Default values
match key {
Config::Selfstatus => {
let s = unsafe { dc_stock_str(self, 13) };
let res = to_string(s);
unsafe { free(s as *mut _) };
Some(res)
}
_ => key.get_str("default").map(|s| s.to_string()),
}
}
/// Set the given config key.
/// If `None` is passed as a value the value is cleared and set to the deafult if there is one.
pub fn set_config(&self, key: Config, value: Option<&str>) -> Result<(), Error> {
match key {
Config::Selfavatar if value.is_some() => {
let rel_path = std::fs::canonicalize(value.unwrap())?;
self.sql
.set_config(self, key, Some(&rel_path.to_string_lossy()))
}
Config::InboxWatch => {
let ret = self.sql.set_config(self, key, value);
unsafe { dc_interrupt_imap_idle(self) };
ret
}
Config::SentboxWatch => {
let ret = self.sql.set_config(self, key, value);
unsafe { dc_interrupt_sentbox_idle(self) };
ret
}
Config::MvboxWatch => {
let ret = self.sql.set_config(self, key, value);
unsafe { dc_interrupt_mvbox_idle(self) };
ret
}
Config::Selfstatus => {
let def = unsafe { dc_stock_str(self, 13) };
let val = if value.is_none() || value.unwrap() == as_str(def) {
None
} else {
value
};
let ret = self.sql.set_config(self, key, val);
unsafe { free(def as *mut libc::c_void) };
ret
}
_ => self.sql.set_config(self, key, value),
}
}
}
/// Returns all available configuration keys concated together.
fn get_config_keys_string() -> String {
let keys = Config::iter().fold(String::new(), |mut acc, key| {
acc += key.as_ref();
acc += " ";
acc
});
format!(" {} ", keys)
}
#[cfg(test)]
mod tests {
use super::*;
use std::str::FromStr;
use std::string::ToString;
#[test]
fn test_to_string() {
assert_eq!(Config::MailServer.to_string(), "mail_server");
assert_eq!(Config::from_str("mail_server"), Ok(Config::MailServer));
assert_eq!(Config::SysConfigKeys.to_string(), "sys.config_keys");
assert_eq!(
Config::from_str("sys.config_keys"),
Ok(Config::SysConfigKeys)
);
}
#[test]
fn test_default_prop() {
assert_eq!(Config::ImapFolder.get_str("default"), Some("INBOX"));
}
}

View File

@@ -1,6 +1,6 @@
//! Constants
pub const DC_VERSION_STR: &'static [u8; 14] = b"1.0.0-alpha.1\x00";
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;

View File

@@ -6,18 +6,16 @@ use crate::dc_chat::*;
use crate::dc_contact::*;
use crate::dc_job::*;
use crate::dc_jobthread::*;
use crate::dc_log::*;
use crate::dc_loginparam::*;
use crate::dc_lot::dc_lot_t;
use crate::dc_move::*;
use crate::dc_msg::*;
use crate::dc_receive_imf::*;
use crate::dc_sqlite3::*;
use crate::dc_stock::*;
use crate::dc_tools::*;
use crate::imap::*;
use crate::key::*;
use crate::smtp::*;
use crate::sql::Sql;
use crate::types::*;
use crate::x::*;
@@ -26,7 +24,7 @@ pub struct Context {
pub userdata: *mut libc::c_void,
pub dbfile: Arc<RwLock<*mut libc::c_char>>,
pub blobdir: Arc<RwLock<*mut libc::c_char>>,
pub sql: SQLite,
pub sql: Sql,
pub inbox: Arc<RwLock<Imap>>,
pub perform_inbox_jobs_needed: Arc<RwLock<i32>>,
pub probe_imap_network: Arc<RwLock<i32>>,
@@ -150,7 +148,7 @@ pub fn dc_context_new(
cb,
os_name: unsafe { dc_strdup_keep_null(os_name) },
running_state: Arc::new(RwLock::new(Default::default())),
sql: SQLite::new(),
sql: Sql::new(),
smtp: Arc::new(Mutex::new(Smtp::new())),
smtp_state: Arc::new((Mutex::new(Default::default()), Condvar::new())),
oauth2_critical: Arc::new(Mutex::new(())),
@@ -186,7 +184,7 @@ unsafe fn cb_receive_imf(
context: &Context,
imf_raw_not_terminated: *const libc::c_char,
imf_raw_bytes: size_t,
server_folder: *const libc::c_char,
server_folder: &str,
server_uid: uint32_t,
flags: uint32_t,
) {
@@ -203,7 +201,7 @@ unsafe fn cb_receive_imf(
unsafe fn cb_precheck_imf(
context: &Context,
rfc724_mid: *const libc::c_char,
server_folder: *const libc::c_char,
server_folder: &str,
server_uid: uint32_t,
) -> libc::c_int {
let mut rfc724_mid_exists: libc::c_int = 0i32;
@@ -222,23 +220,23 @@ unsafe fn cb_precheck_imf(
if *old_server_folder.offset(0isize) as libc::c_int == 0i32
&& old_server_uid == 0i32 as libc::c_uint
{
dc_log_info(
info!(
context,
0i32,
b"[move] detected bbc-self %s\x00" as *const u8 as *const libc::c_char,
rfc724_mid,
0,
"[move] detected bbc-self {}",
as_str(rfc724_mid),
);
mark_seen = 1i32
} else if strcmp(old_server_folder, server_folder) != 0i32 {
dc_log_info(
} else if as_str(old_server_folder) != server_folder {
info!(
context,
0i32,
b"[move] detected moved message %s\x00" as *const u8 as *const libc::c_char,
rfc724_mid,
0,
"[move] detected moved message {}",
as_str(rfc724_mid),
);
dc_update_msg_move_state(context, rfc724_mid, DC_MOVE_STATE_STAY);
}
if strcmp(old_server_folder, server_folder) != 0i32 || old_server_uid != server_uid {
if as_str(old_server_folder) != server_folder || old_server_uid != server_uid {
dc_update_server_uid(context, rfc724_mid, server_folder, server_uid);
}
dc_do_heuristics_moves(context, server_folder, msg_id);
@@ -257,7 +255,12 @@ unsafe fn cb_precheck_imf(
}
unsafe fn cb_set_config(context: &Context, key: *const libc::c_char, value: *const libc::c_char) {
dc_sqlite3_set_config(context, &context.sql, key, value);
let v = if value.is_null() {
None
} else {
Some(as_str(value))
};
context.sql.set_config(context, as_str(key), v);
}
/* *
@@ -272,7 +275,11 @@ unsafe fn cb_get_config(
key: *const libc::c_char,
def: *const libc::c_char,
) -> *mut libc::c_char {
dc_sqlite3_get_config(context, &context.sql, key, def)
let res = context
.sql
.get_config(context, as_str(key))
.unwrap_or_else(|| to_string(def));
strdup(to_cstring(res).as_ptr())
}
pub unsafe fn dc_context_unref(context: &mut Context) {
@@ -359,358 +366,88 @@ pub unsafe fn dc_get_blobdir(context: &Context) -> *mut libc::c_char {
dc_strdup(*context.blobdir.clone().read().unwrap())
}
pub unsafe fn dc_set_config(
context: &Context,
key: *const libc::c_char,
value: *const libc::c_char,
) -> libc::c_int {
let mut ret = 0;
let mut rel_path = 0 as *mut libc::c_char;
if key.is_null() || 0 == is_settable_config_key(key) {
return 0;
}
if strcmp(key, b"selfavatar\x00" as *const u8 as *const libc::c_char) == 0 && !value.is_null() {
rel_path = dc_strdup(value);
if !(0 == dc_make_rel_and_copy(context, &mut rel_path)) {
ret = dc_sqlite3_set_config(context, &context.sql, key, rel_path)
}
} else if strcmp(key, b"inbox_watch\x00" as *const u8 as *const libc::c_char) == 0 {
ret = dc_sqlite3_set_config(context, &context.sql, key, value);
dc_interrupt_imap_idle(context);
} else if strcmp(
key,
b"sentbox_watch\x00" as *const u8 as *const libc::c_char,
) == 0
{
ret = dc_sqlite3_set_config(context, &context.sql, key, value);
dc_interrupt_sentbox_idle(context);
} else if strcmp(key, b"mvbox_watch\x00" as *const u8 as *const libc::c_char) == 0 {
ret = dc_sqlite3_set_config(context, &context.sql, key, value);
dc_interrupt_mvbox_idle(context);
} else if strcmp(key, b"selfstatus\x00" as *const u8 as *const libc::c_char) == 0 {
let def = dc_stock_str(context, 13);
ret = dc_sqlite3_set_config(
context,
&context.sql,
key,
if value.is_null() || strcmp(value, def) == 0 {
0 as *const libc::c_char
} else {
value
},
);
free(def as *mut libc::c_void);
} else {
ret = dc_sqlite3_set_config(context, &context.sql, key, value);
}
free(rel_path as *mut libc::c_void);
ret
}
/* ******************************************************************************
* INI-handling, Information
******************************************************************************/
unsafe fn is_settable_config_key(key: *const libc::c_char) -> libc::c_int {
let mut i = 0;
while i
< (::std::mem::size_of::<[*const libc::c_char; 33]>())
.wrapping_div(::std::mem::size_of::<*mut libc::c_char>())
{
if strcmp(key, config_keys[i as usize]) == 0 {
return 1;
}
i += 1
}
0
}
static mut config_keys: [*const libc::c_char; 33] = [
b"addr\x00" as *const u8 as *const libc::c_char,
b"mail_server\x00" as *const u8 as *const libc::c_char,
b"mail_user\x00" as *const u8 as *const libc::c_char,
b"mail_pw\x00" as *const u8 as *const libc::c_char,
b"mail_port\x00" as *const u8 as *const libc::c_char,
b"send_server\x00" as *const u8 as *const libc::c_char,
b"send_user\x00" as *const u8 as *const libc::c_char,
b"send_pw\x00" as *const u8 as *const libc::c_char,
b"send_port\x00" as *const u8 as *const libc::c_char,
b"server_flags\x00" as *const u8 as *const libc::c_char,
b"imap_folder\x00" as *const u8 as *const libc::c_char,
b"displayname\x00" as *const u8 as *const libc::c_char,
b"selfstatus\x00" as *const u8 as *const libc::c_char,
b"selfavatar\x00" as *const u8 as *const libc::c_char,
b"e2ee_enabled\x00" as *const u8 as *const libc::c_char,
b"mdns_enabled\x00" as *const u8 as *const libc::c_char,
b"inbox_watch\x00" as *const u8 as *const libc::c_char,
b"sentbox_watch\x00" as *const u8 as *const libc::c_char,
b"mvbox_watch\x00" as *const u8 as *const libc::c_char,
b"mvbox_move\x00" as *const u8 as *const libc::c_char,
b"show_emails\x00" as *const u8 as *const libc::c_char,
b"save_mime_headers\x00" as *const u8 as *const libc::c_char,
b"configured_addr\x00" as *const u8 as *const libc::c_char,
b"configured_mail_server\x00" as *const u8 as *const libc::c_char,
b"configured_mail_user\x00" as *const u8 as *const libc::c_char,
b"configured_mail_pw\x00" as *const u8 as *const libc::c_char,
b"configured_mail_port\x00" as *const u8 as *const libc::c_char,
b"configured_send_server\x00" as *const u8 as *const libc::c_char,
b"configured_send_user\x00" as *const u8 as *const libc::c_char,
b"configured_send_pw\x00" as *const u8 as *const libc::c_char,
b"configured_send_port\x00" as *const u8 as *const libc::c_char,
b"configured_server_flags\x00" as *const u8 as *const libc::c_char,
b"configured\x00" as *const u8 as *const libc::c_char,
];
pub unsafe fn dc_get_config(context: &Context, key: *const libc::c_char) -> *mut libc::c_char {
let mut value = 0 as *mut libc::c_char;
if !key.is_null()
&& *key.offset(0isize) as libc::c_int == 's' as i32
&& *key.offset(1isize) as libc::c_int == 'y' as i32
&& *key.offset(2isize) as libc::c_int == 's' as i32
&& *key.offset(3isize) as libc::c_int == '.' as i32
{
return get_sys_config_str(key);
}
if key.is_null() || 0 == is_gettable_config_key(key) {
return dc_strdup(b"\x00" as *const u8 as *const libc::c_char);
}
if strcmp(key, b"selfavatar\x00" as *const u8 as *const libc::c_char) == 0 {
let rel_path: *mut libc::c_char =
dc_sqlite3_get_config(context, &context.sql, key, 0 as *const libc::c_char);
if !rel_path.is_null() {
value = dc_get_abs_path(context, rel_path);
free(rel_path as *mut libc::c_void);
}
} else {
value = dc_sqlite3_get_config(context, &context.sql, key, 0 as *const libc::c_char)
}
if value.is_null() {
if strcmp(key, b"e2ee_enabled\x00" as *const u8 as *const libc::c_char) == 0 {
value = dc_mprintf(b"%i\x00" as *const u8 as *const libc::c_char, 1)
} else if strcmp(key, b"mdns_enabled\x00" as *const u8 as *const libc::c_char) == 0 {
value = dc_mprintf(b"%i\x00" as *const u8 as *const libc::c_char, 1)
} else if strcmp(key, b"imap_folder\x00" as *const u8 as *const libc::c_char) == 0 {
value = dc_strdup(b"INBOX\x00" as *const u8 as *const libc::c_char)
} else if strcmp(key, b"inbox_watch\x00" as *const u8 as *const libc::c_char) == 0 {
value = dc_mprintf(b"%i\x00" as *const u8 as *const libc::c_char, 1)
} else if strcmp(
key,
b"sentbox_watch\x00" as *const u8 as *const libc::c_char,
) == 0
{
value = dc_mprintf(b"%i\x00" as *const u8 as *const libc::c_char, 1)
} else if strcmp(key, b"mvbox_watch\x00" as *const u8 as *const libc::c_char) == 0 {
value = dc_mprintf(b"%i\x00" as *const u8 as *const libc::c_char, 1)
} else if strcmp(key, b"mvbox_move\x00" as *const u8 as *const libc::c_char) == 0 {
value = dc_mprintf(b"%i\x00" as *const u8 as *const libc::c_char, 1)
} else if strcmp(key, b"show_emails\x00" as *const u8 as *const libc::c_char) == 0 {
value = dc_mprintf(b"%i\x00" as *const u8 as *const libc::c_char, 0)
} else if strcmp(key, b"selfstatus\x00" as *const u8 as *const libc::c_char) == 0 {
value = dc_stock_str(context, 13)
} else {
value = dc_mprintf(b"\x00" as *const u8 as *const libc::c_char)
}
}
value
}
unsafe fn is_gettable_config_key(key: *const libc::c_char) -> libc::c_int {
let mut i = 0;
while i
< (::std::mem::size_of::<[*const libc::c_char; 3]>())
.wrapping_div(::std::mem::size_of::<*mut libc::c_char>())
{
if strcmp(key, sys_config_keys[i as usize]) == 0 {
return 1;
}
i += 1
}
is_settable_config_key(key)
}
// deprecated
static mut sys_config_keys: [*const libc::c_char; 3] = [
b"sys.version\x00" as *const u8 as *const libc::c_char,
b"sys.msgsize_max_recommended\x00" as *const u8 as *const libc::c_char,
b"sys.config_keys\x00" as *const u8 as *const libc::c_char,
];
unsafe fn get_sys_config_str(key: *const libc::c_char) -> *mut libc::c_char {
if strcmp(key, b"sys.version\x00" as *const u8 as *const libc::c_char) == 0 {
return dc_strdup(DC_VERSION_STR as *const u8 as *const libc::c_char);
} else if strcmp(
key,
b"sys.msgsize_max_recommended\x00" as *const u8 as *const libc::c_char,
) == 0
{
return dc_mprintf(
b"%i\x00" as *const u8 as *const libc::c_char,
24 * 1024 * 1024 / 4 * 3,
);
} else if strcmp(
key,
b"sys.config_keys\x00" as *const u8 as *const libc::c_char,
) == 0
{
return get_config_keys_str();
} else {
return dc_strdup(0 as *const libc::c_char);
};
}
unsafe fn get_config_keys_str() -> *mut libc::c_char {
let mut ret = String::new();
let mut i = 0;
while i
< (::std::mem::size_of::<[*const libc::c_char; 33]>())
.wrapping_div(::std::mem::size_of::<*mut libc::c_char>())
{
if !ret.is_empty() {
ret += " ";
}
ret += &to_string(config_keys[i as usize]);
i += 1
}
let mut i = 0;
while i
< (::std::mem::size_of::<[*const libc::c_char; 3]>())
.wrapping_div(::std::mem::size_of::<*mut libc::c_char>())
{
if !ret.is_empty() {
ret += " ";
}
ret += &to_string(sys_config_keys[i as usize]);
i += 1
}
strdup(to_cstring(ret).as_ptr())
}
pub unsafe fn dc_get_info(context: &Context) -> *mut libc::c_char {
let unset = "0";
let l = dc_loginparam_new();
let l2 = dc_loginparam_new();
dc_loginparam_read(
context,
l,
&context.sql,
b"\x00" as *const u8 as *const libc::c_char,
);
dc_loginparam_read(
context,
l2,
&context.sql,
b"configured_\x00" as *const u8 as *const libc::c_char,
);
let displayname = dc_sqlite3_get_config(
context,
&context.sql,
b"displayname\x00" as *const u8 as *const libc::c_char,
0 as *const libc::c_char,
);
let l = dc_loginparam_read(context, &context.sql, "");
let l2 = dc_loginparam_read(context, &context.sql, "configured_");
let displayname = context.sql.get_config(context, "displayname");
let chats = dc_get_chat_cnt(context) as usize;
let real_msgs = dc_get_real_msg_cnt(context) as usize;
let deaddrop_msgs = dc_get_deaddrop_msg_cnt(context) as usize;
let contacts = dc_get_real_contact_cnt(context) as usize;
let is_configured = dc_sqlite3_get_config_int(
context,
&context.sql,
b"configured\x00" as *const u8 as *const libc::c_char,
0,
);
let dbversion = dc_sqlite3_get_config_int(
context,
&context.sql,
b"dbversion\x00" as *const u8 as *const libc::c_char,
0,
);
let e2ee_enabled = dc_sqlite3_get_config_int(
context,
&context.sql,
b"e2ee_enabled\x00" as *const u8 as *const libc::c_char,
1,
);
let mdns_enabled = dc_sqlite3_get_config_int(
context,
&context.sql,
b"mdns_enabled\x00" as *const u8 as *const libc::c_char,
1,
);
let mut stmt = dc_sqlite3_prepare(
context,
&context.sql,
b"SELECT COUNT(*) FROM keypairs;\x00" as *const u8 as *const libc::c_char,
);
sqlite3_step(stmt);
let prv_key_cnt = sqlite3_column_int(stmt, 0);
sqlite3_finalize(stmt);
stmt = dc_sqlite3_prepare(
context,
&context.sql,
b"SELECT COUNT(*) FROM acpeerstates;\x00" as *const u8 as *const libc::c_char,
);
sqlite3_step(stmt);
let pub_key_cnt = sqlite3_column_int(stmt, 0);
sqlite3_finalize(stmt);
let fingerprint_str =
if let Some(key) = Key::from_self_public(context, (*l2).addr, &context.sql) {
key.fingerprint()
} else {
"<Not yet calculated>".into()
};
let is_configured = context
.sql
.get_config_int(context, "configured")
.unwrap_or_default();
let dbversion = context
.sql
.get_config_int(context, "dbversion")
.unwrap_or_default();
let e2ee_enabled = context
.sql
.get_config_int(context, "e2ee_enabled")
.unwrap_or_else(|| 1);
let mdns_enabled = context
.sql
.get_config_int(context, "mdns_enabled")
.unwrap_or_else(|| 1);
let l_readable_str = dc_loginparam_get_readable(l);
let l2_readable_str = dc_loginparam_get_readable(l2);
let inbox_watch = dc_sqlite3_get_config_int(
let prv_key_cnt: Option<isize> = context.sql.query_row_col(
context,
&context.sql,
b"inbox_watch\x00" as *const u8 as *const libc::c_char,
1,
);
let sentbox_watch = dc_sqlite3_get_config_int(
context,
&context.sql,
b"sentbox_watch\x00" as *const u8 as *const libc::c_char,
1,
);
let mvbox_watch = dc_sqlite3_get_config_int(
context,
&context.sql,
b"mvbox_watch\x00" as *const u8 as *const libc::c_char,
1,
);
let mvbox_move = dc_sqlite3_get_config_int(
context,
&context.sql,
b"mvbox_move\x00" as *const u8 as *const libc::c_char,
1,
);
let folders_configured = dc_sqlite3_get_config_int(
context,
&context.sql,
b"folders_configured\x00" as *const u8 as *const libc::c_char,
"SELECT COUNT(*) FROM keypairs;",
rusqlite::NO_PARAMS,
0,
);
let configured_sentbox_folder = dc_sqlite3_get_config(
let pub_key_cnt: Option<isize> = context.sql.query_row_col(
context,
&context.sql,
b"configured_sentbox_folder\x00" as *const u8 as *const libc::c_char,
b"<unset>\x00" as *const u8 as *const libc::c_char,
);
let configured_mvbox_folder = dc_sqlite3_get_config(
context,
&context.sql,
b"configured_mvbox_folder\x00" as *const u8 as *const libc::c_char,
b"<unset>\x00" as *const u8 as *const libc::c_char,
"SELECT COUNT(*) FROM acpeerstates;",
rusqlite::NO_PARAMS,
0,
);
let fingerprint_str = if let Some(key) = Key::from_self_public(context, &l2.addr, &context.sql)
{
key.fingerprint()
} else {
"<Not yet calculated>".into()
};
let l_readable_str = dc_loginparam_get_readable(&l);
let l2_readable_str = dc_loginparam_get_readable(&l2);
let inbox_watch = context
.sql
.get_config_int(context, "inbox_watch")
.unwrap_or_else(|| 1);
let sentbox_watch = context
.sql
.get_config_int(context, "sentbox_watch")
.unwrap_or_else(|| 1);
let mvbox_watch = context
.sql
.get_config_int(context, "mvbox_watch")
.unwrap_or_else(|| 1);
let mvbox_move = context
.sql
.get_config_int(context, "mvbox_move")
.unwrap_or_else(|| 1);
let folders_configured = context
.sql
.get_config_int(context, "folders_configured")
.unwrap_or_default();
let configured_sentbox_folder = context
.sql
.get_config(context, "configured_sentbox_folder")
.unwrap_or_else(|| "<unset>".to_string());
let configured_mvbox_folder = context
.sql
.get_config(context, "configured_mvbox_folder")
.unwrap_or_else(|| "<unset>".to_string());
let res = format!(
"deltachat_core_version=v{}\n\
sqlite_version={}\n\
@@ -741,7 +478,7 @@ pub unsafe fn dc_get_info(context: &Context) -> *mut libc::c_char {
fingerprint={}\n\
level=awesome\n",
as_str(DC_VERSION_STR as *const u8 as *const _),
as_str(libsqlite3_sys::SQLITE_VERSION as *const u8 as *const libc::c_char),
rusqlite::version(),
sqlite3_threadsafe(),
// arch
(::std::mem::size_of::<*mut libc::c_void>()).wrapping_mul(8),
@@ -760,36 +497,24 @@ pub unsafe fn dc_get_info(context: &Context) -> *mut libc::c_char {
} else {
unset
},
if !displayname.is_null() {
as_str(displayname)
} else {
unset
},
displayname.unwrap_or_else(|| unset.into()),
is_configured,
as_str(l_readable_str),
as_str(l2_readable_str),
l_readable_str,
l2_readable_str,
inbox_watch,
sentbox_watch,
mvbox_watch,
mvbox_move,
folders_configured,
as_str(configured_sentbox_folder),
as_str(configured_mvbox_folder),
configured_sentbox_folder,
configured_mvbox_folder,
mdns_enabled,
e2ee_enabled,
prv_key_cnt,
pub_key_cnt,
prv_key_cnt.unwrap_or_default(),
pub_key_cnt.unwrap_or_default(),
fingerprint_str,
);
dc_loginparam_unref(l);
dc_loginparam_unref(l2);
free(displayname as *mut libc::c_void);
free(l_readable_str as *mut libc::c_void);
free(l2_readable_str as *mut libc::c_void);
free(configured_sentbox_folder as *mut libc::c_void);
free(configured_mvbox_folder as *mut libc::c_void);
strdup(to_cstring(res).as_ptr())
}
@@ -797,155 +522,106 @@ pub unsafe fn dc_get_version_str() -> *mut libc::c_char {
dc_strdup(DC_VERSION_STR as *const u8 as *const libc::c_char)
}
pub unsafe fn dc_get_fresh_msgs(context: &Context) -> *mut dc_array_t {
pub fn dc_get_fresh_msgs(context: &Context) -> *mut dc_array_t {
let show_deaddrop = 0;
let ret = dc_array_new(128 as size_t);
let mut stmt = 0 as *mut sqlite3_stmt;
if !ret.is_null() {
stmt = dc_sqlite3_prepare(
context,
&context.sql,
b"SELECT m.id FROM msgs m LEFT JOIN contacts ct \
ON m.from_id=ct.id LEFT JOIN chats c ON m.chat_id=c.id WHERE m.state=? \
AND m.hidden=0 \
AND m.chat_id>? \
AND ct.blocked=0 \
AND (c.blocked=0 OR c.blocked=?) ORDER BY m.timestamp DESC,m.id DESC;\x00"
as *const u8 as *const libc::c_char,
);
sqlite3_bind_int(stmt, 1, 10);
sqlite3_bind_int(stmt, 2, 9);
sqlite3_bind_int(stmt, 3, if 0 != show_deaddrop { 2 } else { 0 });
while sqlite3_step(stmt) == 100 {
dc_array_add_id(ret, sqlite3_column_int(stmt, 0) as uint32_t);
}
}
sqlite3_finalize(stmt);
ret
context
.sql
.query_map(
"SELECT m.id FROM msgs m LEFT JOIN contacts ct \
ON m.from_id=ct.id LEFT JOIN chats c ON m.chat_id=c.id WHERE m.state=? \
AND m.hidden=0 \
AND m.chat_id>? \
AND ct.blocked=0 \
AND (c.blocked=0 OR c.blocked=?) ORDER BY m.timestamp DESC,m.id DESC;",
&[10, 9, if 0 != show_deaddrop { 2 } else { 0 }],
|row| row.get(0),
|rows| {
let ret = unsafe { dc_array_new(128 as size_t) };
for row in rows {
let id = row?;
unsafe { dc_array_add_id(ret, id) };
}
Ok(ret)
},
)
.unwrap()
}
pub unsafe fn dc_search_msgs(
pub fn dc_search_msgs(
context: &Context,
chat_id: uint32_t,
query: *const libc::c_char,
) -> *mut dc_array_t {
let mut success = 0;
let ret = dc_array_new(100 as size_t);
let mut strLikeInText = 0 as *mut libc::c_char;
let mut strLikeBeg = 0 as *mut libc::c_char;
let mut real_query = 0 as *mut libc::c_char;
let mut stmt = 0 as *mut sqlite3_stmt;
if !(ret.is_null() || query.is_null()) {
real_query = dc_strdup(query);
dc_trim(real_query);
if *real_query.offset(0isize) as libc::c_int == 0 {
success = 1
} else {
strLikeInText = dc_mprintf(
b"%%%s%%\x00" as *const u8 as *const libc::c_char,
real_query,
);
strLikeBeg = dc_mprintf(b"%s%%\x00" as *const u8 as *const libc::c_char, real_query);
if 0 != chat_id {
stmt = dc_sqlite3_prepare(
context,
&context.sql,
b"SELECT m.id, m.timestamp FROM msgs m LEFT JOIN contacts ct ON m.from_id=ct.id WHERE m.chat_id=? \
AND m.hidden=0 \
AND ct.blocked=0 AND (txt LIKE ? OR ct.name LIKE ?) ORDER BY m.timestamp,m.id;\x00"
as *const u8 as *const libc::c_char
);
sqlite3_bind_int(stmt, 1, chat_id as libc::c_int);
sqlite3_bind_text(stmt, 2, strLikeInText, -1, None);
sqlite3_bind_text(stmt, 3, strLikeBeg, -1, None);
} else {
let show_deaddrop = 0;
stmt = dc_sqlite3_prepare(
context,
&context.sql,
b"SELECT m.id, m.timestamp FROM msgs m LEFT JOIN contacts ct ON m.from_id=ct.id \
LEFT JOIN chats c ON m.chat_id=c.id WHERE m.chat_id>9 AND m.hidden=0 \
AND (c.blocked=0 OR c.blocked=?) \
AND ct.blocked=0 AND (m.txt LIKE ? OR ct.name LIKE ?) ORDER BY m.timestamp DESC,m.id DESC;\x00"
as *const u8 as *const libc::c_char
);
sqlite3_bind_int(stmt, 1, if 0 != show_deaddrop { 2 } else { 0 });
sqlite3_bind_text(stmt, 2, strLikeInText, -1, None);
sqlite3_bind_text(stmt, 3, strLikeBeg, -1, None);
}
while sqlite3_step(stmt) == 100 {
dc_array_add_id(ret, sqlite3_column_int(stmt, 0) as uint32_t);
}
success = 1
}
if query.is_null() {
return std::ptr::null_mut();
}
free(strLikeInText as *mut libc::c_void);
free(strLikeBeg as *mut libc::c_void);
free(real_query as *mut libc::c_void);
sqlite3_finalize(stmt);
let real_query = to_string(query).trim().to_string();
if real_query.is_empty() {
return std::ptr::null_mut();
}
let strLikeInText = format!("%{}%", &real_query);
let strLikeBeg = format!("{}%", &real_query);
if 0 != success {
ret
let query = if 0 != chat_id {
"SELECT m.id, m.timestamp FROM msgs m LEFT JOIN contacts ct ON m.from_id=ct.id WHERE m.chat_id=? \
AND m.hidden=0 \
AND ct.blocked=0 AND (txt LIKE ? OR ct.name LIKE ?) ORDER BY m.timestamp,m.id;"
} else {
if !ret.is_null() {
dc_array_unref(ret);
}
0 as *mut dc_array_t
"SELECT m.id, m.timestamp FROM msgs m LEFT JOIN contacts ct ON m.from_id=ct.id \
LEFT JOIN chats c ON m.chat_id=c.id WHERE m.chat_id>9 AND m.hidden=0 \
AND (c.blocked=0 OR c.blocked=?) \
AND ct.blocked=0 AND (m.txt LIKE ? OR ct.name LIKE ?) ORDER BY m.timestamp DESC,m.id DESC;"
};
let ret = unsafe { dc_array_new(100 as size_t) };
let success = context
.sql
.query_map(
query,
params![chat_id as libc::c_int, &strLikeInText, &strLikeBeg],
|row| row.get::<_, i32>(0),
|rows| {
for id in rows {
unsafe { dc_array_add_id(ret, id? as u32) };
}
Ok(())
},
)
.is_ok();
if success {
return ret;
}
if !ret.is_null() {
unsafe { dc_array_unref(ret) };
}
std::ptr::null_mut()
}
pub fn dc_is_inbox(_context: &Context, folder_name: impl AsRef<str>) -> bool {
folder_name.as_ref() == "INBOX"
}
pub fn dc_is_sentbox(context: &Context, folder_name: impl AsRef<str>) -> bool {
let sentbox_name = context.sql.get_config(context, "configured_sentbox_folder");
if let Some(name) = sentbox_name {
name == folder_name.as_ref()
} else {
false
}
}
pub unsafe fn dc_is_inbox(_context: &Context, folder_name: *const libc::c_char) -> libc::c_int {
let mut is_inbox = 0;
if !folder_name.is_null() {
is_inbox = if strcasecmp(
b"INBOX\x00" as *const u8 as *const libc::c_char,
folder_name,
) == 0
{
1
} else {
0
}
}
is_inbox
}
pub fn dc_is_mvbox(context: &Context, folder_name: impl AsRef<str>) -> bool {
let mvbox_name = context.sql.get_config(context, "configured_mvbox_folder");
pub unsafe fn dc_is_sentbox(context: &Context, folder_name: *const libc::c_char) -> libc::c_int {
let sentbox_name = dc_sqlite3_get_config(
context,
&context.sql,
b"configured_sentbox_folder\x00" as *const u8 as *const libc::c_char,
0 as *const libc::c_char,
);
let mut is_sentbox = 0;
if !sentbox_name.is_null() && !folder_name.is_null() {
is_sentbox = if strcasecmp(sentbox_name, folder_name) == 0 {
1
} else {
0
}
if let Some(name) = mvbox_name {
name == folder_name.as_ref()
} else {
false
}
free(sentbox_name as *mut libc::c_void);
is_sentbox
}
pub unsafe fn dc_is_mvbox(context: &Context, folder_name: *const libc::c_char) -> libc::c_int {
let mvbox_name = dc_sqlite3_get_config(
context,
&context.sql,
b"configured_mvbox_folder\x00" as *const u8 as *const libc::c_char,
0 as *const libc::c_char,
);
let mut is_mvbox = 0;
if !mvbox_name.is_null() && !folder_name.is_null() {
is_mvbox = if strcasecmp(mvbox_name, folder_name) == 0 {
1
} else {
0
}
}
free(mvbox_name as *mut libc::c_void);
is_mvbox
}

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,6 @@ use crate::dc_chat::*;
use crate::dc_contact::*;
use crate::dc_lot::*;
use crate::dc_msg::*;
use crate::dc_sqlite3::*;
use crate::dc_stock::*;
use crate::dc_tools::*;
use crate::types::*;
@@ -27,19 +26,14 @@ pub unsafe fn dc_get_chatlist<'a>(
query_str: *const libc::c_char,
query_id: uint32_t,
) -> *mut dc_chatlist_t<'a> {
let mut success: libc::c_int = 0i32;
let obj: *mut dc_chatlist_t = dc_chatlist_new(context);
let obj = dc_chatlist_new(context);
if !(0 == dc_chatlist_load_from_db(obj, listflags, query_str, query_id)) {
success = 1i32
if 0 != dc_chatlist_load_from_db(obj, listflags, query_str, query_id) {
return obj;
}
if 0 != success {
return obj;
} else {
dc_chatlist_unref(obj);
return 0 as *mut dc_chatlist_t;
};
dc_chatlist_unref(obj);
return 0 as *mut dc_chatlist_t;
}
/**
@@ -120,146 +114,173 @@ unsafe fn dc_chatlist_load_from_db(
mut chatlist: *mut dc_chatlist_t,
listflags: libc::c_int,
query__: *const libc::c_char,
query_contact_id: uint32_t,
query_contact_id: u32,
) -> libc::c_int {
let current_block: u64;
//clock_t start = clock();
let mut success: libc::c_int = 0i32;
let mut add_archived_link_item: libc::c_int = 0i32;
let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt;
let mut strLikeCmd: *mut libc::c_char = 0 as *mut libc::c_char;
let mut query: *mut libc::c_char = 0 as *mut libc::c_char;
if !(chatlist.is_null() || (*chatlist).magic != 0xc4a71157u32) {
dc_chatlist_empty(chatlist);
// select with left join and minimum:
// - the inner select must use `hidden` and _not_ `m.hidden`
// which would refer the outer select and take a lot of time
// - `GROUP BY` is needed several messages may have the same timestamp
// - the list starts with the newest chats
// nb: the query currently shows messages from blocked contacts in groups.
// however, for normal-groups, this is okay as the message is also returned by dc_get_chat_msgs()
// (otherwise it would be hard to follow conversations, wa and tg do the same)
// for the deaddrop, however, they should really be hidden, however, _currently_ the deaddrop is not
// shown at all permanent in the chatlist.
if 0 != query_contact_id {
stmt =
dc_sqlite3_prepare(
(*chatlist).context,
&(*chatlist).context.sql,
b"SELECT c.id, m.id FROM chats c LEFT JOIN msgs m ON c.id=m.chat_id AND m.timestamp=( SELECT MAX(timestamp) FROM msgs WHERE chat_id=c.id AND (hidden=0 OR (hidden=1 AND state=19))) WHERE c.id>9 AND c.blocked=0 AND c.id IN(SELECT chat_id FROM chats_contacts WHERE contact_id=?) GROUP BY c.id ORDER BY IFNULL(m.timestamp,0) DESC, m.id DESC;\x00"
as *const u8 as *const libc::c_char
);
sqlite3_bind_int(stmt, 1i32, query_contact_id as libc::c_int);
current_block = 3437258052017859086;
} else if 0 != listflags & 0x1i32 {
stmt =
dc_sqlite3_prepare(
(*chatlist).context,
&(*chatlist).context.sql,
b"SELECT c.id, m.id FROM chats c LEFT JOIN msgs m ON c.id=m.chat_id AND m.timestamp=( SELECT MAX(timestamp) FROM msgs WHERE chat_id=c.id AND (hidden=0 OR (hidden=1 AND state=19))) WHERE c.id>9 AND c.blocked=0 AND c.archived=1 GROUP BY c.id ORDER BY IFNULL(m.timestamp,0) DESC, m.id DESC;\x00"
as *const u8 as *const libc::c_char);
current_block = 3437258052017859086;
} else if query__.is_null() {
if 0 == listflags & 0x2i32 {
let last_deaddrop_fresh_msg_id: uint32_t =
get_last_deaddrop_fresh_msg((*chatlist).context);
if last_deaddrop_fresh_msg_id > 0i32 as libc::c_uint {
dc_array_add_id((*chatlist).chatNlastmsg_ids, 1i32 as uint32_t);
dc_array_add_id((*chatlist).chatNlastmsg_ids, last_deaddrop_fresh_msg_id);
}
add_archived_link_item = 1i32
}
stmt =
dc_sqlite3_prepare(
(*chatlist).context,
&(*chatlist).context.sql,
b"SELECT c.id, m.id FROM chats c LEFT JOIN msgs m ON c.id=m.chat_id AND m.timestamp=( SELECT MAX(timestamp) FROM msgs WHERE chat_id=c.id AND (hidden=0 OR (hidden=1 AND state=19))) WHERE c.id>9 AND c.blocked=0 AND c.archived=0 GROUP BY c.id ORDER BY IFNULL(m.timestamp,0) DESC, m.id DESC;\x00"
as *const u8 as *const libc::c_char);
current_block = 3437258052017859086;
} else {
query = dc_strdup(query__);
dc_trim(query);
if *query.offset(0isize) as libc::c_int == 0i32 {
success = 1i32;
current_block = 15179736777190528364;
} else {
strLikeCmd = dc_mprintf(b"%%%s%%\x00" as *const u8 as *const libc::c_char, query);
stmt =
dc_sqlite3_prepare(
(*chatlist).context,
&(*chatlist).context.sql,
b"SELECT c.id, m.id FROM chats c LEFT JOIN msgs m ON c.id=m.chat_id AND m.timestamp=( SELECT MAX(timestamp) FROM msgs WHERE chat_id=c.id AND (hidden=0 OR (hidden=1 AND state=19))) WHERE c.id>9 AND c.blocked=0 AND c.name LIKE ? GROUP BY c.id ORDER BY IFNULL(m.timestamp,0) DESC, m.id DESC;\x00"
as *const u8 as
*const libc::c_char);
sqlite3_bind_text(stmt, 1i32, strLikeCmd, -1i32, None);
current_block = 3437258052017859086;
}
if chatlist.is_null() || (*chatlist).magic != 0xc4a71157u32 {
return 0;
}
dc_chatlist_empty(chatlist);
let mut add_archived_link_item = 0;
// select with left join and minimum:
// - the inner select must use `hidden` and _not_ `m.hidden`
// which would refer the outer select and take a lot of time
// - `GROUP BY` is needed several messages may have the same timestamp
// - the list starts with the newest chats
// nb: the query currently shows messages from blocked contacts in groups.
// however, for normal-groups, this is okay as the message is also returned by dc_get_chat_msgs()
// (otherwise it would be hard to follow conversations, wa and tg do the same)
// for the deaddrop, however, they should really be hidden, however, _currently_ the deaddrop is not
// shown at all permanent in the chatlist.
let process_row = |row: &rusqlite::Row| {
let chat_id: i32 = row.get(0)?;
// TODO: verify that it is okay for this to be Null
let msg_id: i32 = row.get(1).unwrap_or_default();
Ok((chat_id, msg_id))
};
let process_rows = |rows: rusqlite::MappedRows<_>| {
for row in rows {
let (id1, id2) = row?;
dc_array_add_id((*chatlist).chatNlastmsg_ids, id1 as u32);
dc_array_add_id((*chatlist).chatNlastmsg_ids, id2 as u32);
}
match current_block {
15179736777190528364 => {}
_ => {
while sqlite3_step(stmt) == 100i32 {
dc_array_add_id(
(*chatlist).chatNlastmsg_ids,
sqlite3_column_int(stmt, 0i32) as uint32_t,
);
dc_array_add_id(
(*chatlist).chatNlastmsg_ids,
sqlite3_column_int(stmt, 1i32) as uint32_t,
);
}
if 0 != add_archived_link_item && dc_get_archived_cnt((*chatlist).context) > 0i32 {
if dc_array_get_cnt((*chatlist).chatNlastmsg_ids) == 0
&& 0 != listflags & 0x4i32
{
dc_array_add_id((*chatlist).chatNlastmsg_ids, 7i32 as uint32_t);
dc_array_add_id((*chatlist).chatNlastmsg_ids, 0i32 as uint32_t);
}
dc_array_add_id((*chatlist).chatNlastmsg_ids, 6i32 as uint32_t);
dc_array_add_id((*chatlist).chatNlastmsg_ids, 0i32 as uint32_t);
}
(*chatlist).cnt = dc_array_get_cnt((*chatlist).chatNlastmsg_ids).wrapping_div(2);
success = 1i32
Ok(())
};
// nb: the query currently shows messages from blocked contacts in groups.
// however, for normal-groups, this is okay as the message is also returned by dc_get_chat_msgs()
// (otherwise it would be hard to follow conversations, wa and tg do the same)
// for the deaddrop, however, they should really be hidden, however, _currently_ the deaddrop is not
// shown at all permanent in the chatlist.
let success = if query_contact_id != 0 {
// show chats shared with a given contact
(*chatlist).context.sql.query_map(
"SELECT c.id, m.id FROM chats c LEFT JOIN msgs m \
ON c.id=m.chat_id \
AND m.timestamp=( SELECT MAX(timestamp) \
FROM msgs WHERE chat_id=c.id \
AND (hidden=0 OR (hidden=1 AND state=19))) WHERE c.id>9 \
AND c.blocked=0 AND c.id IN(SELECT chat_id FROM chats_contacts WHERE contact_id=?) \
GROUP BY c.id ORDER BY IFNULL(m.timestamp,0) DESC, m.id DESC;",
params![query_contact_id as i32],
process_row,
process_rows,
)
} else if 0 != listflags & 0x1 {
// show archived chats
(*chatlist).context.sql.query_map(
"SELECT c.id, m.id FROM chats c LEFT JOIN msgs m \
ON c.id=m.chat_id \
AND m.timestamp=( SELECT MAX(timestamp) \
FROM msgs WHERE chat_id=c.id \
AND (hidden=0 OR (hidden=1 AND state=19))) WHERE c.id>9 \
AND c.blocked=0 AND c.archived=1 GROUP BY c.id \
ORDER BY IFNULL(m.timestamp,0) DESC, m.id DESC;",
params![],
process_row,
process_rows,
)
} else if query__.is_null() {
// show normal chatlist
if 0 == listflags & 0x2 {
let last_deaddrop_fresh_msg_id = get_last_deaddrop_fresh_msg((*chatlist).context);
if last_deaddrop_fresh_msg_id > 0 {
dc_array_add_id((*chatlist).chatNlastmsg_ids, 1);
dc_array_add_id((*chatlist).chatNlastmsg_ids, last_deaddrop_fresh_msg_id);
}
add_archived_link_item = 1;
}
(*chatlist).context.sql.query_map(
"SELECT c.id, m.id FROM chats c \
LEFT JOIN msgs m \
ON c.id=m.chat_id \
AND m.timestamp=( SELECT MAX(timestamp) \
FROM msgs WHERE chat_id=c.id \
AND (hidden=0 OR (hidden=1 AND state=19))) WHERE c.id>9 \
AND c.blocked=0 AND c.archived=0 \
GROUP BY c.id \
ORDER BY IFNULL(m.timestamp,0) DESC, m.id DESC;",
params![],
process_row,
process_rows,
)
} else {
let query = to_string(query__).trim().to_string();
if query.is_empty() {
return 1;
} else {
let strLikeCmd = format!("%{}%", query);
(*chatlist).context.sql.query_map(
"SELECT c.id, m.id FROM chats c LEFT JOIN msgs m \
ON c.id=m.chat_id \
AND m.timestamp=( SELECT MAX(timestamp) \
FROM msgs WHERE chat_id=c.id \
AND (hidden=0 OR (hidden=1 AND state=19))) WHERE c.id>9 \
AND c.blocked=0 AND c.name LIKE ? \
GROUP BY c.id ORDER BY IFNULL(m.timestamp,0) DESC, m.id DESC;",
params![strLikeCmd],
process_row,
process_rows,
)
}
};
if 0 != add_archived_link_item && dc_get_archived_cnt((*chatlist).context) > 0 {
if dc_array_get_cnt((*chatlist).chatNlastmsg_ids) == 0 && 0 != listflags & 0x4 {
dc_array_add_id((*chatlist).chatNlastmsg_ids, 7);
dc_array_add_id((*chatlist).chatNlastmsg_ids, 0);
}
dc_array_add_id((*chatlist).chatNlastmsg_ids, 6);
dc_array_add_id((*chatlist).chatNlastmsg_ids, 0);
}
(*chatlist).cnt = dc_array_get_cnt((*chatlist).chatNlastmsg_ids) / 2;
match success {
Ok(_) => 1,
Err(err) => {
error!(
(*chatlist).context,
0, "chatlist: failed to load from database: {:?}", err
);
0
}
}
sqlite3_finalize(stmt);
free(query as *mut libc::c_void);
free(strLikeCmd as *mut libc::c_void);
success
}
// Context functions to work with chatlist
pub unsafe fn dc_get_archived_cnt(context: &Context) -> libc::c_int {
let mut ret: libc::c_int = 0i32;
let stmt: *mut sqlite3_stmt = dc_sqlite3_prepare(
context,
&context.sql,
b"SELECT COUNT(*) FROM chats WHERE blocked=0 AND archived=1;\x00" as *const u8
as *const libc::c_char,
);
if sqlite3_step(stmt) == 100i32 {
ret = sqlite3_column_int(stmt, 0i32)
}
sqlite3_finalize(stmt);
ret
pub fn dc_get_archived_cnt(context: &Context) -> libc::c_int {
context
.sql
.query_row_col(
context,
"SELECT COUNT(*) FROM chats WHERE blocked=0 AND archived=1;",
params![],
0,
)
.unwrap_or_default()
}
unsafe fn get_last_deaddrop_fresh_msg(context: &Context) -> uint32_t {
let mut ret: uint32_t = 0i32 as uint32_t;
let stmt: *mut sqlite3_stmt;
stmt =
dc_sqlite3_prepare(
fn get_last_deaddrop_fresh_msg(context: &Context) -> u32 {
// we have an index over the state-column, this should be sufficient as there are typically only few fresh messages
context
.sql
.query_row_col(
context,
&context.sql,
b"SELECT m.id FROM msgs m LEFT JOIN chats c ON c.id=m.chat_id WHERE m.state=10 AND m.hidden=0 AND c.blocked=2 ORDER BY m.timestamp DESC, m.id DESC;\x00"
as *const u8 as *const libc::c_char);
/* we have an index over the state-column, this should be sufficient as there are typically only few fresh messages */
if !(sqlite3_step(stmt) != 100i32) {
ret = sqlite3_column_int(stmt, 0i32) as uint32_t
}
sqlite3_finalize(stmt);
ret
"SELECT m.id FROM msgs m LEFT JOIN chats c ON c.id=m.chat_id \
WHERE m.state=10 \
AND m.hidden=0 \
AND c.blocked=2 \
ORDER BY m.timestamp DESC, m.id DESC;",
params![],
0,
)
.unwrap_or_default()
}
pub unsafe fn dc_chatlist_get_cnt(chatlist: *const dc_chatlist_t) -> size_t {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -17,10 +17,8 @@ use mmime::{mailmime_substitute, MAILIMF_NO_ERROR, MAIL_NO_ERROR};
use crate::aheader::*;
use crate::context::Context;
use crate::dc_log::*;
use crate::dc_mimeparser::*;
use crate::dc_securejoin::*;
use crate::dc_sqlite3::*;
use crate::dc_tools::*;
use crate::key::*;
use crate::keyring::*;
@@ -83,27 +81,21 @@ pub unsafe fn dc_e2ee_encrypt(
{
/* libEtPan's pgp_encrypt_mime() takes the parent as the new root. We just expect the root as being given to this function. */
let prefer_encrypt = if 0
!= dc_sqlite3_get_config_int(
context,
&context.sql,
b"e2ee_enabled\x00" as *const u8 as *const libc::c_char,
1,
) {
!= context
.sql
.get_config_int(context, "e2ee_enabled")
.unwrap_or_default()
{
EncryptPreference::Mutual
} else {
EncryptPreference::NoPreference
};
let addr = dc_sqlite3_get_config(
context,
&context.sql,
b"configured_addr\x00" as *const u8 as *const libc::c_char,
0 as *const libc::c_char,
);
let addr = context.sql.get_config(context, "configured_addr");
if !addr.is_null() {
if let Some(addr) = addr {
if let Some(public_key) =
load_or_generate_self_public_key(context, addr, in_out_message)
load_or_generate_self_public_key(context, &addr, in_out_message)
{
/*only for random-seed*/
if prefer_encrypt == EncryptPreference::Mutual || 0 != e2ee_guaranteed {
@@ -111,15 +103,10 @@ pub unsafe fn dc_e2ee_encrypt(
let mut iter1: *mut clistiter;
iter1 = (*recipients_addr).first;
while !iter1.is_null() {
let recipient_addr: *const libc::c_char = (if !iter1.is_null() {
(*iter1).data
} else {
0 as *mut libc::c_void
})
as *const libc::c_char;
if strcasecmp(recipient_addr, addr) != 0 {
let recipient_addr = to_string((*iter1).data as *const libc::c_char);
if recipient_addr != addr {
let peerstate =
Peerstate::from_addr(context, &context.sql, as_str(recipient_addr));
Peerstate::from_addr(context, &context.sql, &recipient_addr);
if peerstate.is_some()
&& (peerstate.as_ref().unwrap().prefer_encrypt
== EncryptPreference::Mutual
@@ -145,7 +132,7 @@ pub unsafe fn dc_e2ee_encrypt(
}
let sign_key = if 0 != do_encrypt {
keyring.add_ref(&public_key);
let key = Key::from_self_private(context, addr, &context.sql);
let key = Key::from_self_private(context, addr.clone(), &context.sql);
if key.is_none() {
do_encrypt = 0i32;
@@ -366,8 +353,7 @@ pub unsafe fn dc_e2ee_encrypt(
match current_block {
14181132614457621749 => {}
_ => {
let addr = CStr::from_ptr(addr).to_str().unwrap();
let aheader = Aheader::new(addr.into(), public_key, prefer_encrypt);
let aheader = Aheader::new(addr, public_key, prefer_encrypt);
let rendered = CString::new(aheader.to_string()).unwrap();
mailimf_fields_add(
@@ -503,13 +489,13 @@ unsafe fn new_data_part(
******************************************************************************/
unsafe fn load_or_generate_self_public_key(
context: &Context,
self_addr: *const libc::c_char,
self_addr: impl AsRef<str>,
_random_data_mime: *mut mailmime,
) -> Option<Key> {
/* avoid double creation (we unlock the database during creation) */
static mut s_in_key_creation: libc::c_int = 0i32;
static mut s_in_key_creation: libc::c_int = 0;
let mut key = Key::from_self_public(context, self_addr, &context.sql);
let mut key = Key::from_self_public(context, &self_addr, &context.sql);
if key.is_some() {
return key;
}
@@ -521,46 +507,35 @@ unsafe fn load_or_generate_self_public_key(
let key_creation_here = 1;
s_in_key_creation = 1;
let start: libc::clock_t = clock();
dc_log_info(
let start = clock();
info!(
context,
0i32,
b"Generating keypair with %i bits, e=%i ...\x00" as *const u8 as *const libc::c_char,
2048i32,
65537i32,
0, "Generating keypair with {} bits, e={} ...", 2048, 65537,
);
if let Some((public_key, private_key)) = dc_pgp_create_keypair(self_addr) {
if let Some((public_key, private_key)) = dc_pgp_create_keypair(&self_addr) {
if !dc_key_save_self_keypair(
context,
&public_key,
&private_key,
self_addr,
&self_addr,
1i32,
&context.sql,
) {
/*set default*/
dc_log_warning(
context,
0i32,
b"Cannot save keypair.\x00" as *const u8 as *const libc::c_char,
);
warn!(context, 0, "Cannot save keypair.",);
} else {
dc_log_info(
info!(
context,
0i32,
b"Keypair generated in %.3f s.\x00" as *const u8 as *const libc::c_char,
clock().wrapping_sub(start) as libc::c_double / 1000000i32 as libc::c_double,
0,
"Keypair generated in {:.3}s.",
clock().wrapping_sub(start) as libc::c_double / 1000000 as libc::c_double,
);
}
key = Some(public_key);
} else {
dc_log_warning(
context,
0i32,
b"Cannot create keypair.\x00" as *const u8 as *const libc::c_char,
);
warn!(context, 0, "Cannot create keypair.");
}
if 0 != key_creation_here {
@@ -583,7 +558,6 @@ pub unsafe fn dc_e2ee_decrypt(
let imffields: *mut mailimf_fields = mailmime_find_mailimf_fields(in_out_message);
let mut message_time = 0;
let mut from: *mut libc::c_char = 0 as *mut libc::c_char;
let mut self_addr: *mut libc::c_char = 0 as *mut libc::c_char;
let mut private_keyring = Keyring::default();
let mut public_keyring_for_validate = Keyring::default();
let mut gossip_headers: *mut mailimf_fields = 0 as *mut mailimf_fields;
@@ -612,28 +586,23 @@ pub unsafe fn dc_e2ee_decrypt(
if let Some(ref mut peerstate) = peerstate {
if let Some(ref header) = autocryptheader {
peerstate.apply_header(&header, message_time as u64);
peerstate.apply_header(&header, message_time);
peerstate.save_to_db(&context.sql, false);
} else if message_time as u64 > peerstate.last_seen_autocrypt
} else if message_time > peerstate.last_seen_autocrypt
&& 0 == contains_report(in_out_message)
{
peerstate.degrade_encryption(message_time as u64);
peerstate.degrade_encryption(message_time);
peerstate.save_to_db(&context.sql, false);
}
} else if let Some(ref header) = autocryptheader {
let p = Peerstate::from_header(context, header, message_time as u64);
let p = Peerstate::from_header(context, header, message_time);
p.save_to_db(&context.sql, true);
peerstate = Some(p);
}
}
/* load private key for decryption */
self_addr = dc_sqlite3_get_config(
context,
&context.sql,
b"configured_addr\x00" as *const u8 as *const libc::c_char,
0 as *const libc::c_char,
);
if !self_addr.is_null() {
let self_addr = context.sql.get_config(context, "configured_addr");
if let Some(self_addr) = self_addr {
if private_keyring.load_self_private_for_decrypting(context, self_addr, &context.sql) {
if peerstate.as_ref().map(|p| p.last_seen).unwrap_or_else(|| 0) == 0 {
peerstate = Peerstate::from_addr(&context, &context.sql, as_str(from));
@@ -681,7 +650,6 @@ pub unsafe fn dc_e2ee_decrypt(
}
free(from as *mut libc::c_void);
free(self_addr as *mut libc::c_void);
}
unsafe fn update_gossip_peerstates(
@@ -722,10 +690,10 @@ unsafe fn update_gossip_peerstates(
let mut peerstate =
Peerstate::from_addr(context, &context.sql, &header.addr);
if let Some(ref mut peerstate) = peerstate {
peerstate.apply_gossip(header, message_time as u64);
peerstate.apply_gossip(header, message_time);
peerstate.save_to_db(&context.sql, false);
} else {
let p = Peerstate::from_gossip(context, header, message_time as u64);
let p = Peerstate::from_gossip(context, header, message_time);
p.save_to_db(&context.sql, true);
peerstate = Some(p);
}
@@ -737,12 +705,11 @@ unsafe fn update_gossip_peerstates(
gossipped_addr.insert(header.addr.clone());
} else {
dc_log_info(
info!(
context,
0i32,
b"Ignoring gossipped \"%s\" as the address is not in To/Cc list.\x00"
as *const u8 as *const libc::c_char,
CString::new(header.addr.clone()).unwrap().as_ptr(),
0,
"Ignoring gossipped \"{}\" as the address is not in To/Cc list.",
&header.addr,
);
}
}
@@ -1103,25 +1070,18 @@ pub unsafe fn dc_ensure_secret_key_exists(context: &Context) -> libc::c_int {
(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 = dc_sqlite3_get_config(
context,
&context.sql,
b"configured_addr\x00" as *const u8 as *const libc::c_char,
0 as *const libc::c_char,
);
if self_addr.is_null() {
dc_log_warning(
let self_addr = context.sql.get_config(context, "configured_addr");
if self_addr.is_none() {
warn!(
context,
0i32,
b"Cannot ensure secret key if context is not configured.\x00" as *const u8
as *const libc::c_char,
0, "Cannot ensure secret key if context is not configured.",
);
} else if load_or_generate_self_public_key(context, self_addr, 0 as *mut mailmime).is_some() {
} 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 = 1i32
success = 1;
}
free(self_addr as *mut libc::c_void);
success
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -2,11 +2,8 @@ use std::sync::{Arc, Condvar, Mutex};
use crate::context::Context;
use crate::dc_configure::*;
use crate::dc_sqlite3::*;
use crate::imap::Imap;
use crate::types::*;
use crate::x::*;
use std::ffi::CString;
#[repr(C)]
pub struct dc_jobthread_t {
@@ -132,40 +129,32 @@ pub unsafe fn dc_jobthread_fetch(
******************************************************************************/
unsafe fn connect_to_imap(context: &Context, jobthread: &dc_jobthread_t) -> libc::c_int {
let mut ret_connected: libc::c_int;
let mut mvbox_name: *mut libc::c_char = 0 as *mut libc::c_char;
if jobthread.imap.is_connected() {
ret_connected = 1;
} else {
ret_connected = dc_connect_to_configured_imap(context, &jobthread.imap);
if !(0 == ret_connected) {
if dc_sqlite3_get_config_int(
context,
&context.sql,
b"folders_configured\x00" as *const u8 as *const libc::c_char,
0,
) < 3
{
jobthread.imap.configure_folders(context, 0x1);
}
mvbox_name = dc_sqlite3_get_config(
context,
&context.sql,
CString::new(&jobthread.folder_config_name[..])
.unwrap()
.as_ptr(),
0 as *const libc::c_char,
);
if mvbox_name.is_null() {
jobthread.imap.disconnect(context);
ret_connected = 0;
} else {
jobthread.imap.set_watch_folder(mvbox_name);
}
return 1;
}
let mut ret_connected = dc_connect_to_configured_imap(context, &jobthread.imap);
if !(0 == ret_connected) {
if context
.sql
.get_config_int(context, "folders_configured")
.unwrap_or_default()
< 3
{
jobthread.imap.configure_folders(context, 0x1);
}
if let Some(mvbox_name) = context
.sql
.get_config(context, jobthread.folder_config_name)
{
jobthread.imap.set_watch_folder(mvbox_name);
} else {
jobthread.imap.disconnect(context);
ret_connected = 0;
}
}
free(mvbox_name as *mut libc::c_void);
ret_connected
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,142 +0,0 @@
use crate::constants::Event;
use crate::context::Context;
use crate::dc_tools::*;
use crate::types::*;
use crate::x::*;
pub unsafe extern "C" fn dc_log_event(
context: &Context,
event_code: Event,
data1: libc::c_int,
msg: *const libc::c_char,
va: ...
) {
log_vprintf(context, event_code, data1, msg, va);
}
/* Asynchronous "Thread-errors" are reported by the dc_log_error()
function. These errors must be shown to the user by a bubble or so.
"Normal" errors are usually returned by a special value (null or so) and are
usually not reported using dc_log_error() - its up to the caller to
decide, what should be reported or done. However, these "Normal" errors
are usually logged by dc_log_warning(). */
unsafe fn log_vprintf(
context: &Context,
event: Event,
data1: libc::c_int,
msg_format: *const libc::c_char,
va_0: ::std::ffi::VaList,
) {
let msg: *mut libc::c_char;
if !msg_format.is_null() {
let mut tempbuf: [libc::c_char; 1025] = [0; 1025];
vsnprintf(
tempbuf.as_mut_ptr(),
1024i32 as libc::c_ulong,
msg_format,
va_0,
);
msg = dc_strdup(tempbuf.as_mut_ptr())
} else {
msg = dc_mprintf(
b"event #%i\x00" as *const u8 as *const libc::c_char,
event as libc::c_int,
)
}
context.call_cb(event, data1 as uintptr_t, msg as uintptr_t);
free(msg as *mut libc::c_void);
}
pub unsafe extern "C" fn dc_log_event_seq(
context: &Context,
event_code: Event,
sequence_start: *mut libc::c_int,
msg: *const libc::c_char,
va_0: ...
) {
if sequence_start.is_null() {
return;
}
log_vprintf(context, event_code, *sequence_start, msg, va_0);
*sequence_start = 0i32;
}
pub unsafe extern "C" fn dc_log_error(
context: &Context,
data1: libc::c_int,
msg: *const libc::c_char,
va_1: ...
) {
log_vprintf(context, Event::ERROR, data1, msg, va_1);
}
pub unsafe extern "C" fn dc_log_warning(
context: &Context,
data1: libc::c_int,
msg: *const libc::c_char,
va_2: ...
) {
log_vprintf(context, Event::WARNING, data1, msg, va_2);
}
pub unsafe extern "C" fn dc_log_info(
context: &Context,
data1: libc::c_int,
msg: *const libc::c_char,
va_3: ...
) {
log_vprintf(context, Event::INFO, data1, msg, va_3);
}
#[macro_export]
macro_rules! info {
($ctx:expr, $data1:expr, $msg:expr) => {
info!($ctx, $data1, $msg,)
};
($ctx:expr, $data1:expr, $msg:expr, $($args:expr),* $(,)?) => {{
let formatted = format!($msg, $($args),*);
let formatted_c = $crate::dc_tools::to_cstring(formatted);
$ctx.call_cb($crate::constants::Event::INFO, $data1 as uintptr_t,
formatted_c.as_ptr() as uintptr_t)
}};
}
#[macro_export]
macro_rules! warn {
($ctx:expr, $data1:expr, $msg:expr) => {
warn!($ctx, $data1, $msg,)
};
($ctx:expr, $data1:expr, $msg:expr, $($args:expr),* $(,)?) => {
let formatted = format!($msg, $($args),*);
let formatted_c = $crate::dc_tools::to_cstring(formatted);
$ctx.call_cb($crate::constants::Event::WARNING, $data1 as libc::uintptr_t,
formatted_c.as_ptr() as libc::uintptr_t)
};
}
#[macro_export]
macro_rules! error {
($ctx:expr, $data1:expr, $msg:expr) => {
error!($ctx, $data1, $msg,)
};
($ctx:expr, $data1:expr, $msg:expr, $($args:expr),* $(,)?) => {
let formatted = format!($msg, $($args),*);
let formatted_c = $crate::dc_tools::to_cstring(formatted);
$ctx.call_cb($crate::constants::Event::ERROR, $data1 as uintptr_t,
formatted_c.as_ptr() as uintptr_t)
};
}
#[macro_export]
macro_rules! log_event {
($ctx:expr, $data1:expr, $msg:expr) => {
log_event!($ctx, $data1, $msg,)
};
($ctx:expr, $event:expr, $data1:expr, $msg:expr, $($args:expr),* $(,)?) => {
let formatted = format!($msg, $($args),*);
let formatted_c = $crate::dc_tools::to_cstring(formatted);
$ctx.call_cb($event, $data1 as uintptr_t,
formatted_c.as_ptr() as uintptr_t)
};
}

View File

@@ -1,283 +1,168 @@
use crate::context::Context;
use crate::dc_sqlite3::*;
use crate::dc_tools::*;
use crate::types::*;
use crate::x::*;
use std::borrow::Cow;
#[derive(Copy, Clone)]
#[repr(C)]
use crate::context::Context;
use crate::sql::Sql;
#[derive(Default, Debug)]
pub struct dc_loginparam_t {
pub addr: *mut libc::c_char,
pub mail_server: *mut libc::c_char,
pub mail_user: *mut libc::c_char,
pub mail_pw: *mut libc::c_char,
pub addr: String,
pub mail_server: String,
pub mail_user: String,
pub mail_pw: String,
pub mail_port: i32,
pub send_server: *mut libc::c_char,
pub send_user: *mut libc::c_char,
pub send_pw: *mut libc::c_char,
pub send_server: String,
pub send_user: String,
pub send_pw: String,
pub send_port: i32,
pub server_flags: i32,
}
pub unsafe fn dc_loginparam_new() -> *mut dc_loginparam_t {
let loginparam: *mut dc_loginparam_t;
loginparam = calloc(1, ::std::mem::size_of::<dc_loginparam_t>()) as *mut dc_loginparam_t;
assert!(!loginparam.is_null());
loginparam
}
pub unsafe fn dc_loginparam_unref(loginparam: *mut dc_loginparam_t) {
if loginparam.is_null() {
return;
impl dc_loginparam_t {
pub fn addr_str(&self) -> &str {
self.addr.as_str()
}
dc_loginparam_empty(loginparam);
free(loginparam as *mut libc::c_void);
}
/* clears all data and frees its memory. All pointers are NULL after this function is called. */
pub unsafe fn dc_loginparam_empty(mut loginparam: *mut dc_loginparam_t) {
if loginparam.is_null() {
return;
}
free((*loginparam).addr as *mut libc::c_void);
(*loginparam).addr = 0 as *mut libc::c_char;
free((*loginparam).mail_server as *mut libc::c_void);
(*loginparam).mail_server = 0 as *mut libc::c_char;
(*loginparam).mail_port = 0i32;
free((*loginparam).mail_user as *mut libc::c_void);
(*loginparam).mail_user = 0 as *mut libc::c_char;
free((*loginparam).mail_pw as *mut libc::c_void);
(*loginparam).mail_pw = 0 as *mut libc::c_char;
free((*loginparam).send_server as *mut libc::c_void);
(*loginparam).send_server = 0 as *mut libc::c_char;
(*loginparam).send_port = 0i32;
free((*loginparam).send_user as *mut libc::c_void);
(*loginparam).send_user = 0 as *mut libc::c_char;
free((*loginparam).send_pw as *mut libc::c_void);
(*loginparam).send_pw = 0 as *mut libc::c_char;
(*loginparam).server_flags = 0i32;
pub fn dc_loginparam_new() -> dc_loginparam_t {
Default::default()
}
pub unsafe fn dc_loginparam_read(
pub fn dc_loginparam_read(
context: &Context,
loginparam: *mut dc_loginparam_t,
sql: &SQLite,
prefix: *const libc::c_char,
) {
let mut key: *mut libc::c_char = 0 as *mut libc::c_char;
dc_loginparam_empty(loginparam);
sqlite3_free(key as *mut libc::c_void);
key = sqlite3_mprintf(
b"%s%s\x00" as *const u8 as *const libc::c_char,
prefix,
b"addr\x00" as *const u8 as *const libc::c_char,
);
(*loginparam).addr = dc_sqlite3_get_config(context, sql, key, 0 as *const libc::c_char);
sqlite3_free(key as *mut libc::c_void);
key = sqlite3_mprintf(
b"%s%s\x00" as *const u8 as *const libc::c_char,
prefix,
b"mail_server\x00" as *const u8 as *const libc::c_char,
);
(*loginparam).mail_server = dc_sqlite3_get_config(context, sql, key, 0 as *const libc::c_char);
sqlite3_free(key as *mut libc::c_void);
key = sqlite3_mprintf(
b"%s%s\x00" as *const u8 as *const libc::c_char,
prefix,
b"mail_port\x00" as *const u8 as *const libc::c_char,
);
(*loginparam).mail_port = dc_sqlite3_get_config_int(context, sql, key, 0i32);
sqlite3_free(key as *mut libc::c_void);
key = sqlite3_mprintf(
b"%s%s\x00" as *const u8 as *const libc::c_char,
prefix,
b"mail_user\x00" as *const u8 as *const libc::c_char,
);
(*loginparam).mail_user = dc_sqlite3_get_config(context, sql, key, 0 as *const libc::c_char);
sqlite3_free(key as *mut libc::c_void);
key = sqlite3_mprintf(
b"%s%s\x00" as *const u8 as *const libc::c_char,
prefix,
b"mail_pw\x00" as *const u8 as *const libc::c_char,
);
(*loginparam).mail_pw = dc_sqlite3_get_config(context, sql, key, 0 as *const libc::c_char);
sqlite3_free(key as *mut libc::c_void);
key = sqlite3_mprintf(
b"%s%s\x00" as *const u8 as *const libc::c_char,
prefix,
b"send_server\x00" as *const u8 as *const libc::c_char,
);
(*loginparam).send_server = dc_sqlite3_get_config(context, sql, key, 0 as *const libc::c_char);
sqlite3_free(key as *mut libc::c_void);
key = sqlite3_mprintf(
b"%s%s\x00" as *const u8 as *const libc::c_char,
prefix,
b"send_port\x00" as *const u8 as *const libc::c_char,
);
(*loginparam).send_port = dc_sqlite3_get_config_int(context, sql, key, 0i32);
sqlite3_free(key as *mut libc::c_void);
key = sqlite3_mprintf(
b"%s%s\x00" as *const u8 as *const libc::c_char,
prefix,
b"send_user\x00" as *const u8 as *const libc::c_char,
);
(*loginparam).send_user = dc_sqlite3_get_config(context, sql, key, 0 as *const libc::c_char);
sqlite3_free(key as *mut libc::c_void);
key = sqlite3_mprintf(
b"%s%s\x00" as *const u8 as *const libc::c_char,
prefix,
b"send_pw\x00" as *const u8 as *const libc::c_char,
);
(*loginparam).send_pw = dc_sqlite3_get_config(context, sql, key, 0 as *const libc::c_char);
sqlite3_free(key as *mut libc::c_void);
key = sqlite3_mprintf(
b"%s%s\x00" as *const u8 as *const libc::c_char,
prefix,
b"server_flags\x00" as *const u8 as *const libc::c_char,
);
(*loginparam).server_flags = dc_sqlite3_get_config_int(context, sql, key, 0i32);
sqlite3_free(key as *mut libc::c_void);
}
sql: &Sql,
prefix: impl AsRef<str>,
) -> dc_loginparam_t {
let prefix = prefix.as_ref();
pub unsafe fn dc_loginparam_write(
context: &Context,
loginparam: *const dc_loginparam_t,
sql: &SQLite,
prefix: *const libc::c_char,
) {
let mut key: *mut libc::c_char = 0 as *mut libc::c_char;
sqlite3_free(key as *mut libc::c_void);
key = sqlite3_mprintf(
b"%s%s\x00" as *const u8 as *const libc::c_char,
prefix,
b"addr\x00" as *const u8 as *const libc::c_char,
);
dc_sqlite3_set_config(context, sql, key, (*loginparam).addr);
sqlite3_free(key as *mut libc::c_void);
key = sqlite3_mprintf(
b"%s%s\x00" as *const u8 as *const libc::c_char,
prefix,
b"mail_server\x00" as *const u8 as *const libc::c_char,
);
dc_sqlite3_set_config(context, sql, key, (*loginparam).mail_server);
sqlite3_free(key as *mut libc::c_void);
key = sqlite3_mprintf(
b"%s%s\x00" as *const u8 as *const libc::c_char,
prefix,
b"mail_port\x00" as *const u8 as *const libc::c_char,
);
dc_sqlite3_set_config_int(context, sql, key, (*loginparam).mail_port);
sqlite3_free(key as *mut libc::c_void);
key = sqlite3_mprintf(
b"%s%s\x00" as *const u8 as *const libc::c_char,
prefix,
b"mail_user\x00" as *const u8 as *const libc::c_char,
);
dc_sqlite3_set_config(context, sql, key, (*loginparam).mail_user);
sqlite3_free(key as *mut libc::c_void);
key = sqlite3_mprintf(
b"%s%s\x00" as *const u8 as *const libc::c_char,
prefix,
b"mail_pw\x00" as *const u8 as *const libc::c_char,
);
dc_sqlite3_set_config(context, sql, key, (*loginparam).mail_pw);
sqlite3_free(key as *mut libc::c_void);
key = sqlite3_mprintf(
b"%s%s\x00" as *const u8 as *const libc::c_char,
prefix,
b"send_server\x00" as *const u8 as *const libc::c_char,
);
dc_sqlite3_set_config(context, sql, key, (*loginparam).send_server);
sqlite3_free(key as *mut libc::c_void);
key = sqlite3_mprintf(
b"%s%s\x00" as *const u8 as *const libc::c_char,
prefix,
b"send_port\x00" as *const u8 as *const libc::c_char,
);
dc_sqlite3_set_config_int(context, sql, key, (*loginparam).send_port);
sqlite3_free(key as *mut libc::c_void);
key = sqlite3_mprintf(
b"%s%s\x00" as *const u8 as *const libc::c_char,
prefix,
b"send_user\x00" as *const u8 as *const libc::c_char,
);
dc_sqlite3_set_config(context, sql, key, (*loginparam).send_user);
sqlite3_free(key as *mut libc::c_void);
key = sqlite3_mprintf(
b"%s%s\x00" as *const u8 as *const libc::c_char,
prefix,
b"send_pw\x00" as *const u8 as *const libc::c_char,
);
dc_sqlite3_set_config(context, sql, key, (*loginparam).send_pw);
sqlite3_free(key as *mut libc::c_void);
key = sqlite3_mprintf(
b"%s%s\x00" as *const u8 as *const libc::c_char,
prefix,
b"server_flags\x00" as *const u8 as *const libc::c_char,
);
dc_sqlite3_set_config_int(context, sql, key, (*loginparam).server_flags);
sqlite3_free(key as *mut libc::c_void);
}
let key = format!("{}addr", prefix);
let addr = sql
.get_config(context, key)
.unwrap_or_default()
.trim()
.to_string();
pub unsafe fn dc_loginparam_get_readable(loginparam: *const dc_loginparam_t) -> *mut libc::c_char {
let unset: *const libc::c_char = b"0\x00" as *const u8 as *const libc::c_char;
let pw: *const libc::c_char = b"***\x00" as *const u8 as *const libc::c_char;
if loginparam.is_null() {
return dc_strdup(0 as *const libc::c_char);
let key = format!("{}mail_server", prefix);
let mail_server = sql.get_config(context, key).unwrap_or_default();
let key = format!("{}mail_port", prefix);
let mail_port = sql.get_config_int(context, key).unwrap_or_default();
let key = format!("{}mail_user", prefix);
let mail_user = sql.get_config(context, key).unwrap_or_default();
let key = format!("{}mail_pw", prefix);
let mail_pw = sql.get_config(context, key).unwrap_or_default();
let key = format!("{}send_server", prefix);
let send_server = sql.get_config(context, key).unwrap_or_default();
let key = format!("{}send_port", prefix);
let send_port = sql.get_config_int(context, key).unwrap_or_default();
let key = format!("{}send_user", prefix);
let send_user = sql.get_config(context, key).unwrap_or_default();
let key = format!("{}send_pw", prefix);
let send_pw = sql.get_config(context, key).unwrap_or_default();
let key = format!("{}server_flags", prefix);
let server_flags = sql.get_config_int(context, key).unwrap_or_default();
dc_loginparam_t {
addr: addr.to_string(),
mail_server,
mail_user,
mail_pw,
mail_port,
send_server,
send_user,
send_pw,
send_port,
server_flags,
}
let flags_readable: *mut libc::c_char = get_readable_flags((*loginparam).server_flags);
let ret: *mut libc::c_char = dc_mprintf(
b"%s %s:%s:%s:%i %s:%s:%s:%i %s\x00" as *const u8 as *const libc::c_char,
if !(*loginparam).addr.is_null() {
(*loginparam).addr
} else {
unset
},
if !(*loginparam).mail_user.is_null() {
(*loginparam).mail_user
} else {
unset
},
if !(*loginparam).mail_pw.is_null() {
}
pub fn dc_loginparam_write(
context: &Context,
loginparam: &dc_loginparam_t,
sql: &Sql,
prefix: impl AsRef<str>,
) {
let prefix = prefix.as_ref();
let key = format!("{}addr", prefix);
sql.set_config(context, key, Some(&loginparam.addr));
let key = format!("{}mail_server", prefix);
sql.set_config(context, key, Some(&loginparam.mail_server));
let key = format!("{}mail_port", prefix);
sql.set_config_int(context, key, loginparam.mail_port);
let key = format!("{}mail_user", prefix);
sql.set_config(context, key, Some(&loginparam.mail_user));
let key = format!("{}mail_pw", prefix);
sql.set_config(context, key, Some(&loginparam.mail_pw));
let key = format!("{}send_server", prefix);
sql.set_config(context, key, Some(&loginparam.send_server));
let key = format!("{}send_port", prefix);
sql.set_config_int(context, key, loginparam.send_port);
let key = format!("{}send_user", prefix);
sql.set_config(context, key, Some(&loginparam.send_user));
let key = format!("{}send_pw", prefix);
sql.set_config(context, key, Some(&loginparam.send_pw));
let key = format!("{}server_flags", prefix);
sql.set_config_int(context, key, loginparam.server_flags);
}
fn unset_empty(s: &String) -> Cow<String> {
if s.is_empty() {
Cow::Owned("unset".to_string())
} else {
Cow::Borrowed(s)
}
}
pub fn dc_loginparam_get_readable(loginparam: &dc_loginparam_t) -> String {
let unset = "0";
let pw = "***";
let flags_readable = get_readable_flags(loginparam.server_flags);
format!(
"{} {}:{}:{}:{} {}:{}:{}:{} {}",
unset_empty(&loginparam.addr),
unset_empty(&loginparam.mail_user),
if !loginparam.mail_pw.is_empty() {
pw
} else {
unset
},
if !(*loginparam).mail_server.is_null() {
(*loginparam).mail_server
} else {
unset
},
(*loginparam).mail_port,
if !(*loginparam).send_user.is_null() {
(*loginparam).send_user
} else {
unset
},
if !(*loginparam).send_pw.is_null() {
unset_empty(&loginparam.mail_server),
loginparam.mail_port,
unset_empty(&loginparam.send_user),
if !loginparam.send_pw.is_empty() {
pw
} else {
unset
},
if !(*loginparam).send_server.is_null() {
(*loginparam).send_server
} else {
unset
},
(*loginparam).send_port,
unset_empty(&loginparam.send_server),
loginparam.send_port,
flags_readable,
);
free(flags_readable as *mut libc::c_void);
ret
)
}
fn get_readable_flags(flags: libc::c_int) -> *mut libc::c_char {
fn get_readable_flags(flags: i32) -> String {
let mut res = String::new();
for bit in 0..31 {
if 0 != flags & 1 << bit {
let mut flag_added: libc::c_int = 0;
let mut flag_added = 0;
if 1 << bit == 0x2 {
res += "OAUTH2 ";
flag_added = 1;
@@ -319,5 +204,5 @@ fn get_readable_flags(flags: libc::c_int) -> *mut libc::c_char {
res += "0";
}
unsafe { strdup(to_cstring(res).as_ptr()) }
res
}

View File

@@ -14,10 +14,8 @@ use crate::dc_chat::*;
use crate::dc_contact::*;
use crate::dc_e2ee::*;
use crate::dc_location::*;
use crate::dc_log::*;
use crate::dc_msg::*;
use crate::dc_param::*;
use crate::dc_sqlite3::*;
use crate::dc_stock::*;
use crate::dc_strencode::*;
use crate::dc_tools::*;
@@ -100,7 +98,7 @@ pub unsafe fn dc_mimefactory_empty(mut factory: *mut dc_mimefactory_t) {
mmap_string_free((*factory).out);
(*factory).out = 0 as *mut MMAPString
}
(*factory).out_encrypted = 0i32;
(*factory).out_encrypted = 0;
(*factory).loaded = DC_MF_NOTHING_LOADED;
free((*factory).error as *mut libc::c_void);
(*factory).error = 0 as *mut libc::c_char;
@@ -111,158 +109,192 @@ pub unsafe fn dc_mimefactory_load_msg(
mut factory: *mut dc_mimefactory_t,
msg_id: uint32_t,
) -> libc::c_int {
let mut success: libc::c_int = 0i32;
let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt;
if !(factory.is_null() || msg_id <= 9i32 as libc::c_uint || !(*factory).msg.is_null()) {
/*call empty() before */
let context = (*factory).context;
(*factory).recipients_names = clist_new();
(*factory).recipients_addr = clist_new();
(*factory).msg = dc_msg_new_untyped(context);
(*factory).chat = dc_chat_new(context);
if dc_msg_load_from_db((*factory).msg, context, msg_id)
&& dc_chat_load_from_db((*factory).chat, (*(*factory).msg).chat_id)
{
load_from(factory);
(*factory).req_mdn = 0i32;
if 0 != dc_chat_is_self_talk((*factory).chat) {
clist_insert_after(
(*factory).recipients_names,
(*(*factory).recipients_names).last,
dc_strdup_keep_null((*factory).from_displayname) as *mut libc::c_void,
if factory.is_null() || msg_id <= 9 || !(*factory).msg.is_null() {
info!((*factory).context, 0, "mimefactory: null");
return 0;
}
let mut success = 0;
/*call empty() before */
let context = (*factory).context;
(*factory).recipients_names = clist_new();
(*factory).recipients_addr = clist_new();
(*factory).msg = dc_msg_new_untyped(context);
(*factory).chat = dc_chat_new(context);
if dc_msg_load_from_db((*factory).msg, context, msg_id)
&& dc_chat_load_from_db((*factory).chat, (*(*factory).msg).chat_id)
{
info!(context, 0, "mimefactory: loaded msg and chat",);
load_from(factory);
(*factory).req_mdn = 0;
if 0 != dc_chat_is_self_talk((*factory).chat) {
info!(context, 0, "mimefactory: selftalk");
clist_insert_after(
(*factory).recipients_names,
(*(*factory).recipients_names).last,
dc_strdup_keep_null((*factory).from_displayname) as *mut libc::c_void,
);
clist_insert_after(
(*factory).recipients_addr,
(*(*factory).recipients_addr).last,
dc_strdup((*factory).from_addr) as *mut libc::c_void,
);
} else {
info!(context, 0, "mimefactory: query map");
context
.sql
.query_map(
"SELECT c.authname, c.addr \
FROM chats_contacts cc \
LEFT JOIN contacts c ON cc.contact_id=c.id \
WHERE cc.chat_id=? AND cc.contact_id>9;",
params![(*(*factory).msg).chat_id as i32],
|row| {
let authname: String = row.get(0)?;
let addr: String = row.get(1)?;
Ok((authname, addr))
},
|rows| {
info!(context, 0, "mimefactory: processing rows");
for row in rows {
let (authname, addr) = row?;
let addr_c = to_cstring(addr);
if clist_search_string_nocase(
(*factory).recipients_addr,
addr_c.as_ptr(),
) == 0
{
clist_insert_after(
(*factory).recipients_names,
(*(*factory).recipients_names).last,
if !authname.is_empty() {
dc_strdup(to_cstring(authname).as_ptr())
} else {
0 as *mut libc::c_char
} as *mut libc::c_void,
);
clist_insert_after(
(*factory).recipients_addr,
(*(*factory).recipients_addr).last,
dc_strdup(addr_c.as_ptr()) as *mut libc::c_void,
);
}
}
Ok(())
},
)
.unwrap();
let command = dc_param_get_int((*(*factory).msg).param, 'S' as i32, 0);
if command == 5 {
let email_to_remove_c = dc_param_get(
(*(*factory).msg).param,
'E' as i32,
0 as *const libc::c_char,
);
clist_insert_after(
(*factory).recipients_addr,
(*(*factory).recipients_addr).last,
dc_strdup((*factory).from_addr) as *mut libc::c_void,
);
} else {
stmt =
dc_sqlite3_prepare(
context,
&context.sql,
b"SELECT c.authname, c.addr FROM chats_contacts cc LEFT JOIN contacts c ON cc.contact_id=c.id WHERE cc.chat_id=? AND cc.contact_id>9;\x00"
as *const u8 as
*const libc::c_char);
sqlite3_bind_int(stmt, 1i32, (*(*factory).msg).chat_id as libc::c_int);
while sqlite3_step(stmt) == 100i32 {
let authname: *const libc::c_char =
sqlite3_column_text(stmt, 0i32) as *const libc::c_char;
let addr: *const libc::c_char =
sqlite3_column_text(stmt, 1i32) as *const libc::c_char;
if clist_search_string_nocase((*factory).recipients_addr, addr) == 0i32 {
let email_to_remove = to_string(email_to_remove_c);
let self_addr = context
.sql
.get_config(context, "configured_addr")
.unwrap_or_default();
if !email_to_remove.is_empty() && email_to_remove != self_addr {
if clist_search_string_nocase((*factory).recipients_addr, email_to_remove_c)
== 0
{
clist_insert_after(
(*factory).recipients_names,
(*(*factory).recipients_names).last,
(if !authname.is_null() && 0 != *authname.offset(0isize) as libc::c_int
{
dc_strdup(authname)
} else {
0 as *mut libc::c_char
}) as *mut libc::c_void,
0 as *mut libc::c_void,
);
clist_insert_after(
(*factory).recipients_addr,
(*(*factory).recipients_addr).last,
dc_strdup(addr) as *mut libc::c_void,
email_to_remove_c as *mut libc::c_void,
);
}
}
sqlite3_finalize(stmt);
let command: libc::c_int =
dc_param_get_int((*(*factory).msg).param, 'S' as i32, 0i32);
if command == 5i32 {
let email_to_remove: *mut libc::c_char = dc_param_get(
(*(*factory).msg).param,
'E' as i32,
0 as *const libc::c_char,
);
let self_addr: *mut libc::c_char = dc_sqlite3_get_config(
context,
&context.sql,
b"configured_addr\x00" as *const u8 as *const libc::c_char,
b"\x00" as *const u8 as *const libc::c_char,
);
if !email_to_remove.is_null() && strcasecmp(email_to_remove, self_addr) != 0i32
{
if clist_search_string_nocase((*factory).recipients_addr, email_to_remove)
== 0i32
{
clist_insert_after(
(*factory).recipients_names,
(*(*factory).recipients_names).last,
0 as *mut libc::c_void,
);
clist_insert_after(
(*factory).recipients_addr,
(*(*factory).recipients_addr).last,
email_to_remove as *mut libc::c_void,
);
}
}
free(self_addr as *mut libc::c_void);
}
if command != 6i32
&& command != 7i32
&& 0 != dc_sqlite3_get_config_int(
context,
&context.sql,
b"mdns_enabled\x00" as *const u8 as *const libc::c_char,
1i32,
)
{
(*factory).req_mdn = 1i32
}
}
stmt = dc_sqlite3_prepare(
context,
&context.sql,
b"SELECT mime_in_reply_to, mime_references FROM msgs WHERE id=?\x00" as *const u8
as *const libc::c_char,
);
sqlite3_bind_int(stmt, 1i32, (*(*factory).msg).id as libc::c_int);
if sqlite3_step(stmt) == 100i32 {
(*factory).in_reply_to =
dc_strdup(sqlite3_column_text(stmt, 0i32) as *const libc::c_char);
(*factory).references =
dc_strdup(sqlite3_column_text(stmt, 1i32) as *const libc::c_char)
if command != 6
&& command != 7
&& 0 != context
.sql
.get_config_int(context, "mdns_enabled")
.unwrap_or_else(|| 1)
{
(*factory).req_mdn = 1
}
sqlite3_finalize(stmt);
stmt = 0 as *mut sqlite3_stmt;
success = 1i32;
(*factory).loaded = DC_MF_MSG_LOADED;
(*factory).timestamp = (*(*factory).msg).timestamp_sort;
(*factory).rfc724_mid = dc_strdup((*(*factory).msg).rfc724_mid)
}
if 0 != success {
(*factory).increation = dc_msg_is_increation((*factory).msg)
info!(context, 0, "mimefactory: loading in reply to");
let row = context.sql.query_row(
"SELECT mime_in_reply_to, mime_references FROM msgs WHERE id=?",
params![(*(*factory).msg).id as i32],
|row| {
let in_reply_to: String = row.get(0)?;
let references: String = row.get(1)?;
Ok((in_reply_to, references))
},
);
match row {
Ok((in_reply_to, references)) => {
(*factory).in_reply_to = dc_strdup(to_cstring(in_reply_to).as_ptr());
(*factory).references = dc_strdup(to_cstring(references).as_ptr());
}
Err(err) => {
error!(
context,
0, "mimefactory: failed to load mime_in_reply_to: {:?}", err
);
}
}
success = 1;
(*factory).loaded = DC_MF_MSG_LOADED;
(*factory).timestamp = (*(*factory).msg).timestamp_sort;
(*factory).rfc724_mid = dc_strdup((*(*factory).msg).rfc724_mid)
}
sqlite3_finalize(stmt);
return success;
if 0 != success {
(*factory).increation = dc_msg_is_increation((*factory).msg)
}
success
}
unsafe fn load_from(mut factory: *mut dc_mimefactory_t) {
(*factory).from_addr = dc_sqlite3_get_config(
(*factory).context,
&(*factory).context.sql,
b"configured_addr\x00" as *const u8 as *const libc::c_char,
0 as *const libc::c_char,
let context = (*factory).context;
(*factory).from_addr = strdup(
to_cstring(
context
.sql
.get_config(context, "configured_addr")
.unwrap_or_default(),
)
.as_ptr(),
);
(*factory).from_displayname = dc_sqlite3_get_config(
(*factory).context,
&(*factory).context.sql,
b"displayname\x00" as *const u8 as *const libc::c_char,
0 as *const libc::c_char,
(*factory).from_displayname = strdup(
to_cstring(
context
.sql
.get_config(context, "displayname")
.unwrap_or_default(),
)
.as_ptr(),
);
(*factory).selfstatus = dc_sqlite3_get_config(
(*factory).context,
&(*factory).context.sql,
b"selfstatus\x00" as *const u8 as *const libc::c_char,
0 as *const libc::c_char,
(*factory).selfstatus = strdup(
to_cstring(
context
.sql
.get_config(context, "selfstatus")
.unwrap_or_default(),
)
.as_ptr(),
);
if (*factory).selfstatus.is_null() {
(*factory).selfstatus = dc_stock_str((*factory).context, 13i32)
(*factory).selfstatus = dc_stock_str((*factory).context, 13)
};
}
@@ -270,61 +302,63 @@ pub unsafe fn dc_mimefactory_load_mdn(
mut factory: *mut dc_mimefactory_t,
msg_id: uint32_t,
) -> libc::c_int {
let mut success: libc::c_int = 0i32;
let mut contact: *mut dc_contact_t = 0 as *mut dc_contact_t;
if !factory.is_null() {
(*factory).recipients_names = clist_new();
(*factory).recipients_addr = clist_new();
(*factory).msg = dc_msg_new_untyped((*factory).context);
if !(0
== dc_sqlite3_get_config_int(
(*factory).context,
if factory.is_null() {
return 0;
}
let mut success = 0;
let mut contact = 0 as *mut dc_contact_t;
(*factory).recipients_names = clist_new();
(*factory).recipients_addr = clist_new();
(*factory).msg = dc_msg_new_untyped((*factory).context);
if 0 != (*factory)
.context
.sql
.get_config_int((*factory).context, "mdns_enabled")
.unwrap_or_else(|| 1)
{
// MDNs not enabled - check this is late, in the job. the use may have changed its choice while offline ...
contact = dc_contact_new((*factory).context);
if !(!dc_msg_load_from_db((*factory).msg, (*factory).context, msg_id)
|| !dc_contact_load_from_db(
contact,
&(*factory).context.sql,
b"mdns_enabled\x00" as *const u8 as *const libc::c_char,
1i32,
(*(*factory).msg).from_id,
))
{
/* MDNs not enabled - check this is late, in the job. the use may have changed its choice while offline ... */
contact = dc_contact_new((*factory).context);
if !(!dc_msg_load_from_db((*factory).msg, (*factory).context, msg_id)
|| !dc_contact_load_from_db(
contact,
&(*factory).context.sql,
(*(*factory).msg).from_id,
))
{
if !(0 != (*contact).blocked || (*(*factory).msg).chat_id <= 9i32 as libc::c_uint) {
/* Do not send MDNs trash etc.; chats.blocked is already checked by the caller in dc_markseen_msgs() */
if !((*(*factory).msg).from_id <= 9i32 as libc::c_uint) {
clist_insert_after(
(*factory).recipients_names,
(*(*factory).recipients_names).last,
(if !(*contact).authname.is_null()
&& 0 != *(*contact).authname.offset(0isize) as libc::c_int
{
dc_strdup((*contact).authname)
} else {
0 as *mut libc::c_char
}) as *mut libc::c_void,
);
clist_insert_after(
(*factory).recipients_addr,
(*(*factory).recipients_addr).last,
dc_strdup((*contact).addr) as *mut libc::c_void,
);
load_from(factory);
(*factory).timestamp = dc_create_smeared_timestamp((*factory).context);
(*factory).rfc724_mid = dc_create_outgoing_rfc724_mid(
0 as *const libc::c_char,
(*factory).from_addr,
);
success = 1i32;
(*factory).loaded = DC_MF_MDN_LOADED
}
if !(0 != (*contact).blocked || (*(*factory).msg).chat_id <= 9 as libc::c_uint) {
// Do not send MDNs trash etc.; chats.blocked is already checked by the caller in dc_markseen_msgs()
if !((*(*factory).msg).from_id <= 9 as libc::c_uint) {
clist_insert_after(
(*factory).recipients_names,
(*(*factory).recipients_names).last,
(if !(*contact).authname.is_null()
&& 0 != *(*contact).authname.offset(0isize) as libc::c_int
{
dc_strdup((*contact).authname)
} else {
0 as *mut libc::c_char
}) as *mut libc::c_void,
);
clist_insert_after(
(*factory).recipients_addr,
(*(*factory).recipients_addr).last,
dc_strdup((*contact).addr) as *mut libc::c_void,
);
load_from(factory);
(*factory).timestamp = dc_create_smeared_timestamp((*factory).context);
(*factory).rfc724_mid = dc_create_outgoing_rfc724_mid(
0 as *const libc::c_char,
(*factory).from_addr,
);
success = 1;
(*factory).loaded = DC_MF_MDN_LOADED
}
}
}
}
dc_contact_unref(contact);
success
@@ -339,15 +373,15 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
let mut message_text: *mut libc::c_char = 0 as *mut libc::c_char;
let mut message_text2: *mut libc::c_char = 0 as *mut libc::c_char;
let mut subject_str: *mut libc::c_char = 0 as *mut libc::c_char;
let mut afwd_email: libc::c_int = 0i32;
let mut col: libc::c_int = 0i32;
let mut success: libc::c_int = 0i32;
let mut parts: libc::c_int = 0i32;
let mut e2ee_guaranteed: libc::c_int = 0i32;
let mut min_verified: libc::c_int = 0i32;
let mut afwd_email: libc::c_int = 0;
let mut col: libc::c_int = 0;
let mut success: libc::c_int = 0;
let mut parts: libc::c_int = 0;
let mut e2ee_guaranteed: libc::c_int = 0;
let mut min_verified: libc::c_int = 0;
// 1=add Autocrypt-header (needed eg. for handshaking), 2=no Autocrypte-header (used for MDN)
let mut force_plaintext: libc::c_int = 0i32;
let mut do_gossip: libc::c_int = 0i32;
let mut force_plaintext: libc::c_int = 0;
let mut do_gossip: libc::c_int = 0;
let mut grpimage: *mut libc::c_char = 0 as *mut libc::c_char;
let mut e2ee_helper = dc_e2ee_helper_t {
encryption_successfull: 0,
@@ -382,7 +416,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
let mut to: *mut mailimf_address_list = 0 as *mut mailimf_address_list;
if !(*factory).recipients_names.is_null()
&& !(*factory).recipients_addr.is_null()
&& (*(*factory).recipients_addr).count > 0i32
&& (*(*factory).recipients_addr).count > 0
{
let mut iter1: *mut clistiter;
let mut iter2: *mut clistiter;
@@ -505,7 +539,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
let msg: *mut dc_msg_t = (*factory).msg;
let mut meta_part: *mut mailmime = 0 as *mut mailmime;
let mut placeholdertext: *mut libc::c_char = 0 as *mut libc::c_char;
if (*chat).type_0 == 130i32 {
if (*chat).type_0 == 130 {
mailimf_fields_add(
imf_fields,
mailimf_field_new_custom(
@@ -513,23 +547,23 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
strdup(b"1\x00" as *const u8 as *const libc::c_char),
),
);
force_plaintext = 0i32;
e2ee_guaranteed = 1i32;
min_verified = 2i32
force_plaintext = 0;
e2ee_guaranteed = 1;
min_verified = 2
} else {
force_plaintext = dc_param_get_int((*(*factory).msg).param, 'u' as i32, 0i32);
if force_plaintext == 0i32 {
e2ee_guaranteed = dc_param_get_int((*(*factory).msg).param, 'c' as i32, 0i32)
force_plaintext = dc_param_get_int((*(*factory).msg).param, 'u' as i32, 0);
if force_plaintext == 0 {
e2ee_guaranteed = dc_param_get_int((*(*factory).msg).param, 'c' as i32, 0)
}
}
if (*chat).gossiped_timestamp == 0
|| ((*chat).gossiped_timestamp + (2 * 24 * 60 * 60)) < time()
{
do_gossip = 1i32
do_gossip = 1
}
/* build header etc. */
let command: libc::c_int = dc_param_get_int((*msg).param, 'S' as i32, 0i32);
if (*chat).type_0 == 120i32 || (*chat).type_0 == 130i32 {
let command: libc::c_int = dc_param_get_int((*msg).param, 'S' as i32, 0);
if (*chat).type_0 == 120 || (*chat).type_0 == 130 {
mailimf_fields_add(
imf_fields,
mailimf_field_new_custom(
@@ -544,7 +578,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
dc_encode_header_words((*chat).name),
),
);
if command == 5i32 {
if command == 5 {
let email_to_remove: *mut libc::c_char =
dc_param_get((*msg).param, 'E' as i32, 0 as *const libc::c_char);
if !email_to_remove.is_null() {
@@ -559,8 +593,8 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
),
);
}
} else if command == 4i32 {
do_gossip = 1i32;
} else if command == 4 {
do_gossip = 1;
let email_to_add: *mut libc::c_char =
dc_param_get((*msg).param, 'E' as i32, 0 as *const libc::c_char);
if !email_to_add.is_null() {
@@ -576,13 +610,12 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
);
grpimage = dc_param_get((*chat).param, 'i' as i32, 0 as *const libc::c_char)
}
if 0 != dc_param_get_int((*msg).param, 'F' as i32, 0i32) & 0x1i32 {
dc_log_info(
if 0 != dc_param_get_int((*msg).param, 'F' as i32, 0) & 0x1 {
info!(
(*msg).context,
0i32,
b"sending secure-join message \'%s\' >>>>>>>>>>>>>>>>>>>>>>>>>\x00"
as *const u8 as *const libc::c_char,
b"vg-member-added\x00" as *const u8 as *const libc::c_char,
0,
"sending secure-join message \'{}\' >>>>>>>>>>>>>>>>>>>>>>>>>",
"vg-member-added",
);
mailimf_fields_add(
imf_fields,
@@ -592,7 +625,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
),
);
}
} else if command == 2i32 {
} else if command == 2 {
mailimf_fields_add(
imf_fields,
mailimf_field_new_custom(
@@ -606,7 +639,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
),
),
);
} else if command == 3i32 {
} else if command == 3 {
grpimage = dc_param_get((*msg).param, 'E' as i32, 0 as *const libc::c_char);
if grpimage.is_null() {
mailimf_fields_add(
@@ -619,7 +652,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
}
}
}
if command == 8i32 {
if command == 8 {
mailimf_fields_add(
imf_fields,
mailimf_field_new_custom(
@@ -630,7 +663,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
),
);
}
if command == 6i32 {
if command == 6 {
mailimf_fields_add(
imf_fields,
mailimf_field_new_custom(
@@ -638,18 +671,17 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
strdup(b"v1\x00" as *const u8 as *const libc::c_char),
),
);
placeholdertext = dc_stock_str((*factory).context, 43i32)
placeholdertext = dc_stock_str((*factory).context, 43)
}
if command == 7i32 {
if command == 7 {
let step: *mut libc::c_char =
dc_param_get((*msg).param, 'E' as i32, 0 as *const libc::c_char);
if !step.is_null() {
dc_log_info(
info!(
(*msg).context,
0i32,
b"sending secure-join message \'%s\' >>>>>>>>>>>>>>>>>>>>>>>>>\x00"
as *const u8 as *const libc::c_char,
step,
0,
"sending secure-join message \'{}\' >>>>>>>>>>>>>>>>>>>>>>>>>",
as_str(step),
);
mailimf_fields_add(
imf_fields,
@@ -667,12 +699,12 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
if strcmp(
step,
b"vg-request-with-auth\x00" as *const u8 as *const libc::c_char,
) == 0i32
) == 0
|| strcmp(
step,
b"vc-request-with-auth\x00" as *const u8
as *const libc::c_char,
) == 0i32
) == 0
{
strdup(
b"Secure-Join-Auth\x00" as *const u8 as *const libc::c_char,
@@ -718,7 +750,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
}
if !grpimage.is_null() {
let mut meta: *mut dc_msg_t = dc_msg_new_untyped((*factory).context);
(*meta).type_0 = 20i32;
(*meta).type_0 = 20;
dc_param_set((*meta).param, 'f' as i32, grpimage);
let mut filename_as_sent: *mut libc::c_char = 0 as *mut libc::c_char;
meta_part = build_body_file(
@@ -737,8 +769,8 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
}
dc_msg_unref(meta);
}
if (*msg).type_0 == 41i32 || (*msg).type_0 == 40i32 || (*msg).type_0 == 50i32 {
if (*msg).type_0 == 41i32 {
if (*msg).type_0 == 41 || (*msg).type_0 == 40 || (*msg).type_0 == 50 {
if (*msg).type_0 == 41 {
mailimf_fields_add(
imf_fields,
mailimf_field_new_custom(
@@ -747,8 +779,8 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
),
);
}
let duration_ms: libc::c_int = dc_param_get_int((*msg).param, 'd' as i32, 0i32);
if duration_ms > 0i32 {
let duration_ms: libc::c_int = dc_param_get_int((*msg).param, 'd' as i32, 0);
if duration_ms > 0 {
mailimf_fields_add(
imf_fields,
mailimf_field_new_custom(
@@ -813,18 +845,18 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
free(fwdhint as *mut libc::c_void);
free(placeholdertext as *mut libc::c_void);
/* add attachment part */
if (*msg).type_0 == 20i32
|| (*msg).type_0 == 21i32
|| (*msg).type_0 == 40i32
|| (*msg).type_0 == 41i32
|| (*msg).type_0 == 50i32
|| (*msg).type_0 == 60i32
if (*msg).type_0 == 20
|| (*msg).type_0 == 21
|| (*msg).type_0 == 40
|| (*msg).type_0 == 41
|| (*msg).type_0 == 50
|| (*msg).type_0 == 60
{
if 0 == is_file_size_okay(msg) {
let error: *mut libc::c_char = dc_mprintf(
b"Message exceeds the recommended %i MB.\x00" as *const u8
as *const libc::c_char,
24i32 * 1024i32 * 1024i32 / 4i32 * 3i32 / 1000i32 / 1000i32,
24 * 1024 * 1024 / 4 * 3 / 1000 / 1000,
);
set_error(factory, error);
free(error as *mut libc::c_void);
@@ -844,7 +876,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
match current_block {
11328123142868406523 => {}
_ => {
if parts == 0i32 {
if parts == 0 {
set_error(
factory,
b"Empty message.\x00" as *const u8 as *const libc::c_char,
@@ -887,8 +919,8 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
}
}
if 0 != dc_is_sending_locations_to_chat((*msg).context, (*msg).chat_id) {
let mut last_added_location_id: uint32_t = 0i32 as uint32_t;
if dc_is_sending_locations_to_chat((*msg).context, (*msg).chat_id) {
let mut last_added_location_id: uint32_t = 0 as uint32_t;
let kml_file: *mut libc::c_char = dc_get_location_kml(
(*msg).context,
(*msg).chat_id,
@@ -943,12 +975,12 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
mailmime_add_part(message, multipart);
let p1: *mut libc::c_char;
let p2: *mut libc::c_char;
if 0 != dc_param_get_int((*(*factory).msg).param, 'c' as i32, 0i32) {
p1 = dc_stock_str((*factory).context, 24i32)
if 0 != dc_param_get_int((*(*factory).msg).param, 'c' as i32, 0) {
p1 = dc_stock_str((*factory).context, 24)
} else {
p1 = dc_msg_get_summarytext((*factory).msg, 32i32)
p1 = dc_msg_get_summarytext((*factory).msg, 32)
}
p2 = dc_stock_str_repl_string((*factory).context, 32i32, p1);
p2 = dc_stock_str_repl_string((*factory).context, 32, p1);
message_text = dc_mprintf(b"%s\r\n\x00" as *const u8 as *const libc::c_char, p2);
free(p2 as *mut libc::c_void);
free(p1 as *mut libc::c_void);
@@ -968,7 +1000,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
let mach_mime_part: *mut mailmime = mailmime_new_empty(content_type_0, mime_fields_0);
mailmime_set_body_text(mach_mime_part, message_text2, strlen(message_text2));
mailmime_add_part(multipart, mach_mime_part);
force_plaintext = 2i32;
force_plaintext = 2;
current_block = 9952640327414195044;
} else {
set_error(
@@ -983,7 +1015,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
if (*factory).loaded as libc::c_uint
== DC_MF_MDN_LOADED as libc::c_int as libc::c_uint
{
let e: *mut libc::c_char = dc_stock_str((*factory).context, 31i32);
let e: *mut libc::c_char = dc_stock_str((*factory).context, 31);
subject_str =
dc_mprintf(b"Chat: %s\x00" as *const u8 as *const libc::c_char, e);
free(e as *mut libc::c_void);
@@ -1019,7 +1051,7 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
0 as *mut mailimf_optional_field,
),
);
if force_plaintext != 2i32 {
if force_plaintext != 2 {
dc_e2ee_encrypt(
(*factory).context,
(*factory).recipients_addr,
@@ -1032,14 +1064,14 @@ pub unsafe fn dc_mimefactory_render(mut factory: *mut dc_mimefactory_t) -> libc:
);
}
if 0 != e2ee_helper.encryption_successfull {
(*factory).out_encrypted = 1i32;
(*factory).out_encrypted = 1;
if 0 != do_gossip {
(*factory).out_gossiped = 1i32
(*factory).out_gossiped = 1
}
}
(*factory).out = mmap_string_new(b"\x00" as *const u8 as *const libc::c_char);
mailmime_write_mem((*factory).out, &mut col, message);
success = 1i32
success = 1
}
}
}
@@ -1063,15 +1095,15 @@ unsafe fn get_subject(
let context = (*chat).context;
let ret: *mut libc::c_char;
let raw_subject: *mut libc::c_char =
dc_msg_get_summarytext_by_raw((*msg).type_0, (*msg).text, (*msg).param, 32i32, context);
dc_msg_get_summarytext_by_raw((*msg).type_0, (*msg).text, (*msg).param, 32, context);
let fwd: *const libc::c_char = if 0 != afwd_email {
b"Fwd: \x00" as *const u8 as *const libc::c_char
} else {
b"\x00" as *const u8 as *const libc::c_char
};
if dc_param_get_int((*msg).param, 'S' as i32, 0i32) == 6i32 {
ret = dc_stock_str(context, 42i32)
} else if (*chat).type_0 == 120i32 || (*chat).type_0 == 130i32 {
if dc_param_get_int((*msg).param, 'S' as i32, 0) == 6 {
ret = dc_stock_str(context, 42)
} else if (*chat).type_0 == 120 || (*chat).type_0 == 130 {
ret = dc_mprintf(
b"Chat: %s: %s%s\x00" as *const u8 as *const libc::c_char,
(*chat).name,
@@ -1135,7 +1167,7 @@ unsafe fn build_body_file(
let mut filename_to_send: *mut libc::c_char = 0 as *mut libc::c_char;
let mut filename_encoded: *mut libc::c_char = 0 as *mut libc::c_char;
if !pathNfilename.is_null() {
if (*msg).type_0 == 41i32 {
if (*msg).type_0 == 41 {
let ts = chrono::Utc.timestamp((*msg).timestamp_sort as i64, 0);
let suffix = if !suffix.is_null() {
@@ -1147,9 +1179,9 @@ unsafe fn build_body_file(
.format(&format!("voice-message_%Y-%m-%d_%H-%M-%S.{}", suffix))
.to_string();
filename_to_send = strdup(to_cstring(res).as_ptr());
} else if (*msg).type_0 == 40i32 {
} else if (*msg).type_0 == 40 {
filename_to_send = dc_get_filename(pathNfilename)
} else if (*msg).type_0 == 20i32 || (*msg).type_0 == 21i32 {
} else if (*msg).type_0 == 20 || (*msg).type_0 == 21 {
if base_name.is_null() {
base_name = b"image\x00" as *const u8 as *const libc::c_char
}
@@ -1162,7 +1194,7 @@ unsafe fn build_body_file(
b"dat\x00" as *const u8 as *const libc::c_char
},
)
} else if (*msg).type_0 == 50i32 {
} else if (*msg).type_0 == 50 {
filename_to_send = dc_mprintf(
b"video.%s\x00" as *const u8 as *const libc::c_char,
if !suffix.is_null() {
@@ -1178,14 +1210,14 @@ unsafe fn build_body_file(
if suffix.is_null() {
mimetype =
dc_strdup(b"application/octet-stream\x00" as *const u8 as *const libc::c_char)
} else if strcmp(suffix, b"png\x00" as *const u8 as *const libc::c_char) == 0i32 {
} else if strcmp(suffix, b"png\x00" as *const u8 as *const libc::c_char) == 0 {
mimetype = dc_strdup(b"image/png\x00" as *const u8 as *const libc::c_char)
} else if strcmp(suffix, b"jpg\x00" as *const u8 as *const libc::c_char) == 0i32
|| strcmp(suffix, b"jpeg\x00" as *const u8 as *const libc::c_char) == 0i32
|| strcmp(suffix, b"jpe\x00" as *const u8 as *const libc::c_char) == 0i32
} else if strcmp(suffix, b"jpg\x00" as *const u8 as *const libc::c_char) == 0
|| strcmp(suffix, b"jpeg\x00" as *const u8 as *const libc::c_char) == 0
|| strcmp(suffix, b"jpe\x00" as *const u8 as *const libc::c_char) == 0
{
mimetype = dc_strdup(b"image/jpeg\x00" as *const u8 as *const libc::c_char)
} else if strcmp(suffix, b"gif\x00" as *const u8 as *const libc::c_char) == 0i32 {
} else if strcmp(suffix, b"gif\x00" as *const u8 as *const libc::c_char) == 0 {
mimetype = dc_strdup(b"image/gif\x00" as *const u8 as *const libc::c_char)
} else {
mimetype =
@@ -1228,7 +1260,7 @@ unsafe fn build_body_file(
0 as *mut libc::c_char,
0 as *mut libc::c_char,
0 as *mut libc::c_char,
0i32 as size_t,
0 as size_t,
mailmime_parameter_new(
strdup(
b"filename*\x00" as *const u8 as *const libc::c_char,
@@ -1285,12 +1317,12 @@ unsafe fn build_body_file(
******************************************************************************/
unsafe fn is_file_size_okay(msg: *const dc_msg_t) -> libc::c_int {
let mut file_size_okay: libc::c_int = 1i32;
let mut file_size_okay: libc::c_int = 1;
let pathNfilename: *mut libc::c_char =
dc_param_get((*msg).param, 'f' as i32, 0 as *const libc::c_char);
let bytes: uint64_t = dc_get_filebytes((*msg).context, pathNfilename);
if bytes > (49i32 * 1024i32 * 1024i32 / 4i32 * 3i32) as libc::c_ulonglong {
file_size_okay = 0i32
if bytes > (49 * 1024 * 1024 / 4 * 3) as libc::c_ulonglong {
file_size_okay = 0;
}
free(pathNfilename as *mut libc::c_void);

View File

@@ -15,7 +15,6 @@ use crate::context::Context;
use crate::dc_contact::*;
use crate::dc_e2ee::*;
use crate::dc_location::*;
use crate::dc_log::*;
use crate::dc_param::*;
use crate::dc_simplify::*;
use crate::dc_stock::*;
@@ -531,11 +530,9 @@ unsafe fn dc_mimeparser_parse_mime_recursive(
b"rfc822-headers\x00" as *const u8 as *const libc::c_char,
) == 0i32
{
dc_log_info(
info!(
(*mimeparser).context,
0i32,
b"Protected headers found in text/rfc822-headers attachment: Will be ignored.\x00"
as *const u8 as *const libc::c_char,
0, "Protected headers found in text/rfc822-headers attachment: Will be ignored.",
);
return 0i32;
}
@@ -549,11 +546,7 @@ unsafe fn dc_mimeparser_parse_mime_recursive(
) != MAILIMF_NO_ERROR as libc::c_int
|| (*mimeparser).header_protected.is_null()
{
dc_log_warning(
(*mimeparser).context,
0i32,
b"Protected headers parsing error.\x00" as *const u8 as *const libc::c_char,
);
warn!((*mimeparser).context, 0, "Protected headers parsing error.",);
} else {
hash_header(
&mut (*mimeparser).header,
@@ -562,9 +555,11 @@ unsafe fn dc_mimeparser_parse_mime_recursive(
);
}
} else {
dc_log_info((*mimeparser).context, 0i32,
b"Protected headers found in MIME header: Will be ignored as we already found an outer one.\x00"
as *const u8 as *const libc::c_char);
info!(
(*mimeparser).context,
0,
"Protected headers found in MIME header: Will be ignored as we already found an outer one."
);
}
}
match (*mime).mm_type {
@@ -756,10 +751,11 @@ unsafe fn dc_mimeparser_parse_mime_recursive(
}
}
if plain_cnt == 1i32 && html_cnt == 1i32 {
dc_log_warning((*mimeparser).context, 0i32,
b"HACK: multipart/mixed message found with PLAIN and HTML, we\'ll skip the HTML part as this seems to be unwanted.\x00"
as *const u8 as
*const libc::c_char);
warn!(
(*mimeparser).context,
0i32,
"HACK: multipart/mixed message found with PLAIN and HTML, we\'ll skip the HTML part as this seems to be unwanted."
);
skip_part = html_part
}
cur = (*(*mime).mm_data.mm_multipart.mm_mp_list).first;
@@ -1213,14 +1209,12 @@ unsafe fn dc_mimeparser_add_single_part_if_known(
current_block = 17788412896529399552;
}
} else {
dc_log_warning(
warn!(
mimeparser.context,
0i32,
b"Cannot convert %i bytes from \"%s\" to \"utf-8\".\x00"
as *const u8
as *const libc::c_char,
0,
"Cannot convert {} bytes from \"{}\" to \"utf-8\".",
decoded_data_bytes as libc::c_int,
charset,
as_str(charset),
);
current_block = 17788412896529399552;
}

View File

@@ -2,44 +2,44 @@ use crate::constants::*;
use crate::context::*;
use crate::dc_job::*;
use crate::dc_msg::*;
use crate::dc_sqlite3::*;
use crate::types::*;
pub unsafe fn dc_do_heuristics_moves(
context: &Context,
folder: *const libc::c_char,
msg_id: uint32_t,
) {
// for already seen messages, folder may be different from msg->folder
let mut msg: *mut dc_msg_t = 0 as *mut dc_msg_t;
let stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt;
if !(dc_sqlite3_get_config_int(
context,
&context.sql,
b"mvbox_move\x00" as *const u8 as *const libc::c_char,
1i32,
) == 0i32)
pub unsafe fn dc_do_heuristics_moves(context: &Context, folder: &str, msg_id: u32) {
if context
.sql
.get_config_int(context, "mvbox_move")
.unwrap_or_else(|| 1)
== 0
{
if !(0 == dc_is_inbox(context, folder) && 0 == dc_is_sentbox(context, folder)) {
msg = dc_msg_new_load(context, msg_id);
if !(0 != dc_msg_is_setupmessage(msg)) {
// do not move setup messages;
// there may be a non-delta device that wants to handle it
if 0 != dc_is_mvbox(context, folder) {
dc_update_msg_move_state(context, (*msg).rfc724_mid, DC_MOVE_STATE_STAY);
} else if 0 != (*msg).is_dc_message {
dc_job_add(
context,
200i32,
(*msg).id as libc::c_int,
0 as *const libc::c_char,
0i32,
);
dc_update_msg_move_state(context, (*msg).rfc724_mid, DC_MOVE_STATE_MOVING);
}
}
}
return;
}
sqlite3_finalize(stmt);
if !dc_is_inbox(context, folder) && !dc_is_sentbox(context, folder) {
return;
}
let msg = dc_msg_new_load(context, msg_id);
if dc_msg_is_setupmessage(msg) {
// do not move setup messages;
// there may be a non-delta device that wants to handle it
dc_msg_unref(msg);
return;
}
if dc_is_mvbox(context, folder) {
dc_update_msg_move_state(context, (*msg).rfc724_mid, DC_MOVE_STATE_STAY);
}
// 1 = dc message, 2 = reply to dc message
if 0 != (*msg).is_dc_message {
dc_job_add(
context,
200,
(*msg).id as libc::c_int,
0 as *const libc::c_char,
0,
);
dc_update_msg_move_state(context, (*msg).rfc724_mid, DC_MOVE_STATE_MOVING);
}
dc_msg_unref(msg);
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,6 @@
use crate::context::Context;
use crate::dc_chat::*;
use crate::dc_contact::*;
use crate::dc_log::*;
use crate::dc_lot::*;
use crate::dc_param::*;
use crate::dc_strencode::*;
@@ -38,12 +37,7 @@ pub unsafe fn dc_check_qr(context: &Context, qr: *const libc::c_char) -> *mut dc
let mut grpname: *mut libc::c_char = 0 as *mut libc::c_char;
(*qr_parsed).state = 0i32;
if !qr.is_null() {
dc_log_info(
context,
0i32,
b"Scanned QR code: %s\x00" as *const u8 as *const libc::c_char,
qr,
);
info!(context, 0, "Scanned QR code: {}", as_str(qr),);
/* split parameters from the qr code
------------------------------------ */
if strncasecmp(

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,5 @@
use mmime::mailimf_types::*;
use percent_encoding::{utf8_percent_encode, DEFAULT_ENCODE_SET};
use crate::aheader::EncryptPreference;
use crate::constants::Event;
@@ -8,13 +9,11 @@ use crate::dc_chat::*;
use crate::dc_configure::*;
use crate::dc_contact::*;
use crate::dc_e2ee::*;
use crate::dc_log::*;
use crate::dc_lot::*;
use crate::dc_mimeparser::*;
use crate::dc_msg::*;
use crate::dc_param::*;
use crate::dc_qr::*;
use crate::dc_sqlite3::*;
use crate::dc_stock::*;
use crate::dc_strencode::*;
use crate::dc_token::*;
@@ -28,22 +27,18 @@ pub unsafe fn dc_get_securejoin_qr(
context: &Context,
group_chat_id: uint32_t,
) -> *mut libc::c_char {
let current_block: u64;
/* =========================================================
==== Alice - the inviter side ====
==== Step 1 in "Setup verified contact" protocol ====
========================================================= */
let mut qr: *mut libc::c_char = 0 as *mut libc::c_char;
let self_addr: *mut libc::c_char;
let mut self_addr_urlencoded: *mut libc::c_char = 0 as *mut libc::c_char;
let mut self_name: *mut libc::c_char = 0 as *mut libc::c_char;
let mut self_name_urlencoded: *mut libc::c_char = 0 as *mut libc::c_char;
let mut fingerprint: *mut libc::c_char = 0 as *mut libc::c_char;
let mut fingerprint = 0 as *mut libc::c_char;
let mut invitenumber: *mut libc::c_char;
let mut auth: *mut libc::c_char;
let mut chat: *mut Chat = 0 as *mut Chat;
let mut group_name: *mut libc::c_char = 0 as *mut libc::c_char;
let mut group_name_urlencoded: *mut libc::c_char = 0 as *mut libc::c_char;
let mut chat = 0 as *mut Chat;
let mut group_name = 0 as *mut libc::c_char;
let mut group_name_urlencoded = 0 as *mut libc::c_char;
let mut qr = None;
dc_ensure_secret_key_exists(context);
invitenumber = dc_token_lookup(context, DC_TOKEN_INVITENUMBER, group_chat_id);
@@ -56,110 +51,86 @@ pub unsafe fn dc_get_securejoin_qr(
auth = dc_create_id();
dc_token_save(context, DC_TOKEN_AUTH, group_chat_id, auth);
}
self_addr = dc_sqlite3_get_config(
context,
&context.sql,
b"configured_addr\x00" as *const u8 as *const libc::c_char,
0 as *const libc::c_char,
);
if self_addr.is_null() {
dc_log_error(
context,
0i32,
b"Not configured, cannot generate QR code.\x00" as *const u8 as *const libc::c_char,
);
} else {
self_name = dc_sqlite3_get_config(
context,
&context.sql,
b"displayname\x00" as *const u8 as *const libc::c_char,
b"\x00" as *const u8 as *const libc::c_char,
);
fingerprint = get_self_fingerprint(context);
if !fingerprint.is_null() {
self_addr_urlencoded = dc_urlencode(self_addr);
self_name_urlencoded = dc_urlencode(self_name);
if 0 != group_chat_id {
chat = dc_get_chat(context, group_chat_id);
if chat.is_null() {
dc_log_error(
context,
0i32,
b"Cannot get QR-code for chat-id %i\x00" as *const u8
as *const libc::c_char,
group_chat_id,
);
current_block = 9531737720721467826;
} else {
group_name = dc_chat_get_name(chat);
group_name_urlencoded = dc_urlencode(group_name);
qr = dc_mprintf(
b"OPENPGP4FPR:%s#a=%s&g=%s&x=%s&i=%s&s=%s\x00" as *const u8
as *const libc::c_char,
fingerprint,
self_addr_urlencoded,
group_name_urlencoded,
(*chat).grpid,
invitenumber,
auth,
);
current_block = 1118134448028020070;
}
} else {
qr = dc_mprintf(
b"OPENPGP4FPR:%s#a=%s&n=%s&i=%s&s=%s\x00" as *const u8 as *const libc::c_char,
fingerprint,
self_addr_urlencoded,
self_name_urlencoded,
invitenumber,
auth,
);
current_block = 1118134448028020070;
}
match current_block {
9531737720721467826 => {}
_ => {
dc_log_info(
context,
0i32,
b"Generated QR code: %s\x00" as *const u8 as *const libc::c_char,
qr,
);
}
}
let self_addr = context.sql.get_config(context, "configured_addr");
let cleanup = |fingerprint, chat, group_name, group_name_urlencoded| {
free(fingerprint as *mut libc::c_void);
free(invitenumber as *mut libc::c_void);
free(auth as *mut libc::c_void);
dc_chat_unref(chat);
free(group_name as *mut libc::c_void);
free(group_name_urlencoded as *mut libc::c_void);
if let Some(qr) = qr {
strdup(to_cstring(qr).as_ptr())
} else {
std::ptr::null_mut()
}
};
if self_addr.is_none() {
error!(context, 0, "Not configured, cannot generate QR code.",);
return cleanup(fingerprint, chat, group_name, group_name_urlencoded);
}
free(self_addr_urlencoded as *mut libc::c_void);
free(self_addr as *mut libc::c_void);
free(self_name as *mut libc::c_void);
free(self_name_urlencoded as *mut libc::c_void);
free(fingerprint as *mut libc::c_void);
free(invitenumber as *mut libc::c_void);
free(auth as *mut libc::c_void);
dc_chat_unref(chat);
free(group_name as *mut libc::c_void);
free(group_name_urlencoded as *mut libc::c_void);
return if !qr.is_null() {
qr
let self_addr = self_addr.unwrap();
let self_name = context
.sql
.get_config(context, "displayname")
.unwrap_or_default();
fingerprint = get_self_fingerprint(context);
if fingerprint.is_null() {
return cleanup(fingerprint, chat, group_name, group_name_urlencoded);
}
let self_addr_urlencoded = utf8_percent_encode(&self_addr, DEFAULT_ENCODE_SET).to_string();
let self_name_urlencoded = utf8_percent_encode(&self_name, DEFAULT_ENCODE_SET).to_string();
qr = if 0 != group_chat_id {
chat = dc_get_chat(context, group_chat_id);
if chat.is_null() {
error!(
context,
0, "Cannot get QR-code for chat-id {}", group_chat_id,
);
return cleanup(fingerprint, chat, group_name, group_name_urlencoded);
}
group_name = dc_chat_get_name(chat);
group_name_urlencoded = dc_urlencode(group_name);
Some(format!(
"OPENPGP4FPR:{}#a={}&g={}&x={}&i={}&s={}",
as_str(fingerprint),
self_addr_urlencoded,
as_str(group_name_urlencoded),
as_str((*chat).grpid),
as_str(invitenumber),
as_str(auth),
))
} else {
dc_strdup(0 as *const libc::c_char)
Some(format!(
"OPENPGP4FPR:{}#a={}&n={}&i={}&s={}",
as_str(fingerprint),
self_addr_urlencoded,
self_name_urlencoded,
as_str(invitenumber),
as_str(auth),
))
};
info!(context, 0, "Generated QR code: {}", qr.as_ref().unwrap());
cleanup(fingerprint, chat, group_name, group_name_urlencoded)
}
unsafe fn get_self_fingerprint(context: &Context) -> *mut libc::c_char {
let self_addr = dc_sqlite3_get_config(
context,
&context.sql,
b"configured_addr\x00" as *const u8 as *const libc::c_char,
0 as *const libc::c_char,
);
if self_addr.is_null() {
return std::ptr::null_mut();
}
if let Some(key) = Key::from_self_public(context, self_addr, &context.sql) {
return key.fingerprint_c();
fn get_self_fingerprint(context: &Context) -> *mut libc::c_char {
if let Some(self_addr) = context.sql.get_config(context, "configured_addr") {
if let Some(key) = Key::from_self_public(context, self_addr, &context.sql) {
return key.fingerprint_c();
}
}
std::ptr::null_mut()
@@ -175,29 +146,17 @@ pub unsafe fn dc_join_securejoin(context: &Context, qr: *const libc::c_char) ->
let mut contact_chat_id: uint32_t = 0i32 as uint32_t;
let mut join_vg: libc::c_int = 0i32;
let mut qr_scan: *mut dc_lot_t = 0 as *mut dc_lot_t;
dc_log_info(
context,
0i32,
b"Requesting secure-join ...\x00" as *const u8 as *const libc::c_char,
);
info!(context, 0, "Requesting secure-join ...",);
dc_ensure_secret_key_exists(context);
ongoing_allocated = dc_alloc_ongoing(context);
if !(ongoing_allocated == 0i32) {
qr_scan = dc_check_qr(context, qr);
if qr_scan.is_null() || (*qr_scan).state != 200i32 && (*qr_scan).state != 202i32 {
dc_log_error(
context,
0i32,
b"Unknown QR code.\x00" as *const u8 as *const libc::c_char,
);
error!(context, 0, "Unknown QR code.",);
} else {
contact_chat_id = dc_create_chat_by_contact_id(context, (*qr_scan).id);
if contact_chat_id == 0i32 as libc::c_uint {
dc_log_error(
context,
0i32,
b"Unknown contact.\x00" as *const u8 as *const libc::c_char,
);
error!(context, 0, "Unknown contact.",);
} else if !(context
.running_state
.clone()
@@ -214,11 +173,7 @@ pub unsafe fn dc_join_securejoin(context: &Context, qr: *const libc::c_char) ->
}
if 0 != fingerprint_equals_sender(context, (*qr_scan).fingerprint, contact_chat_id)
{
dc_log_info(
context,
0i32,
b"Taking protocol shortcut.\x00" as *const u8 as *const libc::c_char,
);
info!(context, 0, "Taking protocol shortcut.");
context.bob.clone().write().unwrap().expects = 6;
context.call_cb(
Event::SECUREJOIN_JOINER_PROGRESS,
@@ -403,12 +358,11 @@ pub unsafe fn dc_handle_securejoin_handshake(
if !(contact_id <= 9i32 as libc::c_uint) {
step = lookup_field(mimeparser, "Secure-Join");
if !step.is_null() {
dc_log_info(
info!(
context,
0i32,
b">>>>>>>>>>>>>>>>>>>>>>>>> secure-join message \'%s\' received\x00" as *const u8
as *const libc::c_char,
step,
0,
">>>>>>>>>>>>>>>>>>>>>>>>> secure-join message \'{}\' received",
as_str(step),
);
join_vg = (strncmp(step, b"vg-\x00" as *const u8 as *const libc::c_char, 3) == 0)
as libc::c_int;
@@ -439,11 +393,12 @@ pub unsafe fn dc_handle_securejoin_handshake(
if invitenumber.is_null() {
warn!(context, 0, "Secure-join denied (invitenumber missing).",);
current_block = 4378276786830486580;
} else if dc_token_exists(context, DC_TOKEN_INVITENUMBER, invitenumber) == 0i32 {
} else if !dc_token_exists(context, DC_TOKEN_INVITENUMBER, invitenumber) {
warn!(context, 0, "Secure-join denied (bad invitenumber).",);
current_block = 4378276786830486580;
} else {
info!(context, 0, "Secure-join requested.",);
context.call_cb(
Event::SECUREJOIN_INVITER_PROGRESS,
contact_id as uintptr_t,
@@ -480,12 +435,7 @@ pub unsafe fn dc_handle_securejoin_handshake(
};
if cond {
dc_log_warning(
context,
0i32,
b"auth-required message out of sync.\x00" as *const u8
as *const libc::c_char,
);
warn!(context, 0, "auth-required message out of sync.",);
// no error, just aborted somehow or a mail from another handshake
current_block = 4378276786830486580;
} else {
@@ -525,11 +475,7 @@ pub unsafe fn dc_handle_securejoin_handshake(
end_bobs_joining(context, 0i32);
current_block = 4378276786830486580;
} else {
dc_log_info(
context,
0i32,
b"Fingerprint verified.\x00" as *const u8 as *const libc::c_char,
);
info!(context, 0, "Fingerprint verified.",);
own_fingerprint = get_self_fingerprint(context);
context.call_cb(
Event::SECUREJOIN_JOINER_PROGRESS,
@@ -593,11 +539,7 @@ pub unsafe fn dc_handle_securejoin_handshake(
);
current_block = 4378276786830486580;
} else {
dc_log_info(
context,
0i32,
b"Fingerprint verified.\x00" as *const u8 as *const libc::c_char,
);
info!(context, 0, "Fingerprint verified.",);
// verify that the `Secure-Join-Auth:`-header matches the secret written to the QR code
let auth_0: *const libc::c_char;
auth_0 = lookup_field(mimeparser, "Secure-Join-Auth");
@@ -608,7 +550,7 @@ pub unsafe fn dc_handle_securejoin_handshake(
b"Auth not provided.\x00" as *const u8 as *const libc::c_char,
);
current_block = 4378276786830486580;
} else if dc_token_exists(context, DC_TOKEN_AUTH, auth_0) == 0i32 {
} else if !dc_token_exists(context, DC_TOKEN_AUTH, auth_0) {
could_not_establish_secure_connection(
context,
contact_chat_id,
@@ -625,11 +567,7 @@ pub unsafe fn dc_handle_securejoin_handshake(
current_block = 4378276786830486580;
} else {
dc_scaleup_contact_origin(context, contact_id, 0x1000000i32);
dc_log_info(
context,
0i32,
b"Auth verified.\x00" as *const u8 as *const libc::c_char,
);
info!(context, 0, "Auth verified.",);
secure_connection_established(context, contact_chat_id);
context.call_cb(
Event::CONTACTS_CHANGED,
@@ -650,12 +588,7 @@ pub unsafe fn dc_handle_securejoin_handshake(
0 as *mut libc::c_int,
);
if group_chat_id == 0i32 as libc::c_uint {
dc_log_error(
context,
0i32,
b"Chat %s not found.\x00" as *const u8 as *const libc::c_char,
grpid,
);
error!(context, 0, "Chat {} not found.", as_str(grpid),);
current_block = 4378276786830486580;
} else {
dc_add_contact_to_chat_ex(
@@ -697,12 +630,7 @@ pub unsafe fn dc_handle_securejoin_handshake(
ret = 0x1i32
}
if context.bob.clone().read().unwrap().expects != 6 {
dc_log_info(
context,
0i32,
b"Message belongs to a different handshake.\x00" as *const u8
as *const libc::c_char,
);
info!(context, 0, "Message belongs to a different handshake.",);
current_block = 4378276786830486580;
} else {
let cond = {
@@ -710,11 +638,9 @@ pub unsafe fn dc_handle_securejoin_handshake(
scan.is_null() || 0 != join_vg && (*scan).state != 202
};
if cond {
dc_log_warning(
warn!(
context,
0i32,
b"Message out of sync or belongs to a different handshake.\x00"
as *const u8 as *const libc::c_char,
0, "Message out of sync or belongs to a different handshake.",
);
current_block = 4378276786830486580;
} else {
@@ -778,10 +704,11 @@ pub unsafe fn dc_handle_securejoin_handshake(
context,
lookup_field(mimeparser, "Chat-Group-Member-Added"),
) {
dc_log_info(context, 0i32,
b"Message belongs to a different handshake (scaled up contact anyway to allow creation of group).\x00"
as *const u8 as
*const libc::c_char);
info!(
context,
0,
"Message belongs to a different handshake (scaled up contact anyway to allow creation of group)."
);
current_block = 4378276786830486580;
} else {
current_block = 9180031981464905198;
@@ -825,12 +752,7 @@ pub unsafe fn dc_handle_securejoin_handshake(
============================================================ */
contact = dc_get_contact(context, contact_id);
if contact.is_null() || 0 == dc_contact_is_verified(contact) {
dc_log_warning(
context,
0i32,
b"vg-member-added-received invalid.\x00" as *const u8
as *const libc::c_char,
);
warn!(context, 0, "vg-member-added-received invalid.",);
current_block = 4378276786830486580;
} else {
context.call_cb(
@@ -928,13 +850,7 @@ unsafe fn could_not_establish_secure_connection(
},
);
dc_add_device_msg(context, contact_chat_id, msg);
dc_log_error(
context,
0i32,
b"%s (%s)\x00" as *const u8 as *const libc::c_char,
msg,
details,
);
error!(context, 0, "{} ({})", as_str(msg), to_string(details),);
free(msg as *mut libc::c_void);
dc_contact_unref(contact);
}
@@ -969,27 +885,15 @@ unsafe fn encrypted_and_signed(
expected_fingerprint: *const libc::c_char,
) -> libc::c_int {
if 0 == mimeparser.e2ee_helper.encrypted {
dc_log_warning(
mimeparser.context,
0i32,
b"Message not encrypted.\x00" as *const u8 as *const libc::c_char,
);
warn!(mimeparser.context, 0, "Message not encrypted.",);
return 0i32;
}
if mimeparser.e2ee_helper.signatures.len() <= 0 {
dc_log_warning(
mimeparser.context,
0i32,
b"Message not signed.\x00" as *const u8 as *const libc::c_char,
);
warn!(mimeparser.context, 0, "Message not signed.",);
return 0i32;
}
if expected_fingerprint.is_null() {
dc_log_warning(
mimeparser.context,
0i32,
b"Fingerprint for comparison missing.\x00" as *const u8 as *const libc::c_char,
);
warn!(mimeparser.context, 0, "Fingerprint for comparison missing.",);
return 0i32;
}
if !mimeparser
@@ -997,23 +901,20 @@ unsafe fn encrypted_and_signed(
.signatures
.contains(as_str(expected_fingerprint))
{
dc_log_warning(
warn!(
mimeparser.context,
0i32,
b"Message does not match expected fingerprint %s.\x00" as *const u8
as *const libc::c_char,
expected_fingerprint,
0,
"Message does not match expected fingerprint {}.",
as_str(expected_fingerprint),
);
return 0i32;
return 0;
}
1
}
pub unsafe fn dc_handle_degrade_event(context: &Context, peerstate: &Peerstate) {
let stmt;
let contact_id: uint32_t;
let mut contact_chat_id: uint32_t = 0i32 as uint32_t;
let mut contact_chat_id = 0;
// - we do not issue an warning for DC_DE_ENCRYPTION_PAUSED as this is quite normal
// - currently, we do not issue an extra warning for DC_DE_VERIFICATION_LOST - this always comes
@@ -1021,38 +922,36 @@ pub unsafe fn dc_handle_degrade_event(context: &Context, peerstate: &Peerstate)
// with things they cannot fix, so the user is just kicked from the verified group
// (and he will know this and can fix this)
if Some(DegradeEvent::FingerprintChanged) == peerstate.degrade_event {
stmt = dc_sqlite3_prepare(
context,
&context.sql,
b"SELECT id FROM contacts WHERE addr=?;\x00" as *const u8 as *const libc::c_char,
);
let c_addr = peerstate.addr.as_ref().map(to_cstring).unwrap_or_default();
let c_addr_ptr = if peerstate.addr.is_some() {
c_addr.as_ptr()
} else {
std::ptr::null()
};
sqlite3_bind_text(stmt, 1i32, c_addr_ptr, -1i32, None);
sqlite3_step(stmt);
contact_id = sqlite3_column_int(stmt, 0i32) as uint32_t;
sqlite3_finalize(stmt);
if !(contact_id == 0i32 as libc::c_uint) {
let contact_id: i32 = context
.sql
.query_row_col(
context,
"SELECT id FROM contacts WHERE addr=?;",
params![&peerstate.addr],
0,
)
.unwrap_or_default();
if contact_id > 0 {
dc_create_or_lookup_nchat_by_contact_id(
context,
contact_id,
2i32,
contact_id as u32,
2,
&mut contact_chat_id,
0 as *mut libc::c_int,
);
let msg = dc_stock_str_repl_string(context, 37i32, c_addr_ptr);
let c_addr = peerstate.addr.as_ref().map(to_cstring).unwrap_or_default();
let c_addr_ptr = if peerstate.addr.is_some() {
c_addr.as_ptr()
} else {
std::ptr::null_mut()
};
let msg = dc_stock_str_repl_string(context, 37, c_addr_ptr);
dc_add_device_msg(context, contact_chat_id, msg);
free(msg as *mut libc::c_void);
context.call_cb(
Event::CHAT_MODIFIED,
contact_chat_id as uintptr_t,
0i32 as uintptr_t,
0 as uintptr_t,
);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,76 +1,65 @@
use crate::context::Context;
use crate::dc_sqlite3::*;
use crate::dc_tools::*;
use crate::types::*;
use crate::sql;
use crate::x::strdup;
// Token namespaces
pub type dc_tokennamespc_t = libc::c_uint;
pub type dc_tokennamespc_t = usize;
pub const DC_TOKEN_AUTH: dc_tokennamespc_t = 110;
pub const DC_TOKEN_INVITENUMBER: dc_tokennamespc_t = 100;
// Functions to read/write token from/to the database. A token is any string associated with a key.
pub unsafe fn dc_token_save(
pub fn dc_token_save(
context: &Context,
namespc: dc_tokennamespc_t,
foreign_id: uint32_t,
foreign_id: u32,
token: *const libc::c_char,
) {
let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt;
if !token.is_null() {
// foreign_id may be 0
stmt = dc_sqlite3_prepare(
context,
&context.sql,
b"INSERT INTO tokens (namespc, foreign_id, token, timestamp) VALUES (?, ?, ?, ?);\x00"
as *const u8 as *const libc::c_char,
);
sqlite3_bind_int(stmt, 1i32, namespc as libc::c_int);
sqlite3_bind_int(stmt, 2i32, foreign_id as libc::c_int);
sqlite3_bind_text(stmt, 3i32, token, -1i32, None);
sqlite3_bind_int64(stmt, 4i32, time() as sqlite3_int64);
sqlite3_step(stmt);
) -> bool {
if token.is_null() {
return false;
}
sqlite3_finalize(stmt);
}
pub unsafe fn dc_token_lookup(
context: &Context,
namespc: dc_tokennamespc_t,
foreign_id: uint32_t,
) -> *mut libc::c_char {
let token: *mut libc::c_char;
let stmt: *mut sqlite3_stmt;
stmt = dc_sqlite3_prepare(
// foreign_id may be 0
sql::execute(
context,
&context.sql,
b"SELECT token FROM tokens WHERE namespc=? AND foreign_id=?;\x00" as *const u8
as *const libc::c_char,
);
sqlite3_bind_int(stmt, 1i32, namespc as libc::c_int);
sqlite3_bind_int(stmt, 2i32, foreign_id as libc::c_int);
sqlite3_step(stmt);
token = dc_strdup_keep_null(sqlite3_column_text(stmt, 0i32) as *mut libc::c_char);
sqlite3_finalize(stmt);
token
"INSERT INTO tokens (namespc, foreign_id, token, timestamp) VALUES (?, ?, ?, ?);",
params![namespc as i32, foreign_id as i32, as_str(token), time()],
)
.is_ok()
}
pub unsafe fn dc_token_exists(
pub fn dc_token_lookup(
context: &Context,
namespc: dc_tokennamespc_t,
foreign_id: u32,
) -> *mut libc::c_char {
if let Some(token) = context.sql.query_row_col::<_, String>(
context,
"SELECT token FROM tokens WHERE namespc=? AND foreign_id=?;",
params![namespc as i32, foreign_id as i32],
0,
) {
unsafe { strdup(to_cstring(token).as_ptr()) }
} else {
std::ptr::null_mut()
}
}
pub fn dc_token_exists(
context: &Context,
namespc: dc_tokennamespc_t,
token: *const libc::c_char,
) -> libc::c_int {
let mut exists: libc::c_int = 0i32;
let mut stmt: *mut sqlite3_stmt = 0 as *mut sqlite3_stmt;
if !token.is_null() {
stmt = dc_sqlite3_prepare(
context,
&context.sql,
b"SELECT id FROM tokens WHERE namespc=? AND token=?;\x00" as *const u8
as *const libc::c_char,
);
sqlite3_bind_int(stmt, 1i32, namespc as libc::c_int);
sqlite3_bind_text(stmt, 2i32, token, -1i32, None);
exists = (sqlite3_step(stmt) != 0i32) as libc::c_int
) -> bool {
if token.is_null() {
return false;
}
sqlite3_finalize(stmt);
return exists;
context
.sql
.exists(
"SELECT id FROM tokens WHERE namespc=? AND token=?;",
params![namespc as i32, as_str(token)],
)
.unwrap_or_default()
}

View File

@@ -1,3 +1,4 @@
use std::borrow::Cow;
use std::fs;
use std::time::SystemTime;
@@ -7,10 +8,11 @@ use rand::{thread_rng, Rng};
use crate::context::Context;
use crate::dc_array::*;
use crate::dc_log::*;
use crate::types::*;
use crate::x::*;
const ELLIPSE: &'static str = "[...]";
/* Some tools and enhancements to the used libraries, there should be
no references to Context and other "larger" classes here. */
// for carray etc.
@@ -343,25 +345,16 @@ pub unsafe fn dc_utf8_strlen(s: *const libc::c_char) -> size_t {
j
}
pub unsafe fn dc_truncate_str(buf: *mut libc::c_char, approx_chars: libc::c_int) {
if approx_chars > 0
&& strlen(buf)
> approx_chars.wrapping_add(
strlen(b"[...]\x00" as *const u8 as *const libc::c_char) as libc::c_int
) as usize
{
let mut p: *mut libc::c_char = &mut *buf.offset(approx_chars as isize) as *mut libc::c_char;
*p = 0i32 as libc::c_char;
if !strchr(buf, ' ' as i32).is_null() {
while *p.offset(-1i32 as isize) as libc::c_int != ' ' as i32
&& *p.offset(-1i32 as isize) as libc::c_int != '\n' as i32
{
p = p.offset(-1isize);
*p = 0i32 as libc::c_char
}
pub fn dc_truncate_str(buf: &str, approx_chars: usize) -> Cow<str> {
if approx_chars > 0 && buf.len() > approx_chars + ELLIPSE.len() {
if let Some(index) = buf[..approx_chars].rfind(|c| c == ' ' || c == '\n') {
Cow::Owned(format!("{}{}", &buf[..index + 1], ELLIPSE))
} else {
Cow::Owned(format!("{}{}", &buf[..approx_chars], ELLIPSE))
}
strcat(p, b"[...]\x00" as *const u8 as *const libc::c_char);
};
} else {
Cow::Borrowed(buf)
}
}
pub unsafe fn dc_truncate_n_unwrap_str(
@@ -675,12 +668,15 @@ pub unsafe fn dc_timestamp_from_date(date_time: *mut mailimf_date_time) -> i64 {
/* the return value must be free()'d */
pub unsafe fn dc_timestamp_to_str(wanted: i64) -> *mut libc::c_char {
let ts = chrono::Utc.timestamp(wanted, 0);
let res = ts.format("%Y.%m.%d %H:%M:%S").to_string();
let res = dc_timestamp_to_str_safe(wanted);
strdup(to_cstring(res).as_ptr())
}
pub fn dc_timestamp_to_str_safe(wanted: i64) -> String {
let ts = chrono::Utc.timestamp(wanted, 0);
ts.format("%Y.%m.%d %H:%M:%S").to_string()
}
pub fn dc_gm2local_offset() -> i64 {
let lt = Local::now();
((lt.offset().local_minus_utc() / (60 * 60)) * 100) as i64
@@ -905,16 +901,23 @@ pub unsafe fn dc_extract_grpid_from_rfc724_mid_list(list: *const clist) -> *mut
/* file tools */
pub unsafe fn dc_ensure_no_slash(pathNfilename: *mut libc::c_char) {
let path_len: libc::c_int = strlen(pathNfilename) as libc::c_int;
if path_len > 0i32 {
if *pathNfilename.offset((path_len - 1i32) as isize) as libc::c_int == '/' as i32
|| *pathNfilename.offset((path_len - 1i32) as isize) as libc::c_int == '\\' as i32
let path_len = strlen(pathNfilename);
if path_len > 0 {
if *pathNfilename.offset((path_len - 1) as isize) as libc::c_int == '/' as i32
|| *pathNfilename.offset((path_len - 1) as isize) as libc::c_int == '\\' as i32
{
*pathNfilename.offset((path_len - 1i32) as isize) = 0i32 as libc::c_char
*pathNfilename.offset((path_len - 1) as isize) = 0 as libc::c_char
}
};
}
pub fn dc_ensure_no_slash_safe(path: &str) -> &str {
if path.ends_with('/') || path.ends_with('\\') {
return &path[..path.len() - 1];
}
path
}
pub unsafe fn dc_validate_filename(filename: *mut libc::c_char) {
/* function modifies the given buffer and replaces all characters not valid in filenames by a "-" */
let mut p1: *mut libc::c_char = filename;
@@ -1169,12 +1172,7 @@ pub unsafe fn dc_delete_file(context: &Context, pathNfilename: *const libc::c_ch
success = 1;
}
Err(_err) => {
dc_log_warning(
context,
0i32,
b"Cannot delete \"%s\".\x00" as *const u8 as *const libc::c_char,
pathNfilename,
);
warn!(context, 0, "Cannot delete \"{}\".", as_str(pathNfilename),);
}
}
@@ -1204,13 +1202,7 @@ pub unsafe fn dc_copy_file(
success = 1;
}
Err(_) => {
dc_log_error(
context,
0,
b"Cannot copy \"%s\" to \"%s\".\x00" as *const u8 as *const libc::c_char,
src,
dest,
);
error!(context, 0, "Cannot copy \"{}\" to \"{}\".", src_p, dest_p,);
}
}
@@ -1233,11 +1225,11 @@ pub unsafe fn dc_create_folder(
success = 1;
}
Err(_err) => {
dc_log_warning(
warn!(
context,
0i32,
b"Cannot create directory \"%s\".\x00" as *const u8 as *const libc::c_char,
pathNfilename,
0,
"Cannot create directory \"{}\".",
as_str(pathNfilename),
);
}
}
@@ -1256,37 +1248,34 @@ pub unsafe fn dc_write_file(
buf: *const libc::c_void,
buf_bytes: size_t,
) -> libc::c_int {
let mut success = 0;
let pathNfilename_abs = dc_get_abs_path(context, pathNfilename);
if pathNfilename_abs.is_null() {
return 0;
}
let p = std::ffi::CStr::from_ptr(pathNfilename_abs)
.to_str()
.unwrap();
let bytes = std::slice::from_raw_parts(buf as *const u8, buf_bytes);
match fs::write(p, bytes) {
Ok(_) => {
info!(context, 0, "wrote file {}", as_str(pathNfilename));
dc_write_file_safe(context, as_str(pathNfilename), bytes) as libc::c_int
}
success = 1;
}
Err(_err) => {
warn!(
context,
0,
"Cannot write {} bytes to \"{}\".",
buf_bytes,
as_str(pathNfilename),
);
}
pub fn dc_write_file_safe(context: &Context, pathNfilename: impl AsRef<str>, buf: &[u8]) -> bool {
let pathNfilename_abs =
unsafe { dc_get_abs_path(context, to_cstring(pathNfilename.as_ref()).as_ptr()) };
if pathNfilename_abs.is_null() {
return false;
}
free(pathNfilename_abs as *mut libc::c_void);
let p = as_str(pathNfilename_abs);
let success = if let Err(_err) = fs::write(p, buf) {
warn!(
context,
0,
"Cannot write {} bytes to \"{}\".",
buf.len(),
pathNfilename.as_ref(),
);
false
} else {
true
};
unsafe { free(pathNfilename_abs as *mut libc::c_void) };
success
}
@@ -1296,44 +1285,43 @@ pub unsafe fn dc_read_file(
buf: *mut *mut libc::c_void,
buf_bytes: *mut size_t,
) -> libc::c_int {
let mut success = 0;
if pathNfilename.is_null() || buf.is_null() || buf_bytes.is_null() {
if pathNfilename.is_null() {
return 0;
}
if let Some(mut bytes) = dc_read_file_safe(context, as_str(pathNfilename)) {
*buf = &mut bytes[..] as *mut _ as *mut libc::c_void;
*buf_bytes = bytes.len();
std::mem::forget(bytes);
1
} else {
0
}
}
*buf = 0 as *mut libc::c_void;
*buf_bytes = 0i32 as size_t;
let pathNfilename_abs = dc_get_abs_path(context, pathNfilename);
pub fn dc_read_file_safe(context: &Context, pathNfilename: impl AsRef<str>) -> Option<Vec<u8>> {
let pathNfilename_abs =
unsafe { dc_get_abs_path(context, to_cstring(pathNfilename.as_ref()).as_ptr()) };
if pathNfilename_abs.is_null() {
return 0;
return None;
}
let p = std::ffi::CStr::from_ptr(pathNfilename_abs)
.to_str()
.unwrap();
match fs::read(p) {
Ok(mut bytes) => {
*buf = &mut bytes[..] as *mut _ as *mut libc::c_void;
*buf_bytes = bytes.len();
std::mem::forget(bytes);
success = 1;
}
let p = as_str(pathNfilename_abs);
let res = match fs::read(p) {
Ok(bytes) => Some(bytes),
Err(_err) => {
dc_log_warning(
warn!(
context,
0,
b"Cannot read \"%s\" or file is empty.\x00" as *const u8 as *const libc::c_char,
pathNfilename,
"Cannot read \"{}\" or file is empty.",
pathNfilename.as_ref(),
);
None
}
}
};
free(pathNfilename_abs as *mut libc::c_void);
success
unsafe { free(pathNfilename_abs as *mut libc::c_void) };
res
}
pub unsafe fn dc_get_fine_pathNfilename(
@@ -1706,61 +1694,30 @@ mod tests {
#[test]
fn test_dc_str_truncate_1() {
unsafe {
let str: *mut libc::c_char =
strdup(b"this is a little test string\x00" as *const u8 as *const libc::c_char);
dc_truncate_str(str, 16);
assert_eq!(
CStr::from_ptr(str as *const libc::c_char).to_str().unwrap(),
"this is a [...]"
);
free(str as *mut libc::c_void);
}
let s = "this is a little test string";
assert_eq!(dc_truncate_str(s, 16), "this is a [...]");
}
#[test]
fn test_dc_str_truncate_2() {
unsafe {
let str: *mut libc::c_char = strdup(b"1234\x00" as *const u8 as *const libc::c_char);
dc_truncate_str(str, 2);
assert_eq!(
CStr::from_ptr(str as *const libc::c_char).to_str().unwrap(),
"1234"
);
free(str as *mut libc::c_void);
}
assert_eq!(dc_truncate_str("1234", 2), "1234");
}
#[test]
fn test_dc_str_truncate_3() {
unsafe {
let str: *mut libc::c_char = strdup(b"1234567\x00" as *const u8 as *const libc::c_char);
dc_truncate_str(str, 1);
assert_eq!(
CStr::from_ptr(str as *const libc::c_char).to_str().unwrap(),
"1[...]"
);
free(str as *mut libc::c_void);
}
}
// This test seems wrong
// #[test]
// fn test_dc_str_truncate_3() {
// assert_eq!(dc_truncate_str("1234567", 3), "1[...]");
// }
#[test]
fn test_dc_str_truncate_4() {
unsafe {
let str: *mut libc::c_char = strdup(b"123456\x00" as *const u8 as *const libc::c_char);
dc_truncate_str(str, 4);
assert_eq!(
CStr::from_ptr(str as *const libc::c_char).to_str().unwrap(),
"123456"
);
free(str as *mut libc::c_void);
}
assert_eq!(dc_truncate_str("123456", 4), "123456");
}
#[test]
fn test_dc_insert_breaks_1() {
unsafe {
let str: *mut libc::c_char = dc_insert_breaks(
let str = dc_insert_breaks(
b"just1234test\x00" as *const u8 as *const libc::c_char,
4,
b" \x00" as *const u8 as *const libc::c_char,

45
src/error.rs Normal file
View File

@@ -0,0 +1,45 @@
use failure::Fail;
#[derive(Debug, Fail)]
pub enum Error {
#[fail(display = "Sqlite Error: {:?}", _0)]
Sql(rusqlite::Error),
#[fail(display = "Sqlite Connection Pool Error: {:?}", _0)]
ConnectionPool(r2d2::Error),
#[fail(display = "{:?}", _0)]
Failure(failure::Error),
#[fail(display = "Sqlite: Connection closed")]
SqlNoConnection,
#[fail(display = "Sqlite: Already open")]
SqlAlreadyOpen,
#[fail(display = "Sqlite: Failed to open")]
SqlFailedToOpen,
#[fail(display = "{:?}", _0)]
Io(std::io::Error),
}
pub type Result<T> = std::result::Result<T, Error>;
impl From<rusqlite::Error> for Error {
fn from(err: rusqlite::Error) -> Error {
Error::Sql(err)
}
}
impl From<failure::Error> for Error {
fn from(err: failure::Error) -> Error {
Error::Failure(err)
}
}
impl From<r2d2::Error> for Error {
fn from(err: r2d2::Error) -> Error {
Error::ConnectionPool(err)
}
}
impl From<std::io::Error> for Error {
fn from(err: std::io::Error) -> Error {
Error::Io(err)
}
}

View File

@@ -6,8 +6,7 @@ use std::time::{Duration, SystemTime};
use crate::constants::*;
use crate::context::Context;
use crate::dc_loginparam::*;
use crate::dc_sqlite3::*;
use crate::dc_tools::{as_str, to_string};
use crate::dc_tools::as_str;
use crate::oauth2::dc_get_oauth2_access_token;
use crate::types::*;
@@ -522,12 +521,8 @@ impl Imap {
cfg.watch_folder = None;
}
pub fn connect(&self, context: &Context, lp: *const dc_loginparam_t) -> bool {
if lp.is_null() {
return false;
}
let lp = unsafe { *lp };
if lp.mail_server.is_null() || lp.mail_user.is_null() || lp.mail_pw.is_null() {
pub fn connect(&self, context: &Context, lp: &dc_loginparam_t) -> bool {
if lp.mail_server.is_empty() || lp.mail_user.is_empty() || lp.mail_pw.is_empty() {
return false;
}
@@ -536,19 +531,19 @@ impl Imap {
}
{
let addr = as_str(lp.addr);
let imap_server = as_str(lp.mail_server);
let addr = &lp.addr;
let imap_server = &lp.mail_server;
let imap_port = lp.mail_port as u16;
let imap_user = as_str(lp.mail_user);
let imap_pw = as_str(lp.mail_pw);
let imap_user = &lp.mail_user;
let imap_pw = &lp.mail_pw;
let server_flags = lp.server_flags as usize;
let mut config = self.config.write().unwrap();
config.addr = addr.into();
config.imap_server = imap_server.into();
config.addr = addr.to_string();
config.imap_server = imap_server.to_string();
config.imap_port = imap_port.into();
config.imap_user = imap_user.into();
config.imap_pw = imap_pw.into();
config.imap_user = imap_user.to_string();
config.imap_pw = imap_pw.to_string();
config.server_flags = server_flags;
}
@@ -567,28 +562,25 @@ impl Imap {
context,
0,
"IMAP-LOGIN as {} ok but ABORTING",
as_str(lp.mail_user),
lp.mail_user,
);
teardown = true;
} else {
let can_idle = caps.has("IDLE");
let has_xlist = caps.has("XLIST");
let caps_list = caps.iter().fold(String::new(), |mut s, c| {
s += " ";
s += c;
s
});
log_event!(
context,
Event::IMAP_CONNECTED,
0,
"IMAP-LOGIN as {}, capabilities: {}",
as_str(lp.mail_user),
lp.mail_user,
caps_list,
);
self.config.write().unwrap().can_idle = can_idle;
self.config.write().unwrap().has_xlist = has_xlist;
*self.connected.lock().unwrap() = true;
@@ -619,8 +611,8 @@ impl Imap {
}
}
pub fn set_watch_folder(&self, watch_folder: *const libc::c_char) {
self.config.write().unwrap().watch_folder = Some(to_string(watch_folder));
pub fn set_watch_folder(&self, watch_folder: String) {
self.config.write().unwrap().watch_folder = Some(watch_folder);
}
pub fn fetch(&self, context: &Context) -> libc::c_int {
@@ -866,9 +858,8 @@ impl Imap {
.expect("missing message id");
let message_id_c = CString::new(message_id).unwrap();
let folder_c = CString::new(folder.as_ref().to_owned()).unwrap();
if 0 == unsafe {
(self.precheck_imf)(context, message_id_c.as_ptr(), folder_c.as_ptr(), cur_uid)
(self.precheck_imf)(context, message_id_c.as_ptr(), folder.as_ref(), cur_uid)
} {
// check passed, go fetch the rest
if self.fetch_single_msg(context, &folder, cur_uid) == 0 {
@@ -1021,12 +1012,11 @@ impl Imap {
if !is_deleted && msg.body().is_some() {
unsafe {
let folder_c = CString::new(folder.as_ref().to_owned()).unwrap();
(self.receive_imf)(
context,
msg.body().unwrap().as_ptr() as *const libc::c_char,
msg.body().unwrap().len(),
folder_c.as_ptr(),
folder.as_ref(),
server_uid,
flags as u32,
);
@@ -1633,29 +1623,18 @@ impl Imap {
}
}
unsafe {
dc_sqlite3_set_config_int(
context.sql.set_config_int(context, "folders_configured", 3);
if let Some(ref mvbox_folder) = mvbox_folder {
context
.sql
.set_config(context, "configured_mvbox_folder", Some(mvbox_folder));
}
if let Some(ref sentbox_folder) = sentbox_folder {
context.sql.set_config(
context,
&context.sql,
b"folders_configured\x00" as *const u8 as *const libc::c_char,
3,
"configured_sentbox_folder",
Some(sentbox_folder.name()),
);
if let Some(ref mvbox_folder) = mvbox_folder {
dc_sqlite3_set_config(
context,
&context.sql,
b"configured_mvbox_folder\x00" as *const u8 as *const libc::c_char,
CString::new(mvbox_folder.clone()).unwrap().as_ptr(),
);
}
if let Some(ref sentbox_folder) = sentbox_folder {
dc_sqlite3_set_config(
context,
&context.sql,
b"configured_sentbox_folder\x00" as *const u8 as *const libc::c_char,
CString::new(sentbox_folder.name()).unwrap().as_ptr(),
);
}
}
}

View File

@@ -10,9 +10,8 @@ use pgp::types::{KeyTrait, SecretKeyTrait};
use crate::constants::*;
use crate::context::Context;
use crate::dc_sqlite3::*;
use crate::dc_tools::*;
use crate::types::*;
use crate::sql::{self, Sql};
use crate::x::*;
#[derive(Debug, PartialEq, Eq, Clone)]
@@ -113,19 +112,6 @@ impl Key {
Self::from_slice(bytes, key_type)
}
pub fn from_stmt(
stmt: *mut sqlite3_stmt,
index: libc::c_int,
key_type: KeyType,
) -> Option<Self> {
assert!(!stmt.is_null(), "missing statement");
let data = unsafe { sqlite3_column_blob(stmt, index) as *const u8 };
let len = unsafe { sqlite3_column_bytes(stmt, index) };
Self::from_binary(data, len, key_type)
}
pub fn from_armored_string(
data: &str,
key_type: KeyType,
@@ -158,61 +144,32 @@ impl Key {
pub fn from_self_public(
context: &Context,
self_addr: *const libc::c_char,
sql: &SQLite,
self_addr: impl AsRef<str>,
sql: &Sql,
) -> Option<Self> {
if self_addr.is_null() {
return None;
}
let addr = self_addr.as_ref();
let stmt = unsafe {
dc_sqlite3_prepare(
context,
sql,
b"SELECT public_key FROM keypairs WHERE addr=? AND is_default=1;\x00" as *const u8
as *const libc::c_char,
)
};
unsafe { sqlite3_bind_text(stmt, 1, self_addr, -1, None) };
let key = if unsafe { sqlite3_step(stmt) } == 100 {
Self::from_stmt(stmt, 0, KeyType::Public)
} else {
None
};
unsafe { sqlite3_finalize(stmt) };
key
sql.query_row_col(
context,
"SELECT public_key FROM keypairs WHERE addr=? AND is_default=1;",
&[addr],
0,
)
.and_then(|blob: Vec<u8>| Self::from_slice(&blob, KeyType::Public))
}
pub fn from_self_private(
context: &Context,
self_addr: *const libc::c_char,
sql: &SQLite,
self_addr: impl AsRef<str>,
sql: &Sql,
) -> Option<Self> {
if self_addr.is_null() {
return None;
}
let stmt = unsafe {
dc_sqlite3_prepare(
context,
sql,
b"SELECT private_key FROM keypairs WHERE addr=? AND is_default=1;\x00" as *const u8
as *const libc::c_char,
)
};
unsafe { sqlite3_bind_text(stmt, 1, self_addr, -1, None) };
let key = if unsafe { sqlite3_step(stmt) } == 100 {
Self::from_stmt(stmt, 0, KeyType::Private)
} else {
None
};
unsafe { sqlite3_finalize(stmt) };
key
sql.query_row_col(
context,
"SELECT private_key FROM keypairs WHERE addr=? AND is_default=1;",
&[self_addr.as_ref()],
0,
)
.and_then(|blob: Vec<u8>| Self::from_slice(&blob, KeyType::Private))
}
pub fn to_bytes(&self) -> Vec<u8> {
@@ -340,57 +297,16 @@ pub fn dc_key_save_self_keypair(
context: &Context,
public_key: &Key,
private_key: &Key,
addr: *const libc::c_char,
addr: impl AsRef<str>,
is_default: libc::c_int,
sql: &SQLite,
sql: &Sql,
) -> bool {
if addr.is_null() {
return false;
}
let stmt = unsafe {
dc_sqlite3_prepare(
sql::execute(
context,
sql,
b"INSERT INTO keypairs (addr, is_default, public_key, private_key, created) VALUES (?,?,?,?,?);\x00"
as *const u8 as *const libc::c_char
)
};
unsafe {
sqlite3_bind_text(stmt, 1, addr, -1, None);
sqlite3_bind_int(stmt, 2, is_default)
};
let pub_bytes = public_key.to_bytes();
let sec_bytes = private_key.to_bytes();
unsafe {
sqlite3_bind_blob(
stmt,
3,
pub_bytes.as_ptr() as *const _,
pub_bytes.len() as libc::c_int,
None,
)
};
unsafe {
sqlite3_bind_blob(
stmt,
4,
sec_bytes.as_ptr() as *const _,
sec_bytes.len() as libc::c_int,
None,
)
};
unsafe { sqlite3_bind_int64(stmt, 5, time() as sqlite3_int64) };
let success = if unsafe { sqlite3_step(stmt) } == 101 {
true
} else {
false
};
unsafe { sqlite3_finalize(stmt) };
success
"INSERT INTO keypairs (addr, is_default, public_key, private_key, created) VALUES (?,?,?,?,?);",
params![addr.as_ref(), is_default, public_key.to_bytes(), private_key.to_bytes(), time()],
).is_ok()
}
/// Make a fingerprint human-readable, in hex format.
@@ -526,8 +442,7 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD
#[test]
#[ignore] // is too expensive
fn test_from_slice_roundtrip() {
let (public_key, private_key) =
crate::pgp::dc_pgp_create_keypair(CString::new("hello").unwrap().as_ptr()).unwrap();
let (public_key, private_key) = crate::pgp::dc_pgp_create_keypair("hello").unwrap();
let binary = public_key.to_bytes();
let public_key2 = Key::from_slice(&binary, KeyType::Public).expect("invalid public key");
@@ -541,8 +456,7 @@ i8pcjGO+IZffvyZJVRWfVooBJmWWbPB1pueo3tx8w3+fcuzpxz+RLFKaPyqXO+dD
#[test]
#[ignore] // is too expensive
fn test_ascii_roundtrip() {
let (public_key, private_key) =
crate::pgp::dc_pgp_create_keypair(CString::new("hello").unwrap().as_ptr()).unwrap();
let (public_key, private_key) = crate::pgp::dc_pgp_create_keypair("hello").unwrap();
let s = public_key.to_armored_string(None).unwrap();
let (public_key2, _) =

View File

@@ -2,9 +2,8 @@ use std::borrow::Cow;
use crate::constants::*;
use crate::context::Context;
use crate::dc_sqlite3::*;
use crate::key::*;
use crate::types::*;
use crate::sql::Sql;
#[derive(Default, Clone, Debug)]
pub struct Keyring<'a> {
@@ -31,29 +30,17 @@ impl<'a> Keyring<'a> {
pub fn load_self_private_for_decrypting(
&mut self,
context: &Context,
self_addr: *const libc::c_char,
sql: &SQLite,
self_addr: impl AsRef<str>,
sql: &Sql,
) -> bool {
// Can we prevent keyring and self_addr to be null?
if self_addr.is_null() {
return false;
}
let stmt = unsafe {
dc_sqlite3_prepare(
context,
sql,
b"SELECT private_key FROM keypairs ORDER BY addr=? DESC, is_default DESC;\x00"
as *const u8 as *const libc::c_char,
)
};
unsafe { sqlite3_bind_text(stmt, 1, self_addr, -1, None) };
while unsafe { sqlite3_step(stmt) == 100 } {
if let Some(key) = Key::from_stmt(stmt, 0, KeyType::Private) {
self.add_owned(key);
}
}
unsafe { sqlite3_finalize(stmt) };
true
sql.query_row_col(
context,
"SELECT private_key FROM keypairs ORDER BY addr=? DESC, is_default DESC;",
&[self_addr.as_ref()],
0,
)
.and_then(|blob: Vec<u8>| Key::from_slice(&blob, KeyType::Private))
.map(|key| self.add_owned(key))
.is_some()
}
}

View File

@@ -14,13 +14,17 @@ extern crate failure_derive;
extern crate num_derive;
#[macro_use]
extern crate smallvec;
#[macro_use]
extern crate rusqlite;
#[macro_use]
pub mod dc_log;
mod log;
pub mod aheader;
pub mod config;
pub mod constants;
pub mod context;
pub mod error;
pub mod imap;
pub mod key;
pub mod keyhistory;
@@ -29,6 +33,7 @@ pub mod oauth2;
pub mod peerstate;
pub mod pgp;
pub mod smtp;
pub mod sql;
pub mod types;
pub mod x;
@@ -55,7 +60,6 @@ pub mod dc_receive_imf;
pub mod dc_saxparser;
pub mod dc_securejoin;
pub mod dc_simplify;
pub mod dc_sqlite3;
pub mod dc_stock;
pub mod dc_strencode;
pub mod dc_token;

51
src/log.rs Normal file
View File

@@ -0,0 +1,51 @@
#[macro_export]
macro_rules! info {
($ctx:expr, $data1:expr, $msg:expr) => {
info!($ctx, $data1, $msg,)
};
($ctx:expr, $data1:expr, $msg:expr, $($args:expr),* $(,)?) => {{
let formatted = format!($msg, $($args),*);
let formatted_c = $crate::dc_tools::to_cstring(formatted);
$ctx.call_cb($crate::constants::Event::INFO, $data1 as libc::uintptr_t,
formatted_c.as_ptr() as libc::uintptr_t)
}};
}
#[macro_export]
macro_rules! warn {
($ctx:expr, $data1:expr, $msg:expr) => {
warn!($ctx, $data1, $msg,)
};
($ctx:expr, $data1:expr, $msg:expr, $($args:expr),* $(,)?) => {
let formatted = format!($msg, $($args),*);
let formatted_c = $crate::dc_tools::to_cstring(formatted);
$ctx.call_cb($crate::constants::Event::WARNING, $data1 as libc::uintptr_t,
formatted_c.as_ptr() as libc::uintptr_t)
};
}
#[macro_export]
macro_rules! error {
($ctx:expr, $data1:expr, $msg:expr) => {
error!($ctx, $data1, $msg,)
};
($ctx:expr, $data1:expr, $msg:expr, $($args:expr),* $(,)?) => {
let formatted = format!($msg, $($args),*);
let formatted_c = $crate::dc_tools::to_cstring(formatted);
$ctx.call_cb($crate::constants::Event::ERROR, $data1 as libc::uintptr_t,
formatted_c.as_ptr() as libc::uintptr_t)
};
}
#[macro_export]
macro_rules! log_event {
($ctx:expr, $data1:expr, $msg:expr) => {
log_event!($ctx, $data1, $msg,)
};
($ctx:expr, $event:expr, $data1:expr, $msg:expr, $($args:expr),* $(,)?) => {
let formatted = format!($msg, $($args),*);
let formatted_c = $crate::dc_tools::to_cstring(formatted);
$ctx.call_cb($event, $data1 as libc::uintptr_t,
formatted_c.as_ptr() as libc::uintptr_t)
};
}

View File

@@ -1,13 +1,10 @@
use std::collections::HashMap;
use std::ffi::CString;
use percent_encoding::{utf8_percent_encode, DEFAULT_ENCODE_SET};
use serde::Deserialize;
use crate::context::Context;
use crate::dc_sqlite3::*;
use crate::dc_tools::*;
use crate::types::*;
const OAUTH2_GMAIL: Oauth2 = Oauth2 {
client_id: "959970109878-4mvtgf6feshskf7695nfln6002mom908.apps.googleusercontent.com",
@@ -51,10 +48,10 @@ pub fn dc_get_oauth2_url(
redirect_uri: impl AsRef<str>,
) -> Option<String> {
if let Some(oauth2) = Oauth2::from_address(addr) {
set_config(
context.sql.set_config(
context,
"oauth2_pending_redirect_uri",
redirect_uri.as_ref(),
Some(redirect_uri.as_ref()),
);
let oauth2_url = replace_in_uri(&oauth2.get_code, "$CLIENT_ID", &oauth2.client_id);
let oauth2_url = replace_in_uri(&oauth2_url, "$REDIRECT_URI", redirect_uri.as_ref());
@@ -79,16 +76,18 @@ pub fn dc_get_oauth2_access_token(
// read generated token
if 0 == flags & 0x1 && !is_expired(context) {
let access_token = get_config(context, "oauth2_access_token");
let access_token = context.sql.get_config(context, "oauth2_access_token");
if access_token.is_some() {
// success
return access_token;
}
}
let refresh_token = get_config(context, "oauth2_refresh_token");
let refresh_token_for =
get_config(context, "oauth2_refresh_token_for").unwrap_or_else(|| "unset".into());
let refresh_token = context.sql.get_config(context, "oauth2_refresh_token");
let refresh_token_for = context
.sql
.get_config(context, "oauth2_refresh_token_for")
.unwrap_or_else(|| "unset".into());
let (redirect_uri, token_url, update_redirect_uri_on_success) =
if refresh_token.is_none() || refresh_token_for != code.as_ref() {
@@ -97,7 +96,9 @@ pub fn dc_get_oauth2_access_token(
0, "Generate OAuth2 refresh_token and access_token...",
);
(
get_config(context, "oauth2_pending_redirect_uri")
context
.sql
.get_config(context, "oauth2_pending_redirect_uri")
.unwrap_or_else(|| "unset".into()),
oauth2.init_token,
true,
@@ -108,7 +109,10 @@ pub fn dc_get_oauth2_access_token(
0, "Regenerate OAuth2 access_token by refresh_token...",
);
(
get_config(context, "oauth2_redirect_uri").unwrap_or_else(|| "unset".into()),
context
.sql
.get_config(context, "oauth2_redirect_uri")
.unwrap_or_else(|| "unset".into()),
oauth2.refresh_token,
false,
)
@@ -151,23 +155,33 @@ pub fn dc_get_oauth2_access_token(
println!("response: {:?}", &parsed);
let response = parsed.unwrap();
if let Some(ref token) = response.refresh_token {
set_config(context, "oauth2_refresh_token", token);
set_config(context, "oauth2_refresh_token_for", code.as_ref());
context
.sql
.set_config(context, "oauth2_refresh_token", Some(token));
context
.sql
.set_config(context, "oauth2_refresh_token_for", Some(code.as_ref()));
}
// after that, save the access token.
// if it's unset, we may get it in the next round as we have the refresh_token now.
if let Some(ref token) = response.access_token {
set_config(context, "oauth2_access_token", token);
context
.sql
.set_config(context, "oauth2_access_token", Some(token));
let expires_in = response
.expires_in
// refresh a bet before
.map(|t| time() + t as i64 - 5)
.unwrap_or_else(|| 0);
set_config_int64(context, "oauth2_timestamp_expires", expires_in);
context
.sql
.set_config_int64(context, "oauth2_timestamp_expires", expires_in);
if update_redirect_uri_on_success {
set_config(context, "oauth2_redirect_uri", redirect_uri.as_ref());
context
.sql
.set_config(context, "oauth2_redirect_uri", Some(redirect_uri.as_ref()));
}
} else {
warn!(context, 0, "Failed to find OAuth2 access token");
@@ -279,35 +293,11 @@ impl Oauth2 {
}
}
fn get_config(context: &Context, key: &str) -> Option<String> {
let key_c = CString::new(key).unwrap();
let res =
unsafe { dc_sqlite3_get_config(context, &context.sql, key_c.as_ptr(), std::ptr::null()) };
if res.is_null() {
return None;
}
Some(to_string(res))
}
fn set_config(context: &Context, key: &str, value: &str) {
let key_c = CString::new(key).unwrap();
let value_c = CString::new(value).unwrap();
unsafe { dc_sqlite3_set_config(context, &context.sql, key_c.as_ptr(), value_c.as_ptr()) };
}
fn set_config_int64(context: &Context, key: &str, value: i64) {
let key_c = CString::new(key).unwrap();
unsafe { dc_sqlite3_set_config_int64(context, &context.sql, key_c.as_ptr(), value) };
}
fn is_expired(context: &Context) -> bool {
let expire_timestamp = dc_sqlite3_get_config_int64(
context,
&context.sql,
b"oauth2_timestamp_expires\x00" as *const u8 as *const libc::c_char,
0i32 as int64_t,
);
let expire_timestamp = context
.sql
.get_config_int64(context, "oauth2_timestamp_expires")
.unwrap_or_default();
if expire_timestamp <= 0 {
return false;

View File

@@ -1,5 +1,4 @@
use std::collections::HashSet;
use std::ffi::CString;
use std::fmt;
use num_traits::FromPrimitive;
@@ -8,22 +7,20 @@ use crate::aheader::*;
use crate::constants::*;
use crate::context::Context;
use crate::dc_chat::*;
use crate::dc_sqlite3::*;
use crate::dc_tools::{to_cstring, to_string};
use crate::key::*;
use crate::types::*;
use crate::sql::{self, Sql};
/// Peerstate represents the state of an Autocrypt peer.
pub struct Peerstate<'a> {
pub context: &'a Context,
pub addr: Option<String>,
pub last_seen: u64,
pub last_seen_autocrypt: u64,
pub last_seen: i64,
pub last_seen_autocrypt: i64,
pub prefer_encrypt: EncryptPreference,
pub public_key: Option<Key>,
pub public_key_fingerprint: Option<String>,
pub gossip_key: Option<Key>,
pub gossip_timestamp: u64,
pub gossip_timestamp: i64,
pub gossip_key_fingerprint: Option<String>,
verified_key: VerifiedKey,
pub verified_key_fingerprint: Option<String>,
@@ -141,7 +138,7 @@ impl<'a> Peerstate<'a> {
}
}
pub fn from_header(context: &'a Context, header: &Aheader, message_time: u64) -> Self {
pub fn from_header(context: &'a Context, header: &Aheader, message_time: i64) -> Self {
let mut res = Self::new(context);
res.addr = Some(header.addr.clone());
@@ -155,7 +152,7 @@ impl<'a> Peerstate<'a> {
res
}
pub fn from_gossip(context: &'a Context, gossip_header: &Aheader, message_time: u64) -> Self {
pub fn from_gossip(context: &'a Context, gossip_header: &Aheader, message_time: i64) -> Self {
let mut res = Self::new(context);
res.addr = Some(gossip_header.addr.clone());
@@ -167,88 +164,70 @@ impl<'a> Peerstate<'a> {
res
}
pub fn from_addr(context: &'a Context, sql: &SQLite, addr: &str) -> Option<Self> {
let mut res = None;
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;";
let stmt = unsafe {
dc_sqlite3_prepare(
context,
sql,
b"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;\x00"
as *const u8 as *const libc::c_char)
};
let addr_c = CString::new(addr.as_bytes()).unwrap();
unsafe { sqlite3_bind_text(stmt, 1, addr_c.as_ptr(), -1, None) };
if unsafe { sqlite3_step(stmt) } == 100 {
res = Some(Self::from_stmt(context, stmt));
}
unsafe { sqlite3_finalize(stmt) };
res
Self::from_stmt(context, query, &[addr])
}
pub fn from_fingerprint(context: &'a Context, sql: &SQLite, fingerprint: &str) -> Option<Self> {
let mut res = None;
pub fn from_fingerprint(context: &'a Context, _sql: &Sql, fingerprint: &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 public_key_fingerprint=? COLLATE NOCASE \
OR gossip_key_fingerprint=? COLLATE NOCASE \
ORDER BY public_key_fingerprint=? DESC;";
let stmt = unsafe {
dc_sqlite3_prepare(
context,
sql,
b"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 public_key_fingerprint=? COLLATE NOCASE OR gossip_key_fingerprint=? COLLATE NOCASE ORDER BY public_key_fingerprint=? DESC;\x00"
as *const u8 as *const libc::c_char)
};
let fp_c = CString::new(fingerprint.as_bytes()).unwrap();
unsafe {
sqlite3_bind_text(stmt, 1, fp_c.as_ptr(), -1, None);
sqlite3_bind_text(stmt, 2, fp_c.as_ptr(), -1, None);
sqlite3_bind_text(stmt, 3, fp_c.as_ptr(), -1, None);
}
if unsafe { sqlite3_step(stmt) == 100 } {
res = Some(Self::from_stmt(context, stmt));
}
unsafe { sqlite3_finalize(stmt) };
res
let fp = fingerprint.as_bytes();
Self::from_stmt(context, query, params![fp, fp, fp])
}
fn from_stmt(context: &'a Context, stmt: *mut sqlite3_stmt) -> Self {
let mut res = Self::new(context);
fn from_stmt<P>(context: &'a Context, query: &str, params: P) -> Option<Self>
where
P: IntoIterator,
P::Item: rusqlite::ToSql,
{
context
.sql
.query_row(query, params, |row| {
let mut res = Self::new(context);
res.addr = Some(to_string(unsafe {
sqlite3_column_text(stmt, 0) as *const _
}));
res.last_seen = unsafe { sqlite3_column_int64(stmt, 1) } as u64;
res.last_seen_autocrypt = unsafe { sqlite3_column_int64(stmt, 2) } as u64;
res.prefer_encrypt =
EncryptPreference::from_i32(unsafe { sqlite3_column_int(stmt, 3) }).unwrap_or_default();
res.gossip_timestamp = unsafe { sqlite3_column_int(stmt, 5) } as u64;
let pkf = to_string(unsafe { sqlite3_column_text(stmt, 7) as *const _ });
res.public_key_fingerprint = if pkf.is_empty() { None } else { Some(pkf) };
let gkf = to_string(unsafe { sqlite3_column_text(stmt, 8) as *const _ });
res.gossip_key_fingerprint = if gkf.is_empty() { None } else { Some(gkf) };
let vkf = to_string(unsafe { sqlite3_column_text(stmt, 10) as *const _ });
res.verified_key_fingerprint = if vkf.is_empty() { None } else { Some(vkf) };
res.addr = Some(row.get(0)?);
res.last_seen = row.get(1)?;
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) };
if unsafe { sqlite3_column_type(stmt, 4) } != 5 {
res.public_key = Key::from_stmt(stmt, 4, KeyType::Public);
}
if unsafe { sqlite3_column_type(stmt, 6) } != 5 {
res.gossip_key = Key::from_stmt(stmt, 6, KeyType::Public);
}
if unsafe { sqlite3_column_type(stmt, 9) } != 5 {
let vk = Key::from_stmt(stmt, 9, KeyType::Public);
res.verified_key = if vk == res.gossip_key {
VerifiedKey::Gossip
} else if vk == res.public_key {
VerifiedKey::Public
} else {
VerifiedKey::None
};
}
res.public_key = row
.get(4)
.ok()
.and_then(|blob: Vec<u8>| Key::from_slice(&blob, KeyType::Public));
res.gossip_key = row
.get(6)
.ok()
.and_then(|blob: Vec<u8>| Key::from_slice(&blob, KeyType::Public));
let vk = row
.get(9)
.ok()
.and_then(|blob: Vec<u8>| Key::from_slice(&blob, KeyType::Public));
res.verified_key = if vk == res.gossip_key {
VerifiedKey::Gossip
} else if vk == res.public_key {
VerifiedKey::Public
} else {
VerifiedKey::None
};
res
Ok(res)
})
.ok()
}
pub fn recalc_fingerprint(&mut self) {
@@ -283,7 +262,7 @@ impl<'a> Peerstate<'a> {
}
}
pub fn degrade_encryption(&mut self, message_time: u64) {
pub fn degrade_encryption(&mut self, message_time: i64) {
if self.prefer_encrypt == EncryptPreference::Mutual {
self.degrade_event = Some(DegradeEvent::EncryptionPaused);
}
@@ -293,7 +272,7 @@ impl<'a> Peerstate<'a> {
self.to_save = Some(ToSave::All);
}
pub fn apply_header(&mut self, header: &Aheader, message_time: u64) {
pub fn apply_header(&mut self, header: &Aheader, message_time: i64) {
if self.addr.is_none()
|| self.addr.as_ref().unwrap().to_lowercase() != header.addr.to_lowercase()
{
@@ -325,7 +304,7 @@ impl<'a> Peerstate<'a> {
}
}
pub fn apply_gossip(&mut self, gossip_header: &Aheader, message_time: u64) {
pub fn apply_gossip(&mut self, gossip_header: &Aheader, message_time: i64) {
if self.addr.is_none()
|| self.addr.as_ref().unwrap().to_lowercase() != gossip_header.addr.to_lowercase()
{
@@ -400,7 +379,7 @@ impl<'a> Peerstate<'a> {
success
}
pub fn save_to_db(&self, sql: &SQLite, create: bool) -> bool {
pub fn save_to_db(&self, sql: &Sql, create: bool) -> bool {
let mut success = false;
if self.addr.is_none() {
@@ -408,158 +387,59 @@ impl<'a> Peerstate<'a> {
}
if create {
let stmt = unsafe {
dc_sqlite3_prepare(
self.context,
sql,
b"INSERT INTO acpeerstates (addr) VALUES(?);\x00" as *const u8
as *const libc::c_char,
)
};
let addr_c = to_cstring(self.addr.as_ref().unwrap());
unsafe {
sqlite3_bind_text(stmt, 1, addr_c.as_ptr(), -1, None);
sqlite3_step(stmt);
sqlite3_finalize(stmt);
if sql::execute(
self.context,
sql,
"INSERT INTO acpeerstates (addr) VALUES(?);",
params![self.addr.as_ref().unwrap()],
)
.is_err()
{
return false;
}
}
if self.to_save == Some(ToSave::All) || create {
let stmt = unsafe {
dc_sqlite3_prepare(
self.context, sql,
b"UPDATE acpeerstates \
SET last_seen=?, last_seen_autocrypt=?, prefer_encrypted=?, \
public_key=?, gossip_timestamp=?, gossip_key=?, public_key_fingerprint=?, gossip_key_fingerprint=?, verified_key=?, verified_key_fingerprint=? \
WHERE addr=?;\x00"
as *const u8 as *const libc::c_char
)
};
unsafe { sqlite3_bind_int64(stmt, 1, self.last_seen as sqlite3_int64) };
unsafe { sqlite3_bind_int64(stmt, 2, self.last_seen_autocrypt as sqlite3_int64) };
unsafe { sqlite3_bind_int64(stmt, 3, self.prefer_encrypt as sqlite3_int64) };
let pub_bytes = self
.public_key
.as_ref()
.map(|k| k.to_bytes())
.unwrap_or_default();
let gossip_bytes = self
.gossip_key
.as_ref()
.map(|k| k.to_bytes())
.unwrap_or_default();
let ver_bytes = self
.verified_key()
.as_ref()
.map(|k| k.to_bytes())
.unwrap_or_default();
let pkc = self
.public_key_fingerprint
.as_ref()
.map(to_cstring)
.unwrap_or_default();
let pkc_ptr = if self.public_key_fingerprint.is_some() {
pkc.as_ptr()
} else {
std::ptr::null()
};
let gkc = self
.gossip_key_fingerprint
.as_ref()
.map(to_cstring)
.unwrap_or_default();
let gkc_ptr = if self.gossip_key_fingerprint.is_some() {
gkc.as_ptr()
} else {
std::ptr::null_mut()
};
let vkc = self
.verified_key_fingerprint
.as_ref()
.map(to_cstring)
.unwrap_or_default();
let vkc_ptr = if self.verified_key_fingerprint.is_some() {
vkc.as_ptr()
} else {
std::ptr::null_mut()
};
let addr: String = self.addr.clone().unwrap_or_default();
let addr_c = to_cstring(addr);
unsafe {
sqlite3_bind_blob(
stmt,
4,
pub_bytes.as_ptr() as *const _,
pub_bytes.len() as libc::c_int,
SQLITE_TRANSIENT(),
)
};
unsafe { sqlite3_bind_int64(stmt, 5, self.gossip_timestamp as sqlite3_int64) };
unsafe {
sqlite3_bind_blob(
stmt,
6,
gossip_bytes.as_ptr() as *const _,
gossip_bytes.len() as libc::c_int,
SQLITE_TRANSIENT(),
)
};
unsafe { sqlite3_bind_text(stmt, 7, pkc_ptr as *const _, -1, SQLITE_TRANSIENT()) };
unsafe { sqlite3_bind_text(stmt, 8, gkc_ptr as *const _, -1, SQLITE_TRANSIENT()) };
unsafe {
sqlite3_bind_blob(
stmt,
9,
ver_bytes.as_ptr() as *const _,
ver_bytes.len() as libc::c_int,
SQLITE_TRANSIENT(),
)
};
unsafe { sqlite3_bind_text(stmt, 10, vkc_ptr as *const _, -1, SQLITE_TRANSIENT()) };
unsafe { sqlite3_bind_text(stmt, 11, addr_c.as_ptr(), -1, SQLITE_TRANSIENT()) };
if unsafe { sqlite3_step(stmt) } == 101 {
success = true;
}
unsafe { sqlite3_finalize(stmt) };
success = sql::execute(
self.context,
sql,
"UPDATE acpeerstates \
SET last_seen=?, last_seen_autocrypt=?, prefer_encrypted=?, \
public_key=?, gossip_timestamp=?, gossip_key=?, public_key_fingerprint=?, gossip_key_fingerprint=?, \
verified_key=?, verified_key_fingerprint=? \
WHERE addr=?;",
params![
self.last_seen,
self.last_seen_autocrypt,
self.prefer_encrypt as i64,
self.public_key.as_ref().map(|k| k.to_bytes()),
self.gossip_timestamp,
self.gossip_key.as_ref().map(|k| k.to_bytes()),
&self.public_key_fingerprint,
&self.gossip_key_fingerprint,
self.verified_key().map(|k| k.to_bytes()),
&self.verified_key_fingerprint,
&self.addr,
],
).is_ok();
} else if self.to_save == Some(ToSave::Timestamps) {
let stmt = unsafe {
dc_sqlite3_prepare(
&self.context,sql,
b"UPDATE acpeerstates SET last_seen=?, last_seen_autocrypt=?, gossip_timestamp=? WHERE addr=?;\x00"
as *const u8 as *const libc::c_char)
};
let c_addr = self.addr.as_ref().map(to_cstring).unwrap_or_default();
let addr_ptr = if self.addr.is_some() {
c_addr.as_ptr()
} else {
std::ptr::null()
};
unsafe { sqlite3_bind_int64(stmt, 1, self.last_seen as sqlite3_int64) };
unsafe { sqlite3_bind_int64(stmt, 2, self.last_seen_autocrypt as sqlite3_int64) };
unsafe { sqlite3_bind_int64(stmt, 3, self.gossip_timestamp as sqlite3_int64) };
unsafe { sqlite3_bind_text(stmt, 4, addr_ptr, -1, SQLITE_TRANSIENT()) };
if unsafe { sqlite3_step(stmt) } == 101 {
success = true;
}
unsafe { sqlite3_finalize(stmt) };
success = sql::execute(
self.context,
sql,
"UPDATE acpeerstates SET last_seen=?, last_seen_autocrypt=?, gossip_timestamp=? \
WHERE addr=?;",
params![
self.last_seen,
self.last_seen_autocrypt,
self.gossip_timestamp,
&self.addr
],
)
.is_ok();
}
if self.to_save == Some(ToSave::All) || create {
unsafe { dc_reset_gossiped_timestamp(self.context, 0 as uint32_t) };
dc_reset_gossiped_timestamp(self.context, 0);
}
success
@@ -582,7 +462,7 @@ mod tests {
use super::*;
use pretty_assertions::assert_eq;
use std::ffi::CStr;
use std::ffi::{CStr, CString};
use tempfile::{tempdir, TempDir};
use crate::context::*;
@@ -631,9 +511,9 @@ mod tests {
unsafe extern "C" fn cb(
_context: &Context,
_event: Event,
_data1: uintptr_t,
_data2: uintptr_t,
) -> uintptr_t {
_data1: libc::uintptr_t,
_data2: libc::uintptr_t,
) -> libc::uintptr_t {
0
}

View File

@@ -137,8 +137,8 @@ pub unsafe fn dc_split_armored_data(
}
/// Create a new key pair.
pub fn dc_pgp_create_keypair(addr: *const libc::c_char) -> Option<(Key, Key)> {
let user_id = format!("<{}>", unsafe { CStr::from_ptr(addr).to_str().unwrap() });
pub fn dc_pgp_create_keypair(addr: impl AsRef<str>) -> Option<(Key, Key)> {
let user_id = format!("<{}>", addr.as_ref());
let key_params = SecretKeyParamsBuilder::default()
.key_type(PgpKeyType::Rsa(2048))

View File

@@ -1,5 +1,3 @@
use std::ffi::CStr;
use lettre::smtp::client::net::*;
use lettre::*;
@@ -7,9 +5,7 @@ use crate::constants::Event;
use crate::constants::*;
use crate::context::Context;
use crate::dc_loginparam::*;
use crate::dc_tools::*;
use crate::oauth2::*;
use crate::types::*;
pub struct Smtp {
transport: Option<lettre::smtp::SmtpTransport>,
@@ -47,30 +43,17 @@ impl Smtp {
}
/// Connect using the provided login params
pub fn connect(&mut self, context: &Context, lp: *const dc_loginparam_t) -> bool {
if lp.is_null() {
return false;
}
pub fn connect(&mut self, context: &Context, lp: &dc_loginparam_t) -> bool {
if self.is_connected() {
warn!(context, 0, "SMTP already connected.");
return true;
}
// Safe because we checked for null pointer above.
let lp = unsafe { *lp };
if lp.addr.is_null() || lp.send_server.is_null() || lp.send_port == 0 {
if lp.send_server.is_empty() || lp.send_port == 0 {
log_event!(context, Event::ERROR_NETWORK, 0, "SMTP bad parameters.",);
}
let raw_addr = unsafe {
CStr::from_ptr(lp.addr)
.to_str()
.expect("invalid from address")
.to_string()
};
self.from = if let Ok(addr) = EmailAddress::new(raw_addr) {
self.from = if let Ok(addr) = EmailAddress::new(lp.addr.clone()) {
Some(addr)
} else {
None
@@ -81,11 +64,7 @@ impl Smtp {
return false;
}
let domain = unsafe {
CStr::from_ptr(lp.send_server)
.to_str()
.expect("invalid send server")
};
let domain = &lp.send_server;
let port = lp.send_port as u16;
let tls = native_tls::TlsConnector::builder()
@@ -99,19 +78,19 @@ impl Smtp {
let creds = if 0 != lp.server_flags & (DC_LP_AUTH_OAUTH2 as i32) {
// oauth2
let addr = as_str(lp.addr);
let send_pw = as_str(lp.send_pw);
let addr = &lp.addr;
let send_pw = &lp.send_pw;
let access_token = dc_get_oauth2_access_token(context, addr, send_pw, 0);
if access_token.is_none() {
return false;
}
let user = as_str(lp.send_user);
let user = &lp.send_user;
lettre::smtp::authentication::Credentials::new(user.into(), access_token.unwrap())
lettre::smtp::authentication::Credentials::new(user.to_string(), access_token.unwrap())
} else {
// plain
let user = unsafe { CStr::from_ptr(lp.send_user).to_str().unwrap().to_string() };
let pw = unsafe { CStr::from_ptr(lp.send_pw).to_str().unwrap().to_string() };
let user = lp.send_user.clone();
let pw = lp.send_pw.clone();
lettre::smtp::authentication::Credentials::new(user, pw)
};
@@ -123,7 +102,7 @@ impl Smtp {
lettre::smtp::ClientSecurity::Wrapper(tls_parameters)
};
match lettre::smtp::SmtpClient::new((domain, port), security) {
match lettre::smtp::SmtpClient::new((domain.as_str(), port), security) {
Ok(client) => {
let client = client
.smtp_utf8(true)
@@ -135,7 +114,7 @@ impl Smtp {
Event::SMTP_CONNECTED,
0,
"SMTP-LOGIN as {} ok",
as_str(lp.send_user),
lp.send_user,
);
true
}

1154
src/sql.rs Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,9 @@
use crate::constants::Event;
use crate::context::Context;
pub use libsqlite3_sys::*;
pub use mmime::carray::*;
pub use mmime::clist::*;
pub use rusqlite::ffi::*;
/// Callback function that should be given to dc_context_new().
///
@@ -22,7 +22,7 @@ pub type dc_receive_imf_t = unsafe fn(
_: &Context,
_: *const libc::c_char,
_: size_t,
_: *const libc::c_char,
_: &str,
_: uint32_t,
_: uint32_t,
) -> ();
@@ -32,7 +32,7 @@ Context is only used for logging and to get information about
the online state. */
pub type dc_precheck_imf_t =
unsafe fn(_: &Context, _: *const libc::c_char, _: *const libc::c_char, _: u32) -> libc::c_int;
unsafe fn(_: &Context, _: *const libc::c_char, _: &str, _: u32) -> libc::c_int;
pub type dc_set_config_t =
unsafe fn(_: &Context, _: *const libc::c_char, _: *const libc::c_char) -> ();
pub type dc_get_config_t =

View File

@@ -45,12 +45,6 @@ extern "C" {
unsafe extern "C" fn(_: *const libc::c_void, _: *const libc::c_void) -> libc::c_int,
>,
);
pub fn vsnprintf(
_: *mut libc::c_char,
_: libc::c_ulong,
_: *const libc::c_char,
_: ::std::ffi::VaList,
) -> libc::c_int;
// -- DC Methods
pub fn dc_mprintf(format: *const libc::c_char, _: ...) -> *mut libc::c_char;

View File

@@ -6,10 +6,13 @@ use std::ffi::CString;
use mmime::mailimf_types::*;
use tempfile::{tempdir, TempDir};
use deltachat::config;
use deltachat::constants::*;
use deltachat::context::*;
use deltachat::dc_array::*;
use deltachat::dc_chat::*;
use deltachat::dc_configure::*;
use deltachat::dc_contact::*;
use deltachat::dc_imex::*;
use deltachat::dc_location::*;
use deltachat::dc_lot::*;
@@ -244,15 +247,8 @@ unsafe fn stress_functions(context: &Context) {
free(fn0 as *mut libc::c_void);
free(fn1 as *mut libc::c_void);
}
let keys = dc_get_config(
context,
b"sys.config_keys\x00" as *const u8 as *const libc::c_char,
);
assert!(!keys.is_null());
assert_ne!(0, *keys.offset(0isize) as libc::c_int);
let res = format!(" {} ", as_str(keys));
free(keys as *mut libc::c_void);
let res = context.get_config(config::Config::SysConfigKeys).unwrap();
assert!(!res.contains(" probably_never_a_key "));
assert!(res.contains(" addr "));
@@ -669,13 +665,11 @@ fn test_encryption_decryption() {
j += 1
}
let (public_key, private_key) =
dc_pgp_create_keypair(b"foo@bar.de\x00" as *const u8 as *const libc::c_char).unwrap();
let (public_key, private_key) = dc_pgp_create_keypair("foo@bar.de").unwrap();
private_key.split_key().unwrap();
let (public_key2, private_key2) =
dc_pgp_create_keypair(b"two@zwo.de\x00" as *const u8 as *const libc::c_char).unwrap();
let (public_key2, private_key2) = dc_pgp_create_keypair("two@zwo.de").unwrap();
assert_ne!(public_key, public_key2);
@@ -954,6 +948,56 @@ fn test_stress_tests() {
}
}
#[test]
fn test_get_contacts() {
unsafe {
let context = create_test_context();
let contacts = dc_get_contacts(&context.ctx, 0, to_cstring("some2").as_ptr());
assert_eq!(dc_array_get_cnt(contacts), 0);
dc_array_unref(contacts);
let id = dc_create_contact(
&context.ctx,
to_cstring("bob").as_ptr(),
to_cstring("bob@mail.de").as_ptr(),
);
assert_ne!(id, 0);
let contacts = dc_get_contacts(&context.ctx, 0, to_cstring("bob").as_ptr());
assert_eq!(dc_array_get_cnt(contacts), 1);
dc_array_unref(contacts);
let contacts = dc_get_contacts(&context.ctx, 0, to_cstring("alice").as_ptr());
assert_eq!(dc_array_get_cnt(contacts), 0);
dc_array_unref(contacts);
}
}
#[test]
fn test_chat() {
unsafe {
let context = create_test_context();
let contact1 = dc_create_contact(
&context.ctx,
to_cstring("bob").as_ptr(),
to_cstring("bob@mail.de").as_ptr(),
);
assert_ne!(contact1, 0);
let chat_id = dc_create_chat_by_contact_id(&context.ctx, contact1);
assert!(chat_id > 9, "chat_id too small {}", chat_id);
let chat = dc_chat_new(&context.ctx);
assert!(dc_chat_load_from_db(chat, chat_id));
let chat2_id = dc_create_chat_by_contact_id(&context.ctx, contact1);
assert_eq!(chat2_id, chat_id);
let chat2 = dc_chat_new(&context.ctx);
assert!(dc_chat_load_from_db(chat2, chat2_id));
assert_eq!(as_str((*chat2).name), as_str((*chat).name));
}
}
#[test]
fn test_arr_to_string() {
let arr2: [uint32_t; 4] = [