most prep done

This commit is contained in:
dignifiedquire
2019-07-10 16:21:44 +02:00
parent 8c14924964
commit 5b04dc8fa6
5 changed files with 524 additions and 619 deletions

View File

@@ -119,68 +119,66 @@ pub fn dc_chat_load_from_db(chat: *mut Chat, chat_id: u32) -> bool {
let context = unsafe { (*chat).context }; let context = unsafe { (*chat).context };
if let Some(mut stmt) = dc_sqlite3_prepare( context
context, .sql
&context.sql, .query_row(
"SELECT c.id,c.type,c.name, c.grpid,c.param,c.archived, \ "SELECT c.id,c.type,c.name, c.grpid,c.param,c.archived, \
c.blocked, c.gossiped_timestamp, c.locations_send_until \ c.blocked, c.gossiped_timestamp, c.locations_send_until \
FROM chats c WHERE c.id=?;", FROM chats c WHERE c.id=?;",
) { params![chat_id as i32],
stmt.query_row(params![chat_id as i32], |row| { |row| {
let c = unsafe { &mut *chat }; let c = unsafe { &mut *chat };
c.id = row.get(0)?; c.id = row.get(0)?;
c.type_0 = row.get(1)?; c.type_0 = row.get(1)?;
c.name = { c.name = {
let raw: String = row.get(2)?; let raw: String = row.get(2)?;
unsafe { strdup(to_cstring(raw).as_ptr()) } unsafe { strdup(to_cstring(raw).as_ptr()) }
}; };
c.grpid = { c.grpid = {
let raw: String = row.get(3)?; let raw: String = row.get(3)?;
unsafe { strdup(to_cstring(raw).as_ptr()) } unsafe { strdup(to_cstring(raw).as_ptr()) }
}; };
let packed: String = row.get(4)?; let packed: String = row.get(4)?;
unsafe { dc_param_set_packed((*chat).param, to_cstring(&packed).as_ptr()) }; unsafe { dc_param_set_packed((*chat).param, to_cstring(&packed).as_ptr()) };
c.archived = row.get(5)?; c.archived = row.get(5)?;
c.blocked = row.get(6)?; c.blocked = row.get(6)?;
c.gossiped_timestamp = row.get(7)?; c.gossiped_timestamp = row.get(7)?;
c.is_sending_locations = row.get(8)?; c.is_sending_locations = row.get(8)?;
match c.id { match c.id {
1 => unsafe { 1 => unsafe {
free((*chat).name as *mut libc::c_void); free((*chat).name as *mut libc::c_void);
(*chat).name = dc_stock_str((*chat).context, 8); (*chat).name = dc_stock_str((*chat).context, 8);
}, },
6 => unsafe { 6 => unsafe {
free((*chat).name as *mut libc::c_void); free((*chat).name as *mut libc::c_void);
let tempname: *mut libc::c_char = dc_stock_str((*chat).context, 40); let tempname: *mut libc::c_char = dc_stock_str((*chat).context, 40);
(*chat).name = dc_mprintf( (*chat).name = dc_mprintf(
b"%s (%i)\x00" as *const u8 as *const libc::c_char, b"%s (%i)\x00" as *const u8 as *const libc::c_char,
tempname, tempname,
dc_get_archived_cnt((*chat).context), dc_get_archived_cnt((*chat).context),
); );
free(tempname as *mut libc::c_void); free(tempname as *mut libc::c_void);
}, },
5 => unsafe { 5 => unsafe {
free((*chat).name as *mut libc::c_void); free((*chat).name as *mut libc::c_void);
(*chat).name = dc_stock_str((*chat).context, 41); (*chat).name = dc_stock_str((*chat).context, 41);
}, },
_ => { _ => {
if 0 != unsafe { dc_param_exists((*chat).param, 'K' as i32) } { if 0 != unsafe { dc_param_exists((*chat).param, 'K' as i32) } {
unsafe { unsafe {
free((*chat).name as *mut libc::c_void); free((*chat).name as *mut libc::c_void);
(*chat).name = dc_stock_str((*chat).context, 2); (*chat).name = dc_stock_str((*chat).context, 2);
}
} }
} }
} }
} Ok(())
Ok(()) },
}) )
.is_ok() .is_ok()
} else {
false
}
} }
pub unsafe fn dc_create_chat_by_contact_id(context: &Context, contact_id: uint32_t) -> uint32_t { pub unsafe fn dc_create_chat_by_contact_id(context: &Context, contact_id: uint32_t) -> uint32_t {
@@ -318,20 +316,15 @@ pub fn dc_lookup_real_nchat_by_contact_id(
return; return;
} }
if let Some(mut stmt) = dc_sqlite3_prepare( context.sql.query_row(
context,
&context.sql,
"SELECT c.id, c.blocked FROM chats c INNER JOIN chats_contacts j ON c.id=j.chat_id WHERE c.type=100 AND c.id>9 AND j.contact_id=?;", "SELECT c.id, c.blocked FROM chats c INNER JOIN chats_contacts j ON c.id=j.chat_id WHERE c.type=100 AND c.id>9 AND j.contact_id=?;",
) { params![contact_id as i32],
stmt.query_row( |row| {
params![contact_id as i32], unsafe { *ret_chat_id = row.get(0)? };
|row| { unsafe { *ret_chat_blocked = row.get(1)? };
unsafe { *ret_chat_id = row.get(0)? }; Ok(())
unsafe { *ret_chat_blocked = row.get(1)? }; }
Ok(()) ).unwrap();
}
).unwrap();
}
} }
pub unsafe fn dc_get_chat_id_by_contact_id(context: &Context, contact_id: uint32_t) -> uint32_t { pub unsafe fn dc_get_chat_id_by_contact_id(context: &Context, contact_id: uint32_t) -> uint32_t {
@@ -560,16 +553,13 @@ unsafe fn prepare_msg_raw(
let mut can_encrypt: libc::c_int = 1; let mut can_encrypt: libc::c_int = 1;
let mut all_mutual: libc::c_int = 1; let mut all_mutual: libc::c_int = 1;
if let Some(mut stmt) = dc_sqlite3_prepare( context.sql.query_row(
context,
&context.sql,
"SELECT ps.prefer_encrypted, c.addr \ "SELECT ps.prefer_encrypted, c.addr \
FROM chats_contacts cc \ FROM chats_contacts cc \
LEFT JOIN contacts c ON cc.contact_id=c.id \ LEFT JOIN contacts c ON cc.contact_id=c.id \
LEFT JOIN acpeerstates ps ON c.addr=ps.addr \ LEFT JOIN acpeerstates ps ON c.addr=ps.addr \
WHERE cc.chat_id=? AND cc.contact_id>9;", WHERE cc.chat_id=? AND cc.contact_id>9;",
) { params![(*chat).id], |row| {
stmt.query_row(params![(*chat).id], |row| {
let state: String = row.get(1)?; let state: String = row.get(1)?;
if let Some(prefer_encrypted) = row.get::<_, Option<i32>>(0)? { if let Some(prefer_encrypted) = row.get::<_, Option<i32>>(0)? {
@@ -593,9 +583,8 @@ unsafe fn prepare_msg_raw(
all_mutual = 0; all_mutual = 0;
} }
Ok(()) Ok(())
}) }
.unwrap(); ).unwrap();
}
if 0 != can_encrypt { if 0 != can_encrypt {
if 0 != all_mutual { if 0 != all_mutual {
@@ -765,33 +754,33 @@ unsafe fn get_parent_mime_headers(
|| parent_in_reply_to.is_null() || parent_in_reply_to.is_null()
|| parent_references.is_null()) || parent_references.is_null())
{ {
if let Some(mut stmt) = dc_sqlite3_prepare( success = (*chat)
(*chat).context, .context
&(*chat).context.sql, .sql
"SELECT rfc724_mid, mime_in_reply_to, mime_references \ .query_row(
FROM msgs WHERE timestamp=(SELECT max(timestamp) \ "SELECT rfc724_mid, mime_in_reply_to, mime_references \
FROM msgs WHERE chat_id=? AND from_id!=?);", FROM msgs WHERE timestamp=(SELECT max(timestamp) \
) { FROM msgs WHERE chat_id=? AND from_id!=?);",
success = stmt params![(*chat).id as i32, 1],
.query_row(params![(*chat).id as i32, 1], |row| { |row| {
*parent_rfc724_mid = dc_strdup(to_cstring(row.get::<_, String>(0)?).as_ptr()); *parent_rfc724_mid = dc_strdup(to_cstring(row.get::<_, String>(0)?).as_ptr());
*parent_in_reply_to = dc_strdup(to_cstring(row.get::<_, String>(1)?).as_ptr()); *parent_in_reply_to = dc_strdup(to_cstring(row.get::<_, String>(1)?).as_ptr());
*parent_references = dc_strdup(to_cstring(row.get::<_, String>(2)?).as_ptr()); *parent_references = dc_strdup(to_cstring(row.get::<_, String>(2)?).as_ptr());
Ok(()) Ok(())
}) },
.is_ok() as libc::c_int; )
} .is_ok() as libc::c_int;
if 0 == success { if 0 == success {
if let Some(mut stmt) = dc_sqlite3_prepare( success = (*chat)
(*chat).context, .context
&(*chat).context.sql, .sql
"SELECT rfc724_mid, mime_in_reply_to, mime_references \ .query_row(
FROM msgs WHERE timestamp=(SELECT min(timestamp) \ "SELECT rfc724_mid, mime_in_reply_to, mime_references \
FROM msgs WHERE chat_id=? AND from_id==?);", FROM msgs WHERE timestamp=(SELECT min(timestamp) \
) { FROM msgs WHERE chat_id=? AND from_id==?);",
success = stmt params![(*chat).id as i32, 1],
.query_row(params![(*chat).id as i32, 1], |row| { |row| {
*parent_rfc724_mid = *parent_rfc724_mid =
dc_strdup(to_cstring(row.get::<_, String>(0)?).as_ptr()); dc_strdup(to_cstring(row.get::<_, String>(0)?).as_ptr());
*parent_in_reply_to = *parent_in_reply_to =
@@ -799,9 +788,9 @@ unsafe fn get_parent_mime_headers(
*parent_references = *parent_references =
dc_strdup(to_cstring(row.get::<_, String>(2)?).as_ptr()); dc_strdup(to_cstring(row.get::<_, String>(2)?).as_ptr());
Ok(()) Ok(())
}) },
.is_ok() as libc::c_int; )
} .is_ok() as libc::c_int;
} }
} }
success success
@@ -1074,75 +1063,16 @@ pub unsafe fn dc_get_chat_msgs(
flags: uint32_t, flags: uint32_t,
marker1before: uint32_t, marker1before: uint32_t,
) -> *mut dc_array_t { ) -> *mut dc_array_t {
//clock_t start = clock(); let ret = dc_array_new(512);
let mut success: libc::c_int = 0i32; assert!(!ret.is_null());
let ret = dc_array_new(512i32 as size_t);
let mut last_day = 0; let mut last_day = 0;
let cnv_to_local = dc_gm2local_offset(); let cnv_to_local = dc_gm2local_offset();
if ret.is_null() {
return ret;
}
let process_row = |row: &rusqlite::Row| Ok((row.get::<_, i32>(0)?, row.get::<_, i64>(1)?)); let process_row = |row: &rusqlite::Row| Ok((row.get::<_, i32>(0)?, row.get::<_, i64>(1)?));
let process_rows = |rows: rusqlite::MappedRows<_>| {
let rows = if chat_id == 1 { for row in rows {
let show_emails = dc_sqlite3_get_config_int(context, &context.sql, "show_emails", 0); let (curr_id, ts) = row?;
if let Some(mut stmt) = dc_sqlite3_prepare(
context,
&context.sql,
"SELECT m.id, m.timestamp FROM msgs m \
LEFT JOIN chats ON m.chat_id=chats.id \
LEFT JOIN contacts ON m.from_id=contacts.id WHERE m.from_id!=1 \
AND m.from_id!=2 \
AND m.hidden=0 \
AND chats.blocked=2 \
AND contacts.blocked=0 \
AND m.msgrmsg>=? \
ORDER BY m.timestamp,m.id;",
) {
stmt.query_map(params![if show_emails == 2 { 0 } else { 1 }], process_row)
.and_then(|res| res.collect::<rusqlite::Result<Vec<_>>>())
} else {
dc_array_unref(ret);
return std::ptr::null_mut();
}
} else if chat_id == 5 {
if let Some(mut stmt) = dc_sqlite3_prepare(
context,
&context.sql,
"SELECT m.id, m.timestamp FROM msgs m \
LEFT JOIN contacts ct ON m.from_id=ct.id WHERE m.starred=1 \
AND m.hidden=0 \
AND ct.blocked=0 \
ORDER BY m.timestamp,m.id;",
) {
stmt.query_map(params![], process_row)
.and_then(|res| res.collect::<rusqlite::Result<Vec<_>>>())
} else {
dc_array_unref(ret);
return std::ptr::null_mut();
}
} else {
if let Some(mut stmt) = dc_sqlite3_prepare(
context,
&context.sql,
"SELECT m.id, m.timestamp FROM msgs m \
WHERE m.chat_id=? \
AND m.hidden=0 \
ORDER BY m.timestamp,m.id;",
) {
stmt.query_map(params![chat_id as i32], process_row)
.and_then(|res| res.collect::<rusqlite::Result<Vec<_>>>())
} else {
dc_array_unref(ret);
return std::ptr::null_mut();
}
};
if let Ok(rows) = rows {
for (curr_id, ts) in rows {
if curr_id as u32 == marker1before { if curr_id as u32 == marker1before {
dc_array_add_id(ret, 1); dc_array_add_id(ret, 1);
} }
@@ -1156,10 +1086,49 @@ pub unsafe fn dc_get_chat_msgs(
} }
dc_array_add_id(ret, curr_id as u32); dc_array_add_id(ret, curr_id as u32);
} }
success = 1; Ok(())
} };
if 0 != success { let success = if chat_id == 1 {
let show_emails = dc_sqlite3_get_config_int(context, &context.sql, "show_emails", 0);
context.sql.query_map(
"SELECT m.id, m.timestamp FROM msgs m \
LEFT JOIN chats ON m.chat_id=chats.id \
LEFT JOIN contacts ON m.from_id=contacts.id WHERE m.from_id!=1 \
AND m.from_id!=2 \
AND m.hidden=0 \
AND chats.blocked=2 \
AND contacts.blocked=0 \
AND m.msgrmsg>=? \
ORDER BY m.timestamp,m.id;",
params![if show_emails == 2 { 0 } else { 1 }],
process_row,
process_rows,
)
} else if chat_id == 5 {
context.sql.query_map(
"SELECT m.id, m.timestamp FROM msgs m \
LEFT JOIN contacts ct ON m.from_id=ct.id WHERE m.starred=1 \
AND m.hidden=0 \
AND ct.blocked=0 \
ORDER BY m.timestamp,m.id;",
params![],
process_row,
process_rows,
)
} else {
context.sql.query_map(
"SELECT m.id, m.timestamp FROM msgs m \
WHERE m.chat_id=? \
AND m.hidden=0 \
ORDER BY m.timestamp,m.id;",
params![chat_id as i32],
process_row,
process_rows,
)
};
if success.is_ok() {
ret ret
} else { } else {
if !ret.is_null() { if !ret.is_null() {
@@ -1249,42 +1218,30 @@ pub fn dc_get_chat_media(
msg_type2: libc::c_int, msg_type2: libc::c_int,
msg_type3: libc::c_int, msg_type3: libc::c_int,
) -> *mut dc_array_t { ) -> *mut dc_array_t {
let ret = unsafe { dc_array_new(100) }; context.sql.query_map(
"SELECT id FROM msgs WHERE chat_id=? AND (type=? OR type=? OR type=?) ORDER BY timestamp, id;",
if let Some(mut stmt) = dc_sqlite3_prepare( params![
context, chat_id as i32,
&context.sql, msg_type,
"SELECT id FROM msgs WHERE chat_id=? AND (type=? OR type=? OR type=?) ORDER BY timestamp, id;" if msg_type2 > 0 {
) { msg_type2
let rows = stmt.query_map( } else {
params![ msg_type
chat_id as i32, }, if msg_type3 > 0 {
msg_type, msg_type3
if msg_type2 > 0 { } else {
msg_type2 msg_type
} else { },
msg_type ],
}, if msg_type3 > 0 { |row| row.get::<_, i32>(0),
msg_type3 |ids| {
} else { let ret = unsafe { dc_array_new(100) };
msg_type
},
],
|row| row.get::<_, i32>(0)
);
if let Ok(ids) = rows {
for id in ids { for id in ids {
if let Ok(id) = id { unsafe { dc_array_add_id(ret, id? as u32) };
unsafe { dc_array_add_id(ret, id as u32) };
}
} }
return ret; Ok(ret)
} }
} ).unwrap_or_else(|_| std::ptr::null_mut())
unsafe { dc_array_unref(ret) };
std::ptr::null_mut()
} }
pub unsafe fn dc_get_next_media( pub unsafe fn dc_get_next_media(
@@ -1425,31 +1382,28 @@ pub fn dc_get_chat_contacts(context: &Context, chat_id: u32) -> *mut dc_array_t
return std::ptr::null_mut(); return std::ptr::null_mut();
} }
let ret = unsafe { dc_array_new(100) };
// we could also create a list for all contacts in the deaddrop by searching contacts belonging to chats with // we could also create a list for all contacts in the deaddrop by searching contacts belonging to chats with
// chats.blocked=2, however, currently this is not needed // chats.blocked=2, however, currently this is not needed
if let Some(mut stmt) = dc_sqlite3_prepare( context
context, .sql
&context.sql, .query_map(
"SELECT cc.contact_id FROM chats_contacts cc \ "SELECT cc.contact_id FROM chats_contacts cc \
LEFT JOIN contacts c ON c.id=cc.contact_id WHERE cc.chat_id=? \ LEFT JOIN contacts c ON c.id=cc.contact_id WHERE cc.chat_id=? \
ORDER BY c.id=1, LOWER(c.name||c.addr), c.id;", ORDER BY c.id=1, LOWER(c.name||c.addr), c.id;",
) { params![chat_id as i32],
let rows = stmt.query_map(params![chat_id as i32], |row| row.get::<_, i32>(0)); |row| row.get::<_, i32>(0),
if let Ok(ids) = rows { |ids| {
for id in ids { let ret = unsafe { dc_array_new(100) };
if let Ok(id) = id {
unsafe { dc_array_add_id(ret, id as u32) }; for id in ids {
unsafe { dc_array_add_id(ret, id? as u32) };
} }
}
return ret; Ok(ret)
} },
} )
.unwrap_or_else(|_| std::ptr::null_mut())
unsafe { dc_array_unref(ret) }
std::ptr::null_mut()
} }
pub unsafe fn dc_get_chat(context: &Context, chat_id: uint32_t) -> *mut Chat { pub unsafe fn dc_get_chat(context: &Context, chat_id: uint32_t) -> *mut Chat {
@@ -1962,9 +1916,9 @@ pub unsafe fn dc_forward_msgs(
let msg = dc_msg_new_untyped(context); let msg = dc_msg_new_untyped(context);
let chat = dc_chat_new(context); let chat = dc_chat_new(context);
let contact: *mut dc_contact_t = dc_contact_new(context); let contact = dc_contact_new(context);
let created_db_entries: *mut carray = carray_new(16i32 as libc::c_uint); let created_db_entries = carray_new(16);
let mut idsstr: *mut libc::c_char = 0 as *mut libc::c_char; let mut idsstr = 0 as *mut libc::c_char;
let mut curr_timestamp: i64; let mut curr_timestamp: i64;
let original_param: *mut dc_param_t = dc_param_new(); let original_param: *mut dc_param_t = dc_param_new();
@@ -1973,16 +1927,15 @@ pub unsafe fn dc_forward_msgs(
curr_timestamp = dc_create_smeared_timestamps(context, msg_cnt); curr_timestamp = dc_create_smeared_timestamps(context, msg_cnt);
idsstr = dc_arr_to_string(msg_ids, msg_cnt); idsstr = dc_arr_to_string(msg_ids, msg_cnt);
if let Some(mut stmt) = dc_sqlite3_prepare( context
context, .sql
&context.sql, .query_map(
"SELECT id FROM msgs WHERE id IN(?) ORDER BY timestamp,id", "SELECT id FROM msgs WHERE id IN(?) ORDER BY timestamp,id",
) { params![as_str(idsstr)],
let rows = stmt.query_map(params![as_str(idsstr)], |row| row.get::<_, i32>(0)); |row| row.get::<_, i32>(0),
|ids| {
if let Ok(ids) = rows { for id in ids {
for id in ids { let src_msg_id = id?;
if let Ok(src_msg_id) = id {
if !dc_msg_load_from_db(msg, context, src_msg_id as u32) { if !dc_msg_load_from_db(msg, context, src_msg_id as u32) {
break; break;
} }
@@ -2034,9 +1987,10 @@ pub unsafe fn dc_forward_msgs(
0 as *mut libc::c_uint, 0 as *mut libc::c_uint,
); );
} }
} Ok(())
} },
} )
.unwrap(); // TODO: better error handling
} }
if !created_db_entries.is_null() { if !created_db_entries.is_null() {
@@ -2241,26 +2195,24 @@ pub unsafe fn dc_get_chat_id_by_grpid(
*ret_verified = 0; *ret_verified = 0;
} }
dc_sqlite3_prepare( context
context, .sql
&context.sql, .query_row(
"SELECT id, blocked, type FROM chats WHERE grpid=?;", "SELECT id, blocked, type FROM chats WHERE grpid=?;",
) params![as_str(grpid)],
.and_then(|mut stmt| { |row| {
stmt.query_row(params![as_str(grpid)], |row| { let chat_id = row.get(0)?;
let chat_id = row.get(0)?; if !ret_blocked.is_null() {
if !ret_blocked.is_null() { *ret_blocked = row.get(1)?;
*ret_blocked = row.get(1)?; }
} if !ret_verified.is_null() {
if !ret_verified.is_null() { let v: i32 = row.get(2)?;
let v: i32 = row.get(2)?; *ret_verified = (v == 130) as libc::c_int;
*ret_verified = (v == 130) as libc::c_int; }
} Ok(chat_id)
Ok(chat_id) },
}) )
.ok() .unwrap_or_default()
})
.unwrap_or_default()
} }
pub fn dc_add_device_msg(context: &Context, chat_id: uint32_t, text: *const libc::c_char) { pub fn dc_add_device_msg(context: &Context, chat_id: uint32_t, text: *const libc::c_char) {
@@ -2274,9 +2226,7 @@ pub fn dc_add_device_msg(context: &Context, chat_id: uint32_t, text: *const libc
) )
}; };
if !dc_sqlite3_execute( if context.sql.execute(
context,
&context.sql,
"INSERT INTO msgs (chat_id,from_id,to_id, timestamp,type,state, txt,rfc724_mid) VALUES (?,?,?, ?,?,?, ?,?);", "INSERT INTO msgs (chat_id,from_id,to_id, timestamp,type,state, txt,rfc724_mid) VALUES (?,?,?, ?,?,?, ?,?);",
params![ params![
chat_id as i32, chat_id as i32,
@@ -2288,7 +2238,8 @@ pub fn dc_add_device_msg(context: &Context, chat_id: uint32_t, text: *const libc
as_str(text), as_str(text),
as_str(rfc724_mid), as_str(rfc724_mid),
] ]
) { ).is_err() {
unsafe { free(rfc724_mid as *mut libc::c_void) };
return; return;
} }

View File

@@ -604,27 +604,23 @@ pub fn dc_get_blocked_cnt(context: &Context) -> libc::c_int {
} }
pub fn dc_get_blocked_contacts(context: &Context) -> *mut dc_array_t { pub fn dc_get_blocked_contacts(context: &Context) -> *mut dc_array_t {
let ret = unsafe { dc_array_new(100) }; context
.sql
.query_map(
"SELECT id FROM contacts WHERE id>? AND blocked!=0 ORDER BY LOWER(name||addr),id;",
params![9],
|row| row.get::<_, i32>(0),
|ids| {
let ret = unsafe { dc_array_new(100) };
if let Some(mut stmt) = dc_sqlite3_prepare( for id in ids {
context, unsafe { dc_array_add_id(ret, id? as u32) };
&context.sql,
"SELECT id FROM contacts WHERE id>? AND blocked!=0 ORDER BY LOWER(name||addr),id;",
) {
let rows = stmt.query_map(params![9], |row| row.get::<_, i32>(0));
if let Ok(ids) = rows {
for id in ids {
if let Ok(id) = id {
unsafe { dc_array_add_id(ret, id as u32) };
} }
}
return ret; Ok(ret)
} },
} )
.unwrap_or_else(|_| std::ptr::null_mut())
unsafe { dc_array_unref(ret) };
std::ptr::null_mut()
} }
pub unsafe fn dc_get_contact_encrinfo( pub unsafe fn dc_get_contact_encrinfo(
@@ -1057,18 +1053,23 @@ pub fn dc_real_contact_exists(context: &Context, contact_id: u32) -> bool {
return false; return false;
} }
dc_sqlite3_prepare(context, &context.sql, "SELECT id FROM contacts WHERE id=?;") context
.map(|mut stmt| stmt.exists(params![contact_id as i32]).unwrap_or_default()) .sql
.exists(
"SELECT id FROM contacts WHERE id=?;",
params![contact_id as i32],
)
.unwrap_or_default() .unwrap_or_default()
} }
pub fn dc_scaleup_contact_origin(context: &Context, contact_id: u32, origin: libc::c_int) -> bool { pub fn dc_scaleup_contact_origin(context: &Context, contact_id: u32, origin: libc::c_int) -> bool {
dc_sqlite3_execute( context
context, .sql
&context.sql, .execute(
"UPDATE contacts SET origin=? WHERE id=? AND origin<?;", "UPDATE contacts SET origin=? WHERE id=? AND origin<?;",
params![origin, contact_id as i32, origin], params![origin, contact_id as i32, origin],
) )
.is_ok()
} }
#[cfg(test)] #[cfg(test)]

View File

@@ -4,7 +4,6 @@ use crate::context::Context;
use crate::dc_configure::*; use crate::dc_configure::*;
use crate::dc_sqlite3::*; use crate::dc_sqlite3::*;
use crate::imap::Imap; use crate::imap::Imap;
use crate::types::*;
use crate::x::*; use crate::x::*;
#[repr(C)] #[repr(C)]

View File

@@ -118,20 +118,13 @@ unsafe fn schedule_MAYBE_SEND_LOCATIONS(context: &Context, flags: libc::c_int) {
} }
pub fn dc_is_sending_locations_to_chat(context: &Context, chat_id: u32) -> bool { pub fn dc_is_sending_locations_to_chat(context: &Context, chat_id: u32) -> bool {
dc_sqlite3_prepare( context
context, .sql
&context.sql, .exists(
"SELECT id FROM chats WHERE (? OR id=?) AND locations_send_until>?;", "SELECT id FROM chats WHERE (? OR id=?) AND locations_send_until>?;",
) params![if chat_id == 0 { 1 } else { 0 }, chat_id as i32, time()],
.and_then(|mut stmt| { )
stmt.exists(params![ .unwrap_or_default()
if chat_id == 0 { 1 } else { 0 },
chat_id as i32,
time()
])
.ok()
})
.unwrap_or_default()
} }
pub fn dc_set_location( pub fn dc_set_location(
@@ -144,43 +137,35 @@ pub fn dc_set_location(
return 1; return 1;
} }
let mut continue_streaming = false; context.sql.query_map(
let rows = if let Some(mut stmt) = dc_sqlite3_prepare(
context,
&context.sql,
"SELECT id FROM chats WHERE locations_send_until>?;", "SELECT id FROM chats WHERE locations_send_until>?;",
) { params![time()], |row| row.get::<_, i32>(0),
stmt.query_map(params![time()], |row| row.get::<_, i32>(0)) |chats| {
.and_then(|res| res.collect::<rusqlite::Result<Vec<_>>>()) let mut continue_streaming = false;
.ok()
} else {
None
};
if let Some(chats) = rows { for chat in chats {
for chat_id in chats { let chat_id = chat?;
dc_sqlite3_execute( context.sql.execute(
context, "INSERT INTO locations \
&context.sql, (latitude, longitude, accuracy, timestamp, chat_id, from_id) VALUES (?,?,?,?,?,?);",
"INSERT INTO locations (latitude, longitude, accuracy, timestamp, chat_id, from_id) VALUES (?,?,?,?,?,?);", params![
params![ latitude,
latitude, longitude,
longitude, accuracy,
accuracy, time(),
time(), chat_id,
chat_id, 1,
1, ]
] )?;
); continue_streaming = true;
continue_streaming = true; }
if continue_streaming {
context.call_cb(Event::LOCATION_CHANGED, 1, 0);
};
unsafe { schedule_MAYBE_SEND_LOCATIONS(context, 0) };
Ok(continue_streaming as libc::c_int)
} }
if continue_streaming { ).unwrap_or_default()
context.call_cb(Event::LOCATION_CHANGED, 1, 0);
};
unsafe { schedule_MAYBE_SEND_LOCATIONS(context, 0) };
}
continue_streaming as libc::c_int
} }
pub fn dc_get_locations( pub fn dc_get_locations(
@@ -194,19 +179,15 @@ pub fn dc_get_locations(
timestamp_to = time() + 10; timestamp_to = time() + 10;
} }
let ret = unsafe { dc_array_new_typed(1, 500) }; context
.sql
let locations = if let Some(mut stmt) = dc_sqlite3_prepare( .query_map(
context, "SELECT l.id, l.latitude, l.longitude, l.accuracy, l.timestamp, l.independent, \
&context.sql, m.id, l.from_id, l.chat_id, m.txt \
"SELECT l.id, l.latitude, l.longitude, l.accuracy, l.timestamp, l.independent, \ FROM locations l LEFT JOIN msgs m ON l.id=m.location_id WHERE (? OR l.chat_id=?) \
m.id, l.from_id, l.chat_id, m.txt \ AND (? OR l.from_id=?) \
FROM locations l LEFT JOIN msgs m ON l.id=m.location_id WHERE (? OR l.chat_id=?) \ AND (l.independent=1 OR (l.timestamp>=? AND l.timestamp<=?)) \
AND (? OR l.from_id=?) \ ORDER BY l.timestamp DESC, l.id DESC, m.id DESC;",
AND (l.independent=1 OR (l.timestamp>=? AND l.timestamp<=?)) \
ORDER BY l.timestamp DESC, l.id DESC, m.id DESC;",
) {
stmt.query_map(
params![ params![
if chat_id == 0 { 1 } else { 0 }, if chat_id == 0 { 1 } else { 0 },
chat_id as i32, chat_id as i32,
@@ -239,22 +220,16 @@ pub fn dc_get_locations(
} }
Ok(loc) Ok(loc)
}, },
) |locations| {
.and_then(|res| res.collect::<rusqlite::Result<Vec<_>>>()) let ret = unsafe { dc_array_new_typed(1, 500) };
.ok()
} else {
None
};
if let Some(locations) = locations { for location in locations {
for location in locations { unsafe { dc_array_add_ptr(ret, location? as *mut libc::c_void) };
unsafe { dc_array_add_ptr(ret, location as *mut libc::c_void) }; }
} Ok(ret)
ret },
} else { )
unsafe { dc_array_unref(ret) } .unwrap_or_else(|_| std::ptr::null_mut())
std::ptr::null_mut()
}
} }
// TODO should be bool /rtn // TODO should be bool /rtn
@@ -295,29 +270,23 @@ pub fn dc_get_location_kml(
let self_addr = self_addr.unwrap(); let self_addr = self_addr.unwrap();
if let Some((locations_send_begin, locations_send_until, locations_last_sent)) = dc_sqlite3_prepare( if let Ok((locations_send_begin, locations_send_until, locations_last_sent)) = context.sql.query_row(
context,
&context.sql,
"SELECT locations_send_begin, locations_send_until, locations_last_sent FROM chats WHERE id=?;", "SELECT locations_send_begin, locations_send_until, locations_last_sent FROM chats WHERE id=?;",
params![chat_id as i32], |row| {
).and_then(|mut stmt| {
stmt.query_row(params![chat_id as i32], |row| {
let send_begin: i64 = row.get(0)?; let send_begin: i64 = row.get(0)?;
let send_until: i64 = row.get(1)?; let send_until: i64 = row.get(1)?;
let last_sent: i64 = row.get(2)?; let last_sent: i64 = row.get(2)?;
Ok((send_begin, send_until, last_sent)) Ok((send_begin, send_until, last_sent))
}).ok() }
}) { ) {
if !(locations_send_begin == 0 || now > locations_send_until) { if !(locations_send_begin == 0 || now > locations_send_until) {
ret += &format!( ret += &format!(
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n<Document addr=\"{}\">\n", "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n<Document addr=\"{}\">\n",
self_addr, self_addr,
); );
let rows = if let Some(mut stmt) = dc_sqlite3_prepare( context.sql.query_map(
context,
&context.sql,
"SELECT id, latitude, longitude, accuracy, timestamp\ "SELECT id, latitude, longitude, accuracy, timestamp\
FROM locations WHERE from_id=? \ FROM locations WHERE from_id=? \
AND timestamp>=? \ AND timestamp>=? \
@@ -325,38 +294,35 @@ pub fn dc_get_location_kml(
AND independent=0 \ AND independent=0 \
GROUP BY timestamp \ GROUP BY timestamp \
ORDER BY timestamp;", ORDER BY timestamp;",
){ params![1, locations_send_begin, locations_last_sent, 1],
stmt.query_map( |row| {
params![1, locations_send_begin, locations_last_sent, 1], let location_id: i32 = row.get(0)?;
|row| { let latitude: f64 = row.get(1)?;
let location_id: i32 = row.get(0)?; let longitude: f64 = row.get(2)?;
let latitude: f64 = row.get(1)?; let accuracy: f64 = row.get(3)?;
let longitude: f64 = row.get(2)?; let timestamp = unsafe { get_kml_timestamp(row.get(4)?) };
let accuracy: f64 = row.get(3)?;
let timestamp = unsafe { get_kml_timestamp(row.get(4)?) };
Ok((location_id, latitude, longitude, accuracy, timestamp)) Ok((location_id, latitude, longitude, accuracy, timestamp))
}).and_then(|res| res.collect::<rusqlite::Result<Vec<_>>>()).ok() },
} else { |rows| {
None for row in rows {
}; let (location_id, latitude, longitude, accuracy, timestamp) = row?;
ret += &format!(
if let Some(rows) = rows { "<Placemark><Timestamp><when>{}</when></Timestamp><Point><coordinates accuracy=\"{}\">{},{}</coordinates></Point></Placemark>\n\x00",
for (location_id, latitude, longitude, accuracy, timestamp) in rows { as_str(timestamp),
ret += &format!( accuracy,
"<Placemark><Timestamp><when>{}</when></Timestamp><Point><coordinates accuracy=\"{}\">{},{}</coordinates></Point></Placemark>\n\x00", longitude,
as_str(timestamp), latitude
accuracy, );
longitude, location_count += 1;
latitude if !last_added_location_id.is_null() {
); unsafe { *last_added_location_id = location_id as u32 };
location_count += 1; }
if !last_added_location_id.is_null() { unsafe { free(timestamp as *mut libc::c_void) };
unsafe { *last_added_location_id = location_id as u32 };
} }
unsafe { free(timestamp as *mut libc::c_void) }; Ok(())
} }
} ).unwrap(); // TODO: better error handling
} }
} }
@@ -690,74 +656,78 @@ pub unsafe fn dc_job_do_DC_JOB_MAYBE_SEND_LOCATIONS(context: &Context, _job: *mu
as *const libc::c_char, as *const libc::c_char,
); );
if let Some(mut stmt) = dc_sqlite3_prepare( context
context, .sql
&context.sql, .query_map(
"SELECT id, locations_send_begin, locations_last_sent \ "SELECT id, locations_send_begin, locations_last_sent \
FROM chats \ FROM chats \
WHERE locations_send_until>?;", WHERE locations_send_until>?;",
) { params![now],
if let Ok(rows) = stmt.query_map(params![now], |row| { |row| {
let chat_id: i32 = row.get(0)?; let chat_id: i32 = row.get(0)?;
let locations_send_begin: i64 = row.get(1)?; let locations_send_begin: i64 = row.get(1)?;
let locations_last_sent: i64 = row.get(2)?; let locations_last_sent: i64 = row.get(2)?;
continue_streaming = 1; continue_streaming = 1;
// be a bit tolerant as the timer may not align exactly with time(NULL) // be a bit tolerant as the timer may not align exactly with time(NULL)
if now - locations_last_sent < (60 - 3) { if now - locations_last_sent < (60 - 3) {
Ok(None) Ok(None)
} else { } else {
Ok(Some((chat_id, locations_send_begin, locations_last_sent))) Ok(Some((chat_id, locations_send_begin, locations_last_sent)))
}
}) {
let stmt_locations = dc_sqlite3_prepare(
context,
&context.sql,
"SELECT id \
FROM locations \
WHERE from_id=? \
AND timestamp>=? \
AND timestamp>? \
AND independent=0 \
ORDER BY timestamp;",
);
if stmt_locations.is_none() {
// TODO: handle error
return;
}
let mut stmt_locations = stmt_locations.unwrap();
for (chat_id, locations_send_begin, locations_last_sent) in rows.filter_map(|r| match r
{
Ok(Some(v)) => Some(v),
_ => None,
}) {
// TODO: do I need to reset?
if !stmt_locations
.exists(params![1, locations_send_begin, locations_last_sent,])
.unwrap_or_default()
{
// if there is no new location, there's nothing to send.
// however, maybe we want to bypass this test eg. 15 minutes
continue;
} }
// pending locations are attached automatically to every message, },
// so also to this empty text message. |rows| {
// DC_CMD_LOCATION is only needed to create a nicer subject. let stmt_locations = dc_sqlite3_prepare(
// context,
// for optimisation and to avoid flooding the sending queue, &context.sql,
// we could sending these messages only if we're really online. "SELECT id \
// the easiest way to determine this, is to check for an empty message queue. FROM locations \
// (might not be 100%, however, as positions are sent combined later WHERE from_id=? \
// and dc_set_location() is typically called periodically, this is ok) AND timestamp>=? \
let mut msg = dc_msg_new(context, 10); AND timestamp>? \
(*msg).hidden = 1; AND independent=0 \
dc_param_set_int((*msg).param, 'S' as i32, 9); ORDER BY timestamp;",
dc_send_msg(context, chat_id as u32, msg); );
dc_msg_unref(msg); if stmt_locations.is_none() {
} // TODO: handle error
} return Ok(());
} }
let mut stmt_locations = stmt_locations.unwrap();
for (chat_id, locations_send_begin, locations_last_sent) in
rows.filter_map(|r| match r {
Ok(Some(v)) => Some(v),
_ => None,
})
{
// TODO: do I need to reset?
if !stmt_locations
.exists(params![1, locations_send_begin, locations_last_sent,])
.unwrap_or_default()
{
// if there is no new location, there's nothing to send.
// however, maybe we want to bypass this test eg. 15 minutes
continue;
}
// pending locations are attached automatically to every message,
// so also to this empty text message.
// DC_CMD_LOCATION is only needed to create a nicer subject.
//
// for optimisation and to avoid flooding the sending queue,
// we could sending these messages only if we're really online.
// the easiest way to determine this, is to check for an empty message queue.
// (might not be 100%, however, as positions are sent combined later
// and dc_set_location() is typically called periodically, this is ok)
let mut msg = dc_msg_new(context, 10);
(*msg).hidden = 1;
dc_param_set_int((*msg).param, 'S' as i32, 9);
dc_send_msg(context, chat_id as u32, msg);
dc_msg_unref(msg);
}
Ok(())
},
)
.unwrap(); // TODO: Better error handling
if 0 != continue_streaming { if 0 != continue_streaming {
schedule_MAYBE_SEND_LOCATIONS(context, 0x1); schedule_MAYBE_SEND_LOCATIONS(context, 0x1);
@@ -772,29 +742,21 @@ pub unsafe fn dc_job_do_DC_JOB_MAYBE_SEND_LOC_ENDED(context: &Context, job: &mut
let chat_id = (*job).foreign_id; let chat_id = (*job).foreign_id;
let mut stock_str = 0 as *mut libc::c_char; let mut stock_str = 0 as *mut libc::c_char;
if let Some((send_begin, send_until)) = dc_sqlite3_prepare( if let Ok((send_begin, send_until)) = context.sql.query_row(
context,
&context.sql,
"SELECT locations_send_begin, locations_send_until FROM chats WHERE id=?", "SELECT locations_send_begin, locations_send_until FROM chats WHERE id=?",
) params![chat_id as i32],
.and_then(|mut stmt| { |row| Ok((row.get::<_, i64>(0)?, row.get::<_, i64>(1)?)),
stmt.query_row(params![chat_id as i32], |row| { ) {
Ok((row.get::<_, i64>(0)?, row.get::<_, i64>(1)?))
})
.ok()
}) {
if !(send_begin != 0 && time() <= send_until) { if !(send_begin != 0 && time() <= send_until) {
// still streaming - // still streaming -
// may happen as several calls to dc_send_locations_to_chat() // may happen as several calls to dc_send_locations_to_chat()
// do not un-schedule pending DC_MAYBE_SEND_LOC_ENDED jobs // do not un-schedule pending DC_MAYBE_SEND_LOC_ENDED jobs
if !(send_begin == 0 && send_until == 0) { if !(send_begin == 0 && send_until == 0) {
// not streaming, device-message already sent // not streaming, device-message already sent
if dc_sqlite3_execute( if context.sql.execute(
context,
&context.sql,
"UPDATE chats SET locations_send_begin=0, locations_send_until=0 WHERE id=?", "UPDATE chats SET locations_send_begin=0, locations_send_until=0 WHERE id=?",
params![chat_id as i32], params![chat_id as i32],
) { ).is_ok() {
stock_str = dc_stock_system_msg( stock_str = dc_stock_system_msg(
context, context,
65, 65,

View File

@@ -1492,16 +1492,16 @@ unsafe fn create_or_lookup_adhoc_group(
chat_ids = search_chat_ids_by_contact_ids(context, member_ids); chat_ids = search_chat_ids_by_contact_ids(context, member_ids);
if dc_array_get_cnt(chat_ids) > 0 { if dc_array_get_cnt(chat_ids) > 0 {
chat_ids_str = dc_array_get_string(chat_ids, b",\x00" as *const u8 as *const _); chat_ids_str = dc_array_get_string(chat_ids, b",\x00" as *const u8 as *const _);
let res = dc_sqlite3_prepare( let res = context.sql.query_row(
context,
&context.sql,
"SELECT c.id, c.blocked FROM chats c \ "SELECT c.id, c.blocked FROM chats c \
LEFT JOIN msgs m ON m.chat_id=c.id WHERE c.id IN(?) ORDER BY m.timestamp DESC, m.id DESC LIMIT 1;", LEFT JOIN msgs m ON m.chat_id=c.id WHERE c.id IN(?) ORDER BY m.timestamp DESC, m.id DESC LIMIT 1;",
).and_then(|mut stmt| stmt.query_row(params![as_str(chat_ids_str)], |row| { params![as_str(chat_ids_str)],
Ok((row.get::<_, i32>(0)?, row.get::<_, i32>(1)?)) |row| {
}).ok()); Ok((row.get::<_, i32>(0)?, row.get::<_, i32>(1)?))
}
);
if let Some((id, id_blocked)) = res { if let Ok((id, id_blocked)) = res {
chat_id = id as u32; chat_id = id as u32;
chat_id_blocked = id_blocked; chat_id_blocked = id_blocked;
/* success, chat found */ /* success, chat found */
@@ -1607,32 +1607,26 @@ unsafe fn create_adhoc_grp_id(context: &Context, member_ids: *mut dc_array_t) ->
.unwrap() .unwrap()
.to_lowercase(); .to_lowercase();
let rows = if let Some(mut stmt) = dc_sqlite3_prepare( let members = context
context, .sql
&context.sql, .query_map(
"SELECT addr FROM contacts WHERE id IN(?) AND id!=1", "SELECT addr FROM contacts WHERE id IN(?) AND id!=1",
) { params![as_str(member_ids_str)],
stmt.query_map(params![as_str(member_ids_str)], |row| { |row| row.get::<_, String>(0),
row.get::<_, String>(0) |rows| {
}) let mut addrs = rows.collect::<Result<Vec<_>, _>>()?;
.and_then(|res| res.collect::<rusqlite::Result<Vec<_>>>()) addrs.sort();
.ok() let mut acc = member_cs.clone();
} else { for addr in &addrs {
None acc += ",";
}; acc += &addr.to_lowercase();
}
Ok(acc)
},
)
.unwrap_or_else(|_| member_cs);
free(member_ids_str as *mut libc::c_void); free(member_ids_str as *mut libc::c_void);
let members = rows
.map(|mut addrs| {
addrs.sort();
addrs.iter().fold(member_cs.clone(), |mut acc, addr| {
acc += ",";
acc += &addr.to_lowercase();
acc
})
})
.unwrap_or_else(|| member_cs);
hex_hash(&members) as *mut _ hex_hash(&members) as *mut _
} }
@@ -1673,47 +1667,40 @@ unsafe fn search_chat_ids_by_contact_ids(
contact_ids_str = contact_ids_str =
dc_array_get_string(contact_ids, b",\x00" as *const u8 as *const libc::c_char); dc_array_get_string(contact_ids, b",\x00" as *const u8 as *const libc::c_char);
let rows = if let Some(mut stmt) = dc_sqlite3_prepare( context.sql.query_map(
context,
&context.sql,
"SELECT DISTINCT cc.chat_id, cc.contact_id FROM chats_contacts cc LEFT JOIN chats c ON c.id=cc.chat_id WHERE cc.chat_id IN(SELECT chat_id FROM chats_contacts WHERE contact_id IN(?)) AND c.type=120 AND cc.contact_id!=1 ORDER BY cc.chat_id, cc.contact_id;", "SELECT DISTINCT cc.chat_id, cc.contact_id FROM chats_contacts cc LEFT JOIN chats c ON c.id=cc.chat_id WHERE cc.chat_id IN(SELECT chat_id FROM chats_contacts WHERE contact_id IN(?)) AND c.type=120 AND cc.contact_id!=1 ORDER BY cc.chat_id, cc.contact_id;",
) { params![as_str(contact_ids_str)],
stmt.query_map( |row| Ok((row.get::<_, i32>(0)?, row.get::<_, i32>(1)?)),
params![as_str(contact_ids_str)], |rows| {
|row| Ok((row.get::<_, i32>(0)?, row.get::<_, i32>(1)?)) let mut last_chat_id = 0;
).and_then(|res| res.collect::<rusqlite::Result<Vec<_>>>()).ok() let mut matches = 0;
} else { let mut mismatches = 0;
None
};
if let Some(rows) = rows { for row in rows {
let mut last_chat_id = 0; let (chat_id, contact_id) = row?;
let mut matches = 0; if chat_id as u32 != last_chat_id {
let mut mismatches = 0; if matches == dc_array_get_cnt(contact_ids) && mismatches == 0 {
dc_array_add_id(chat_ids, last_chat_id);
for (chat_id, contact_id) in rows { }
if chat_id as u32 != last_chat_id { last_chat_id = chat_id as u32;
if matches == dc_array_get_cnt(contact_ids) && mismatches == 0 { matches = 0;
dc_array_add_id(chat_ids, last_chat_id); mismatches = 0;
}
if contact_id as u32 == dc_array_get_id(contact_ids, matches as size_t) {
matches += 1;
} else {
mismatches += 1;
} }
last_chat_id = chat_id as u32;
matches = 0;
mismatches = 0;
} }
if contact_id as u32 == dc_array_get_id(contact_ids, matches as size_t) {
matches += 1;
} else {
mismatches += 1;
}
}
if matches == dc_array_get_cnt(contact_ids) && mismatches == 0 { if matches == dc_array_get_cnt(contact_ids) && mismatches == 0 {
dc_array_add_id(chat_ids, last_chat_id); dc_array_add_id(chat_ids, last_chat_id);
}
Ok(())
} }
} ).unwrap(); // TODO: better error handling
} }
} }
free(contact_ids_str as *mut libc::c_void); free(contact_ids_str as *mut libc::c_void);
dc_array_unref(contact_ids); dc_array_unref(contact_ids);
@@ -1727,10 +1714,9 @@ unsafe fn check_verified_properties(
to_ids: *const dc_array_t, to_ids: *const dc_array_t,
failure_reason: *mut *mut libc::c_char, failure_reason: *mut *mut libc::c_char,
) -> libc::c_int { ) -> libc::c_int {
let mut everythings_okay: libc::c_int = 0; let contact = dc_contact_new(context);
let contact: *mut dc_contact_t = dc_contact_new(context);
let verify_fail = |reason| { let verify_fail = |reason: String| {
*failure_reason = *failure_reason =
strdup(to_cstring(format!("{}. See \"Info\" for details.", reason)).as_ptr()); strdup(to_cstring(format!("{}. See \"Info\" for details.", reason)).as_ptr());
warn!(context, 0, "{}", reason); warn!(context, 0, "{}", reason);
@@ -1741,13 +1727,13 @@ unsafe fn check_verified_properties(
}; };
if !dc_contact_load_from_db(contact, &context.sql, from_id) { if !dc_contact_load_from_db(contact, &context.sql, from_id) {
verify_fail("Internal Error; cannot load contact"); verify_fail("Internal Error; cannot load contact".into());
cleanup(); cleanup();
return 0; return 0;
} }
if 0 == mimeparser.e2ee_helper.encrypted { if 0 == mimeparser.e2ee_helper.encrypted {
verify_fail("This message is not encrypted"); verify_fail("This message is not encrypted".into());
cleanup(); cleanup();
return 0; return 0;
} }
@@ -1760,14 +1746,14 @@ unsafe fn check_verified_properties(
let peerstate = Peerstate::from_addr(context, &context.sql, as_str((*contact).addr)); let peerstate = Peerstate::from_addr(context, &context.sql, as_str((*contact).addr));
if peerstate.is_none() || dc_contact_is_verified_ex(contact, peerstate.as_ref()) != 2 { if peerstate.is_none() || dc_contact_is_verified_ex(contact, peerstate.as_ref()) != 2 {
verify_fail("The sender of this message is not verified."); verify_fail("The sender of this message is not verified.".into());
cleanup(); cleanup();
return 0; return 0;
} }
if let Some(peerstate) = peerstate { if let Some(peerstate) = peerstate {
if !peerstate.has_verified_key(&mimeparser.e2ee_helper.signatures) { if !peerstate.has_verified_key(&mimeparser.e2ee_helper.signatures) {
verify_fail("The message was sent with non-verified encryption."); verify_fail("The message was sent with non-verified encryption.".into());
cleanup(); cleanup();
return 0; return 0;
} }
@@ -1778,65 +1764,65 @@ unsafe fn check_verified_properties(
let to_ids_str = to_string(to_ids_str_c); let to_ids_str = to_string(to_ids_str_c);
free(to_ids_str_c as *mut libc::c_void); free(to_ids_str_c as *mut libc::c_void);
let rows = if let Some(mut stmt) = dc_sqlite3_prepare( let ok = context
context, .sql
&context.sql, .query_map(
"SELECT c.addr, LENGTH(ps.verified_key_fingerprint) FROM contacts c \ "SELECT c.addr, LENGTH(ps.verified_key_fingerprint) FROM contacts c \
LEFT JOIN acpeerstates ps ON c.addr=ps.addr WHERE c.id IN(?) ", LEFT JOIN acpeerstates ps ON c.addr=ps.addr WHERE c.id IN(?) ",
) { params![&to_ids_str],
stmt.query_map(params![&to_ids_str], |row| { |row| Ok((row.get::<_, String>(0)?, row.get::<_, i32>(1)?)),
Ok((row.get::<_, String>(0)?, row.get::<_, i32>(1)?)) |rows| {
}) for row in rows {
.and_then(|res| res.collect::<rusqlite::Result<Vec<_>>>()) let (to_addr, mut is_verified) = row?;
.ok() let mut peerstate = Peerstate::from_addr(context, &context.sql, &to_addr);
} else { if mimeparser.e2ee_helper.gossipped_addr.contains(&to_addr)
None && peerstate.is_some()
}; {
let peerstate = peerstate.as_mut().unwrap();
if let Some(rows) = rows { // if we're here, we know the gossip key is verified:
for (to_addr, mut is_verified) in rows { // - use the gossip-key as verified-key if there is no verified-key
let mut peerstate = Peerstate::from_addr(context, &context.sql, &to_addr); // - OR if the verified-key does not match public-key or gossip-key
if mimeparser.e2ee_helper.gossipped_addr.contains(&to_addr) && peerstate.is_some() { // (otherwise a verified key can _only_ be updated through QR scan which might be annoying,
let peerstate = peerstate.as_mut().unwrap(); // see https://github.com/nextleap-project/countermitm/issues/46 for a discussion about this point)
if 0 == is_verified
// if we're here, we know the gossip key is verified: || peerstate.verified_key_fingerprint
// - use the gossip-key as verified-key if there is no verified-key != peerstate.public_key_fingerprint
// - OR if the verified-key does not match public-key or gossip-key && peerstate.verified_key_fingerprint
// (otherwise a verified key can _only_ be updated through QR scan which might be annoying, != peerstate.gossip_key_fingerprint
// see https://github.com/nextleap-project/countermitm/issues/46 for a discussion about this point) {
if 0 == is_verified info!(
|| peerstate.verified_key_fingerprint != peerstate.public_key_fingerprint context,
&& peerstate.verified_key_fingerprint != peerstate.gossip_key_fingerprint 0,
{ "{} has verfied {}.",
info!( as_str((*contact).addr),
context, to_addr,
0, );
"{} has verfied {}.", let fp = peerstate.gossip_key_fingerprint.clone();
as_str((*contact).addr), if let Some(fp) = fp {
to_addr, peerstate.set_verified(0, &fp, 2);
); peerstate.save_to_db(&context.sql, false);
let fp = peerstate.gossip_key_fingerprint.clone(); is_verified = 1;
if let Some(fp) = fp { }
peerstate.set_verified(0, &fp, 2); }
peerstate.save_to_db(&context.sql, false); }
is_verified = 1; if 0 == is_verified {
verify_fail(format!(
"{} is not a member of this verified group",
to_addr
));
cleanup();
return Err(failure::format_err!("not a valid memember").into());
} }
} }
} Ok(())
if 0 == is_verified { },
verify_fail(&format!( )
"{} is not a member of this verified group", .is_ok(); // TODO: Better default
to_addr
));
cleanup();
return 0;
}
}
everythings_okay = 1;
}
cleanup(); cleanup();
everythings_okay
ok as libc::c_int
} }
unsafe fn set_better_msg(mime_parser: &dc_mimeparser_t, better_msg: *mut *mut libc::c_char) { unsafe fn set_better_msg(mime_parser: &dc_mimeparser_t, better_msg: *mut *mut libc::c_char) {
@@ -1932,10 +1918,16 @@ fn is_known_rfc724_mid(context: &Context, rfc724_mid: *const libc::c_char) -> li
if rfc724_mid.is_null() { if rfc724_mid.is_null() {
return 0; return 0;
} }
dc_sqlite3_prepare( context
context, &context.sql, .sql
"SELECT m.id FROM msgs m LEFT JOIN chats c ON m.chat_id=c.id WHERE m.rfc724_mid=? AND m.chat_id>9 AND c.blocked=0;" .exists(
).and_then(|mut stmt| stmt.exists(params![as_str(rfc724_mid)]).ok()).unwrap_or_default() as libc::c_int "SELECT m.id FROM msgs m \
LEFT JOIN chats c ON m.chat_id=c.id \
WHERE m.rfc724_mid=? \
AND m.chat_id>9 AND c.blocked=0;",
params![as_str(rfc724_mid)],
)
.unwrap_or_default() as libc::c_int
} }
unsafe fn dc_is_reply_to_messenger_message( unsafe fn dc_is_reply_to_messenger_message(
@@ -2010,13 +2002,13 @@ fn is_msgrmsg_rfc724_mid(context: &Context, rfc724_mid: *const libc::c_char) ->
if rfc724_mid.is_null() { if rfc724_mid.is_null() {
return 0; return 0;
} }
dc_sqlite3_prepare( context
context, .sql
&context.sql, .exists(
"SELECT id FROM msgs WHERE rfc724_mid=? AND msgrmsg!=0 AND chat_id>9;", "SELECT id FROM msgs WHERE rfc724_mid=? AND msgrmsg!=0 AND chat_id>9;",
) params![as_str(rfc724_mid)],
.and_then(|mut stmt| stmt.exists(params![as_str(rfc724_mid)]).ok()) )
.unwrap_or_default() as libc::c_int .unwrap_or_default() as libc::c_int
} }
unsafe fn dc_add_or_lookup_contacts_by_address_list( unsafe fn dc_add_or_lookup_contacts_by_address_list(