mirror of
https://github.com/chatmail/core.git
synced 2026-04-02 05:22:14 +03:00
Merge branch 'master' into eventlogging
This commit is contained in:
@@ -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
3
.gitignore
vendored
@@ -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
2918
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
@@ -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!(
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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
3
release.toml
Normal 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
|
||||
@@ -1 +1 @@
|
||||
nightly-2019-06-16
|
||||
nightly-2019-07-10
|
||||
|
||||
@@ -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
177
src/config.rs
Normal 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"));
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
694
src/context.rs
694
src/context.rs
@@ -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
|
||||
}
|
||||
|
||||
2191
src/dc_chat.rs
2191
src/dc_chat.rs
File diff suppressed because it is too large
Load Diff
@@ -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 {
|
||||
|
||||
1618
src/dc_configure.rs
1618
src/dc_configure.rs
File diff suppressed because it is too large
Load Diff
1031
src/dc_contact.rs
1031
src/dc_contact.rs
File diff suppressed because it is too large
Load Diff
134
src/dc_e2ee.rs
134
src/dc_e2ee.rs
@@ -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
|
||||
}
|
||||
|
||||
866
src/dc_imex.rs
866
src/dc_imex.rs
File diff suppressed because it is too large
Load Diff
728
src/dc_job.rs
728
src/dc_job.rs
File diff suppressed because it is too large
Load Diff
@@ -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
142
src/dc_log.rs
142
src/dc_log.rs
@@ -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)
|
||||
};
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
1090
src/dc_msg.rs
1090
src/dc_msg.rs
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
1605
src/dc_sqlite3.rs
1605
src/dc_sqlite3.rs
File diff suppressed because it is too large
Load Diff
101
src/dc_token.rs
101
src/dc_token.rs
@@ -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()
|
||||
}
|
||||
|
||||
231
src/dc_tools.rs
231
src/dc_tools.rs
@@ -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
45
src/error.rs
Normal 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)
|
||||
}
|
||||
}
|
||||
75
src/imap.rs
75
src/imap.rs
@@ -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(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
142
src/key.rs
142
src/key.rs
@@ -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, _) =
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
51
src/log.rs
Normal 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)
|
||||
};
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
348
src/peerstate.rs
348
src/peerstate.rs
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
45
src/smtp.rs
45
src/smtp.rs
@@ -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
1154
src/sql.rs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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 =
|
||||
|
||||
6
src/x.rs
6
src/x.rs
@@ -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;
|
||||
|
||||
@@ -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] = [
|
||||
|
||||
Reference in New Issue
Block a user