mirror of
https://github.com/chatmail/core.git
synced 2026-04-03 14:02:10 +03:00
Compare commits
15 Commits
ci/python-
...
test/faile
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0823e82b05 | ||
|
|
c9a8c55d04 | ||
|
|
711bc69750 | ||
|
|
7263c9490d | ||
|
|
0c88bc6ac7 | ||
|
|
fda8d0a2e2 | ||
|
|
14bdf7fae8 | ||
|
|
d4ff7ecbaa | ||
|
|
030aec7373 | ||
|
|
6a351de4f9 | ||
|
|
bbff1c9c3e | ||
|
|
bbb8144129 | ||
|
|
83f3e23297 | ||
|
|
4f880932ae | ||
|
|
62e8c2497c |
@@ -39,8 +39,12 @@ if [ -n "$TESTS" ]; then
|
||||
# run tox. The circle-ci project env-var-setting DCC_PY_LIVECONFIG
|
||||
# allows running of "liveconfig" tests but for speed reasons
|
||||
# we run them only for the highest python version we support
|
||||
|
||||
tox --workdir "$TOXWORKDIR" -e py37
|
||||
|
||||
# we split out qr-tests run to minimize likelyness of flaky tests
|
||||
# (some qr tests are pretty heavy in terms of send/received
|
||||
# messages and rust's imap code likely has concurrency problems)
|
||||
tox --workdir "$TOXWORKDIR" -e py37 -- -k "not qr"
|
||||
tox --workdir "$TOXWORKDIR" -e py37 -- -k "qr"
|
||||
unset DCC_PY_LIVECONFIG
|
||||
tox --workdir "$TOXWORKDIR" -p4 -e lint,py35,py36,doc
|
||||
tox --workdir "$TOXWORKDIR" -e auditwheels
|
||||
|
||||
@@ -11,6 +11,16 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct _dc_context dc_context_t;
|
||||
typedef struct _dc_array dc_array_t;
|
||||
typedef struct _dc_chatlist dc_chatlist_t;
|
||||
typedef struct _dc_chat dc_chat_t;
|
||||
typedef struct _dc_msg dc_msg_t;
|
||||
typedef struct _dc_contact dc_contact_t;
|
||||
typedef struct _dc_lot dc_lot_t;
|
||||
typedef struct _dc_provider dc_provider_t;
|
||||
|
||||
|
||||
/**
|
||||
* @mainpage Getting started
|
||||
*
|
||||
@@ -189,13 +199,6 @@ extern "C" {
|
||||
* SQLite database for offline functionality and for account-related
|
||||
* settings.
|
||||
*/
|
||||
typedef struct _dc_context dc_context_t;
|
||||
typedef struct _dc_array dc_array_t;
|
||||
typedef struct _dc_chatlist dc_chatlist_t;
|
||||
typedef struct _dc_chat dc_chat_t;
|
||||
typedef struct _dc_msg dc_msg_t;
|
||||
typedef struct _dc_contact dc_contact_t;
|
||||
typedef struct _dc_lot dc_lot_t;
|
||||
|
||||
|
||||
/**
|
||||
@@ -442,112 +445,6 @@ char* dc_get_info (dc_context_t* context);
|
||||
*/
|
||||
char* dc_get_oauth2_url (dc_context_t* context, const char* addr, const char* redirect_uri);
|
||||
|
||||
/**
|
||||
* Opaque object containing information about one single email provider.
|
||||
*/
|
||||
typedef struct _dc_provider dc_provider_t;
|
||||
|
||||
/**
|
||||
* Create a provider struct for the given domain.
|
||||
*
|
||||
* @param doamin The domain to get provider info for.
|
||||
* @return a dc_provider_t struct which can be used with the dc_provider_get_*
|
||||
* accessor functions. If no provider info is found, NULL will be
|
||||
* returned.
|
||||
*/
|
||||
dc_provider_t* dc_provider_new_from_domain (char* domain);
|
||||
|
||||
/**
|
||||
* Create a provider struct for the given email address.
|
||||
*
|
||||
* The provider is extracted from the email address and it's information is returned.
|
||||
*
|
||||
* @param email The user's email address to extract the provider info form.
|
||||
* @return a dc_provider_t struct which can be used with the dc_provider_get_*
|
||||
* accessor functions. If no provider info is found, NULL will be
|
||||
* returned.
|
||||
*/
|
||||
dc_provider_t* dc_provider_new_from_email (char* email);
|
||||
|
||||
/**
|
||||
* URL of the overview page.
|
||||
*
|
||||
* This URL allows linking to the providers page on providers.delta.chat.
|
||||
*
|
||||
* @param provider The dc_provider_t struct.
|
||||
* @return A string which must be free()d.
|
||||
*/
|
||||
char* dc_provider_get_overview_page (const dc_provider_t* provider);
|
||||
|
||||
/**
|
||||
* The provider's name.
|
||||
*
|
||||
* The name of the provider, e.g. "POSTEO".
|
||||
*
|
||||
* @param provider The dc_provider_t struct.
|
||||
* @return A string which must be free()d.
|
||||
*/
|
||||
char* dc_provider_get_name (const dc_provider_t* provider);
|
||||
|
||||
/**
|
||||
* The markdown content of the providers page.
|
||||
*
|
||||
* This contains the preparation steps or additional information if the status
|
||||
* is DC_PROVIDER_STATUS_BROKEN.
|
||||
*
|
||||
* @param provider The dc_provider_t struct.
|
||||
* @return A string which must be free()d.
|
||||
*/
|
||||
char* dc_provider_get_markdown (const dc_provider_t* provider);
|
||||
|
||||
/**
|
||||
* Date of when the state was last checked/updated.
|
||||
*
|
||||
* This is returned as a string.
|
||||
*
|
||||
* @param provider The dc_provider_t struct.
|
||||
* @return A string which must be free()d.
|
||||
*/
|
||||
char* dc_provider_get_status_date (const dc_provider_t* provider);
|
||||
|
||||
/**
|
||||
* Whether DC works with this provider.
|
||||
*
|
||||
* Can be one of @ref DC_PROVIDER_STATUS_OK, @ref
|
||||
* DC_PROVIDER_STATUS_PREPARATION and @ref DC_PROVIDER_STATUS_BROKEN.
|
||||
*
|
||||
* @param provider The dc_provider_t struct.
|
||||
* @return The status as a constant number.
|
||||
*/
|
||||
int dc_provider_get_status (const dc_provider_t* provider);
|
||||
|
||||
/**
|
||||
* Free the provider info struct.
|
||||
*
|
||||
* @param provider The dc_provider_t struct.
|
||||
*/
|
||||
void dc_provider_unref (const dc_provider_t* provider);
|
||||
|
||||
/**
|
||||
* Provider status returned by dc_provider_get_status().
|
||||
*
|
||||
* Works right out of the box without any preperation steps needed
|
||||
*/
|
||||
#define DC_PROVIDER_STATUS_OK 1
|
||||
|
||||
/**
|
||||
* Provider status returned by dc_provider_get_status().
|
||||
*
|
||||
* Works, but preparation steps are needed
|
||||
*/
|
||||
#define DC_PROVIDER_STATUS_PREPARATION 2
|
||||
|
||||
/**
|
||||
* Provider status returned by dc_provider_get_status().
|
||||
*
|
||||
* Doesn't work (too unstable to use falls also in this category)
|
||||
*/
|
||||
#define DC_PROVIDER_STATUS_BROKEN 3
|
||||
|
||||
// connect
|
||||
|
||||
@@ -3524,6 +3421,110 @@ int dc_contact_is_blocked (const dc_contact_t* contact);
|
||||
int dc_contact_is_verified (dc_contact_t* contact);
|
||||
|
||||
|
||||
/**
|
||||
* @class dc_provider_t
|
||||
*
|
||||
* Opaque object containing information about one single email provider.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Create a provider struct for the given domain.
|
||||
*
|
||||
* @memberof dc_provider_t
|
||||
* @param domain The domain to get provider info for.
|
||||
* @return a dc_provider_t struct which can be used with the dc_provider_get_*
|
||||
* accessor functions. If no provider info is found, NULL will be
|
||||
* returned.
|
||||
*/
|
||||
dc_provider_t* dc_provider_new_from_domain (char* domain);
|
||||
|
||||
|
||||
/**
|
||||
* Create a provider struct for the given email address.
|
||||
*
|
||||
* The provider is extracted from the email address and it's information is returned.
|
||||
*
|
||||
* @memberof dc_provider_t
|
||||
* @param email The user's email address to extract the provider info form.
|
||||
* @return a dc_provider_t struct which can be used with the dc_provider_get_*
|
||||
* accessor functions. If no provider info is found, NULL will be
|
||||
* returned.
|
||||
*/
|
||||
dc_provider_t* dc_provider_new_from_email (char* email);
|
||||
|
||||
|
||||
/**
|
||||
* URL of the overview page.
|
||||
*
|
||||
* This URL allows linking to the providers page on providers.delta.chat.
|
||||
*
|
||||
* @memberof dc_provider_t
|
||||
* @param provider The dc_provider_t struct.
|
||||
* @return A string which must be free()d.
|
||||
*/
|
||||
char* dc_provider_get_overview_page (const dc_provider_t* provider);
|
||||
|
||||
|
||||
/**
|
||||
* The provider's name.
|
||||
*
|
||||
* The name of the provider, e.g. "POSTEO".
|
||||
*
|
||||
* @memberof dc_provider_t
|
||||
* @param provider The dc_provider_t struct.
|
||||
* @return A string which must be free()d.
|
||||
*/
|
||||
char* dc_provider_get_name (const dc_provider_t* provider);
|
||||
|
||||
|
||||
/**
|
||||
* The markdown content of the providers page.
|
||||
*
|
||||
* This contains the preparation steps or additional information if the status
|
||||
* is @ref DC_PROVIDER_STATUS_BROKEN.
|
||||
*
|
||||
* @memberof dc_provider_t
|
||||
* @param provider The dc_provider_t struct.
|
||||
* @return A string which must be free()d.
|
||||
*/
|
||||
char* dc_provider_get_markdown (const dc_provider_t* provider);
|
||||
|
||||
|
||||
/**
|
||||
* Date of when the state was last checked/updated.
|
||||
*
|
||||
* This is returned as a string.
|
||||
*
|
||||
* @memberof dc_provider_t
|
||||
* @param provider The dc_provider_t struct.
|
||||
* @return A string which must be free()d.
|
||||
*/
|
||||
char* dc_provider_get_status_date (const dc_provider_t* provider);
|
||||
|
||||
|
||||
/**
|
||||
* Whether DC works with this provider.
|
||||
*
|
||||
* Can be one of @ref DC_PROVIDER_STATUS_OK, @ref
|
||||
* DC_PROVIDER_STATUS_PREPARATION and @ref DC_PROVIDER_STATUS_BROKEN.
|
||||
*
|
||||
* @memberof dc_provider_t
|
||||
* @param provider The dc_provider_t struct.
|
||||
* @return The status as a constant number.
|
||||
*/
|
||||
int dc_provider_get_status (const dc_provider_t* provider);
|
||||
|
||||
|
||||
/**
|
||||
* Free the provider info struct.
|
||||
*
|
||||
* @memberof dc_provider_t
|
||||
* @param provider The dc_provider_t struct.
|
||||
*/
|
||||
void dc_provider_unref (const dc_provider_t* provider);
|
||||
|
||||
|
||||
/**
|
||||
* @class dc_lot_t
|
||||
*
|
||||
@@ -4131,6 +4132,41 @@ void dc_array_add_id (dc_array_t*, uint32_t); // depreca
|
||||
#define DC_SHOW_EMAILS_ALL 2
|
||||
|
||||
|
||||
/**
|
||||
* @defgroup DC_PROVIDER_STATUS DC_PROVIDER_STATUS
|
||||
*
|
||||
* These constants are used as return values for dc_provider_get_status().
|
||||
*
|
||||
* @addtogroup DC_PROVIDER_STATUS
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Provider status returned by dc_provider_get_status().
|
||||
*
|
||||
* Works right out of the box without any preperation steps needed
|
||||
*/
|
||||
#define DC_PROVIDER_STATUS_OK 1
|
||||
|
||||
/**
|
||||
* Provider status returned by dc_provider_get_status().
|
||||
*
|
||||
* Works, but preparation steps are needed
|
||||
*/
|
||||
#define DC_PROVIDER_STATUS_PREPARATION 2
|
||||
|
||||
/**
|
||||
* Provider status returned by dc_provider_get_status().
|
||||
*
|
||||
* Doesn't work (too unstable to use falls also in this category)
|
||||
*/
|
||||
#define DC_PROVIDER_STATUS_BROKEN 3
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* TODO: Strings need some doumentation about used placeholders.
|
||||
*
|
||||
|
||||
@@ -150,7 +150,7 @@ def acfactory(pytestconfig, tmpdir, request, session_liveconfig):
|
||||
lib.dc_set_config(ac._dc_context, b"configured", b"1")
|
||||
return ac
|
||||
|
||||
def get_online_configuring_account(self):
|
||||
def get_online_config(self):
|
||||
if not session_liveconfig:
|
||||
pytest.skip("specify DCC_PY_LIVECONFIG or --liveconfig")
|
||||
configdict = session_liveconfig.get(self.live_count)
|
||||
@@ -161,6 +161,10 @@ def acfactory(pytestconfig, tmpdir, request, session_liveconfig):
|
||||
ac = self.make_account(tmpdb.strpath, logid="ac{}".format(self.live_count))
|
||||
ac._evlogger.init_time = self.init_time
|
||||
ac._evlogger.set_timeout(30)
|
||||
return ac, dict(configdict)
|
||||
|
||||
def get_online_configuring_account(self):
|
||||
ac, configdict = self.get_online_config()
|
||||
ac.configure(**configdict)
|
||||
ac.start_threads()
|
||||
return ac
|
||||
@@ -206,12 +210,13 @@ def lp():
|
||||
return Printer()
|
||||
|
||||
|
||||
def wait_configuration_progress(account, target):
|
||||
def wait_configuration_progress(account, min_target, max_target=1001):
|
||||
min_target = min(min_target, max_target)
|
||||
while 1:
|
||||
evt_name, data1, data2 = \
|
||||
account._evlogger.get_matching("DC_EVENT_CONFIGURE_PROGRESS")
|
||||
if data1 >= target:
|
||||
print("** CONFIG PROGRESS {}".format(target), account)
|
||||
if data1 >= min_target and data1 <= max_target:
|
||||
print("** CONFIG PROGRESS {}".format(min_target), account)
|
||||
break
|
||||
|
||||
|
||||
|
||||
@@ -616,3 +616,32 @@ class TestOnlineAccount:
|
||||
chat1b = ac1.create_chat_by_message(ev[2])
|
||||
assert chat1b.get_profile_image() is None
|
||||
assert chat.get_profile_image() is None
|
||||
|
||||
|
||||
class TestOnlineConfigureFails:
|
||||
def test_invalid_password(self, acfactory):
|
||||
ac1, configdict = acfactory.get_online_config()
|
||||
ac1.configure(addr=configdict["addr"], mail_pw="123")
|
||||
ac1.start_threads()
|
||||
wait_configuration_progress(ac1, 500)
|
||||
ev1 = ac1._evlogger.get_matching("DC_EVENT_ERROR_NETWORK")
|
||||
assert "authentication failed" in ev1[2].lower()
|
||||
wait_configuration_progress(ac1, 0, 0)
|
||||
|
||||
def test_invalid_user(self, acfactory):
|
||||
ac1, configdict = acfactory.get_online_config()
|
||||
ac1.configure(addr="x" + configdict["addr"], mail_pw=configdict["mail_pw"])
|
||||
ac1.start_threads()
|
||||
wait_configuration_progress(ac1, 500)
|
||||
ev1 = ac1._evlogger.get_matching("DC_EVENT_ERROR_NETWORK")
|
||||
assert "authentication failed" in ev1[2].lower()
|
||||
wait_configuration_progress(ac1, 0, 0)
|
||||
|
||||
def test_invalid_domain(self, acfactory):
|
||||
ac1, configdict = acfactory.get_online_config()
|
||||
ac1.configure(addr=configdict["addr"] + "x", mail_pw=configdict["mail_pw"])
|
||||
ac1.start_threads()
|
||||
wait_configuration_progress(ac1, 500)
|
||||
ev1 = ac1._evlogger.get_matching("DC_EVENT_ERROR_NETWORK")
|
||||
assert "could not connect" in ev1[2].lower()
|
||||
wait_configuration_progress(ac1, 0, 0)
|
||||
|
||||
23
src/chat.rs
23
src/chat.rs
@@ -1,6 +1,5 @@
|
||||
use std::ffi::CString;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::ptr;
|
||||
|
||||
use crate::chatlist::*;
|
||||
use crate::config::*;
|
||||
@@ -16,7 +15,6 @@ use crate::message::*;
|
||||
use crate::param::*;
|
||||
use crate::sql::{self, Sql};
|
||||
use crate::stock::StockMessage;
|
||||
use crate::x::*;
|
||||
|
||||
/// An object representing a single chat in memory.
|
||||
/// Chat objects are created using eg. `Chat::load_from_db`
|
||||
@@ -272,7 +270,7 @@ impl Chat {
|
||||
Chattype::Group | Chattype::VerifiedGroup => Some(self.grpid.as_str()),
|
||||
_ => None,
|
||||
};
|
||||
dc_create_outgoing_rfc724_mid_safe(grpid, &from)
|
||||
dc_create_outgoing_rfc724_mid(grpid, &from)
|
||||
};
|
||||
|
||||
if self.typ == Chattype::Single {
|
||||
@@ -1840,12 +1838,7 @@ pub fn get_chat_id_by_grpid(context: &Context, grpid: impl AsRef<str>) -> (u32,
|
||||
}
|
||||
|
||||
pub fn add_device_msg(context: &Context, chat_id: u32, text: impl AsRef<str>) {
|
||||
let rfc724_mid = unsafe {
|
||||
dc_create_outgoing_rfc724_mid(
|
||||
ptr::null(),
|
||||
b"@device\x00" as *const u8 as *const libc::c_char,
|
||||
)
|
||||
};
|
||||
let rfc724_mid = dc_create_outgoing_rfc724_mid(None, "@device");
|
||||
|
||||
if context.sql.execute(
|
||||
"INSERT INTO msgs (chat_id,from_id,to_id, timestamp,type,state, txt,rfc724_mid) VALUES (?,?,?, ?,?,?, ?,?);",
|
||||
@@ -1857,21 +1850,13 @@ pub fn add_device_msg(context: &Context, chat_id: u32, text: impl AsRef<str>) {
|
||||
Viewtype::Text,
|
||||
MessageState::InNoticed,
|
||||
text.as_ref(),
|
||||
as_str(rfc724_mid),
|
||||
rfc724_mid,
|
||||
]
|
||||
).is_err() {
|
||||
unsafe { free(rfc724_mid as *mut libc::c_void) };
|
||||
return;
|
||||
}
|
||||
|
||||
let msg_id = sql::get_rowid(
|
||||
context,
|
||||
&context.sql,
|
||||
"msgs",
|
||||
"rfc724_mid",
|
||||
as_str(rfc724_mid),
|
||||
);
|
||||
unsafe { free(rfc724_mid as *mut libc::c_void) };
|
||||
let msg_id = sql::get_rowid(context, &context.sql, "msgs", "rfc724_mid", &rfc724_mid);
|
||||
context.call_cb(Event::MsgsChanged { chat_id, msg_id });
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ use auto_mozilla::moz_autoconfigure;
|
||||
macro_rules! progress {
|
||||
($context:tt, $progress:expr) => {
|
||||
assert!(
|
||||
$progress > 0 && $progress <= 1000,
|
||||
$progress <= 1000,
|
||||
"value in range 0..1000 expected with: 0=error, 1..999=progress, 1000=success"
|
||||
);
|
||||
$context.call_cb($crate::events::Event::ConfigureProgress($progress));
|
||||
@@ -660,3 +660,36 @@ pub fn read_autoconf_file(context: &Context, url: &str) -> *mut libc::c_char {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use crate::config::*;
|
||||
use crate::configure::dc_job_do_DC_JOB_CONFIGURE_IMAP;
|
||||
use crate::job::*;
|
||||
use crate::param::*;
|
||||
use crate::test_utils::*;
|
||||
|
||||
#[test]
|
||||
fn test_no_panic_on_bad_credentials() {
|
||||
let t = dummy_context();
|
||||
t.ctx
|
||||
.set_config(Config::Addr, Some("probably@unexistant.addr"))
|
||||
.unwrap();
|
||||
t.ctx.set_config(Config::MailPw, Some("123456")).unwrap();
|
||||
let job = Job {
|
||||
job_id: 1,
|
||||
action: Action::ConfigureImap,
|
||||
foreign_id: 0,
|
||||
desired_timestamp: 0,
|
||||
added_timestamp: 0,
|
||||
tries: 0,
|
||||
param: Params::new(),
|
||||
try_again: 0,
|
||||
pending_error: None,
|
||||
};
|
||||
unsafe {
|
||||
dc_job_do_DC_JOB_CONFIGURE_IMAP(&t.ctx, &job);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,7 +362,7 @@ impl Context {
|
||||
}
|
||||
|
||||
if self.is_mvbox(folder) {
|
||||
dc_update_msg_move_state(self, msg.rfc724_mid, MoveState::Stay);
|
||||
dc_update_msg_move_state(self, &msg.rfc724_mid, MoveState::Stay);
|
||||
}
|
||||
|
||||
// 1 = dc message, 2 = reply to dc message
|
||||
@@ -374,7 +374,7 @@ impl Context {
|
||||
Params::new(),
|
||||
0,
|
||||
);
|
||||
dc_update_msg_move_state(self, msg.rfc724_mid, MoveState::Moving);
|
||||
dc_update_msg_move_state(self, &msg.rfc724_mid, MoveState::Moving);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ pub struct dc_mimefactory_t<'a> {
|
||||
pub recipients_names: *mut clist,
|
||||
pub recipients_addr: *mut clist,
|
||||
pub timestamp: i64,
|
||||
pub rfc724_mid: *mut libc::c_char,
|
||||
pub rfc724_mid: String,
|
||||
pub loaded: dc_mimefactory_loaded_t,
|
||||
pub msg: Message,
|
||||
pub chat: Option<Chat>,
|
||||
@@ -57,7 +57,6 @@ impl<'a> Drop for dc_mimefactory_t<'a> {
|
||||
unsafe {
|
||||
free(self.from_addr as *mut libc::c_void);
|
||||
free(self.from_displayname as *mut libc::c_void);
|
||||
free(self.rfc724_mid as *mut libc::c_void);
|
||||
if !self.recipients_names.is_null() {
|
||||
clist_free_content(self.recipients_names);
|
||||
clist_free(self.recipients_names);
|
||||
@@ -98,7 +97,7 @@ pub unsafe fn dc_mimefactory_load_msg(
|
||||
recipients_names: clist_new(),
|
||||
recipients_addr: clist_new(),
|
||||
timestamp: 0,
|
||||
rfc724_mid: ptr::null_mut(),
|
||||
rfc724_mid: String::default(),
|
||||
loaded: DC_MF_NOTHING_LOADED,
|
||||
msg,
|
||||
chat: Some(chat),
|
||||
@@ -232,7 +231,7 @@ pub unsafe fn dc_mimefactory_load_msg(
|
||||
|
||||
factory.loaded = DC_MF_MSG_LOADED;
|
||||
factory.timestamp = factory.msg.timestamp_sort;
|
||||
factory.rfc724_mid = dc_strdup(factory.msg.rfc724_mid);
|
||||
factory.rfc724_mid = factory.msg.rfc724_mid.clone();
|
||||
factory.increation = dc_msg_is_increation(&factory.msg);
|
||||
|
||||
Ok(factory)
|
||||
@@ -288,7 +287,7 @@ pub unsafe fn dc_mimefactory_load_mdn<'a>(
|
||||
recipients_names: clist_new(),
|
||||
recipients_addr: clist_new(),
|
||||
timestamp: 0,
|
||||
rfc724_mid: ptr::null_mut(),
|
||||
rfc724_mid: String::default(),
|
||||
loaded: DC_MF_NOTHING_LOADED,
|
||||
msg,
|
||||
chat: None,
|
||||
@@ -330,7 +329,7 @@ pub unsafe fn dc_mimefactory_load_mdn<'a>(
|
||||
);
|
||||
load_from(&mut factory);
|
||||
factory.timestamp = dc_create_smeared_timestamp(factory.context);
|
||||
factory.rfc724_mid = dc_create_outgoing_rfc724_mid(0 as *const libc::c_char, factory.from_addr);
|
||||
factory.rfc724_mid = dc_create_outgoing_rfc724_mid(None, as_str(factory.from_addr));
|
||||
factory.loaded = DC_MF_MDN_LOADED;
|
||||
|
||||
Ok(factory)
|
||||
@@ -447,7 +446,7 @@ pub unsafe fn dc_mimefactory_render(context: &Context, factory: &mut dc_mimefact
|
||||
to,
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
dc_strdup(factory.rfc724_mid),
|
||||
factory.rfc724_mid.strdup(),
|
||||
in_reply_to_list,
|
||||
references_list,
|
||||
ptr::null_mut(),
|
||||
@@ -951,7 +950,7 @@ pub unsafe fn dc_mimefactory_render(context: &Context, factory: &mut dc_mimefact
|
||||
version,
|
||||
as_str(factory.from_addr),
|
||||
as_str(factory.from_addr),
|
||||
as_str(factory.msg.rfc724_mid)
|
||||
factory.msg.rfc724_mid
|
||||
).strdup();
|
||||
|
||||
let content_type_0: *mut mailmime_content = mailmime_content_new_with_str(
|
||||
|
||||
@@ -995,6 +995,19 @@ impl<'a> MimeParser<'a> {
|
||||
|
||||
assert_eq!(self.parts.len(), 1);
|
||||
}
|
||||
|
||||
pub fn get_rfc724_mid(&mut self) -> Option<String> {
|
||||
// get Message-ID from header
|
||||
if let Some(field) = self.lookup_field_typ("Message-ID", MAILIMF_FIELD_MESSAGE_ID) {
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for MimeParser<'a> {
|
||||
@@ -1641,6 +1654,27 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_rfc724_mid_exists() {
|
||||
let context = dummy_context();
|
||||
let raw = include_bytes!("../test-data/message/mail_with_message_id.txt");
|
||||
let mut mimeparser = MimeParser::new(&context.ctx);
|
||||
unsafe { mimeparser.parse(&raw[..]) };
|
||||
assert_eq!(
|
||||
mimeparser.get_rfc724_mid(),
|
||||
Some("2dfdbde7@example.org".into())
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_rfc724_mid_not_exists() {
|
||||
let context = dummy_context();
|
||||
let raw = include_bytes!("../test-data/message/issue_523.txt");
|
||||
let mut mimeparser = MimeParser::new(&context.ctx);
|
||||
unsafe { mimeparser.parse(&raw[..]) };
|
||||
assert_eq!(mimeparser.get_rfc724_mid(), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mimeparser_with_context() {
|
||||
unsafe {
|
||||
|
||||
@@ -85,8 +85,6 @@ pub unsafe fn dc_receive_imf(
|
||||
let mut add_delete_job: libc::c_int = 0;
|
||||
let mut insert_msg_id = 0;
|
||||
|
||||
// Message-ID from the header
|
||||
let rfc724_mid = std::ptr::null_mut();
|
||||
let mut sent_timestamp = 0;
|
||||
let mut created_db_entries = Vec::new();
|
||||
let mut create_event_to_send = Some(CreateEvent::MsgsChanged);
|
||||
@@ -96,12 +94,9 @@ pub unsafe fn dc_receive_imf(
|
||||
|
||||
// helper method to handle early exit and memory cleanup
|
||||
let cleanup = |context: &Context,
|
||||
rfc724_mid: *mut libc::c_char,
|
||||
create_event_to_send: &Option<CreateEvent>,
|
||||
created_db_entries: &Vec<(usize, usize)>,
|
||||
rr_event_to_send: &Vec<(u32, u32)>| {
|
||||
free(rfc724_mid.cast());
|
||||
|
||||
if let Some(create_event_to_send) = create_event_to_send {
|
||||
for (chat_id, msg_id) in created_db_entries {
|
||||
let event = match create_event_to_send {
|
||||
@@ -184,6 +179,28 @@ pub unsafe fn dc_receive_imf(
|
||||
}
|
||||
|
||||
// Add parts
|
||||
|
||||
let rfc724_mid = match mime_parser.get_rfc724_mid() {
|
||||
Some(x) => x,
|
||||
None => {
|
||||
// missing Message-IDs may come if the mail was set from this account with another
|
||||
// client that relies in the SMTP server to generate one.
|
||||
// true eg. for the Webmailer used in all-inkl-KAS
|
||||
match dc_create_incoming_rfc724_mid(sent_timestamp, from_id, &to_ids) {
|
||||
Some(x) => x.to_string(),
|
||||
None => {
|
||||
error!(context, "can not create incoming rfc724_mid");
|
||||
cleanup(
|
||||
context,
|
||||
&create_event_to_send,
|
||||
&created_db_entries,
|
||||
&rr_event_to_send,
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
if mime_parser.get_last_nonmeta().is_some() {
|
||||
if let Err(err) = add_parts(
|
||||
context,
|
||||
@@ -195,7 +212,7 @@ pub unsafe fn dc_receive_imf(
|
||||
server_folder.as_ref(),
|
||||
server_uid,
|
||||
&mut to_ids,
|
||||
rfc724_mid,
|
||||
&rfc724_mid,
|
||||
&mut sent_timestamp,
|
||||
&mut from_id,
|
||||
from_id_blocked,
|
||||
@@ -213,7 +230,6 @@ pub unsafe fn dc_receive_imf(
|
||||
|
||||
cleanup(
|
||||
context,
|
||||
rfc724_mid,
|
||||
&create_event_to_send,
|
||||
&created_db_entries,
|
||||
&rr_event_to_send,
|
||||
@@ -263,14 +279,11 @@ pub unsafe fn dc_receive_imf(
|
||||
|
||||
info!(
|
||||
context,
|
||||
"received message {} has Message-Id: {}",
|
||||
server_uid,
|
||||
to_string(rfc724_mid)
|
||||
"received message {} has Message-Id: {}", server_uid, rfc724_mid
|
||||
);
|
||||
|
||||
cleanup(
|
||||
context,
|
||||
rfc724_mid,
|
||||
&create_event_to_send,
|
||||
&created_db_entries,
|
||||
&rr_event_to_send,
|
||||
@@ -287,7 +300,7 @@ unsafe fn add_parts(
|
||||
server_folder: impl AsRef<str>,
|
||||
server_uid: u32,
|
||||
to_ids: &mut Vec<u32>,
|
||||
mut rfc724_mid: *mut libc::c_char,
|
||||
rfc724_mid: &str,
|
||||
sent_timestamp: &mut i64,
|
||||
from_id: &mut u32,
|
||||
from_id_blocked: i32,
|
||||
@@ -336,25 +349,6 @@ unsafe fn add_parts(
|
||||
}
|
||||
}
|
||||
|
||||
// get Message-ID; if the header is lacking one, generate one based on fields that do never
|
||||
// change. (missing Message-IDs may come if the mail was set from this account with another
|
||||
// client that relies in the SMTP server to generate one.
|
||||
// true eg. for the Webmailer used in all-inkl-KAS)
|
||||
if let Some(field) = mime_parser.lookup_field_typ("Message-ID", MAILIMF_FIELD_MESSAGE_ID) {
|
||||
let fld_message_id = (*field).fld_data.fld_message_id;
|
||||
if !fld_message_id.is_null() {
|
||||
rfc724_mid = dc_strdup((*fld_message_id).mid_value)
|
||||
}
|
||||
}
|
||||
|
||||
if rfc724_mid.is_null() {
|
||||
rfc724_mid = dc_create_incoming_rfc724_mid(*sent_timestamp, *from_id, to_ids);
|
||||
if rfc724_mid.is_null() {
|
||||
cleanup(mime_in_reply_to, mime_references);
|
||||
bail!("Cannot create Message-ID");
|
||||
}
|
||||
}
|
||||
|
||||
// check, if the mail is already in our database - if so, just update the folder/uid
|
||||
// (if the mail was moved around) and finish. (we may get a mail twice eg. if it is
|
||||
// moved between folders. make sure, this check is done eg. before securejoin-processing) */
|
||||
@@ -363,12 +357,12 @@ unsafe fn add_parts(
|
||||
|
||||
if 0 != dc_rfc724_mid_exists(
|
||||
context,
|
||||
rfc724_mid,
|
||||
&rfc724_mid,
|
||||
&mut old_server_folder,
|
||||
&mut old_server_uid,
|
||||
) {
|
||||
if as_str(old_server_folder) != server_folder.as_ref() || old_server_uid != server_uid {
|
||||
dc_update_server_uid(context, rfc724_mid, server_folder.as_ref(), server_uid);
|
||||
dc_update_server_uid(context, &rfc724_mid, server_folder.as_ref(), server_uid);
|
||||
}
|
||||
|
||||
free(old_server_folder.cast());
|
||||
@@ -667,7 +661,7 @@ unsafe fn add_parts(
|
||||
}
|
||||
|
||||
stmt.execute(params![
|
||||
as_str(rfc724_mid),
|
||||
rfc724_mid,
|
||||
server_folder.as_ref(),
|
||||
server_uid as libc::c_int,
|
||||
*chat_id as libc::c_int,
|
||||
@@ -698,13 +692,8 @@ unsafe fn add_parts(
|
||||
])?;
|
||||
|
||||
txt_raw = None;
|
||||
*insert_msg_id = sql::get_rowid_with_conn(
|
||||
context,
|
||||
conn,
|
||||
"msgs",
|
||||
"rfc724_mid",
|
||||
as_str(rfc724_mid),
|
||||
);
|
||||
*insert_msg_id =
|
||||
sql::get_rowid_with_conn(context, conn, "msgs", "rfc724_mid", &rfc724_mid);
|
||||
created_db_entries.push((*chat_id as usize, *insert_msg_id as usize));
|
||||
}
|
||||
Ok(())
|
||||
@@ -867,7 +856,7 @@ unsafe fn handle_reports(
|
||||
if 0 != dc_mdn_from_ext(
|
||||
context,
|
||||
from_id,
|
||||
rfc724_mid_0,
|
||||
as_str(rfc724_mid_0),
|
||||
sent_timestamp,
|
||||
&mut chat_id_0,
|
||||
&mut msg_id,
|
||||
@@ -1870,11 +1859,11 @@ unsafe fn is_msgrmsg_rfc724_mid_in_list(context: &Context, mid_list: *const clis
|
||||
while !cur.is_null() {
|
||||
if 0 != is_msgrmsg_rfc724_mid(
|
||||
context,
|
||||
(if !cur.is_null() {
|
||||
(*cur).data
|
||||
if !cur.is_null() {
|
||||
as_str((*cur).data as *const libc::c_char)
|
||||
} else {
|
||||
ptr::null_mut()
|
||||
}) as *const libc::c_char,
|
||||
""
|
||||
},
|
||||
) {
|
||||
return 1;
|
||||
}
|
||||
@@ -1889,15 +1878,15 @@ unsafe fn is_msgrmsg_rfc724_mid_in_list(context: &Context, mid_list: *const clis
|
||||
}
|
||||
|
||||
/// Check if a message is a reply to any messenger message.
|
||||
fn is_msgrmsg_rfc724_mid(context: &Context, rfc724_mid: *const libc::c_char) -> libc::c_int {
|
||||
if rfc724_mid.is_null() {
|
||||
fn is_msgrmsg_rfc724_mid(context: &Context, rfc724_mid: &str) -> libc::c_int {
|
||||
if rfc724_mid.is_empty() {
|
||||
return 0;
|
||||
}
|
||||
context
|
||||
.sql
|
||||
.exists(
|
||||
"SELECT id FROM msgs WHERE rfc724_mid=? AND msgrmsg!=0 AND chat_id>9;",
|
||||
params![as_str(rfc724_mid)],
|
||||
params![rfc724_mid],
|
||||
)
|
||||
.unwrap_or_default() as libc::c_int
|
||||
}
|
||||
|
||||
@@ -572,9 +572,9 @@ pub fn dc_create_incoming_rfc724_mid(
|
||||
message_timestamp: i64,
|
||||
contact_id_from: u32,
|
||||
contact_ids_to: &Vec<u32>,
|
||||
) -> *mut libc::c_char {
|
||||
) -> Option<String> {
|
||||
if contact_ids_to.is_empty() {
|
||||
return ptr::null_mut();
|
||||
return None;
|
||||
}
|
||||
/* find out the largest receiver ID (we could also take the smallest, but it should be unique) */
|
||||
let largest_id_to = contact_ids_to.iter().max().copied().unwrap_or_default();
|
||||
@@ -583,37 +583,14 @@ pub fn dc_create_incoming_rfc724_mid(
|
||||
"{}-{}-{}@stub",
|
||||
message_timestamp, contact_id_from, largest_id_to
|
||||
);
|
||||
|
||||
unsafe { result.strdup() }
|
||||
Some(result)
|
||||
}
|
||||
|
||||
/// Function generates a Message-ID that can be used for a new outgoing message.
|
||||
/// - this function is called for all outgoing messages.
|
||||
/// - the message ID should be globally unique
|
||||
/// - do not add a counter or any private data as as this may give unneeded information to the receiver
|
||||
pub unsafe fn dc_create_outgoing_rfc724_mid(
|
||||
grpid: *const libc::c_char,
|
||||
from_addr: *const libc::c_char,
|
||||
) -> *mut libc::c_char {
|
||||
let rand2 = dc_create_id();
|
||||
|
||||
let at_hostname = as_opt_str(strchr(from_addr, '@' as i32)).unwrap_or_else(|| "@nohost");
|
||||
|
||||
let ret = if !grpid.is_null() {
|
||||
format!("Gr.{}.{}{}", as_str(grpid), rand2, at_hostname,)
|
||||
} else {
|
||||
let rand1 = dc_create_id();
|
||||
format!("Mr.{}.{}{}", rand1, rand2, at_hostname)
|
||||
};
|
||||
|
||||
ret.strdup()
|
||||
}
|
||||
|
||||
/// Generate globally-unique message-id for a new outgoing message.
|
||||
///
|
||||
/// Note: Do not add a counter or any private data as as this may give
|
||||
/// unneeded information to the receiver
|
||||
pub fn dc_create_outgoing_rfc724_mid_safe(grpid: Option<&str>, from_addr: &str) -> String {
|
||||
/// - do not add a counter or any private data as this leaks information unncessarily
|
||||
pub fn dc_create_outgoing_rfc724_mid(grpid: Option<&str>, from_addr: &str) -> String {
|
||||
let hostname = from_addr
|
||||
.find('@')
|
||||
.map(|k| &from_addr[k..])
|
||||
@@ -1813,10 +1790,6 @@ mod tests {
|
||||
#[test]
|
||||
fn test_dc_create_incoming_rfc724_mid() {
|
||||
let res = dc_create_incoming_rfc724_mid(123, 45, &vec![6, 7]);
|
||||
assert_eq!(as_str(res), "123-45-7@stub");
|
||||
|
||||
unsafe {
|
||||
free(res.cast());
|
||||
}
|
||||
assert_eq!(res, Some("123-45-7@stub".into()));
|
||||
}
|
||||
}
|
||||
|
||||
23
src/imap.rs
23
src/imap.rs
@@ -1,4 +1,3 @@
|
||||
use std::ffi::CString;
|
||||
use std::net;
|
||||
use std::ptr;
|
||||
use std::sync::{
|
||||
@@ -10,7 +9,6 @@ use std::time::{Duration, SystemTime};
|
||||
use crate::constants::*;
|
||||
use crate::context::Context;
|
||||
use crate::dc_receive_imf::dc_receive_imf;
|
||||
use crate::dc_tools::CStringExt;
|
||||
use crate::dc_tools::*;
|
||||
use crate::events::Event;
|
||||
use crate::job::{job_add, Action};
|
||||
@@ -821,10 +819,7 @@ impl Imap {
|
||||
.message_id
|
||||
.expect("missing message id");
|
||||
|
||||
if 0 == unsafe {
|
||||
let message_id_c = CString::yolo(message_id);
|
||||
precheck_imf(context, message_id_c.as_ptr(), folder.as_ref(), cur_uid)
|
||||
} {
|
||||
if 0 == unsafe { precheck_imf(context, &message_id, folder.as_ref(), cur_uid) } {
|
||||
// check passed, go fetch the rest
|
||||
if self.fetch_single_msg(context, &folder, cur_uid) == 0 {
|
||||
info!(
|
||||
@@ -1645,7 +1640,7 @@ fn get_folder_meaning(folder_name: &imap::types::Name) -> FolderMeaning {
|
||||
|
||||
unsafe fn precheck_imf(
|
||||
context: &Context,
|
||||
rfc724_mid: *const libc::c_char,
|
||||
rfc724_mid: &str,
|
||||
server_folder: &str,
|
||||
server_uid: u32,
|
||||
) -> libc::c_int {
|
||||
@@ -1656,7 +1651,7 @@ unsafe fn precheck_imf(
|
||||
let mut mark_seen: libc::c_int = 0i32;
|
||||
msg_id = dc_rfc724_mid_exists(
|
||||
context,
|
||||
rfc724_mid,
|
||||
&rfc724_mid,
|
||||
&mut old_server_folder,
|
||||
&mut old_server_uid,
|
||||
);
|
||||
@@ -1665,18 +1660,14 @@ unsafe fn precheck_imf(
|
||||
if *old_server_folder.offset(0isize) as libc::c_int == 0i32
|
||||
&& old_server_uid == 0i32 as libc::c_uint
|
||||
{
|
||||
info!(context, "[move] detected bbc-self {}", as_str(rfc724_mid),);
|
||||
info!(context, "[move] detected bbc-self {}", rfc724_mid,);
|
||||
mark_seen = 1i32
|
||||
} else if as_str(old_server_folder) != server_folder {
|
||||
info!(
|
||||
context,
|
||||
"[move] detected moved message {}",
|
||||
as_str(rfc724_mid),
|
||||
);
|
||||
dc_update_msg_move_state(context, rfc724_mid, MoveState::Stay);
|
||||
info!(context, "[move] detected moved message {}", rfc724_mid,);
|
||||
dc_update_msg_move_state(context, &rfc724_mid, MoveState::Stay);
|
||||
}
|
||||
if as_str(old_server_folder) != server_folder || old_server_uid != server_uid {
|
||||
dc_update_server_uid(context, rfc724_mid, server_folder, server_uid);
|
||||
dc_update_server_uid(context, &rfc724_mid, server_folder, server_uid);
|
||||
}
|
||||
context.do_heuristics_moves(server_folder, msg_id);
|
||||
if 0 != mark_seen {
|
||||
|
||||
19
src/job.rs
19
src/job.rs
@@ -1,4 +1,3 @@
|
||||
use std::ffi::CStr;
|
||||
use std::ptr;
|
||||
use std::time::Duration;
|
||||
|
||||
@@ -253,7 +252,7 @@ impl Job {
|
||||
self.try_again_later(3i32, None);
|
||||
}
|
||||
3 => {
|
||||
dc_update_server_uid(context, msg.rfc724_mid, &dest_folder, dest_uid);
|
||||
dc_update_server_uid(context, &msg.rfc724_mid, &dest_folder, dest_uid);
|
||||
}
|
||||
0 | 2 | _ => {}
|
||||
}
|
||||
@@ -268,12 +267,10 @@ impl Job {
|
||||
let inbox = context.inbox.read().unwrap();
|
||||
|
||||
if let Ok(mut msg) = dc_msg_load_from_db(context, self.foreign_id) {
|
||||
if !(msg.rfc724_mid.is_null()
|
||||
|| unsafe { *msg.rfc724_mid.offset(0isize) as libc::c_int == 0 })
|
||||
{
|
||||
if !msg.rfc724_mid.is_empty() {
|
||||
let ok_to_continue1;
|
||||
/* eg. device messages have no Message-ID */
|
||||
if dc_rfc724_mid_cnt(context, msg.rfc724_mid) != 1 {
|
||||
if dc_rfc724_mid_cnt(context, &msg.rfc724_mid) != 1 {
|
||||
info!(
|
||||
context,
|
||||
"The message is deleted from the server when all parts are deleted.",
|
||||
@@ -295,9 +292,10 @@ impl Job {
|
||||
ok_to_continue = true;
|
||||
}
|
||||
if ok_to_continue {
|
||||
let mid = unsafe { CStr::from_ptr(msg.rfc724_mid).to_str().unwrap() };
|
||||
let mid = msg.rfc724_mid;
|
||||
let server_folder = msg.server_folder.as_ref().unwrap();
|
||||
if 0 == inbox.delete_msg(context, mid, server_folder, &mut msg.server_uid) {
|
||||
if 0 == inbox.delete_msg(context, &mid, server_folder, &mut msg.server_uid)
|
||||
{
|
||||
self.try_again_later(-1i32, None);
|
||||
ok_to_continue1 = false;
|
||||
} else {
|
||||
@@ -1001,8 +999,7 @@ fn add_smtp_job(context: &Context, action: Action, mimefactory: &dc_mimefactory_
|
||||
let mut success: libc::c_int = 0i32;
|
||||
let mut recipients: *mut libc::c_char = ptr::null_mut();
|
||||
let mut param = Params::new();
|
||||
let path_filename =
|
||||
dc_get_fine_path_filename(context, "$BLOBDIR", as_str(mimefactory.rfc724_mid));
|
||||
let path_filename = dc_get_fine_path_filename(context, "$BLOBDIR", &mimefactory.rfc724_mid);
|
||||
let bytes = unsafe {
|
||||
std::slice::from_raw_parts(
|
||||
(*mimefactory.out).str_0 as *const u8,
|
||||
@@ -1013,7 +1010,7 @@ fn add_smtp_job(context: &Context, action: Action, mimefactory: &dc_mimefactory_
|
||||
error!(
|
||||
context,
|
||||
"Could not write message <{}> to \"{}\".",
|
||||
to_string(mimefactory.rfc724_mid),
|
||||
mimefactory.rfc724_mid,
|
||||
path_filename.display(),
|
||||
);
|
||||
} else {
|
||||
|
||||
@@ -151,7 +151,7 @@ pub struct Message {
|
||||
pub timestamp_sent: i64,
|
||||
pub timestamp_rcvd: i64,
|
||||
pub text: Option<String>,
|
||||
pub rfc724_mid: *mut libc::c_char,
|
||||
pub rfc724_mid: String,
|
||||
pub in_reply_to: Option<String>,
|
||||
pub server_folder: Option<String>,
|
||||
pub server_uid: u32,
|
||||
@@ -292,8 +292,8 @@ pub unsafe fn dc_get_msg_info(context: &Context, msg_id: u32) -> *mut libc::c_ch
|
||||
if !rawtxt.is_empty() {
|
||||
ret += &format!("\n{}\n", rawtxt);
|
||||
}
|
||||
if !msg.rfc724_mid.is_null() && 0 != *msg.rfc724_mid.offset(0) as libc::c_int {
|
||||
ret += &format!("\nMessage-ID: {}", as_str(msg.rfc724_mid));
|
||||
if !msg.rfc724_mid.is_empty() {
|
||||
ret += &format!("\nMessage-ID: {}", msg.rfc724_mid);
|
||||
}
|
||||
if let Some(ref server_folder) = msg.server_folder {
|
||||
if server_folder != "" {
|
||||
@@ -322,7 +322,7 @@ pub fn dc_msg_new(viewtype: Viewtype) -> Message {
|
||||
timestamp_sent: 0,
|
||||
timestamp_rcvd: 0,
|
||||
text: None,
|
||||
rfc724_mid: std::ptr::null_mut(),
|
||||
rfc724_mid: String::default(),
|
||||
in_reply_to: None,
|
||||
server_folder: None,
|
||||
server_uid: 0,
|
||||
@@ -334,14 +334,6 @@ pub fn dc_msg_new(viewtype: Viewtype) -> Message {
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Message {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
free(self.rfc724_mid.cast());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dc_msg_get_filemime(msg: &Message) -> String {
|
||||
if let Some(m) = msg.param.get(Param::MimeType) {
|
||||
return m.to_string();
|
||||
@@ -438,7 +430,7 @@ pub fn dc_msg_load_from_db(context: &Context, id: u32) -> Result<Message, Error>
|
||||
unsafe {
|
||||
let mut msg = dc_msg_new_untyped();
|
||||
msg.id = row.get::<_, i32>(0)? as u32;
|
||||
msg.rfc724_mid = row.get::<_, String>(1)?.strdup();
|
||||
msg.rfc724_mid = row.get::<_, String>(1)?;
|
||||
msg.in_reply_to = row.get::<_, Option<String>>(2)?;
|
||||
msg.server_folder = row.get::<_, Option<String>>(3)?;
|
||||
msg.server_uid = row.get(4)?;
|
||||
@@ -996,18 +988,14 @@ pub fn dc_msg_exists(context: &Context, msg_id: u32) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dc_update_msg_move_state(
|
||||
context: &Context,
|
||||
rfc724_mid: *const libc::c_char,
|
||||
state: MoveState,
|
||||
) -> bool {
|
||||
pub fn dc_update_msg_move_state(context: &Context, rfc724_mid: &str, state: MoveState) -> bool {
|
||||
// we update the move_state for all messages belonging to a given Message-ID
|
||||
// so that the state stay intact when parts are deleted
|
||||
sql::execute(
|
||||
context,
|
||||
&context.sql,
|
||||
"UPDATE msgs SET move_state=? WHERE rfc724_mid=?;",
|
||||
params![state as i32, as_str(rfc724_mid)],
|
||||
params![state as i32, rfc724_mid],
|
||||
)
|
||||
.is_ok()
|
||||
}
|
||||
@@ -1042,13 +1030,13 @@ pub fn dc_set_msg_failed(context: &Context, msg_id: u32, error: Option<impl AsRe
|
||||
pub unsafe fn dc_mdn_from_ext(
|
||||
context: &Context,
|
||||
from_id: u32,
|
||||
rfc724_mid: *const libc::c_char,
|
||||
rfc724_mid: &str,
|
||||
timestamp_sent: i64,
|
||||
ret_chat_id: *mut u32,
|
||||
ret_msg_id: *mut u32,
|
||||
) -> libc::c_int {
|
||||
if from_id <= 9
|
||||
|| rfc724_mid.is_null()
|
||||
|| rfc724_mid.is_empty()
|
||||
|| ret_chat_id.is_null()
|
||||
|| ret_msg_id.is_null()
|
||||
|| *ret_chat_id != 0
|
||||
@@ -1064,7 +1052,7 @@ pub unsafe fn dc_mdn_from_ext(
|
||||
LEFT JOIN chats c ON m.chat_id=c.id \
|
||||
WHERE rfc724_mid=? AND from_id=1 \
|
||||
ORDER BY m.id;",
|
||||
params![as_str(rfc724_mid)],
|
||||
params![rfc724_mid],
|
||||
|row| {
|
||||
Ok((
|
||||
row.get::<_, i32>(0)?,
|
||||
@@ -1168,11 +1156,11 @@ pub fn dc_get_deaddrop_msg_cnt(context: &Context) -> libc::size_t {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dc_rfc724_mid_cnt(context: &Context, rfc724_mid: *const libc::c_char) -> libc::c_int {
|
||||
pub fn dc_rfc724_mid_cnt(context: &Context, rfc724_mid: &str) -> libc::c_int {
|
||||
/* check the number of messages with the same rfc724_mid */
|
||||
match context.sql.query_row(
|
||||
"SELECT COUNT(*) FROM msgs WHERE rfc724_mid=?;",
|
||||
&[as_str(rfc724_mid)],
|
||||
&[rfc724_mid],
|
||||
|row| row.get(0),
|
||||
) {
|
||||
Ok(res) => res,
|
||||
@@ -1185,16 +1173,16 @@ pub fn dc_rfc724_mid_cnt(context: &Context, rfc724_mid: *const libc::c_char) ->
|
||||
|
||||
pub fn dc_rfc724_mid_exists(
|
||||
context: &Context,
|
||||
rfc724_mid: *const libc::c_char,
|
||||
rfc724_mid: &str,
|
||||
ret_server_folder: *mut *mut libc::c_char,
|
||||
ret_server_uid: *mut u32,
|
||||
) -> u32 {
|
||||
if rfc724_mid.is_null() || unsafe { *rfc724_mid.offset(0) as libc::c_int } == 0 {
|
||||
if rfc724_mid.is_empty() {
|
||||
return 0;
|
||||
}
|
||||
match context.sql.query_row(
|
||||
"SELECT server_folder, server_uid, id FROM msgs WHERE rfc724_mid=?",
|
||||
&[as_str(rfc724_mid)],
|
||||
&[rfc724_mid],
|
||||
|row| {
|
||||
if !ret_server_folder.is_null() {
|
||||
unsafe { *ret_server_folder = row.get::<_, String>(0)?.strdup() };
|
||||
@@ -1221,13 +1209,13 @@ pub fn dc_rfc724_mid_exists(
|
||||
|
||||
pub fn dc_update_server_uid(
|
||||
context: &Context,
|
||||
rfc724_mid: *const libc::c_char,
|
||||
rfc724_mid: &str,
|
||||
server_folder: impl AsRef<str>,
|
||||
server_uid: u32,
|
||||
) {
|
||||
match context.sql.execute(
|
||||
"UPDATE msgs SET server_folder=?, server_uid=? WHERE rfc724_mid=?;",
|
||||
params![server_folder.as_ref(), server_uid, as_str(rfc724_mid)],
|
||||
params![server_folder.as_ref(), server_uid, rfc724_mid],
|
||||
) {
|
||||
Ok(_) => {}
|
||||
Err(err) => {
|
||||
|
||||
@@ -68,94 +68,11 @@ pub fn configure_alice_keypair(ctx: &Context) -> String {
|
||||
// .unwrap();
|
||||
// println!("{}", public.to_base64(64));
|
||||
// println!("{}", private.to_base64(64));
|
||||
let public = key::Key::from_base64(
|
||||
concat!(
|
||||
"xsBNBF086ewBCACmJKuoxIO6T87yi4Q3MyNpMch3Y8KrtHDQyUszU36eqM3Pmd1l",
|
||||
"FrbcCd8ZWo2pq6OJSwsM/jjRGn1zo2YOaQeJRRrC+KrKGqSUtRSYQBPrPjE2YjSX",
|
||||
"AMbu8jBI6VVUhHeghriBkK79PY9O/oRhIJC0p14IJe6CQ6OI2fTmTUHF9i/nJ3G4",
|
||||
"Wb3/K1bU3yVfyPZjTZQPYPvvh03vxHULKurtYkX5DTEMSWsF4qzLMps+l87VuLV9",
|
||||
"iQnbN7YMRLHHx2KkX5Ivi7JCefhCa54M0K3bDCCxuVWAM5wjQwNZjzR+WL+dYchw",
|
||||
"oFvuF8NrlzjM9dSv+2rn+J7f99ijSXarzPC7ABEBAAHNEzxhbGljZUBleGFtcGxl",
|
||||
"LmNvbT7CwIkEEAEIADMCGQEFAl086fgCGwMECwkIBwYVCAkKCwIDFgIBFiEE+iai",
|
||||
"x4d0doj87Q0ek6DcNkbrcegACgkQk6DcNkbrcei3ogf/cruUmQ+th52TFHTHdkw9",
|
||||
"OHUl3MrXtZ7QmHyOAFvbXE/6n5Eeh+eZoF8MWWV72m14Wbs+vTcNQkFVTdOPptkK",
|
||||
"A8e4cJqwDOHsyAnvQXZ7WNje9+BMzcoipIUawHP4ORFaPDsKLZQ0b4wBbKn8ziea",
|
||||
"6zjGF0/qljTdoxTtsYpv5wXYuhwbYklrLOqgSa5M7LXUe7E3g9mbg+9iX1GuB8m6",
|
||||
"GkquJN814Y+xny4xhZzGOfue6SeP12jJMNSjSP7416dRq7794VGnkkW9V/7oFEUK",
|
||||
"u5wO9FFbgDySOSlEjByGejSGuBmho0iJSjcPjZ7EY/j3M3orq4dpza5C82OeSvxD",
|
||||
"Fc7ATQRdPOnsAQgA5oLxXRLnyugzOmNCy7dxV3JrDZscA6JNlJlDWIShT0YSs+zG",
|
||||
"9JzDeQql+sYXgUSxOoIayItuXtnFn7tstwGoOnYvadm/e5/7V5fKAQRtCtdN51av",
|
||||
"62n18Venlm0yNKpROPcZ6M/sc4m6uU6YRZ/a1idal8VGY0wLKlghjIBuIiBoVQ/R",
|
||||
"noW+/fhmwIg08dQ5m8hQe3GEOZEeLrTWL/9awPlXK7Y+DmJOoR4qbHWEcRfbzS6q",
|
||||
"4zW8vk2ztB8ngwbnqYy8zrN1DCICN1gYdlU++uVw6Bb1XfY8Cdldh1VLKpF35mAm",
|
||||
"jxLZfVDcoObFH3Cv2GB7BEYxv86KC2Y6T74Q/wARAQABwsB2BBgBCAAgBQJdPOn4",
|
||||
"AhsMFiEE+iaix4d0doj87Q0ek6DcNkbrcegACgkQk6DcNkbrcegLxwf/dXshJnoW",
|
||||
"qEnRsf6rVb9/Mc66ti+NVQLfNd275dybh/QIJdK3NmSxdnTPIEJRVspJywJoupwX",
|
||||
"FNrnHG2Ff6QPvHqI+/oNu986r9d7Z1oQibbLHKt8t6kpOfg/xGxotagJuiCQvR9m",
|
||||
"MjD1DqsdB37SjDxGupZOOJSXWi6KX60IE+uM+QOBfeOZziQwuFmA5wV6RDXIeYJf",
|
||||
"qrcbeXeR1d0nfNpPHQR1gBiqmxNb6KBbdXD2+EXW60axC7D2b1APmzMlammDliPw",
|
||||
"sK9U1rc9nuquEBvGDOJf4K+Dzn+mDCqRpP6uAuQ7RKHyim4uyN0wwKObzPqgJCGw",
|
||||
"jTglkixw+aSTXw=="
|
||||
),
|
||||
KeyType::Public,
|
||||
)
|
||||
.unwrap();
|
||||
let public =
|
||||
key::Key::from_base64(include_str!("../test-data/key/public.asc"), KeyType::Public)
|
||||
.unwrap();
|
||||
let private = key::Key::from_base64(
|
||||
concat!(
|
||||
"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",
|
||||
"zPqgJCGwjTglkixw+aSTXw=="
|
||||
),
|
||||
include_str!("../test-data/key/private.asc"),
|
||||
KeyType::Private,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
1
test-data/key/private.asc
Normal file
1
test-data/key/private.asc
Normal file
@@ -0,0 +1 @@
|
||||
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
|
||||
13
test-data/message/mail_with_message_id.txt
Normal file
13
test-data/message/mail_with_message_id.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
Return-Path: <x@testrun.org>
|
||||
Received: from hq5.merlinux.eu
|
||||
by hq5.merlinux.eu (Dovecot) with LMTP id yRKOBakcfV1AewAAPzvFDg
|
||||
; Sat, 14 Sep 2019 19:00:25 +0200
|
||||
Received: from localhost (unknown 7.165.105.24])
|
||||
by hq5.merlinux.eu (Postfix) with ESMTPSA id 8D9844E023;
|
||||
Sat, 14 Sep 2019 19:00:22 +0200 (CEST)
|
||||
message-id: <2dfdbde7@example.org>
|
||||
Date: Sat, 14 Sep 2019 19:00:13 +0200
|
||||
From: lmn <x@tux.org>
|
||||
To: abc <abc@bcd.com>, def <def@def.de>,
|
||||
jik
|
||||
|
||||
Reference in New Issue
Block a user