Compare commits

...
Author SHA1 Message Date
holger krekel 357bce7246 intermediate commit 2019-10-06 01:28:17 +02:00
holger krekel 6bac21b13f some more cleanups but not quite working yet 2019-10-06 01:03:13 +02:00
holger krekel 859e7691d0 first round of configure cleanups 2019-10-06 01:00:11 +02:00
B. Petersen e251c7b1c8 redo some c-comments 2019-10-05 15:53:18 +02:00
björn petersen 2fe98775f9 Merge pull request #673 from deltachat/dont-panic
Don't Panic!
2019-10-05 15:08:15 +02:00
björn petersen 187179d87b Merge pull request #674 from deltachat/to-lossy
always expect bad c-strings
2019-10-05 15:04:32 +02:00
holger krekel dd03f6e8af test and fix that a group with mixed-encryption members (with some we can encrypt, others not) does not break 2019-10-05 15:02:03 +02:00
holger krekel 07b32241bd try fix #677 (this fixes only a test) -- seems like we passed pointers into Rust strings to code that was expecting null-terminated strings. Now do proper "strdup()" and free. The real proper fix is to make dc_split_armored_string into a rust-string function and do away with all c-pointers. 2019-10-05 15:01:28 +02:00
B. Petersen abfff96cd4 cargo fmt 2019-10-05 12:44:08 +02:00
B. Petersen 735bdd1c20 always use to_string_lossy() for converting c-strings to String
the function to_string() is removed;
c-strings may always be badly formatted and this should never lead to a panic.
2019-10-05 00:12:32 +02:00
B. Petersen 9cae075b6f target detailed checks of @flub 2019-10-04 23:07:34 +02:00
B. Petersen 2317518e5e cargo fmt 2019-10-04 23:07:34 +02:00
B. Petersen 477af413c6 if in doubt, prefer unwrap_or_default()
if the past we had lots of crashes because of unexpected unwrap failures,
mostly related to string.
this commit avoids them eg. for string-conversions that may panic
eg. when encountering a null-byte or by logical programming errors
where an object is assumed to be set but is not under unexpected circumstances.
2019-10-04 23:07:33 +02:00
B. Petersen 93f0f5ccae rename sql-config-setters to set_raw_config*()
the rename is reasonable as the getter is called get_raw_config*()
and to make the functional difference to context.set|get_config() clearer.
2019-10-04 11:18:26 +02:00
B. Petersen 79b92727cc prefer get_config_bool() where appropriate
for db input/output, we still use get_config_int() to convert to/from 0/1.
also for info() we prefer get_config_int() to show the real value.
2019-10-04 11:15:11 +02:00
björn petersen 8dfd04672f Merge pull request #670 from deltachat/tweak-config
tweak config
2019-10-03 21:19:45 +02:00
holger krekel 603761e4b7 add DC_EVENT_DELETED_BLOB_FILE 2019-10-03 18:01:56 +02:00
holger krekel 467c09f491 introduce DC_EVENT_NEW_BLOB_FILE event and test for it 2019-10-03 18:01:56 +02:00
B. Petersen a953b494cb cargo fmt 2019-10-03 17:41:09 +02:00
B. Petersen dca9afa10b rename sql.get_config() to sql.get_raw_config() to make clearer that there is not default handling 2019-10-03 17:35:43 +02:00
B. Petersen 23d2d87c24 do not panic on missing or wrong formatted values in the database 2019-10-03 17:15:40 +02:00
B. Petersen c6b2d640ae prefer context.get_config() over context.sql.get_config() as the latter does not handle default values. 2019-10-03 17:15:40 +02:00
38 changed files with 491 additions and 526 deletions
+20
View File
@@ -3924,6 +3924,26 @@ int64_t dc_lot_get_timestamp (const dc_lot_t* lot);
*/
#define DC_EVENT_IMAP_MESSAGE_MOVED 105
/**
* Emitted when a new blob file was successfully written
*
* @param data1 0
* @param data2 (const char*) path name
* Must not be free()'d or modified and is valid only until the callback returns.
* @return 0
*/
#define DC_EVENT_NEW_BLOB_FILE 150
/**
* Emitted when a blob file was successfully deleted
*
* @param data1 0
* @param data2 (const char*) path name
* Must not be free()'d or modified and is valid only until the callback returns.
* @return 0
*/
#define DC_EVENT_DELETED_BLOB_FILE 151
/**
* The library-user should write a warning string to the log.
* Passed to the callback given to dc_context_new().
+10 -10
View File
@@ -24,9 +24,7 @@ use num_traits::{FromPrimitive, ToPrimitive};
use deltachat::contact::Contact;
use deltachat::context::Context;
use deltachat::dc_tools::{
as_path, as_str, dc_strdup, to_string, to_string_lossy, OsStrExt, StrExt,
};
use deltachat::dc_tools::{as_path, as_str, dc_strdup, to_string_lossy, OsStrExt, StrExt};
use deltachat::*;
// as C lacks a good and portable error handling,
@@ -127,11 +125,13 @@ impl ContextWrapper {
| Event::SmtpMessageSent(msg)
| Event::ImapMessageDeleted(msg)
| Event::ImapMessageMoved(msg)
| Event::NewBlobFile(msg)
| Event::DeletedBlobFile(msg)
| Event::Warning(msg)
| Event::Error(msg)
| Event::ErrorNetwork(msg)
| Event::ErrorSelfNotInGroup(msg) => {
let data2 = CString::new(msg).unwrap();
let data2 = CString::new(msg).unwrap_or_default();
ffi_cb(self, event_id, 0, data2.as_ptr() as uintptr_t)
}
Event::MsgsChanged { chat_id, msg_id }
@@ -150,7 +150,7 @@ impl ContextWrapper {
ffi_cb(self, event_id, progress as uintptr_t, 0)
}
Event::ImexFileWritten(file) => {
let data1 = file.to_c_string().unwrap();
let data1 = file.to_c_string().unwrap_or_default();
ffi_cb(self, event_id, data1.as_ptr() as uintptr_t, 0)
}
Event::SecurejoinInviterProgress {
@@ -379,8 +379,8 @@ pub unsafe extern "C" fn dc_get_oauth2_url(
return ptr::null_mut(); // NULL explicitly defined as "unknown"
}
let ffi_context = &*context;
let addr = to_string(addr);
let redirect = to_string(redirect);
let addr = to_string_lossy(addr);
let redirect = to_string_lossy(redirect);
ffi_context
.with_inner(|ctx| match oauth2::dc_get_oauth2_url(ctx, addr, redirect) {
Some(res) => res.strdup(),
@@ -2136,7 +2136,7 @@ pub unsafe extern "C" fn dc_chat_get_profile_image(chat: *mut dc_chat_t) -> *mut
let ffi_context = &*ffi_chat.context;
ffi_context
.with_inner(|ctx| match ffi_chat.chat.get_profile_image(ctx) {
Some(p) => p.to_str().unwrap().to_string().strdup(),
Some(p) => p.to_str().unwrap_or_default().to_string().strdup(),
None => ptr::null_mut(),
})
.unwrap_or_else(|_| ptr::null_mut())
@@ -2481,7 +2481,7 @@ pub unsafe extern "C" fn dc_msg_get_summarytext(
.with_inner(|ctx| {
ffi_msg
.message
.get_summarytext(ctx, approx_characters.try_into().unwrap())
.get_summarytext(ctx, approx_characters.try_into().unwrap_or_default())
})
.unwrap_or_default()
.strdup()
@@ -2773,7 +2773,7 @@ pub unsafe extern "C" fn dc_contact_get_profile_image(
ffi_contact
.contact
.get_profile_image(ctx)
.map(|p| p.to_str().unwrap().to_string().strdup())
.map(|p| p.to_str().unwrap_or_default().to_string().strdup())
.unwrap_or_else(|| std::ptr::null_mut())
})
.unwrap_or_else(|_| ptr::null_mut())
+3 -3
View File
@@ -119,13 +119,13 @@ 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 = to_string(spec);
real_spec = to_string_lossy(spec);
context
.sql
.set_config(context, "import_spec", Some(&real_spec))
.set_raw_config(context, "import_spec", Some(&real_spec))
.unwrap();
} else {
let rs = context.sql.get_config(context, "import_spec");
let rs = context.sql.get_raw_config(context, "import_spec");
if rs.is_none() {
error!(context, "Import: No file or folder given.");
return 0;
+7 -4
View File
@@ -16,13 +16,16 @@ pub unsafe fn charconv(
) -> libc::c_int {
assert!(!fromcode.is_null(), "invalid fromcode");
assert!(!s.is_null(), "invalid input string");
if let Some(encoding) =
charset::Charset::for_label(CStr::from_ptr(fromcode).to_str().unwrap().as_bytes())
{
if let Some(encoding) = charset::Charset::for_label(
CStr::from_ptr(fromcode)
.to_str()
.unwrap_or_default()
.as_bytes(),
) {
let data = std::slice::from_raw_parts(s as *const u8, strlen(s));
let (res, _, _) = encoding.decode(data);
let res_c = CString::new(res.as_bytes()).unwrap();
let res_c = CString::new(res.as_bytes()).unwrap_or_default();
*result = strdup(res_c.as_ptr()) as *mut _;
MAIL_CHARCONV_NO_ERROR as libc::c_int
+1 -1
View File
@@ -1598,7 +1598,7 @@ unsafe fn mailimf_date_time_write_driver(
(*date_time).dt_sec,
(*date_time).dt_zone,
);
let date_str_c = std::ffi::CString::new(date_str).unwrap();
let date_str_c = std::ffi::CString::new(date_str).unwrap_or_default();
let r = mailimf_string_write_driver(
do_write,
data,
+1 -1
View File
@@ -848,7 +848,7 @@ pub unsafe fn mailmime_generate_boundary() -> *mut libc::c_char {
hex::encode(&std::process::id().to_le_bytes()[..2])
);
let c = std::ffi::CString::new(raw).unwrap();
let c = std::ffi::CString::new(raw).unwrap_or_default();
strdup(c.as_ptr())
}
+9 -9
View File
@@ -338,7 +338,7 @@ unsafe fn mailmime_disposition_param_write_driver(
4 => {
let value = (*param).pa_data.pa_size as u32;
let raw = format!("{}", value);
let raw_c = std::ffi::CString::new(raw).unwrap();
let raw_c = std::ffi::CString::new(raw).unwrap_or_default();
sizestr = strdup(raw_c.as_ptr());
len = strlen(b"size=\x00" as *const u8 as *const libc::c_char)
.wrapping_add(strlen(sizestr))
@@ -542,7 +542,7 @@ unsafe fn mailmime_version_write_driver(
}
let raw = format!("{}.{}", (version >> 16) as i32, (version & 0xffff) as i32);
let raw_c = std::ffi::CString::new(raw).unwrap();
let raw_c = std::ffi::CString::new(raw).unwrap_or_default();
let mut versionstr = strdup(raw_c.as_ptr());
r = mailimf_string_write_driver(do_write, data, col, versionstr, strlen(versionstr));
if r != MAILIMF_NO_ERROR as libc::c_int {
@@ -1516,7 +1516,7 @@ pub unsafe fn mailmime_data_write_driver(
1 => {
let filename = CStr::from_ptr((*mime_data).dt_data.dt_filename)
.to_str()
.unwrap();
.unwrap_or_default();
if let Ok(file) = std::fs::File::open(filename) {
if let Ok(mut text) = memmap::MmapOptions::new().map_copy(&file) {
if 0 != (*mime_data).dt_encoded {
@@ -1797,7 +1797,7 @@ pub unsafe fn mailmime_quoted_printable_write_driver(
start = text.offset(i as isize).offset(1isize);
let raw = format!("={:02X}", (ch as libc::c_int));
let raw_c = std::ffi::CString::new(raw).unwrap();
let raw_c = std::ffi::CString::new(raw).unwrap_or_default();
let mut hexstr = strdup(raw_c.as_ptr());
r = mailimf_string_write_driver(
do_write,
@@ -1822,7 +1822,7 @@ pub unsafe fn mailmime_quoted_printable_write_driver(
}
start = text.offset(i as isize).offset(1isize);
let raw = format!("={:02X}", ch as libc::c_int);
let raw_c = std::ffi::CString::new(raw).unwrap();
let raw_c = std::ffi::CString::new(raw).unwrap_or_default();
let mut hexstr = strdup(raw_c.as_ptr());
r = mailimf_string_write_driver(
do_write,
@@ -1866,7 +1866,7 @@ pub unsafe fn mailmime_quoted_printable_write_driver(
}
start = text.offset(i as isize);
let raw = format!("={:02X}", b'\r' as i32);
let raw_c = std::ffi::CString::new(raw).unwrap();
let raw_c = std::ffi::CString::new(raw).unwrap_or_default();
let mut hexstr = strdup(raw_c.as_ptr());
r = mailimf_string_write_driver(do_write, data, col, hexstr, 3i32 as size_t);
if r != MAILIMF_NO_ERROR as libc::c_int {
@@ -1890,7 +1890,7 @@ pub unsafe fn mailmime_quoted_printable_write_driver(
"={:02X}\r\n",
*text.offset(i.wrapping_sub(1i32 as libc::size_t) as isize) as libc::c_int
);
let raw_c = std::ffi::CString::new(raw).unwrap();
let raw_c = std::ffi::CString::new(raw).unwrap_or_default();
let mut hexstr = strdup(raw_c.as_ptr());
r = mailimf_string_write_driver(do_write, data, col, hexstr, strlen(hexstr));
@@ -1917,7 +1917,7 @@ pub unsafe fn mailmime_quoted_printable_write_driver(
"={:02X}\r\n",
*text.offset(i.wrapping_sub(2i32 as libc::size_t) as isize) as libc::c_int
);
let raw_c = std::ffi::CString::new(raw).unwrap();
let raw_c = std::ffi::CString::new(raw).unwrap_or_default();
let mut hexstr = strdup(raw_c.as_ptr());
r = mailimf_string_write_driver(do_write, data, col, hexstr, strlen(hexstr));
@@ -1938,7 +1938,7 @@ pub unsafe fn mailmime_quoted_printable_write_driver(
(*text.offset(i.wrapping_sub(2i32 as libc::size_t) as isize) as u8 as char),
b'\r' as i32
);
let raw_c = std::ffi::CString::new(raw).unwrap();
let raw_c = std::ffi::CString::new(raw).unwrap_or_default();
let mut hexstr = strdup(raw_c.as_ptr());
r = mailimf_string_write_driver(do_write, data, col, hexstr, strlen(hexstr));
+2
View File
@@ -63,6 +63,8 @@ DC_EVENT_IMAP_CONNECTED = 102
DC_EVENT_SMTP_MESSAGE_SENT = 103
DC_EVENT_IMAP_MESSAGE_DELETED = 104
DC_EVENT_IMAP_MESSAGE_MOVED = 105
DC_EVENT_NEW_BLOB_FILE = 150
DC_EVENT_DELETED_BLOB_FILE = 151
DC_EVENT_WARNING = 300
DC_EVENT_ERROR = 400
DC_EVENT_ERROR_NETWORK = 401
+12
View File
@@ -229,7 +229,9 @@ class TestOfflineChat:
chat1.send_image(path="notexists")
fn = data.get_path("d.png")
lp.sec("sending image")
chat1.account._evlogger.consume_events()
msg = chat1.send_image(fn)
chat1.account._evlogger.get_matching("DC_EVENT_NEW_BLOB_FILE")
assert msg.is_image()
assert msg
assert msg.id > 0
@@ -375,6 +377,7 @@ class TestOnlineAccount:
self_addr = ac1.get_config("addr")
ev = ac1._evlogger.get_matching("DC_EVENT_SMTP_MESSAGE_SENT")
assert self_addr in ev[2]
ev = ac1._evlogger.get_matching("DC_EVENT_DELETED_BLOB_FILE")
ac1._evlogger.consume_events()
lp.sec("send out message without bcc")
@@ -384,6 +387,7 @@ class TestOnlineAccount:
assert ev[2] == msg_out.id
ev = ac1._evlogger.get_matching("DC_EVENT_SMTP_MESSAGE_SENT")
assert self_addr not in ev[2]
ev = ac1._evlogger.get_matching("DC_EVENT_DELETED_BLOB_FILE")
def test_mvbox_sentbox_threads(self, acfactory):
ac1 = acfactory.get_online_configuring_account(mvbox=True, sentbox=True)
@@ -512,6 +516,14 @@ class TestOnlineAccount:
assert msg_back.text == "message-back"
assert msg_back.is_encrypted()
lp.sec("create group chat with two members, one of which has no encrypt state")
chat = ac1.create_group_chat("encryption test")
chat.add_contact(ac1.create_contact(ac2.get_config("addr")))
chat.add_contact(ac1.create_contact("notexisting@testrun.org"))
msg = chat.send_text("test not encrypt")
ev = ac1._evlogger.get_matching("DC_EVENT_SMTP_MESSAGE_SENT")
assert not msg.is_encrypted()
def test_saved_mime_on_received_message(self, acfactory, lp):
ac1, ac2 = acfactory.get_two_online_accounts()
+6 -3
View File
@@ -79,13 +79,16 @@ impl Aheader {
let optional_field = unsafe { (*field).fld_data.fld_optional_field };
if !optional_field.is_null()
&& unsafe { !(*optional_field).fld_name.is_null() }
&& unsafe { CStr::from_ptr((*optional_field).fld_name).to_str().unwrap() }
== "Autocrypt"
&& unsafe {
CStr::from_ptr((*optional_field).fld_name)
.to_str()
.unwrap_or_default()
} == "Autocrypt"
{
let value = unsafe {
CStr::from_ptr((*optional_field).fld_value)
.to_str()
.unwrap()
.unwrap_or_default()
};
if let Ok(test) = Self::from_str(value) {
+48 -33
View File
@@ -162,9 +162,13 @@ impl Chat {
let collect = |row: &rusqlite::Row| Ok((row.get(0)?, row.get(1)?, row.get(2)?));
let params = params![self.id as i32, DC_CONTACT_ID_SELF as i32];
let sql = &context.sql;
// use the last messsage of another user in the group as the parent
let main_query = "SELECT rfc724_mid, mime_in_reply_to, mime_references \
FROM msgs WHERE chat_id=?1 AND timestamp=(SELECT max(timestamp) \
FROM msgs WHERE chat_id=?1 AND from_id!=?2);";
// there are no messages of other users - use the first message if SELF as parent
let fallback_query = "SELECT rfc724_mid, mime_in_reply_to, mime_references \
FROM msgs WHERE chat_id=?1 AND timestamp=(SELECT min(timestamp) \
FROM msgs WHERE chat_id=?1 AND from_id==?2);";
@@ -287,7 +291,7 @@ impl Chat {
if self.typ == Chattype::Group || self.typ == Chattype::VerifiedGroup {
if self.param.get_int(Param::Unpromoted).unwrap_or_default() == 1 {
self.param.remove(Param::Unpromoted);
self.update_param(context).unwrap();
self.update_param(context)?;
}
}
}
@@ -299,10 +303,13 @@ impl Chat {
do_guarantee_e2ee = false;
e2ee_enabled = context.get_config_bool(Config::E2eeEnabled);
if e2ee_enabled && msg.param.get_int(Param::ForcePlaintext).unwrap_or_default() == 0 {
let mut can_encrypt = 1;
let mut all_mutual = 1;
let mut can_encrypt = true;
let mut all_mutual = true;
let res = context.sql.query_row(
// take care that this statement returns NULL rows
// if there is no peerstates for a chat member!
// for DC_PARAM_SELFTALK this statement does not return any row
let res = context.sql.query_map(
"SELECT ps.prefer_encrypted, c.addr \
FROM chats_contacts cc \
LEFT JOIN contacts c ON cc.contact_id=c.id \
@@ -310,29 +317,32 @@ impl Chat {
WHERE cc.chat_id=? AND cc.contact_id>9;",
params![self.id],
|row| {
let state: String = row.get(1)?;
let addr: String = row.get(1)?;
if let Some(prefer_encrypted) = row.get::<_, Option<i32>>(0)? {
// the peerstate exist, so we have either public_key or gossip_key
// and can encrypt potentially
if prefer_encrypted != 1 {
info!(
context,
"[autocrypt] peerstate for {} is {}",
state,
addr,
if prefer_encrypted == 0 {
"NOPREFERENCE"
} else {
"RESET"
},
);
all_mutual = 0;
all_mutual = false;
}
} else {
info!(context, "[autocrypt] no peerstate for {}", state,);
can_encrypt = 0;
all_mutual = 0;
info!(context, "[autocrypt] no peerstate for {}", addr,);
can_encrypt = false;
all_mutual = false;
}
Ok(())
},
|rows| rows.collect::<Result<Vec<_>, _>>().map_err(Into::into),
);
match res {
Ok(_) => {}
@@ -341,8 +351,8 @@ impl Chat {
}
}
if 0 != can_encrypt {
if 0 != all_mutual {
if can_encrypt {
if all_mutual {
do_guarantee_e2ee = true;
} else if last_msg_in_chat_encrypted(context, &context.sql, self.id) {
do_guarantee_e2ee = true;
@@ -352,7 +362,15 @@ impl Chat {
if do_guarantee_e2ee {
msg.param.set_int(Param::GuranteeE2ee, 1);
}
// reset eg. for forwarding
msg.param.remove(Param::ErroneousE2ee);
// set "In-Reply-To:" to identify the message to which the composed message is a reply;
// set "References:" to identify the "thread" of the conversation;
// both according to RFC 5322 3.6.4, page 25
//
// as self-talks are mainly used to transfer data between devices,
// we do not set In-Reply-To/References in this case.
if !self.is_self_talk() {
if let Some((parent_rfc724_mid, parent_in_reply_to, parent_references)) =
self.get_parent_mime_headers(context)
@@ -360,6 +378,9 @@ impl Chat {
if !parent_rfc724_mid.is_empty() {
new_in_reply_to = parent_rfc724_mid.clone();
}
// the whole list of messages referenced may be huge;
// only use the oldest and and the parent message
let parent_references = if let Some(n) = parent_references.find(' ') {
&parent_references[0..n]
} else {
@@ -367,6 +388,7 @@ impl Chat {
};
if !parent_references.is_empty() && !parent_rfc724_mid.is_empty() {
// angle brackets are added by the mimefactory later
new_references = format!("{} {}", parent_references, parent_rfc724_mid);
} else if !parent_references.is_empty() {
new_references = parent_references.to_string();
@@ -951,10 +973,7 @@ pub fn get_chat_msgs(context: &Context, chat_id: u32, flags: u32, marker1before:
};
let success = if chat_id == 1 {
let show_emails = context
.sql
.get_config_int(context, "show_emails")
.unwrap_or_default();
let show_emails = context.get_config_int(Config::ShowEmails);
context.sql.query_map(
"SELECT m.id, m.timestamp FROM msgs m \
LEFT JOIN chats ON m.chat_id=chats.id \
@@ -1370,11 +1389,10 @@ pub(crate) fn add_contact_to_chat_ex(
}
if from_handshake && chat.param.get_int(Param::Unpromoted).unwrap_or_default() == 1 {
chat.param.remove(Param::Unpromoted);
chat.update_param(context).unwrap();
chat.update_param(context)?;
}
let self_addr = context
.sql
.get_config(context, "configured_addr")
.get_config(Config::ConfiguredAddr)
.unwrap_or_default();
if contact.get_addr() == &self_addr {
bail!("invalid attempt to add self e-mail address to group");
@@ -1506,7 +1524,7 @@ pub fn remove_contact_from_chat(
if chat.is_promoted() {
msg.type_0 = Viewtype::Text;
if contact.id == DC_CONTACT_ID_SELF {
set_group_explicitly_left(context, chat.grpid).unwrap();
set_group_explicitly_left(context, chat.grpid)?;
msg.text = Some(context.stock_system_msg(
StockMessage::MsgGroupLeft,
"",
@@ -1715,7 +1733,7 @@ pub fn forward_msgs(context: &Context, msg_ids: &[u32], chat_id: u32) -> Result<
let mut created_db_entries = Vec::new();
let mut curr_timestamp: i64;
unarchive(context, chat_id).unwrap();
unarchive(context, chat_id)?;
if let Ok(mut chat) = Chat::load_from_db(context, chat_id) {
curr_timestamp = dc_create_smeared_timestamps(context, msg_ids.len());
let idsstr = msg_ids
@@ -1725,18 +1743,15 @@ pub fn forward_msgs(context: &Context, msg_ids: &[u32], chat_id: u32) -> Result<
(if i == 0 { acc } else { acc + "," }) + &n.to_string()
});
let ids = context
.sql
.query_map(
format!(
"SELECT id FROM msgs WHERE id IN({}) ORDER BY timestamp,id",
idsstr
),
params![],
|row| row.get::<_, i32>(0),
|ids| ids.collect::<Result<Vec<_>, _>>().map_err(Into::into),
)
.unwrap(); // TODO: better error handling
let ids = context.sql.query_map(
format!(
"SELECT id FROM msgs WHERE id IN({}) ORDER BY timestamp,id",
idsstr
),
params![],
|row| row.get::<_, i32>(0),
|ids| ids.collect::<Result<Vec<_>, _>>().map_err(Into::into),
)?;
for id in ids {
let src_msg_id = id;
+12 -10
View File
@@ -78,13 +78,13 @@ impl Context {
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| dc_get_abs_path(self, &p).to_str().unwrap().to_string())
let rel_path = self.sql.get_raw_config(self, key);
rel_path.map(|p| dc_get_abs_path(self, &p).to_string_lossy().into_owned())
}
Config::SysVersion => Some((&*DC_VERSION_STR).clone()),
Config::SysMsgsizeMaxRecommended => Some(format!("{}", 24 * 1024 * 1024 / 4 * 3)),
Config::SysConfigKeys => Some(get_config_keys_string()),
_ => self.sql.get_config(self, key),
_ => self.sql.get_raw_config(self, key),
};
if value.is_some() {
@@ -99,7 +99,9 @@ impl Context {
}
pub fn get_config_int(&self, key: Config) -> i32 {
self.get_config(key).and_then(|s| s.parse().ok()).unwrap()
self.get_config(key)
.and_then(|s| s.parse().ok())
.unwrap_or_default()
}
pub fn get_config_bool(&self, key: Config) -> bool {
@@ -113,20 +115,20 @@ impl Context {
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()))
.set_raw_config(self, key, Some(&rel_path.to_string_lossy()))
}
Config::InboxWatch => {
let ret = self.sql.set_config(self, key, value);
let ret = self.sql.set_raw_config(self, key, value);
interrupt_imap_idle(self);
ret
}
Config::SentboxWatch => {
let ret = self.sql.set_config(self, key, value);
let ret = self.sql.set_raw_config(self, key, value);
interrupt_sentbox_idle(self);
ret
}
Config::MvboxWatch => {
let ret = self.sql.set_config(self, key, value);
let ret = self.sql.set_raw_config(self, key, value);
interrupt_mvbox_idle(self);
ret
}
@@ -138,9 +140,9 @@ impl Context {
value
};
self.sql.set_config(self, key, val)
self.sql.set_raw_config(self, key, val)
}
_ => self.sql.set_config(self, key, value),
_ => self.sql.set_raw_config(self, key, value),
}
}
}
+9 -11
View File
@@ -1,10 +1,8 @@
use libc::free;
use quick_xml;
use quick_xml::events::{BytesEnd, BytesStart, BytesText};
use crate::constants::*;
use crate::context::Context;
use crate::dc_tools::*;
use crate::login_param::LoginParam;
use super::read_autoconf_file;
@@ -24,26 +22,28 @@ struct moz_autoconfigure_t<'a> {
pub tag_config: libc::c_int,
}
pub unsafe fn moz_autoconfigure(
pub fn moz_autoconfigure(
context: &Context,
url: &str,
param_in: &LoginParam,
) -> Option<LoginParam> {
let xml_raw = read_autoconf_file(context, url);
if xml_raw.is_null() {
return None;
}
let xml_raw = match read_autoconf_file(context, url) {
Err(err) => {
info!(context, "can't read file: {}", err);
return None;
}
Ok(content) => content,
};
// Split address into local part and domain part.
let p = param_in.addr.find("@");
if p.is_none() {
free(xml_raw as *mut libc::c_void);
return None;
}
let (in_emaillocalpart, in_emaildomain) = param_in.addr.split_at(p.unwrap());
let in_emaildomain = &in_emaildomain[1..];
let mut reader = quick_xml::Reader::from_str(as_str(xml_raw));
let mut reader = quick_xml::Reader::from_str(&xml_raw);
reader.trim_text(true);
let mut buf = Vec::new();
@@ -88,11 +88,9 @@ pub unsafe fn moz_autoconfigure(
{
let r = moz_ac.out.to_string();
warn!(context, "Bad or incomplete autoconfig: {}", r,);
free(xml_raw as *mut libc::c_void);
return None;
}
free(xml_raw as *mut libc::c_void);
Some(moz_ac.out)
}
+75 -150
View File
@@ -1,13 +1,10 @@
use std::ptr;
use libc::free;
use std::collections::HashMap;
use quick_xml;
use quick_xml::events::{BytesEnd, BytesStart, BytesText};
use crate::constants::*;
use crate::context::Context;
use crate::dc_tools::*;
use crate::login_param::LoginParam;
use quick_xml::events::{BytesEnd};
use super::read_autoconf_file;
/* ******************************************************************************
@@ -17,60 +14,52 @@ use super::read_autoconf_file;
struct outlk_autodiscover_t<'a> {
pub in_0: &'a LoginParam,
pub out: LoginParam,
pub out_imap_set: libc::c_int,
pub out_smtp_set: libc::c_int,
pub tag_config: libc::c_int,
pub config: [*mut libc::c_char; 6],
pub out_imap_set: bool,
pub out_smtp_set: bool,
pub config: HashMap<String, String>,
}
pub unsafe fn outlk_autodiscover(
pub fn outlk_autodiscover(
context: &Context,
url__: &str,
param_in: &LoginParam,
) -> Option<LoginParam> {
let mut xml_raw: *mut libc::c_char = ptr::null_mut();
let mut url = url__.strdup();
let mut url = url__.to_string();
let mut outlk_ad = outlk_autodiscover_t {
in_0: param_in,
out: LoginParam::new(),
out_imap_set: 0,
out_smtp_set: 0,
tag_config: 0,
config: [ptr::null_mut(); 6],
out_imap_set: false,
out_smtp_set: false,
config: HashMap::new(),
};
let ok_to_continue;
let mut i = 0;
loop {
if i >= 10 {
ok_to_continue = true;
break;
}
libc::memset(
&mut outlk_ad as *mut outlk_autodiscover_t as *mut libc::c_void,
0,
::std::mem::size_of::<outlk_autodiscover_t>(),
);
xml_raw = read_autoconf_file(context, as_str(url));
if xml_raw.is_null() {
ok_to_continue = false;
break;
for i in 0..10 {
let xml_raw = read_autoconf_file(context, &url);
if xml_raw.is_err() {
return Some(outlk_ad.out);
}
let xml_raw = xml_raw.unwrap();
let mut reader = quick_xml::Reader::from_str(as_str(xml_raw));
let mut reader = quick_xml::Reader::from_str(&xml_raw);
reader.trim_text(true);
let mut buf = Vec::new();
let current_tag: Option<String> = None;
loop {
match reader.read_event(&mut buf) {
Ok(quick_xml::events::Event::Start(ref e)) => {
outlk_autodiscover_starttag_cb(e, &mut outlk_ad)
current_tag = Some(String::from_utf8_lossy(e.name()).trim().to_lowercase());
}
Ok(quick_xml::events::Event::End(ref e)) => {
outlk_autodiscover_endtag_cb(e, &mut outlk_ad)
if "protocol" == String::from_utf8_lossy(e.name()).trim().to_lowercase() {
finish_settings(e, &mut outlk_ad);
}
current_tag = None;
}
Ok(quick_xml::events::Event::Text(ref e)) => {
outlk_autodiscover_text_cb(e, &mut outlk_ad, &reader)
if let Some(current_tag) = current_tag {
let val = e.unescape_and_decode(&reader).unwrap_or_default();
&outlk_ad.config.insert(current_tag, val);
}
}
Err(e) => {
error!(
@@ -79,134 +68,70 @@ pub unsafe fn outlk_autodiscover(
reader.buffer_position(),
e
);
break;
}
Ok(quick_xml::events::Event::Eof) => break,
_ => (),
}
buf.clear();
}
if !(!outlk_ad.config[5].is_null()
&& 0 != *outlk_ad.config[5usize].offset(0isize) as libc::c_int)
{
ok_to_continue = true;
break;
if let Some(next_url) = outlk_ad.config.get("redirecturl") {
if !next_url.is_empty() {
url = next_url.to_string();
continue;
}
}
free(url as *mut libc::c_void);
url = dc_strdup(outlk_ad.config[5usize]);
outlk_clean_config(&mut outlk_ad);
free(xml_raw as *mut libc::c_void);
xml_raw = ptr::null_mut();
i += 1;
break;
}
if ok_to_continue {
if outlk_ad.out.mail_server.is_empty()
|| outlk_ad.out.mail_port == 0
|| outlk_ad.out.send_server.is_empty()
|| outlk_ad.out.send_port == 0
{
let r = outlk_ad.out.to_string();
warn!(context, "Bad or incomplete autoconfig: {}", r,);
free(url as *mut libc::c_void);
free(xml_raw as *mut libc::c_void);
outlk_clean_config(&mut outlk_ad);
if outlk_ad.out.mail_server.is_empty()
|| outlk_ad.out.mail_port == 0
|| outlk_ad.out.send_server.is_empty()
|| outlk_ad.out.send_port == 0
{
let r = outlk_ad.out.to_string();
warn!(context, "Bad or incomplete autoconfig: {}", r,);
return None;
}
return None;
}
free(url as *mut libc::c_void);
free(xml_raw as *mut libc::c_void);
outlk_clean_config(&mut outlk_ad);
Some(outlk_ad.out)
}
unsafe fn outlk_clean_config(mut outlk_ad: *mut outlk_autodiscover_t) {
for i in 0..6 {
free((*outlk_ad).config[i] as *mut libc::c_void);
(*outlk_ad).config[i] = ptr::null_mut();
}
}
fn outlk_autodiscover_text_cb<B: std::io::BufRead>(
event: &BytesText,
outlk_ad: &mut outlk_autodiscover_t,
reader: &quick_xml::Reader<B>,
) {
let val = event.unescape_and_decode(reader).unwrap_or_default();
unsafe {
free(outlk_ad.config[outlk_ad.tag_config as usize].cast());
outlk_ad.config[outlk_ad.tag_config as usize] = val.trim().strdup();
}
}
unsafe fn outlk_autodiscover_endtag_cb(event: &BytesEnd, outlk_ad: &mut outlk_autodiscover_t) {
let tag = String::from_utf8_lossy(event.name()).trim().to_lowercase();
if tag == "protocol" {
if !outlk_ad.config[1].is_null() {
let port = dc_atoi_null_is_0(outlk_ad.config[3]);
let ssl_on = (!outlk_ad.config[4].is_null()
&& strcasecmp(
outlk_ad.config[4],
b"on\x00" as *const u8 as *const libc::c_char,
) == 0) as libc::c_int;
let ssl_off = (!outlk_ad.config[4].is_null()
&& strcasecmp(
outlk_ad.config[4],
b"off\x00" as *const u8 as *const libc::c_char,
) == 0) as libc::c_int;
if strcasecmp(
outlk_ad.config[1],
b"imap\x00" as *const u8 as *const libc::c_char,
) == 0
&& outlk_ad.out_imap_set == 0
{
outlk_ad.out.mail_server = to_string(outlk_ad.config[2]);
outlk_ad.out.mail_port = port;
if 0 != ssl_on {
outlk_ad.out.server_flags |= DC_LP_IMAP_SOCKET_SSL as i32
} else if 0 != ssl_off {
outlk_ad.out.server_flags |= DC_LP_IMAP_SOCKET_PLAIN as i32
}
outlk_ad.out_imap_set = 1
} else if strcasecmp(
outlk_ad.config[1usize],
b"smtp\x00" as *const u8 as *const libc::c_char,
) == 0
&& outlk_ad.out_smtp_set == 0
{
outlk_ad.out.send_server = to_string(outlk_ad.config[2]);
outlk_ad.out.send_port = port;
if 0 != ssl_on {
outlk_ad.out.server_flags |= DC_LP_SMTP_SOCKET_SSL as i32
} else if 0 != ssl_off {
outlk_ad.out.server_flags |= DC_LP_SMTP_SOCKET_PLAIN as i32
}
outlk_ad.out_smtp_set = 1
fn finish_settings(event: &BytesEnd, outlk_ad: &mut outlk_autodiscover_t) {
let ssl_on = false;
let ssl_off = false;
let config = &outlk_ad.config;
if let Some(type_val) = &config.get("type") {
let port = match config.get("port") {
None => 0,
Some(r) => {
r.parse::<i32>().unwrap_or_default()
}
};
if let Some(ssl) = &config.get("ssl") {
ssl_on = *ssl == "on";
ssl_off = *ssl == "off";
}
let type_val = *type_val;
if !outlk_ad.out_imap_set && type_val == "imap" {
outlk_ad.out.mail_server = config.get("server").unwrap_or("".to_string());
outlk_ad.out.mail_port = port;
if ssl_on {
outlk_ad.out.server_flags |= DC_LP_IMAP_SOCKET_SSL as i32;
} else if ssl_off {
outlk_ad.out.server_flags |= DC_LP_IMAP_SOCKET_PLAIN as i32;
}
outlk_ad.out_imap_set = true;
} else if !outlk_ad.out_smtp_set && type_val == "smtp" {
outlk_ad.out.send_server = &config.get("server").unwrap_or_default();
outlk_ad.out.send_port = port;
if ssl_on {
outlk_ad.out.server_flags |= DC_LP_SMTP_SOCKET_SSL as i32
} else if ssl_off {
outlk_ad.out.server_flags |= DC_LP_SMTP_SOCKET_PLAIN as i32
}
outlk_ad.out_smtp_set = true;
}
outlk_clean_config(outlk_ad);
}
outlk_ad.tag_config = 0;
}
fn outlk_autodiscover_starttag_cb(event: &BytesStart, outlk_ad: &mut outlk_autodiscover_t) {
let tag = String::from_utf8_lossy(event.name()).trim().to_lowercase();
if tag == "protocol" {
unsafe { outlk_clean_config(outlk_ad) };
} else if tag == "type" {
outlk_ad.tag_config = 1
} else if tag == "server" {
outlk_ad.tag_config = 2
} else if tag == "port" {
outlk_ad.tag_config = 3
} else if tag == "ssl" {
outlk_ad.tag_config = 4
} else if tag == "redirecturl" {
outlk_ad.tag_config = 5
};
}
+15 -29
View File
@@ -1,9 +1,11 @@
use percent_encoding::{utf8_percent_encode, NON_ALPHANUMERIC};
use crate::config::Config;
use crate::constants::*;
use crate::context::Context;
use crate::dc_tools::*;
use crate::e2ee;
use crate::error::*;
use crate::imap::*;
use crate::job::*;
use crate::login_param::LoginParam;
@@ -26,7 +28,7 @@ macro_rules! progress {
}
// connect
pub unsafe fn configure(context: &Context) {
pub fn configure(context: &Context) {
if dc_has_ongoing(context) {
warn!(context, "There is already another ongoing process running.",);
return;
@@ -37,7 +39,7 @@ pub unsafe fn configure(context: &Context) {
/// Check if the context is already configured.
pub fn dc_is_configured(context: &Context) -> bool {
context.sql.get_config_bool(context, "configured")
context.sql.get_raw_config_bool(context, "configured")
}
/*******************************************************************************
@@ -45,7 +47,7 @@ pub fn dc_is_configured(context: &Context) -> bool {
******************************************************************************/
// the other dc_job_do_DC_JOB_*() functions are declared static in the c-file
#[allow(non_snake_case, unused_must_use)]
pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context) {
pub fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context) {
let mut success = false;
let mut imap_connected_here = false;
let mut smtp_connected_here = false;
@@ -113,7 +115,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context) {
param.addr = oauth2_addr;
context
.sql
.set_config(context, "addr", Some(param.addr.as_str()))
.set_raw_config(context, "addr", Some(param.addr.as_str()))
.ok();
}
progress!(context, 20);
@@ -476,15 +478,8 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context) {
}
16 => {
progress!(context, 900);
let flags: libc::c_int = if 0
!= context
.sql
.get_config_int(context, "mvbox_watch")
.unwrap_or_else(|| 1)
|| 0 != context
.sql
.get_config_int(context, "mvbox_move")
.unwrap_or_else(|| 1)
let flags: libc::c_int = if context.get_config_bool(Config::MvboxWatch)
|| context.get_config_bool(Config::MvboxMove)
{
DC_CREATE_MVBOX as i32
} else {
@@ -507,7 +502,7 @@ pub unsafe fn dc_job_do_DC_JOB_CONFIGURE_IMAP(context: &Context) {
)
.ok();
context.sql.set_config_bool(context, "configured", true);
context.sql.set_raw_config_bool(context, "configured", true);
true
}
18 => {
@@ -608,12 +603,7 @@ pub fn dc_connect_to_configured_imap(context: &Context, imap: &Imap) -> libc::c_
if imap.is_connected() {
ret_connected = 1
} else if context
.sql
.get_config_int(context, "configured")
.unwrap_or_default()
== 0
{
} else if !context.sql.get_raw_config_bool(context, "configured") {
warn!(context, "Not configured, cannot connect.",);
} else {
let param = LoginParam::from_database(context, "configured_");
@@ -644,7 +634,7 @@ pub fn dc_stop_ongoing_process(context: &Context) {
};
}
pub fn read_autoconf_file(context: &Context, url: &str) -> *mut libc::c_char {
pub fn read_autoconf_file(context: &Context, url: &str) -> Result<String> {
info!(context, "Testing {} ...", url);
match reqwest::Client::new()
@@ -652,12 +642,10 @@ pub fn read_autoconf_file(context: &Context, url: &str) -> *mut libc::c_char {
.send()
.and_then(|mut res| res.text())
{
Ok(res) => unsafe { res.strdup() },
Err(_err) => {
info!(context, "Can\'t read file.",);
std::ptr::null_mut()
Err(err) => {
bail!("{}", err);
}
Ok(res) => Ok(res.to_string()),
}
}
@@ -675,8 +663,6 @@ mod tests {
.set_config(Config::Addr, Some("probably@unexistant.addr"))
.unwrap();
t.ctx.set_config(Config::MailPw, Some("123456")).unwrap();
unsafe {
dc_job_do_DC_JOB_CONFIGURE_IMAP(&t.ctx);
}
dc_job_do_DC_JOB_CONFIGURE_IMAP(&t.ctx);
}
}
+13 -19
View File
@@ -208,7 +208,9 @@ impl Context {
.open(&path)
{
file.write_all(data)?;
return Ok(format!("$BLOBDIR/{}", candidate_basename));
let db_entry = format!("$BLOBDIR/{}", candidate_basename);
self.call_cb(Event::NewBlobFile(db_entry.clone()));
return Ok(db_entry);
}
}
bail!("out of luck to create new blob file");
@@ -222,18 +224,15 @@ impl Context {
let unset = "0";
let l = LoginParam::from_database(self, "");
let l2 = LoginParam::from_database(self, "configured_");
let displayname = self.sql.get_config(self, "displayname");
let displayname = self.get_config(Config::Displayname);
let chats = get_chat_cnt(self) as usize;
let real_msgs = message::get_real_msg_cnt(self) as usize;
let deaddrop_msgs = message::get_deaddrop_msg_cnt(self) as usize;
let contacts = Contact::get_real_cnt(self) as usize;
let is_configured = self
.sql
.get_config_int(self, "configured")
.unwrap_or_default();
let is_configured = self.get_config_int(Config::Configured);
let dbversion = self
.sql
.get_config_int(self, "dbversion")
.get_raw_config_int(self, "dbversion")
.unwrap_or_default();
let e2ee_enabled = self.get_config_int(Config::E2eeEnabled);
@@ -262,16 +261,16 @@ impl Context {
let mvbox_move = self.get_config_int(Config::MvboxMove);
let folders_configured = self
.sql
.get_config_int(self, "folders_configured")
.get_raw_config_int(self, "folders_configured")
.unwrap_or_default();
let configured_sentbox_folder = self
.sql
.get_config(self, "configured_sentbox_folder")
.get_raw_config(self, "configured_sentbox_folder")
.unwrap_or_else(|| "<unset>".to_string());
let configured_mvbox_folder = self
.sql
.get_config(self, "configured_mvbox_folder")
.get_raw_config(self, "configured_mvbox_folder")
.unwrap_or_else(|| "<unset>".to_string());
let mut res = get_info();
@@ -331,7 +330,7 @@ impl Context {
Ok(ret)
},
)
.unwrap()
.unwrap_or_default()
}
#[allow(non_snake_case)]
@@ -375,7 +374,7 @@ impl Context {
}
pub fn is_sentbox(&self, folder_name: impl AsRef<str>) -> bool {
let sentbox_name = self.sql.get_config(self, "configured_sentbox_folder");
let sentbox_name = self.sql.get_raw_config(self, "configured_sentbox_folder");
if let Some(name) = sentbox_name {
name == folder_name.as_ref()
} else {
@@ -384,7 +383,7 @@ impl Context {
}
pub fn is_mvbox(&self, folder_name: impl AsRef<str>) -> bool {
let mvbox_name = self.sql.get_config(self, "configured_mvbox_folder");
let mvbox_name = self.sql.get_raw_config(self, "configured_mvbox_folder");
if let Some(name) = mvbox_name {
name == folder_name.as_ref()
@@ -394,12 +393,7 @@ impl Context {
}
pub fn do_heuristics_moves(&self, folder: &str, msg_id: u32) {
if self
.sql
.get_config_int(self, "mvbox_move")
.unwrap_or_else(|| 1)
== 0
{
if !self.get_config_bool(Config::MvboxMove) {
return;
}
+8 -5
View File
@@ -282,7 +282,7 @@ impl<'a> MimeParser<'a> {
if self.get_last_nonmeta().is_some() {
let mut mb_list: *mut mailimf_mailbox_list = ptr::null_mut();
let mut index_0 = 0;
let dn_field_c = CString::new(dn_field).unwrap();
let dn_field_c = CString::new(dn_field).unwrap_or_default();
if mailimf_mailbox_list_parse(
dn_field_c.as_ptr(),
@@ -620,9 +620,12 @@ impl<'a> MimeParser<'a> {
&& strcmp(charset, b"utf-8\x00" as *const u8 as *const libc::c_char) != 0i32
&& strcmp(charset, b"UTF-8\x00" as *const u8 as *const libc::c_char) != 0i32
{
if let Some(encoding) =
Charset::for_label(CStr::from_ptr(charset).to_str().unwrap().as_bytes())
{
if let Some(encoding) = Charset::for_label(
CStr::from_ptr(charset)
.to_str()
.unwrap_or_default()
.as_bytes(),
) {
let (res, _, _) = encoding.decode(&decoded_data);
if res.is_empty() {
/* no error - but nothing to add */
@@ -890,7 +893,7 @@ impl<'a> MimeParser<'a> {
unsafe {
let fld_message_id = (*field).fld_data.fld_message_id;
if !fld_message_id.is_null() {
return Some(to_string((*fld_message_id).mid_value));
return Some(to_string_lossy((*fld_message_id).mid_value));
}
}
}
+13 -21
View File
@@ -581,11 +581,11 @@ unsafe fn add_parts(
);
// unarchive chat
chat::unarchive(context, *chat_id).unwrap();
chat::unarchive(context, *chat_id)?;
// if the mime-headers should be saved, find out its size
// (the mime-header ends with an empty line)
let save_mime_headers = context.sql.get_config_bool(context, "save_mime_headers");
let save_mime_headers = context.get_config_bool(Config::SaveMimeHeaders);
if let Some(field) = mime_parser.lookup_field_typ("In-Reply-To", MAILIMF_FIELD_IN_REPLY_TO) {
let fld_in_reply_to = (*field).fld_data.fld_in_reply_to;
if !fld_in_reply_to.is_null() {
@@ -688,8 +688,8 @@ unsafe fn add_parts(
} else {
None
},
to_string(mime_in_reply_to),
to_string(mime_references),
to_string_lossy(mime_in_reply_to),
to_string_lossy(mime_references),
])?;
txt_raw = None;
@@ -852,12 +852,7 @@ unsafe fn handle_reports(
let mut param = Params::new();
param.set(Param::ServerFolder, server_folder.as_ref());
param.set_int(Param::ServerUid, server_uid as i32);
if mime_parser.is_send_by_messenger
&& 0 != context
.sql
.get_config_int(context, "mvbox_move")
.unwrap_or_else(|| 1)
{
if mime_parser.is_send_by_messenger && context.get_config_bool(Config::MvboxMove) {
param.set_int(Param::AlsoMove, 1);
}
job_add(context, Action::MarkseenMdnOnImap, 0, param, 0);
@@ -1031,7 +1026,7 @@ unsafe fn create_or_lookup_group(
{
let fld_in_reply_to = (*field).fld_data.fld_in_reply_to;
if !fld_in_reply_to.is_null() {
grpid = to_string(dc_extract_grpid_from_rfc724_mid_list(
grpid = to_string_lossy(dc_extract_grpid_from_rfc724_mid_list(
(*fld_in_reply_to).mid_list,
));
}
@@ -1042,7 +1037,7 @@ unsafe fn create_or_lookup_group(
{
let fld_references = (*field).fld_data.fld_references;
if !fld_references.is_null() {
grpid = to_string(dc_extract_grpid_from_rfc724_mid_list(
grpid = to_string_lossy(dc_extract_grpid_from_rfc724_mid_list(
(*fld_references).mid_list,
));
}
@@ -1159,8 +1154,7 @@ unsafe fn create_or_lookup_group(
group_explicitly_left = chat::is_group_explicitly_left(context, &grpid).unwrap_or_default();
let self_addr = context
.sql
.get_config(context, "configured_addr")
.get_config(Config::ConfiguredAddr)
.unwrap_or_default();
if chat_id == 0
&& !mime_parser.is_mailinglist_message()
@@ -1270,7 +1264,7 @@ unsafe fn create_or_lookup_group(
} else {
chat.param.set(Param::ProfileImage, grpimage);
}
chat.update_param(context).unwrap();
chat.update_param(context).unwrap_or_default();
send_EVENT_CHAT_MODIFIED = 1;
}
}
@@ -1490,8 +1484,7 @@ fn create_adhoc_grp_id(context: &Context, member_ids: &[u32]) -> String {
*/
let member_ids_str = join(member_ids.iter().map(|x| x.to_string()), ",");
let member_cs = context
.sql
.get_config(context, "configured_addr")
.get_config(Config::ConfiguredAddr)
.unwrap_or_else(|| "no-self".to_string())
.to_lowercase();
@@ -1582,7 +1575,7 @@ fn search_chat_ids_by_contact_ids(context: &Context, unsorted_contact_ids: &Vec<
}
Ok(())
}
).unwrap(); // TODO: better error handling
).unwrap_or_default(); // TODO: better error handling
}
}
@@ -1690,7 +1683,7 @@ unsafe fn dc_is_reply_to_known_message(context: &Context, mime_parser: &MimePars
/* check if the message is a reply to a known message; the replies are identified by the Message-ID from
`In-Reply-To`/`References:` (to support non-Delta-Clients) or from `Chat-Predecessor:` (Delta clients, see comment in dc_chat.c) */
if let Some(optional_field) = mime_parser.lookup_optional_field("Chat-Predecessor") {
let optional_field_c = CString::new(optional_field).unwrap();
let optional_field_c = CString::new(optional_field).unwrap_or_default();
if 0 != is_known_rfc724_mid(context, optional_field_c.as_ptr()) {
return 1;
}
@@ -1942,8 +1935,7 @@ unsafe fn add_or_lookup_contact_by_addr(
}
*check_self = 0;
let self_addr = context
.sql
.get_config(context, "configured_addr")
.get_config(Config::ConfiguredAddr)
.unwrap_or_default();
if addr_cmp(self_addr, as_str(addr_spec)) {
+1 -1
View File
@@ -86,7 +86,7 @@ pub(crate) fn dc_decode_header_words(input: &str) -> String {
if r as u32 != MAILIMF_NO_ERROR || out.is_null() {
input.to_string()
} else {
let res = to_string(out);
let res = to_string_lossy(out);
free(out.cast());
res
}
+17 -25
View File
@@ -17,6 +17,7 @@ use rand::{thread_rng, Rng};
use crate::context::Context;
use crate::error::Error;
use crate::events::Event;
pub(crate) fn dc_exactly_one_bit_set(v: libc::c_int) -> bool {
0 != v && 0 == v & (v - 1)
@@ -29,11 +30,11 @@ pub(crate) fn dc_exactly_one_bit_set(v: libc::c_int) -> bool {
/// # Examples
///
/// ```
/// use deltachat::dc_tools::{dc_strdup, to_string};
/// use deltachat::dc_tools::{dc_strdup, to_string_lossy};
/// unsafe {
/// let str_a = b"foobar\x00" as *const u8 as *const libc::c_char;
/// let str_a_copy = dc_strdup(str_a);
/// assert_eq!(to_string(str_a_copy), "foobar");
/// assert_eq!(to_string_lossy(str_a_copy), "foobar");
/// assert_ne!(str_a, str_a_copy);
/// }
/// ```
@@ -512,10 +513,14 @@ pub(crate) fn dc_delete_file(context: &Context, path: impl AsRef<std::path::Path
return false;
}
let dpath = format!("{}", path.as_ref().to_string_lossy());
match fs::remove_file(path_abs) {
Ok(_) => true,
Ok(_) => {
context.call_cb(Event::DeletedBlobFile(dpath));
true
}
Err(_err) => {
warn!(context, "Cannot delete \"{}\".", path.as_ref().display());
warn!(context, "Cannot delete \"{}\".", dpath);
false
}
}
@@ -632,7 +637,10 @@ fn dc_make_rel_path(context: &Context, path: &mut String) {
.map(|s| path.starts_with(s))
.unwrap_or_default()
{
*path = path.replace(context.get_blobdir().to_str().unwrap(), "$BLOBDIR");
*path = path.replace(
context.get_blobdir().to_str().unwrap_or_default(),
"$BLOBDIR",
);
}
}
@@ -793,22 +801,6 @@ impl<T: AsRef<str>> StrExt for T {
}
}
pub fn to_string(s: *const libc::c_char) -> String {
if s.is_null() {
return "".into();
}
let cstr = unsafe { CStr::from_ptr(s) };
cstr.to_str().map(|s| s.to_string()).unwrap_or_else(|err| {
panic!(
"Non utf8 string: '{:?}' ({:?})",
cstr.to_string_lossy(),
err
);
})
}
pub fn to_string_lossy(s: *const libc::c_char) -> String {
if s.is_null() {
return "".into();
@@ -1431,8 +1423,8 @@ mod tests {
unsafe {
let res = strndup(b"helloworld\x00" as *const u8 as *const libc::c_char, 4);
assert_eq!(
to_string(res),
to_string(b"hell\x00" as *const u8 as *const libc::c_char)
to_string_lossy(res),
to_string_lossy(b"hell\x00" as *const u8 as *const libc::c_char)
);
assert_eq!(strlen(res), 4);
free(res as *mut _);
@@ -1526,12 +1518,12 @@ mod tests {
unsafe {
let input = "foo\r\nbar".strdup();
dc_remove_cr_chars(input);
assert_eq!("foo\nbar", to_string(input));
assert_eq!("foo\nbar", to_string_lossy(input));
free(input.cast());
let input = "\rfoo\r\rbar\r".strdup();
dc_remove_cr_chars(input);
assert_eq!("foobar", to_string(input));
assert_eq!("foobar", to_string_lossy(input));
free(input.cast());
}
}
+2 -1
View File
@@ -47,7 +47,8 @@ pub struct EncryptHelper {
impl EncryptHelper {
pub fn new(context: &Context) -> Result<EncryptHelper> {
let prefer_encrypt =
EncryptPreference::from_i32(context.get_config_int(Config::E2eeEnabled)).unwrap();
EncryptPreference::from_i32(context.get_config_int(Config::E2eeEnabled))
.unwrap_or_default();
let addr = match context.get_config(Config::ConfiguredAddr) {
None => {
bail!("addr not configured!");
+12
View File
@@ -54,6 +54,18 @@ pub enum Event {
#[strum(props(id = "105"))]
ImapMessageMoved(String),
/// Emitted when an new file in the $BLOBDIR was created
///
/// @return 0
#[strum(props(id = "150"))]
NewBlobFile(String),
/// Emitted when an new file in the $BLOBDIR was created
///
/// @return 0
#[strum(props(id = "151"))]
DeletedBlobFile(String),
/// The library-user should write a warning string to the log.
/// Passed to the callback given to dc_context_new().
///
+32 -18
View File
@@ -693,12 +693,20 @@ impl Imap {
fn get_config_last_seen_uid<S: AsRef<str>>(&self, context: &Context, folder: S) -> (u32, u32) {
let key = format!("imap.mailbox.{}", folder.as_ref());
if let Some(entry) = context.sql.get_config(context, &key) {
if let Some(entry) = context.sql.get_raw_config(context, &key) {
// the entry has the format `imap.mailbox.<folder>=<uidvalidity>:<lastseenuid>`
let mut parts = entry.split(':');
(
parts.next().unwrap().parse().unwrap_or_else(|_| 0),
parts.next().unwrap().parse().unwrap_or_else(|_| 0),
parts
.next()
.unwrap_or_default()
.parse()
.unwrap_or_else(|_| 0),
parts
.next()
.unwrap_or_default()
.parse()
.unwrap_or_else(|_| 0),
)
} else {
(0, 0)
@@ -742,7 +750,7 @@ impl Imap {
return 0;
}
if mailbox.uid_validity.unwrap() != uid_validity {
if mailbox.uid_validity.unwrap_or_default() != uid_validity {
// first time this folder is selected or UIDVALIDITY has changed, init lastseenuid and save it to config
if mailbox.exists == 0 {
@@ -752,7 +760,12 @@ impl Imap {
// id we do not do this here, we'll miss the first message
// as we will get in here again and fetch from lastseenuid+1 then
self.set_config_last_seen_uid(context, &folder, mailbox.uid_validity.unwrap(), 0);
self.set_config_last_seen_uid(
context,
&folder,
mailbox.uid_validity.unwrap_or_default(),
0,
);
return 0;
}
@@ -783,7 +796,7 @@ impl Imap {
last_seen_uid -= 1;
}
uid_validity = mailbox.uid_validity.unwrap();
uid_validity = mailbox.uid_validity.unwrap_or_default();
self.set_config_last_seen_uid(context, &folder, uid_validity, last_seen_uid);
info!(
context,
@@ -884,7 +897,7 @@ impl Imap {
let key = format!("imap.mailbox.{}", folder.as_ref());
let val = format!("{}:{}", uidvalidity, lastseenuid);
context.sql.set_config(context, &key, Some(&val)).ok();
context.sql.set_raw_config(context, &key, Some(&val)).ok();
}
fn fetch_single_msg<S: AsRef<str>>(
@@ -945,7 +958,7 @@ impl Imap {
let flags = if is_seen { DC_IMAP_SEEN } else { 0 };
if !is_deleted && msg.body().is_some() {
let body = msg.body().unwrap();
let body = msg.body().unwrap_or_default();
unsafe {
dc_receive_imf(context, &body, folder.as_ref(), server_uid, flags as u32);
}
@@ -1056,13 +1069,14 @@ impl Imap {
let mut do_fake_idle = true;
while do_fake_idle {
// wait a moment: every 5 seconds in the first 3 minutes after a new message, after that every 60 seconds.
let seconds_to_wait =
if fake_idle_start_time.elapsed().unwrap() < Duration::new(3 * 60, 0) && !wait_long
{
Duration::new(5, 0)
} else {
Duration::new(60, 0)
};
let seconds_to_wait = if fake_idle_start_time.elapsed().unwrap_or_default()
< Duration::new(3 * 60, 0)
&& !wait_long
{
Duration::new(5, 0)
} else {
Duration::new(60, 0)
};
let &(ref lock, ref cvar) = &*self.watch.clone();
let mut watch = lock.lock().unwrap();
@@ -1396,18 +1410,18 @@ impl Imap {
context
.sql
.set_config_int(context, "folders_configured", 3)
.set_raw_config_int(context, "folders_configured", 3)
.ok();
if let Some(ref mvbox_folder) = mvbox_folder {
context
.sql
.set_config(context, "configured_mvbox_folder", Some(mvbox_folder))
.set_raw_config(context, "configured_mvbox_folder", Some(mvbox_folder))
.ok();
}
if let Some(ref sentbox_folder) = sentbox_folder {
context
.sql
.set_config(
.set_raw_config(
context,
"configured_sentbox_folder",
Some(sentbox_folder.name()),
+17 -14
View File
@@ -90,7 +90,7 @@ pub fn has_backup(context: &Context, dir_name: impl AsRef<Path>) -> Result<Strin
let sql = Sql::new();
if sql.open(context, &path, 0x1) {
let curr_backup_time =
sql.get_config_int(context, "backup_time")
sql.get_raw_config_int(context, "backup_time")
.unwrap_or_default() as u64;
if curr_backup_time > newest_backup_time {
newest_backup_path = Some(path);
@@ -263,7 +263,7 @@ pub fn continue_key_transfer(context: &Context, msg_id: u32, setup_code: &str) -
if msg.is_err() {
bail!("Message is no Autocrypt Setup Message.");
}
let msg = msg.unwrap();
let msg = msg.unwrap_or_default();
ensure!(
msg.is_setupmessage(),
"Message is no Autocrypt Setup Message."
@@ -313,7 +313,7 @@ fn set_self_key(
};
context
.sql
.set_config_int(context, "e2ee_enabled", e2ee_enabled)?;
.set_raw_config_int(context, "e2ee_enabled", e2ee_enabled)?;
}
None => {
if prefer_encrypt_required {
@@ -346,7 +346,7 @@ fn set_self_key(
context,
&public_key,
&private_key,
self_addr.unwrap(),
self_addr.unwrap_or_default(),
set_default,
&context.sql,
) {
@@ -682,7 +682,7 @@ fn export_backup(context: &Context, dir: impl AsRef<Path>) -> Result<()> {
}
Ok(())
}
).unwrap();
).unwrap_or_default();
} else {
error!(
context,
@@ -695,7 +695,7 @@ fn export_backup(context: &Context, dir: impl AsRef<Path>) -> Result<()> {
}
if ok_to_continue {
if sql
.set_config_int(context, "backup_time", now as i32)
.set_raw_config_int(context, "backup_time", now as i32)
.is_ok()
{
context.call_cb(Event::ImexFileWritten(dest_path_filename.clone()));
@@ -763,7 +763,7 @@ fn import_self_keys(context: &Context, dir: impl AsRef<Path>) -> Result<()> {
}
let ccontent = if let Ok(content) = dc_read_file(context, &path_plus_name) {
key = String::from_utf8_lossy(&content).to_string();
CString::new(content).unwrap()
CString::new(content).unwrap_or_default()
} else {
continue;
};
@@ -978,16 +978,17 @@ mod tests {
let mut setupcodebegin = ptr::null();
let mut preferencrypt = ptr::null();
let mut buf_1 = S_EM_SETUPFILE.to_string();
unsafe {
assert!(dc_split_armored_data(
buf_1.as_mut_ptr().cast(),
let buf_1 = S_EM_SETUPFILE.strdup();
let res = dc_split_armored_data(
buf_1,
&mut headerline,
&mut setupcodebegin,
&mut preferencrypt,
ptr::null_mut(),
));
);
libc::free(buf_1 as *mut libc::c_void);
assert!(res);
}
assert_eq!(headerline, "-----BEGIN PGP MESSAGE-----");
assert!(!setupcodebegin.is_null());
@@ -998,18 +999,20 @@ mod tests {
assert!(preferencrypt.is_null());
let mut setup_file = S_EM_SETUPFILE.to_string();
let mut decrypted = unsafe {
let decrypted = unsafe {
decrypt_setup_file(context, S_EM_SETUPCODE, setup_file.as_bytes_mut()).unwrap()
};
unsafe {
let buf1 = decrypted.strdup();
assert!(dc_split_armored_data(
decrypted.as_mut_ptr().cast(),
buf1,
&mut headerline,
&mut setupcodebegin,
&mut preferencrypt,
ptr::null_mut(),
));
libc::free(buf1 as *mut libc::c_void);
}
assert_eq!(headerline, "-----BEGIN PGP PRIVATE KEY BLOCK-----");
+20 -39
View File
@@ -12,7 +12,7 @@ use crate::dc_tools::*;
use crate::error::Error;
use crate::events::Event;
use crate::imap::*;
use crate::imex::*;
use crate::imex::job_do_DC_JOB_IMEX_IMAP;
use crate::location;
use crate::login_param::LoginParam;
use crate::message::{self, Message, MessageState};
@@ -219,13 +219,15 @@ impl Job {
if let Ok(msg) = Message::load_from_db(context, self.foreign_id) {
if context
.sql
.get_config_int(context, "folders_configured")
.get_raw_config_int(context, "folders_configured")
.unwrap_or_default()
< 3
{
inbox.configure_folders(context, 0x1i32);
}
let dest_folder = context.sql.get_config(context, "configured_mvbox_folder");
let dest_folder = context
.sql
.get_raw_config(context, "configured_mvbox_folder");
if let Some(dest_folder) = dest_folder {
let server_folder = msg.server_folder.as_ref().unwrap();
@@ -327,13 +329,15 @@ impl Job {
if 0 != self.param.get_int(Param::AlsoMove).unwrap_or_default() {
if context
.sql
.get_config_int(context, "folders_configured")
.get_raw_config_int(context, "folders_configured")
.unwrap_or_default()
< 3
{
inbox.configure_folders(context, 0x1i32);
}
let dest_folder = context.sql.get_config(context, "configured_mvbox_folder");
let dest_folder = context
.sql
.get_raw_config(context, "configured_mvbox_folder");
if let Some(dest_folder) = dest_folder {
let mut dest_uid = 0;
if ImapResult::RetryLater
@@ -364,12 +368,7 @@ pub fn perform_imap_fetch(context: &Context) {
if 0 == connect_to_inbox(context, &inbox) {
return;
}
if context
.sql
.get_config_int(context, "inbox_watch")
.unwrap_or_else(|| 1)
== 0
{
if !context.get_config_bool(Config::InboxWatch) {
info!(context, "INBOX-watch disabled.",);
return;
}
@@ -404,29 +403,23 @@ pub fn perform_imap_idle(context: &Context) {
}
pub fn perform_mvbox_fetch(context: &Context) {
let use_network = context
.sql
.get_config_int(context, "mvbox_watch")
.unwrap_or_else(|| 1);
let use_network = context.get_config_bool(Config::MvboxWatch);
context
.mvbox_thread
.write()
.unwrap()
.fetch(context, use_network == 1);
.fetch(context, use_network);
}
pub fn perform_mvbox_idle(context: &Context) {
let use_network = context
.sql
.get_config_int(context, "mvbox_watch")
.unwrap_or_else(|| 1);
let use_network = context.get_config_bool(Config::MvboxWatch);
context
.mvbox_thread
.read()
.unwrap()
.idle(context, use_network == 1);
.idle(context, use_network);
}
pub fn interrupt_mvbox_idle(context: &Context) {
@@ -434,29 +427,23 @@ pub fn interrupt_mvbox_idle(context: &Context) {
}
pub fn perform_sentbox_fetch(context: &Context) {
let use_network = context
.sql
.get_config_int(context, "sentbox_watch")
.unwrap_or_else(|| 1);
let use_network = context.get_config_bool(Config::SentboxWatch);
context
.sentbox_thread
.write()
.unwrap()
.fetch(context, use_network == 1);
.fetch(context, use_network);
}
pub fn perform_sentbox_idle(context: &Context) {
let use_network = context
.sql
.get_config_int(context, "sentbox_watch")
.unwrap_or_else(|| 1);
let use_network = context.get_config_bool(Config::SentboxWatch);
context
.sentbox_thread
.read()
.unwrap()
.idle(context, use_network == 1);
.idle(context, use_network);
}
pub fn interrupt_sentbox_idle(context: &Context) {
@@ -794,13 +781,8 @@ fn job_perform(context: &Context, thread: Thread, probe_network: bool) {
Action::MarkseenMdnOnImap => job.do_DC_JOB_MARKSEEN_MDN_ON_IMAP(context),
Action::MoveMsg => job.do_DC_JOB_MOVE_MSG(context),
Action::SendMdn => job.do_DC_JOB_SEND(context),
Action::ConfigureImap => unsafe { dc_job_do_DC_JOB_CONFIGURE_IMAP(context) },
Action::ImexImap => match job_do_DC_JOB_IMEX_IMAP(context, &job) {
Ok(()) => {}
Err(err) => {
error!(context, "{}", err);
}
},
Action::ImexImap => job_do_DC_JOB_IMEX_IMAP(context, &job),
Action::ConfigureImap => dc_job_do_DC_JOB_CONFIGURE_IMAP(context),
Action::MaybeSendLocations => {
location::job_do_DC_JOB_MAYBE_SEND_LOCATIONS(context, &job)
}
@@ -947,7 +929,6 @@ fn add_smtp_job(context: &Context, action: Action, mimefactory: &MimeFactory) ->
)
};
let bpath = context.new_blob_file(&mimefactory.rfc724_mid, bytes)?;
info!(context, "add_smtp_job file written: {:?}", bpath);
let recipients = mimefactory.recipients_addr.join("\x1e");
param.set(Param::File, &bpath);
param.set(Param::Recipients, &recipients);
+2 -2
View File
@@ -116,14 +116,14 @@ impl JobThread {
if ret_connected {
if context
.sql
.get_config_int(context, "folders_configured")
.get_raw_config_int(context, "folders_configured")
.unwrap_or_default()
< 3
{
self.imap.configure_folders(context, 0x1);
}
if let Some(mvbox_name) = context.sql.get_config(context, self.folder_config_name) {
if let Some(mvbox_name) = context.sql.get_raw_config(context, self.folder_config_name) {
self.imap.set_watch_folder(mvbox_name);
} else {
self.imap.disconnect(context);
+2 -2
View File
@@ -163,8 +163,8 @@ impl Key {
pub fn to_bytes(&self) -> Vec<u8> {
match self {
Key::Public(k) => k.to_bytes().unwrap(),
Key::Secret(k) => k.to_bytes().unwrap(),
Key::Public(k) => k.to_bytes().unwrap_or_default(),
Key::Secret(k) => k.to_bytes().unwrap_or_default(),
}
}
+4 -4
View File
@@ -3,6 +3,7 @@ use quick_xml;
use quick_xml::events::{BytesEnd, BytesStart, BytesText};
use crate::chat;
use crate::config::Config;
use crate::constants::*;
use crate::context::*;
use crate::dc_tools::*;
@@ -218,7 +219,7 @@ pub fn send_locations_to_chat(context: &Context, chat_id: u32, seconds: i64) {
msg.text =
Some(context.stock_system_msg(StockMessage::MsgLocationEnabled, "", "", 0));
msg.param.set_int(Param::Cmd, 8);
chat::send_msg(context, chat_id, &mut msg).unwrap();
chat::send_msg(context, chat_id, &mut msg).unwrap_or_default();
} else if 0 == seconds && is_sending_locations_before {
let stock_str =
context.stock_system_msg(StockMessage::MsgLocationDisabled, "", "", 0);
@@ -375,8 +376,7 @@ pub fn get_kml(context: &Context, chat_id: u32) -> Result<(String, u32), Error>
let mut last_added_location_id = 0;
let self_addr = context
.sql
.get_config(context, "configured_addr")
.get_config(Config::ConfiguredAddr)
.unwrap_or_default();
let (locations_send_begin, locations_send_until, locations_last_sent) = context.sql.query_row(
@@ -615,7 +615,7 @@ pub fn job_do_DC_JOB_MAYBE_SEND_LOCATIONS(context: &Context, _job: &Job) {
for (chat_id, mut msg) in msgs.into_iter() {
// TODO: better error handling
chat::send_msg(context, chat_id as u32, &mut msg).unwrap();
chat::send_msg(context, chat_id as u32, &mut msg).unwrap_or_default();
}
}
if 0 != continue_streaming {
+26 -26
View File
@@ -51,53 +51,53 @@ impl LoginParam {
let key = format!("{}addr", prefix);
let addr = sql
.get_config(context, key)
.get_raw_config(context, key)
.unwrap_or_default()
.trim()
.to_string();
let key = format!("{}mail_server", prefix);
let mail_server = sql.get_config(context, key).unwrap_or_default();
let mail_server = sql.get_raw_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 mail_port = sql.get_raw_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 mail_user = sql.get_raw_config(context, key).unwrap_or_default();
let key = format!("{}mail_pw", prefix);
let mail_pw = sql.get_config(context, key).unwrap_or_default();
let mail_pw = sql.get_raw_config(context, key).unwrap_or_default();
let key = format!("{}imap_certificate_checks", prefix);
let imap_certificate_checks =
if let Some(certificate_checks) = sql.get_config_int(context, key) {
num_traits::FromPrimitive::from_i32(certificate_checks).unwrap_or_default()
if let Some(certificate_checks) = sql.get_raw_config_int(context, key) {
num_traits::FromPrimitive::from_i32(certificate_checks).unwrap()
} else {
Default::default()
};
let key = format!("{}send_server", prefix);
let send_server = sql.get_config(context, key).unwrap_or_default();
let send_server = sql.get_raw_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 send_port = sql.get_raw_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 send_user = sql.get_raw_config(context, key).unwrap_or_default();
let key = format!("{}send_pw", prefix);
let send_pw = sql.get_config(context, key).unwrap_or_default();
let send_pw = sql.get_raw_config(context, key).unwrap_or_default();
let key = format!("{}smtp_certificate_checks", prefix);
let smtp_certificate_checks =
if let Some(certificate_checks) = sql.get_config_int(context, key) {
num_traits::FromPrimitive::from_i32(certificate_checks).unwrap_or_default()
if let Some(certificate_checks) = sql.get_raw_config_int(context, key) {
num_traits::FromPrimitive::from_i32(certificate_checks).unwrap()
} else {
Default::default()
};
let key = format!("{}server_flags", prefix);
let server_flags = sql.get_config_int(context, key).unwrap_or_default();
let server_flags = sql.get_raw_config_int(context, key).unwrap_or_default();
LoginParam {
addr: addr.to_string(),
@@ -129,40 +129,40 @@ impl LoginParam {
let sql = &context.sql;
let key = format!("{}addr", prefix);
sql.set_config(context, key, Some(&self.addr))?;
sql.set_raw_config(context, key, Some(&self.addr))?;
let key = format!("{}mail_server", prefix);
sql.set_config(context, key, Some(&self.mail_server))?;
sql.set_raw_config(context, key, Some(&self.mail_server))?;
let key = format!("{}mail_port", prefix);
sql.set_config_int(context, key, self.mail_port)?;
sql.set_raw_config_int(context, key, self.mail_port)?;
let key = format!("{}mail_user", prefix);
sql.set_config(context, key, Some(&self.mail_user))?;
sql.set_raw_config(context, key, Some(&self.mail_user))?;
let key = format!("{}mail_pw", prefix);
sql.set_config(context, key, Some(&self.mail_pw))?;
sql.set_raw_config(context, key, Some(&self.mail_pw))?;
let key = format!("{}imap_certificate_checks", prefix);
sql.set_config_int(context, key, self.imap_certificate_checks as i32)?;
sql.set_raw_config_int(context, key, self.imap_certificate_checks as i32)?;
let key = format!("{}send_server", prefix);
sql.set_config(context, key, Some(&self.send_server))?;
sql.set_raw_config(context, key, Some(&self.send_server))?;
let key = format!("{}send_port", prefix);
sql.set_config_int(context, key, self.send_port)?;
sql.set_raw_config_int(context, key, self.send_port)?;
let key = format!("{}send_user", prefix);
sql.set_config(context, key, Some(&self.send_user))?;
sql.set_raw_config(context, key, Some(&self.send_user))?;
let key = format!("{}send_pw", prefix);
sql.set_config(context, key, Some(&self.send_pw))?;
sql.set_raw_config(context, key, Some(&self.send_pw))?;
let key = format!("{}smtp_certificate_checks", prefix);
sql.set_config_int(context, key, self.smtp_certificate_checks as i32)?;
sql.set_raw_config_int(context, key, self.smtp_certificate_checks as i32)?;
let key = format!("{}server_flags", prefix);
sql.set_config_int(context, key, self.server_flags)?;
sql.set_raw_config_int(context, key, self.server_flags)?;
Ok(())
}
+5 -5
View File
@@ -355,7 +355,7 @@ impl Message {
) && buf_headerline == "-----BEGIN PGP MESSAGE-----"
&& !buf_setupcodebegin.is_null()
{
return Some(to_string(buf_setupcodebegin));
return Some(to_string_lossy(buf_setupcodebegin));
}
}
}
@@ -524,7 +524,7 @@ pub fn get_msg_info(context: &Context, msg_id: u32) -> String {
return ret;
}
let msg = msg.unwrap();
let msg = msg.unwrap_or_default();
let rawtxt: Option<String> = context.sql.query_get_value(
context,
@@ -536,7 +536,7 @@ pub fn get_msg_info(context: &Context, msg_id: u32) -> String {
ret += &format!("Cannot load message #{}.", msg_id as usize);
return ret;
}
let rawtxt = rawtxt.unwrap();
let rawtxt = rawtxt.unwrap_or_default();
let rawtxt = dc_truncate(rawtxt.trim(), 100000, false);
let fts = dc_timestamp_to_str(msg.get_timestamp());
@@ -745,7 +745,7 @@ pub fn markseen_msgs(context: &Context, msg_ids: &[u32]) -> bool {
return false;
}
let mut send_event = false;
let msgs = msgs.unwrap();
let msgs = msgs.unwrap_or_default();
for (id, curr_state, curr_blocked) in msgs.into_iter() {
if curr_blocked == Blocked::Not {
@@ -982,7 +982,7 @@ pub fn mdn_from_ext(
context.sql.execute(
"INSERT INTO msgs_mdns (msg_id, contact_id, timestamp_sent) VALUES (?, ?, ?);",
params![*ret_msg_id as i32, from_id as i32, timestamp_sent],
).unwrap(); // TODO: better error handling
).unwrap_or_default(); // TODO: better error handling
}
// Normal chat? that's quite easy.
+9 -8
View File
@@ -60,11 +60,13 @@ pub struct MimeFactory<'a> {
impl<'a> MimeFactory<'a> {
fn new(context: &'a Context, msg: Message) -> Self {
let cget = |context: &Context, name: &str| context.sql.get_config(context, name);
MimeFactory {
from_addr: cget(&context, "configured_addr").unwrap_or_default(),
from_displayname: cget(&context, "displayname").unwrap_or_default(),
selfstatus: cget(&context, "selfstatus")
from_addr: context
.get_config(Config::ConfiguredAddr)
.unwrap_or_default(),
from_displayname: context.get_config(Config::Displayname).unwrap_or_default(),
selfstatus: context
.get_config(Config::Selfstatus)
.unwrap_or_else(|| context.stock_str(StockMessage::StatusLine).to_string()),
recipients_names: Vec::with_capacity(5),
recipients_addr: Vec::with_capacity(5),
@@ -693,7 +695,7 @@ impl<'a> MimeFactory<'a> {
Ok(())
},
)
.unwrap();
.unwrap_or_default();
let command = factory.msg.param.get_cmd();
let msg = &factory.msg;
@@ -703,8 +705,7 @@ impl<'a> MimeFactory<'a> {
let email_to_remove = msg.param.get(Param::Arg).unwrap_or_default();
let self_addr = context
.sql
.get_config(context, "configured_addr")
.get_config(Config::ConfiguredAddr)
.unwrap_or_default();
if !email_to_remove.is_empty() && email_to_remove != self_addr {
@@ -899,7 +900,7 @@ fn build_body_file(
let mime_sub = mailmime_new_empty(content, mime_fields);
let abs_path = dc_get_abs_path(context, path_filename)
.to_c_string()
.unwrap();
.unwrap_or_default();
mailmime_set_body_file(mime_sub, dc_strdup(abs_path.as_ptr()));
Ok((mime_sub, filename_to_send))
}
+12 -12
View File
@@ -50,7 +50,7 @@ pub fn dc_get_oauth2_url(
if let Some(oauth2) = Oauth2::from_address(addr) {
if context
.sql
.set_config(
.set_raw_config(
context,
"oauth2_pending_redirect_uri",
Some(redirect_uri.as_ref()),
@@ -82,17 +82,17 @@ pub fn dc_get_oauth2_access_token(
// read generated token
if !regenerate && !is_expired(context) {
let access_token = context.sql.get_config(context, "oauth2_access_token");
let access_token = context.sql.get_raw_config(context, "oauth2_access_token");
if access_token.is_some() {
// success
return access_token;
}
}
let refresh_token = context.sql.get_config(context, "oauth2_refresh_token");
let refresh_token = context.sql.get_raw_config(context, "oauth2_refresh_token");
let refresh_token_for = context
.sql
.get_config(context, "oauth2_refresh_token_for")
.get_raw_config(context, "oauth2_refresh_token_for")
.unwrap_or_else(|| "unset".into());
let (redirect_uri, token_url, update_redirect_uri_on_success) =
@@ -101,7 +101,7 @@ pub fn dc_get_oauth2_access_token(
(
context
.sql
.get_config(context, "oauth2_pending_redirect_uri")
.get_raw_config(context, "oauth2_pending_redirect_uri")
.unwrap_or_else(|| "unset".into()),
oauth2.init_token,
true,
@@ -114,7 +114,7 @@ pub fn dc_get_oauth2_access_token(
(
context
.sql
.get_config(context, "oauth2_redirect_uri")
.get_raw_config(context, "oauth2_redirect_uri")
.unwrap_or_else(|| "unset".into()),
oauth2.refresh_token,
false,
@@ -159,11 +159,11 @@ pub fn dc_get_oauth2_access_token(
if let Some(ref token) = response.refresh_token {
context
.sql
.set_config(context, "oauth2_refresh_token", Some(token))
.set_raw_config(context, "oauth2_refresh_token", Some(token))
.ok();
context
.sql
.set_config(context, "oauth2_refresh_token_for", Some(code.as_ref()))
.set_raw_config(context, "oauth2_refresh_token_for", Some(code.as_ref()))
.ok();
}
@@ -172,7 +172,7 @@ pub fn dc_get_oauth2_access_token(
if let Some(ref token) = response.access_token {
context
.sql
.set_config(context, "oauth2_access_token", Some(token))
.set_raw_config(context, "oauth2_access_token", Some(token))
.ok();
let expires_in = response
.expires_in
@@ -181,13 +181,13 @@ pub fn dc_get_oauth2_access_token(
.unwrap_or_else(|| 0);
context
.sql
.set_config_int64(context, "oauth2_timestamp_expires", expires_in)
.set_raw_config_int64(context, "oauth2_timestamp_expires", expires_in)
.ok();
if update_redirect_uri_on_success {
context
.sql
.set_config(context, "oauth2_redirect_uri", Some(redirect_uri.as_ref()))
.set_raw_config(context, "oauth2_redirect_uri", Some(redirect_uri.as_ref()))
.ok();
}
} else {
@@ -293,7 +293,7 @@ impl Oauth2 {
fn is_expired(context: &Context) -> bool {
let expire_timestamp = context
.sql
.get_config_int64(context, "oauth2_timestamp_expires")
.get_raw_config_int64(context, "oauth2_timestamp_expires")
.unwrap_or_default();
if expire_timestamp <= 0 {
+2 -2
View File
@@ -122,8 +122,8 @@ impl str::FromStr for Params {
ensure!(key.is_some(), "Missing key");
ensure!(value.is_some(), "Missing value");
let key = key.unwrap().trim();
let value = value.unwrap().trim();
let key = key.unwrap_or_default().trim();
let value = value.unwrap_or_default().trim();
if let Some(key) = Param::from_u8(key.as_bytes()[0]) {
inner.insert(key, value.to_string());
+6 -7
View File
@@ -82,10 +82,7 @@ pub fn dc_get_securejoin_qr(context: &Context, group_chat_id: u32) -> Option<Str
}
};
let self_name = context
.sql
.get_config(context, "displayname")
.unwrap_or_default();
let self_name = context.get_config(Config::Displayname).unwrap_or_default();
fingerprint = match get_self_fingerprint(context) {
Some(fp) => fp,
@@ -213,7 +210,7 @@ pub fn dc_join_securejoin(context: &Context, qr: &str) -> u32 {
info!(context, "Taking protocol shortcut.");
context.bob.write().unwrap().expects = DC_VC_CONTACT_CONFIRM;
joiner_progress!(context, chat_id_2_contact_id(context, contact_chat_id), 400);
let own_fingerprint = get_self_fingerprint(context).unwrap();
let own_fingerprint = get_self_fingerprint(context).unwrap_or_default();
send_handshake_msg(
context,
contact_chat_id,
@@ -294,7 +291,7 @@ fn send_handshake_msg(
msg.param.set_int(Param::GuranteeE2ee, 1);
}
// TODO. handle cleanup on error
chat::send_msg(context, contact_chat_id, &mut msg).unwrap();
chat::send_msg(context, contact_chat_id, &mut msg).unwrap_or_default();
}
fn chat_id_2_contact_id(context: &Context, contact_chat_id: u32) -> u32 {
@@ -678,7 +675,9 @@ fn mark_peer_as_verified(context: &Context, fingerprint: impl AsRef<str>) -> Res
if peerstate.set_verified(1, fingerprint.as_ref(), 2) {
peerstate.prefer_encrypt = EncryptPreference::Mutual;
peerstate.to_save = Some(ToSave::All);
peerstate.save_to_db(&context.sql, false).unwrap();
peerstate
.save_to_db(&context.sql, false)
.unwrap_or_default();
return Ok(());
}
}
+4 -1
View File
@@ -81,7 +81,10 @@ impl Smtp {
}
let user = &lp.send_user;
lettre::smtp::authentication::Credentials::new(user.to_string(), access_token.unwrap())
lettre::smtp::authentication::Credentials::new(
user.to_string(),
access_token.unwrap_or_default(),
)
} else {
// plain
let user = lp.send_user.clone();
+47 -43
View File
@@ -193,14 +193,14 @@ impl Sql {
///
/// Setting `None` deletes the value. On failure an error message
/// will already have been logged.
pub fn set_config(
pub fn set_raw_config(
&self,
context: &Context,
key: impl AsRef<str>,
value: Option<&str>,
) -> Result<()> {
if !self.is_open() {
error!(context, "set_config(): Database not ready.");
error!(context, "set_raw_config(): Database not ready.");
return Err(Error::SqlNoConnection);
}
@@ -234,14 +234,14 @@ impl Sql {
match res {
Ok(_) => Ok(()),
Err(err) => {
error!(context, "set_config(): Cannot change value. {:?}", &err);
error!(context, "set_raw_config(): Cannot change value. {:?}", &err);
Err(err)
}
}
}
/// Get configuration options from the database.
pub fn get_config(&self, context: &Context, key: impl AsRef<str>) -> Option<String> {
pub fn get_raw_config(&self, context: &Context, key: impl AsRef<str>) -> Option<String> {
if !self.is_open() || key.as_ref().is_empty() {
return None;
}
@@ -252,44 +252,46 @@ impl Sql {
)
}
pub fn set_config_int(
pub fn set_raw_config_int(
&self,
context: &Context,
key: impl AsRef<str>,
value: i32,
) -> Result<()> {
self.set_config(context, key, Some(&format!("{}", value)))
self.set_raw_config(context, key, Some(&format!("{}", value)))
}
pub fn get_config_int(&self, context: &Context, key: impl AsRef<str>) -> Option<i32> {
self.get_config(context, key).and_then(|s| s.parse().ok())
pub fn get_raw_config_int(&self, context: &Context, key: impl AsRef<str>) -> Option<i32> {
self.get_raw_config(context, key)
.and_then(|s| s.parse().ok())
}
pub fn get_config_bool(&self, context: &Context, key: impl AsRef<str>) -> bool {
pub fn get_raw_config_bool(&self, context: &Context, key: impl AsRef<str>) -> bool {
// Not the most obvious way to encode bool as string, but it is matter
// of backward compatibility.
self.get_config_int(context, key).unwrap_or_default() > 0
self.get_raw_config_int(context, key).unwrap_or_default() > 0
}
pub fn set_config_bool<T>(&self, context: &Context, key: T, value: bool) -> Result<()>
pub fn set_raw_config_bool<T>(&self, context: &Context, key: T, value: bool) -> Result<()>
where
T: AsRef<str>,
{
let value = if value { Some("1") } else { None };
self.set_config(context, key, value)
self.set_raw_config(context, key, value)
}
pub fn set_config_int64(
pub fn set_raw_config_int64(
&self,
context: &Context,
key: impl AsRef<str>,
value: i64,
) -> Result<()> {
self.set_config(context, key, Some(&format!("{}", value)))
self.set_raw_config(context, key, Some(&format!("{}", value)))
}
pub fn get_config_int64(&self, context: &Context, key: impl AsRef<str>) -> Option<i64> {
self.get_config(context, key).and_then(|r| r.parse().ok())
pub fn get_raw_config_int64(&self, context: &Context, key: impl AsRef<str>) -> Option<i64> {
self.get_raw_config(context, key)
.and_then(|r| r.parse().ok())
}
fn start_stmt(&self, stmt: impl AsRef<str>) {
@@ -477,11 +479,13 @@ fn open(
// cannot create the tables - maybe we cannot write?
return Err(Error::SqlFailedToOpen);
} else {
sql.set_config_int(context, "dbversion", 0)?;
sql.set_raw_config_int(context, "dbversion", 0)?;
}
} else {
exists_before_update = 1;
dbversion_before_update = sql.get_config_int(context, "dbversion").unwrap_or_default();
dbversion_before_update = sql
.get_raw_config_int(context, "dbversion")
.unwrap_or_default();
}
// (1) update low-level database structure.
@@ -503,7 +507,7 @@ fn open(
params![],
)?;
dbversion = 1;
sql.set_config_int(context, "dbversion", 1)?;
sql.set_raw_config_int(context, "dbversion", 1)?;
}
if dbversion < 2 {
info!(context, "[migration] v2");
@@ -512,7 +516,7 @@ fn open(
params![],
)?;
dbversion = 2;
sql.set_config_int(context, "dbversion", 2)?;
sql.set_raw_config_int(context, "dbversion", 2)?;
}
if dbversion < 7 {
info!(context, "[migration] v7");
@@ -527,7 +531,7 @@ fn open(
params![],
)?;
dbversion = 7;
sql.set_config_int(context, "dbversion", 7)?;
sql.set_raw_config_int(context, "dbversion", 7)?;
}
if dbversion < 10 {
info!(context, "[migration] v10");
@@ -546,7 +550,7 @@ fn open(
params![],
)?;
dbversion = 10;
sql.set_config_int(context, "dbversion", 10)?;
sql.set_raw_config_int(context, "dbversion", 10)?;
}
if dbversion < 12 {
info!(context, "[migration] v12");
@@ -559,7 +563,7 @@ fn open(
params![],
)?;
dbversion = 12;
sql.set_config_int(context, "dbversion", 12)?;
sql.set_raw_config_int(context, "dbversion", 12)?;
}
if dbversion < 17 {
info!(context, "[migration] v17");
@@ -574,7 +578,7 @@ fn open(
)?;
sql.execute("CREATE INDEX msgs_index5 ON msgs (starred);", params![])?;
dbversion = 17;
sql.set_config_int(context, "dbversion", 17)?;
sql.set_raw_config_int(context, "dbversion", 17)?;
}
if dbversion < 18 {
info!(context, "[migration] v18");
@@ -584,7 +588,7 @@ fn open(
)?;
sql.execute("ALTER TABLE acpeerstates ADD COLUMN gossip_key;", params![])?;
dbversion = 18;
sql.set_config_int(context, "dbversion", 18)?;
sql.set_raw_config_int(context, "dbversion", 18)?;
}
if dbversion < 27 {
info!(context, "[migration] v27");
@@ -602,7 +606,7 @@ fn open(
params![],
)?;
dbversion = 27;
sql.set_config_int(context, "dbversion", 27)?;
sql.set_raw_config_int(context, "dbversion", 27)?;
}
if dbversion < 34 {
info!(context, "[migration] v34");
@@ -632,7 +636,7 @@ fn open(
)?;
recalc_fingerprints = 1;
dbversion = 34;
sql.set_config_int(context, "dbversion", 34)?;
sql.set_raw_config_int(context, "dbversion", 34)?;
}
if dbversion < 39 {
info!(context, "[migration] v39");
@@ -663,7 +667,7 @@ fn open(
)?;
}
dbversion = 39;
sql.set_config_int(context, "dbversion", 39)?;
sql.set_raw_config_int(context, "dbversion", 39)?;
}
if dbversion < 40 {
info!(context, "[migration] v40");
@@ -672,25 +676,25 @@ fn open(
params![],
)?;
dbversion = 40;
sql.set_config_int(context, "dbversion", 40)?;
sql.set_raw_config_int(context, "dbversion", 40)?;
}
if dbversion < 41 {
info!(context, "[migration] v41");
update_file_paths = 1;
dbversion = 41;
sql.set_config_int(context, "dbversion", 41)?;
sql.set_raw_config_int(context, "dbversion", 41)?;
}
if dbversion < 42 {
info!(context, "[migration] v42");
sql.execute("UPDATE msgs SET txt='' WHERE type!=10", params![])?;
dbversion = 42;
sql.set_config_int(context, "dbversion", 42)?;
sql.set_raw_config_int(context, "dbversion", 42)?;
}
if dbversion < 44 {
info!(context, "[migration] v44");
sql.execute("ALTER TABLE msgs ADD COLUMN mime_headers TEXT;", params![])?;
dbversion = 44;
sql.set_config_int(context, "dbversion", 44)?;
sql.set_raw_config_int(context, "dbversion", 44)?;
}
if dbversion < 46 {
info!(context, "[migration] v46");
@@ -703,7 +707,7 @@ fn open(
params![],
)?;
dbversion = 46;
sql.set_config_int(context, "dbversion", 46)?;
sql.set_raw_config_int(context, "dbversion", 46)?;
}
if dbversion < 47 {
info!(context, "[migration] v47");
@@ -712,7 +716,7 @@ fn open(
params![],
)?;
dbversion = 47;
sql.set_config_int(context, "dbversion", 47)?;
sql.set_raw_config_int(context, "dbversion", 47)?;
}
if dbversion < 48 {
info!(context, "[migration] v48");
@@ -722,7 +726,7 @@ fn open(
)?;
dbversion = 48;
sql.set_config_int(context, "dbversion", 48)?;
sql.set_raw_config_int(context, "dbversion", 48)?;
}
if dbversion < 49 {
info!(context, "[migration] v49");
@@ -731,15 +735,15 @@ fn open(
params![],
)?;
dbversion = 49;
sql.set_config_int(context, "dbversion", 49)?;
sql.set_raw_config_int(context, "dbversion", 49)?;
}
if dbversion < 50 {
info!(context, "[migration] v50");
if 0 != exists_before_update {
sql.set_config_int(context, "show_emails", 2)?;
sql.set_raw_config_int(context, "show_emails", 2)?;
}
dbversion = 50;
sql.set_config_int(context, "dbversion", 50)?;
sql.set_raw_config_int(context, "dbversion", 50)?;
}
if dbversion < 53 {
info!(context, "[migration] v53");
@@ -772,7 +776,7 @@ fn open(
params![],
)?;
dbversion = 53;
sql.set_config_int(context, "dbversion", 53)?;
sql.set_raw_config_int(context, "dbversion", 53)?;
}
if dbversion < 54 {
info!(context, "[migration] v54");
@@ -782,7 +786,7 @@ fn open(
)?;
sql.execute("CREATE INDEX msgs_index6 ON msgs (location_id);", params![])?;
dbversion = 54;
sql.set_config_int(context, "dbversion", 54)?;
sql.set_raw_config_int(context, "dbversion", 54)?;
}
if dbversion < 55 {
info!(context, "[migration] v55");
@@ -791,7 +795,7 @@ fn open(
params![],
)?;
sql.set_config_int(context, "dbversion", 55)?;
sql.set_raw_config_int(context, "dbversion", 55)?;
}
if 0 != recalc_fingerprints {
@@ -818,7 +822,7 @@ fn open(
// this snippet converts older databases and can be removed after some time.
info!(context, "[migration] update file paths");
let repl_from = sql
.get_config(context, "backup_for")
.get_raw_config(context, "backup_for")
.unwrap_or_else(|| context.get_blobdir().to_string_lossy().into());
let repl_from = dc_ensure_no_slash_safe(&repl_from);
@@ -838,7 +842,7 @@ fn open(
NO_PARAMS,
)?;
sql.set_config(context, "backup_for", None)?;
sql.set_raw_config(context, "backup_for", None)?;
}
}
+2 -2
View File
@@ -118,7 +118,7 @@ impl StockMessage {
///
/// These could be used in logging calls, so no logging here.
fn fallback(&self) -> &'static str {
self.get_str("fallback").unwrap()
self.get_str("fallback").unwrap_or_default()
}
}
@@ -133,7 +133,7 @@ impl Context {
if ptr.is_null() {
Cow::Borrowed(id.fallback())
} else {
let ret = to_string(ptr);
let ret = to_string_lossy(ptr);
unsafe { libc::free(ptr as *mut libc::c_void) };
Cow::Owned(ret)
}
+5 -5
View File
@@ -42,7 +42,7 @@ pub fn get_ct_subtype(mime: *mut Mailmime) -> Option<String> {
let ct: *mut mailmime_content = (*mime).mm_content_type;
if !ct.is_null() && !(*ct).ct_subtype.is_null() {
Some(to_string((*ct).ct_subtype))
Some(to_string_lossy((*ct).ct_subtype))
} else {
None
}
@@ -51,7 +51,7 @@ pub fn get_ct_subtype(mime: *mut Mailmime) -> Option<String> {
pub fn parse_message_id(message_id: &str) -> Result<String, Error> {
let mut dummy = 0;
let c_message_id = CString::new(message_id).unwrap();
let c_message_id = CString::new(message_id).unwrap_or_default();
let c_ptr = c_message_id.as_ptr();
let mut rfc724_mid_c = std::ptr::null_mut();
if unsafe { mailimf_msg_id_parse(c_ptr, libc::strlen(c_ptr), &mut dummy, &mut rfc724_mid_c) }
@@ -448,8 +448,8 @@ pub fn append_ct_param(
value: &str,
) -> Result<(), Error> {
unsafe {
let name_c = CString::new(name).unwrap();
let value_c = CString::new(value).unwrap();
let name_c = CString::new(name).unwrap_or_default();
let value_c = CString::new(value).unwrap_or_default();
clist_append!(
(*content).ct_parameters,
@@ -463,7 +463,7 @@ pub fn append_ct_param(
}
pub fn new_content_type(content_type: &str) -> Result<*mut mailmime_content, Error> {
let ct = CString::new(content_type).unwrap();
let ct = CString::new(content_type).unwrap_or_default();
let content: *mut mailmime_content;
// mailmime_content_new_with_str only parses but does not retain/own ct
unsafe {