Compare commits

..

2 Commits

Author SHA1 Message Date
holger krekel
a9df84d2ee more call sites 2019-12-19 08:08:42 +01:00
holger krekel
53453bb71a never block on interrupt_inbox_idle 2019-12-19 07:36:56 +01:00
12 changed files with 321 additions and 148 deletions

View File

@@ -1,13 +1,5 @@
# Changelog
## 1.0.0-beta.20
- #1074 fix OAUTH2/gmail
- #1072 fix group members not appearing in contact list
- #1071 never block interrupt_idle (thus hopefully also not on maybe_network())
- #1069 reduce smtp-timeout to 30 seconds
- #1066 #1065 avoid unwrap in dehtml, make literals more readable
## 1.0.0-beta.19
- #1058 timeout smtp-send if it doesn't complete in 15 minutes

17
Cargo.lock generated
View File

@@ -85,7 +85,7 @@ dependencies = [
[[package]]
name = "async-imap"
version = "0.1.1"
source = "git+https://github.com/async-email/async-imap?branch=dcc-stable#50e843113e3a67e924a8a14c477833da3ebc1b44"
source = "git+https://github.com/async-email/async-imap?branch=dcc-stable#4f0852971c3f397c2b8a343ef1378992c02f61de"
dependencies = [
"async-attributes 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"async-native-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -96,7 +96,6 @@ dependencies = [
"futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures_codec 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"imap-proto 0.9.1 (git+https://github.com/djc/tokio-imap)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"nom 5.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"pin-utils 0.1.0-alpha.4 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -658,7 +657,7 @@ dependencies = [
[[package]]
name = "deltachat"
version = "1.0.0-beta.20"
version = "1.0.0-beta.19"
dependencies = [
"async-imap 0.1.1 (git+https://github.com/async-email/async-imap?branch=dcc-stable)",
"async-native-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -716,13 +715,12 @@ dependencies = [
[[package]]
name = "deltachat-provider-database"
version = "0.3.0"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)",
"yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -736,15 +734,14 @@ dependencies = [
[[package]]
name = "deltachat_ffi"
version = "1.0.0-beta.20"
version = "1.0.0-beta.19"
dependencies = [
"deltachat 1.0.0-beta.20",
"deltachat-provider-database 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"deltachat 1.0.0-beta.19",
"deltachat-provider-database 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"human-panic 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -3535,7 +3532,7 @@ dependencies = [
"checksum darling_macro 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72"
"checksum debug_stub_derive 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "496b7f8a2f853313c3ca370641d7ff3e42c32974fdccda8f0684599ed0a3ff6b"
"checksum deflate 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)" = "707b6a7b384888a70c8d2e8650b3e60170dfc6a67bb4aa67b6dfca57af4bedb4"
"checksum deltachat-provider-database 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc18fb898a7bc90565c801d7bd17a4b61478f0da0ea06ecf7f0428bd20242c52"
"checksum deltachat-provider-database 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "814dba060d9fdc7a989fccdc4810ada9d1c7a1f09131c78e42412bc6c634b93b"
"checksum derive_builder 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a2658621297f2cf68762a6f7dc0bb7e1ff2cfd6583daef8ee0fed6f7ec468ec0"
"checksum derive_builder_core 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2791ea3e372c8495c0bc2033991d76b512cd799d07491fbd6890124db9458bef"
"checksum des 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "74ba5f1b5aee9772379c2670ba81306e65a93c0ee3caade7a1d22b188d88a3af"

View File

@@ -1,6 +1,6 @@
[package]
name = "deltachat"
version = "1.0.0-beta.20"
version = "1.0.0-beta.19"
authors = ["Delta Chat Developers (ML) <delta@codespeak.net>"]
edition = "2018"
license = "MPL"

View File

@@ -1,6 +1,6 @@
[package]
name = "deltachat_ffi"
version = "1.0.0-beta.20"
version = "1.0.0-beta.19"
description = "Deltachat FFI"
authors = ["Delta Chat Developers (ML) <delta@codespeak.net>"]
edition = "2018"
@@ -16,12 +16,11 @@ crate-type = ["cdylib", "staticlib"]
[dependencies]
deltachat = { path = "../", default-features = false }
deltachat-provider-database = "0.3.0"
deltachat-provider-database = "0.2.1"
libc = "0.2"
human-panic = "1.0.1"
num-traits = "0.2.6"
failure = "0.1.6"
serde_json = "1.0"
[features]
default = ["vendored", "nightly", "ringbuf"]

View File

@@ -18,6 +18,7 @@ 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;
/**
@@ -3659,30 +3660,106 @@ int dc_contact_is_verified (dc_contact_t* contact);
/**
* @class dc_provider_t
*
* Opaque object containing information about one single email provider.
*/
/**
* Get the provider json object for the given domain.
* For more documentation see https://docs.rs/deltachat-provider-database/
* Create a provider struct for the given domain.
*
* @memberof dc_provider_t
* @param domain The domain to get provider info for.
* @return a provider json object as string. If no provider info is found, an empty string will be returned.
* @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.
*/
char* dc_provider_json_from_domain (const char* domain);
dc_provider_t* dc_provider_new_from_domain (const char* domain);
/**
* Get the provider json object for the given email address.
* For more documentation see https://docs.rs/deltachat-provider-database/
* 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 provider json object as string. If no provider info is found, an empty string will be returned.
* @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.
*/
char* dc_provider_json_from_email (const char* email);
dc_provider_t* dc_provider_new_from_email (const 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 released using dc_str_unref().
*/
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 released using dc_str_unref().
*/
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 released using dc_str_unref().
*/
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 released using dc_str_unref().
*/
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);
/**
@@ -4398,6 +4475,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.
*

View File

@@ -1,35 +1,93 @@
extern crate deltachat_provider_database;
use std::ptr;
use crate::string::{to_string_lossy, StrExt};
use deltachat_provider_database::StatusState;
#[no_mangle]
pub type dc_provider_t = deltachat_provider_database::Provider;
#[no_mangle]
pub unsafe extern "C" fn dc_provider_json_from_domain(
pub unsafe extern "C" fn dc_provider_new_from_domain(
domain: *const libc::c_char,
) -> *mut libc::c_char {
let domain = to_string_lossy(domain);
match deltachat_provider_database::get_provider_info(&domain) {
Some(provider) => serde_json::to_string(provider)
.unwrap_or("".to_owned())
.strdup(),
None => "".strdup(),
) -> *const dc_provider_t {
match deltachat_provider_database::get_provider_info(&to_string_lossy(domain)) {
Some(provider) => provider,
None => ptr::null(),
}
}
#[no_mangle]
pub unsafe extern "C" fn dc_provider_json_from_email(
pub unsafe extern "C" fn dc_provider_new_from_email(
email: *const libc::c_char,
) -> *mut libc::c_char {
) -> *const dc_provider_t {
let email = to_string_lossy(email);
let domain = deltachat_provider_database::get_domain_from_email(&email);
match deltachat_provider_database::get_provider_info(domain) {
Some(provider) => serde_json::to_string(provider)
.unwrap_or("".to_owned())
.strdup(),
None => "".strdup(),
Some(provider) => provider,
None => ptr::null(),
}
}
macro_rules! null_guard {
($context:tt) => {
if $context.is_null() {
return ptr::null_mut() as *mut libc::c_char;
}
};
}
#[no_mangle]
pub unsafe extern "C" fn dc_provider_get_overview_page(
provider: *const dc_provider_t,
) -> *mut libc::c_char {
null_guard!(provider);
format!(
"{}/{}",
deltachat_provider_database::PROVIDER_OVERVIEW_URL,
(*provider).overview_page
)
.strdup()
}
#[no_mangle]
pub unsafe extern "C" fn dc_provider_get_name(provider: *const dc_provider_t) -> *mut libc::c_char {
null_guard!(provider);
(*provider).name.strdup()
}
#[no_mangle]
pub unsafe extern "C" fn dc_provider_get_markdown(
provider: *const dc_provider_t,
) -> *mut libc::c_char {
null_guard!(provider);
(*provider).markdown.strdup()
}
#[no_mangle]
pub unsafe extern "C" fn dc_provider_get_status_date(
provider: *const dc_provider_t,
) -> *mut libc::c_char {
null_guard!(provider);
(*provider).status.date.strdup()
}
#[no_mangle]
pub unsafe extern "C" fn dc_provider_get_status(provider: *const dc_provider_t) -> u32 {
if provider.is_null() {
return 0;
}
match (*provider).status.state {
StatusState::OK => 1,
StatusState::PREPARATION => 2,
StatusState::BROKEN => 3,
}
}
#[no_mangle]
pub unsafe extern "C" fn dc_provider_unref(_provider: *const dc_provider_t) {
()
}
// TODO expose general provider overview url?

View File

@@ -1,8 +1,7 @@
"""Provider info class."""
from .capi import lib
from .capi import ffi, lib
from .cutil import as_dc_charpointer, from_dc_charpointer
import json
class ProviderNotFoundError(Exception):
@@ -17,12 +16,13 @@ class Provider(object):
"""
def __init__(self, domain):
provider = from_dc_charpointer(
lib.dc_provider_json_from_domain(as_dc_charpointer(domain))
provider = ffi.gc(
lib.dc_provider_new_from_domain(as_dc_charpointer(domain)),
lib.dc_provider_unref,
)
if provider == "":
if provider == ffi.NULL:
raise ProviderNotFoundError("Provider not found")
self._provider = json.loads(provider)
self._provider = provider
@classmethod
def from_email(cls, email):
@@ -35,30 +35,33 @@ class Provider(object):
@property
def overview_page(self):
"""URL to the overview page of the provider on providers.delta.chat."""
return "https://providers.delta.chat/" + self._provider['overview_page']
return from_dc_charpointer(
lib.dc_provider_get_overview_page(self._provider))
@property
def name(self):
"""The name of the provider."""
return self._provider['name']
return from_dc_charpointer(lib.dc_provider_get_name(self._provider))
@property
def markdown(self):
"""Content of the information page, formatted as markdown."""
return self._provider['markdown']
return from_dc_charpointer(
lib.dc_provider_get_markdown(self._provider))
@property
def status_date(self):
"""The date the provider info was last updated, as a string."""
return self._provider['status']['date']
return from_dc_charpointer(
lib.dc_provider_get_status_date(self._provider))
@property
def status(self):
"""The status of the provider information.
This is
:attr:`"OK"`,
:attr:`"PREPARATION"` or
:attr:`"BROKEN"`.
This is one of the
:attr:`deltachat.const.DC_PROVIDER_STATUS_OK`,
:attr:`deltachat.const.DC_PROVIDER_STATUS_PREPARATION` or
:attr:`deltachat.const.DC_PROVIDER_STATUS_BROKEN` constants.
"""
return self._provider['status']['state']
return lib.dc_provider_get_status(self._provider)

View File

@@ -1209,15 +1209,6 @@ class TestGroupStressTests:
print("chat is", msg.chat)
assert len(msg.chat.get_contacts()) == 4
lp.sec("ac3: checking that 'ac4' is a known contact")
ac3 = accounts[1]
msg3 = ac3.wait_next_incoming_message()
assert msg3.text == "hello"
contacts = ac3.get_contacts()
assert len(contacts) == 3
ac4_contacts = ac3.get_contacts(query=accounts[2].get_config("addr"))
assert len(ac4_contacts) == 1
lp.sec("ac1: removing one contacts and checking things are right")
to_remove = msg.chat.get_contacts()[-1]
msg.chat.remove_contact(to_remove)

View File

@@ -3,7 +3,6 @@ from deltachat import capi, cutil, const, set_context_callback, clear_context_ca
from deltachat.capi import ffi
from deltachat.capi import lib
from deltachat.account import EventLogger
import json
def test_empty_context():
@@ -104,23 +103,18 @@ def test_get_special_message_id_returns_empty_message(acfactory):
def test_provider_info():
provider_json = cutil.from_dc_charpointer(
lib.dc_provider_json_from_email(cutil.as_dc_charpointer("ex@example.com"))
)
provider = json.loads(provider_json)
assert provider['overview_page'] == "example.com"
assert provider['name'] == "Example"
assert provider['markdown'] == "\n..."
assert provider['status']['date'] == "2018-09"
assert provider['status']['state'] == "PREPARATION"
provider = lib.dc_provider_new_from_email(cutil.as_dc_charpointer("ex@example.com"))
assert cutil.from_dc_charpointer(
lib.dc_provider_get_overview_page(provider)
) == "https://providers.delta.chat/example.com"
assert cutil.from_dc_charpointer(lib.dc_provider_get_name(provider)) == "Example"
assert cutil.from_dc_charpointer(lib.dc_provider_get_markdown(provider)) == "\n..."
assert cutil.from_dc_charpointer(lib.dc_provider_get_status_date(provider)) == "2018-09"
assert lib.dc_provider_get_status(provider) == const.DC_PROVIDER_STATUS_PREPARATION
def test_provider_info_none():
provider_json = cutil.from_dc_charpointer(
lib.dc_provider_json_from_email(cutil.as_dc_charpointer("email@unexistent.no"))
)
assert provider_json == ""
assert lib.dc_provider_new_from_email(cutil.as_dc_charpointer("email@unexistent.no")) == ffi.NULL
def test_get_info_closed():

View File

@@ -1,5 +1,6 @@
import pytest
from deltachat import const
from deltachat import provider
@@ -9,7 +10,7 @@ def test_provider_info_from_email():
assert example.name == "Example"
assert example.markdown == "\n..."
assert example.status_date == "2018-09"
assert example.status == "PREPARATION"
assert example.status == const.DC_PROVIDER_STATUS_PREPARATION
def test_provider_info_from_domain():
@@ -18,7 +19,7 @@ def test_provider_info_from_domain():
assert example.name == "Example"
assert example.markdown == "\n..."
assert example.status_date == "2018-09"
assert example.status == "PREPARATION"
assert example.status == const.DC_PROVIDER_STATUS_PREPARATION
def test_provider_info_none():

View File

@@ -114,11 +114,14 @@ impl Default for Origin {
}
impl Origin {
/// Contacts that are known, i. e. they came in via accepted contacts or
/// themselves an accepted contact. Known contacts are shown in the
/// contact list when one creates a chat and wants to add members etc.
pub fn is_known(self) -> bool {
self >= Origin::IncomingReplyTo
/// Contacts that are verified and known not to be spam.
pub fn is_verified(self) -> bool {
self as i32 >= 0x100
}
/// Contacts that are shown in the contact list.
pub fn include_in_contactlist(self) -> bool {
self as i32 >= DC_ORIGIN_MIN_CONTACT_LIST
}
}
@@ -398,7 +401,6 @@ impl Contact {
{
row_id = sql::get_rowid(context, &context.sql, "contacts", "addr", addr);
sth_modified = Modifier::Created;
info!(context, "added contact id={} addr={}", row_id, addr);
} else {
error!(context, "Cannot add contact.");
}
@@ -484,7 +486,7 @@ impl Contact {
params![
self_addr,
DC_CONTACT_ID_LAST_SPECIAL as i32,
Origin::IncomingReplyTo,
0x100,
&s3str_like_cmd,
&s3str_like_cmd,
if flag_verified_only { 0 } else { 1 },

View File

@@ -61,6 +61,9 @@ pub fn dc_receive_imf(
ensure!(mime_parser.has_headers(), "No Headers Found");
// the function returns the number of created messages in the database
let mut incoming = true;
let mut incoming_origin = Origin::Unknown;
let mut to_id = 0u32;
let mut chat_id = 0;
let mut hidden = false;
@@ -71,6 +74,8 @@ pub fn dc_receive_imf(
let mut created_db_entries = Vec::new();
let mut create_event_to_send = Some(CreateEvent::MsgsChanged);
let mut to_ids = ContactIds::new();
// helper method to handle early exit and memory cleanup
let cleanup = |context: &Context,
create_event_to_send: &Option<CreateEvent>,
@@ -97,31 +102,48 @@ pub fn dc_receive_imf(
sent_timestamp = mailparse::dateparse(value).unwrap_or_default();
}
// Make sure, to_ids starts with the first To:-address (Cc: is added in the loop below pass)
if let Some(field) = mime_parser.get(HeaderDef::To) {
dc_add_or_lookup_contacts_by_address_list(
context,
&field,
if !incoming {
Origin::OutgoingTo
} else if incoming_origin.is_verified() {
Origin::IncomingTo
} else {
Origin::IncomingUnknownTo
},
&mut to_ids,
)?;
}
// get From: (it can be an address list!) and check if it is known (for known From:'s we add
// the other To:/Cc: in the 3rd pass)
// or if From: is equal to SELF (in this case, it is any outgoing messages,
// we do not check Return-Path any more as this is unreliable, see issue #150)
let mut from_id = 0;
let mut from_id_blocked = false;
let mut incoming = true;
let mut incoming_origin = Origin::Unknown;
if let Some(field_from) = mime_parser.get(HeaderDef::From_) {
let from_ids = dc_add_or_lookup_contacts_by_address_list(
let mut from_ids = ContactIds::new();
dc_add_or_lookup_contacts_by_address_list(
context,
&field_from,
Origin::IncomingUnknownFrom,
&mut from_ids,
)?;
if from_ids.len() > 1 {
warn!(
context,
"mail has more than one From address, only using first: {:?}", field_from
"mail has more than one address in From: {:?}", field_from
);
}
if from_ids.contains(&DC_CONTACT_ID_SELF) {
incoming = false;
from_id = DC_CONTACT_ID_SELF;
incoming_origin = Origin::OutgoingBcc;
if to_ids.len() == 1 && to_ids.contains(&DC_CONTACT_ID_SELF) {
from_id = DC_CONTACT_ID_SELF;
}
} else if !from_ids.is_empty() {
from_id = from_ids.get_index(0).cloned().unwrap_or_default();
incoming_origin = Contact::get_origin_by_id(context, from_id, &mut from_id_blocked)
@@ -133,23 +155,6 @@ pub fn dc_receive_imf(
}
}
let mut to_ids = ContactIds::new();
for header_def in &[HeaderDef::To, HeaderDef::Cc] {
if let Some(field) = mime_parser.get(header_def.clone()) {
to_ids.extend(&dc_add_or_lookup_contacts_by_address_list(
context,
&field,
if !incoming {
Origin::OutgoingTo
} else if incoming_origin.is_known() {
Origin::IncomingTo
} else {
Origin::IncomingUnknownTo
},
)?);
}
}
// Add parts
let rfc724_mid = match mime_parser.get_rfc724_mid() {
@@ -172,16 +177,17 @@ pub fn dc_receive_imf(
&mut mime_parser,
imf_raw,
incoming,
incoming_origin,
&mut incoming_origin,
server_folder.as_ref(),
server_uid,
&to_ids,
&mut to_ids,
&rfc724_mid,
&mut sent_timestamp,
from_id,
&mut from_id,
from_id_blocked,
&mut hidden,
&mut chat_id,
&mut to_id,
flags,
&mut needs_delete_job,
&mut insert_msg_id,
@@ -251,16 +257,17 @@ fn add_parts(
mut mime_parser: &mut MimeParser,
imf_raw: &[u8],
incoming: bool,
incoming_origin: Origin,
incoming_origin: &mut Origin,
server_folder: impl AsRef<str>,
server_uid: u32,
to_ids: &ContactIds,
to_ids: &mut ContactIds,
rfc724_mid: &str,
sent_timestamp: &mut i64,
from_id: u32,
from_id: &mut u32,
from_id_blocked: bool,
hidden: &mut bool,
chat_id: &mut u32,
to_id: &mut u32,
flags: u32,
needs_delete_job: &mut bool,
insert_msg_id: &mut MsgId,
@@ -274,7 +281,24 @@ fn add_parts(
let mut rcvd_timestamp = 0;
let mut mime_in_reply_to = String::new();
let mut mime_references = String::new();
let mut incoming_origin = incoming_origin;
// collect the rest information, CC: is added to the to-list, BCC: is ignored
// (we should not add BCC to groups as this would split groups. We could add them as "known contacts",
// however, the benefit is very small and this may leak data that is expected to be hidden)
if let Some(fld_cc) = mime_parser.get(HeaderDef::Cc) {
dc_add_or_lookup_contacts_by_address_list(
context,
fld_cc,
if !incoming {
Origin::OutgoingCc
} else if incoming_origin.is_verified() {
Origin::IncomingCc
} else {
Origin::IncomingUnknownCc
},
to_ids,
)?;
}
// 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
@@ -314,15 +338,13 @@ fn add_parts(
// - outgoing messages introduce a chat with the first to: address if they are sent by a messenger
// - incoming messages introduce a chat only for known contacts if they are sent by a messenger
// (of course, the user can add other chats manually later)
let to_id: u32;
if incoming {
state = if 0 != flags & DC_IMAP_SEEN {
MessageState::InSeen
} else {
MessageState::InFresh
};
to_id = DC_CONTACT_ID_SELF;
*to_id = DC_CONTACT_ID_SELF;
let mut needs_stop_ongoing_process = false;
// handshake messages must be processed _before_ chats are created
@@ -332,7 +354,7 @@ fn add_parts(
msgrmsg = 1;
*chat_id = 0;
allow_creation = true;
match handle_securejoin_handshake(context, mime_parser, from_id) {
match handle_securejoin_handshake(context, mime_parser, *from_id) {
Ok(ret) => {
if ret.hide_this_msg {
*hidden = true;
@@ -354,7 +376,7 @@ fn add_parts(
}
let (test_normal_chat_id, test_normal_chat_id_blocked) =
chat::lookup_by_contact_id(context, from_id).unwrap_or_default();
chat::lookup_by_contact_id(context, *from_id).unwrap_or_default();
// get the chat_id - a chat_id here is no indicator that the chat is displayed in the normal list,
// it might also be blocked and displayed in the deaddrop as a result
@@ -374,7 +396,7 @@ fn add_parts(
&mut mime_parser,
allow_creation,
create_blocked,
from_id,
*from_id,
to_ids,
)?;
*chat_id = new_chat_id;
@@ -395,7 +417,7 @@ fn add_parts(
if *chat_id == 0 {
// try to create a normal chat
let create_blocked = if from_id == to_id {
let create_blocked = if *from_id == *to_id {
Blocked::Not
} else {
Blocked::Deaddrop
@@ -406,7 +428,7 @@ fn add_parts(
chat_id_blocked = test_normal_chat_id_blocked;
} else if allow_creation {
let (id, bl) =
chat::create_or_lookup_by_contact_id(context, from_id, create_blocked)
chat::create_or_lookup_by_contact_id(context, *from_id, create_blocked)
.unwrap_or_default();
*chat_id = id;
chat_id_blocked = bl;
@@ -418,13 +440,13 @@ fn add_parts(
} else if is_reply_to_known_message(context, mime_parser) {
// we do not want any chat to be created implicitly. Because of the origin-scale-up,
// the contact requests will pop up and this should be just fine.
Contact::scaleup_origin_by_id(context, from_id, Origin::IncomingReplyTo);
Contact::scaleup_origin_by_id(context, *from_id, Origin::IncomingReplyTo);
info!(
context,
"Message is a reply to a known message, mark sender as known.",
);
if !incoming_origin.is_known() {
incoming_origin = Origin::IncomingReplyTo;
if !incoming_origin.is_verified() {
*incoming_origin = Origin::IncomingReplyTo;
}
}
}
@@ -439,7 +461,7 @@ fn add_parts(
// to not result in a chatlist-contact-request (this would require the state FRESH)
if Blocked::Not != chat_id_blocked
&& state == MessageState::InFresh
&& !incoming_origin.is_known()
&& !incoming_origin.is_verified()
&& msgrmsg == 0
&& show_emails != ShowEmails::All
{
@@ -458,15 +480,16 @@ fn add_parts(
// the mail is on the IMAP server, probably it is also delivered.
// We cannot recreate other states (read, error).
state = MessageState::OutDelivered;
to_id = to_ids.get_index(0).cloned().unwrap_or_default();
*from_id = DC_CONTACT_ID_SELF;
if !to_ids.is_empty() {
*to_id = to_ids.get_index(0).cloned().unwrap_or_default();
if *chat_id == 0 {
let (new_chat_id, new_chat_id_blocked) = create_or_lookup_group(
context,
&mut mime_parser,
allow_creation,
Blocked::Not,
from_id,
*from_id,
to_ids,
)?;
*chat_id = new_chat_id;
@@ -478,13 +501,14 @@ fn add_parts(
}
}
if *chat_id == 0 && allow_creation {
let create_blocked = if 0 != msgrmsg && !Contact::is_blocked_load(context, to_id) {
let create_blocked = if 0 != msgrmsg && !Contact::is_blocked_load(context, *to_id) {
Blocked::Not
} else {
Blocked::Deaddrop
};
let (id, bl) = chat::create_or_lookup_by_contact_id(context, to_id, create_blocked)
.unwrap_or_default();
let (id, bl) =
chat::create_or_lookup_by_contact_id(context, *to_id, create_blocked)
.unwrap_or_default();
*chat_id = id;
chat_id_blocked = bl;
@@ -497,7 +521,7 @@ fn add_parts(
}
}
}
let self_sent = from_id == DC_CONTACT_ID_SELF
let self_sent = *from_id == DC_CONTACT_ID_SELF
&& to_ids.len() == 1
&& to_ids.contains(&DC_CONTACT_ID_SELF);
@@ -524,7 +548,7 @@ fn add_parts(
calc_timestamps(
context,
*chat_id,
from_id,
*from_id,
*sent_timestamp,
0 == flags & DC_IMAP_SEEN,
&mut sort_timestamp,
@@ -588,8 +612,8 @@ fn add_parts(
server_folder.as_ref(),
server_uid as i32,
*chat_id as i32,
from_id as i32,
to_id as i32,
*from_id as i32,
*to_id as i32,
sort_timestamp,
*sent_timestamp,
rcvd_timestamp,
@@ -1513,7 +1537,8 @@ fn dc_add_or_lookup_contacts_by_address_list(
context: &Context,
addr_list_raw: &str,
origin: Origin,
) -> Result<ContactIds> {
to_ids: &mut ContactIds,
) -> Result<()> {
let addrs = match mailparse::addrparse(addr_list_raw) {
Ok(addrs) => addrs,
Err(err) => {
@@ -1521,11 +1546,10 @@ fn dc_add_or_lookup_contacts_by_address_list(
}
};
let mut contact_ids = ContactIds::new();
for addr in addrs.iter() {
match addr {
mailparse::MailAddr::Single(info) => {
contact_ids.insert(add_or_lookup_contact_by_addr(
to_ids.insert(add_or_lookup_contact_by_addr(
context,
&info.display_name,
&info.addr,
@@ -1534,7 +1558,7 @@ fn dc_add_or_lookup_contacts_by_address_list(
}
mailparse::MailAddr::Group(infos) => {
for info in &infos.addrs {
contact_ids.insert(add_or_lookup_contact_by_addr(
to_ids.insert(add_or_lookup_contact_by_addr(
context,
&info.display_name,
&info.addr,
@@ -1545,7 +1569,7 @@ fn dc_add_or_lookup_contacts_by_address_list(
}
}
Ok(contact_ids)
Ok(())
}
/// Add contacts to database on receiving messages.