mirror of
https://github.com/chatmail/core.git
synced 2026-04-19 14:36:29 +03:00
The big sqlite refactor
* refactor: safe sql access * Clean up the worst rebase mistakes * Some more progress on the rebase fallout and this branch * upgrade and compile again * cleanup from rebase * example of how to prepare now * rebase fixes * add sql.query_map * less preparation * more improvements in sql code * fix string truncation * more prepare conversions * most prep done * fix tests * fix ffi * fix last prepares * fix segfaults and some queries * use r2d2 pool * fix dc_job sql call, to reduce contention * try newer rust * No more vararg printing (drop dc_log_) * ignore expected errors * fix: uses exists instead of execute where needed * fix: get_contacts logic was broken * fix: contact creation * test on 32bit linux * ci: try running 32bit without cross * undo 32bit tests * refactor: rename dc_sqlite3 to sql * fix: safer string conversions * more string fixes * try fixing appveyor build to 64bit * chore(ci): hardcode target * chore(ci): appveyor * some cleanup work * try fix darwin * fix and improve sql escaping * fix various bugs * fix chat deletion * refactor: cleanup config values and move to their own file * refactor: move more methods onto the sql struct * dont panic on failed state loading * first round of cr * one more cr fix * stop using strange defaults * remove unused escapes
This commit is contained in:
committed by
GitHub
parent
3e3403d3d7
commit
8a0fc609e6
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,
|
||||
|
||||
Reference in New Issue
Block a user