Compare commits

..

2 Commits

Author SHA1 Message Date
Alexander Krotov
a1a34bc585 Get rid of unnecessary "async move" and ".await" 2019-12-16 19:19:01 +03:00
holger krekel
5814f2d629 try doing an smtp-send timeout 2019-12-16 17:09:37 +01:00
21 changed files with 183 additions and 164 deletions

View File

@@ -1,11 +1,5 @@
# Changelog
## 1.0.0-beta.19
- #1058 timeout smtp-send if it doesn't complete in 15 minutes
- #1059 trim down logging
## 1.0.0-beta.18
- #1056 avoid panicking when we couldn't read imap-server's greeting

8
Cargo.lock generated
View File

@@ -124,7 +124,7 @@ dependencies = [
[[package]]
name = "async-smtp"
version = "0.1.0"
source = "git+https://github.com/async-email/async-smtp#6a4830032953f06020edc09db8daa06193e2b93f"
source = "git+https://github.com/async-email/async-smtp#c26ce542e847c502654c471ebc50d6c996f86cee"
dependencies = [
"async-native-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"async-std 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -657,7 +657,7 @@ dependencies = [
[[package]]
name = "deltachat"
version = "1.0.0-beta.19"
version = "1.0.0-beta.18"
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)",
@@ -734,9 +734,9 @@ dependencies = [
[[package]]
name = "deltachat_ffi"
version = "1.0.0-beta.19"
version = "1.0.0-beta.18"
dependencies = [
"deltachat 1.0.0-beta.19",
"deltachat 1.0.0-beta.18",
"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)",

View File

@@ -1,6 +1,6 @@
[package]
name = "deltachat"
version = "1.0.0-beta.19"
version = "1.0.0-beta.18"
authors = ["Delta Chat Developers (ML) <delta@codespeak.net>"]
edition = "2018"
license = "MPL"
@@ -17,7 +17,7 @@ smallvec = "1.0.0"
reqwest = { version = "0.9.15" }
num-derive = "0.3.0"
num-traits = "0.2.6"
async-smtp = { git = "https://github.com/async-email/async-smtp" }
async-smtp = { git = "https://github.com/async-email/async-smtp", branch = "master" }
email = { git = "https://github.com/deltachat/rust-email", branch = "master" }
lettre_email = { git = "https://github.com/deltachat/lettre", branch = "native_tls" }

View File

@@ -1,6 +1,6 @@
[package]
name = "deltachat_ffi"
version = "1.0.0-beta.19"
version = "1.0.0-beta.18"
description = "Deltachat FFI"
authors = ["Delta Chat Developers (ML) <delta@codespeak.net>"]
edition = "2018"

View File

@@ -509,7 +509,7 @@ pub unsafe extern "C" fn dc_interrupt_imap_idle(context: *mut dc_context_t) {
}
let ffi_context = &*context;
ffi_context
.with_inner(|ctx| job::interrupt_inbox_idle(ctx))
.with_inner(|ctx| job::interrupt_inbox_idle(ctx, true))
.unwrap_or(())
}

View File

@@ -491,7 +491,7 @@ pub fn dc_cmdline(context: &Context, line: &str) -> Result<(), failure::Error> {
println!("{:#?}", context.get_info());
}
"interrupt" => {
interrupt_inbox_idle(context);
interrupt_inbox_idle(context, true);
}
"maybenetwork" => {
maybe_network(context);

View File

@@ -202,7 +202,7 @@ fn stop_threads(context: &Context) {
println!("Stopping threads");
IS_RUNNING.store(false, Ordering::Relaxed);
interrupt_inbox_idle(context);
interrupt_inbox_idle(context, true);
interrupt_mvbox_idle(context);
interrupt_sentbox_idle(context);
interrupt_smtp_idle(context);

View File

@@ -104,7 +104,7 @@ fn main() {
println!("stopping threads");
*running.write().unwrap() = false;
deltachat::job::interrupt_inbox_idle(&ctx);
deltachat::job::interrupt_inbox_idle(&ctx, true);
deltachat::job::interrupt_smtp_idle(&ctx);
println!("joining");

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

@@ -144,7 +144,7 @@ impl Context {
}
Config::InboxWatch => {
let ret = self.sql.set_raw_config(self, key, value);
interrupt_inbox_idle(self);
interrupt_inbox_idle(self, true);
ret
}
Config::SentboxWatch => {

View File

@@ -114,7 +114,7 @@ pub const DC_MSG_ID_LAST_SPECIAL: u32 = 9;
/// approx. max. length returned by dc_msg_get_text()
const DC_MAX_GET_TEXT_LEN: usize = 30000;
/// approx. max. length returned by dc_get_msg_info()
const DC_MAX_GET_INFO_LEN: usize = 100_000;
const DC_MAX_GET_INFO_LEN: usize = 100000;
pub const DC_CONTACT_ID_UNDEFINED: u32 = 0;
pub const DC_CONTACT_ID_SELF: u32 = 1;

View File

@@ -100,11 +100,11 @@ pub enum Origin {
/// address is in our address book
AdressBook = 0x80000,
/// set on Alice's side for contacts like Bob that have scanned the QR code offered by her. Only means the contact has once been established using the "securejoin" procedure in the past, getting the current key verification status requires calling dc_contact_is_verified() !
SecurejoinInvited = 0x0100_0000,
SecurejoinInvited = 0x1000000,
/// set on Bob's side for contacts scanned and verified from a QR code. Only means the contact has once been established using the "securejoin" procedure in the past, getting the current key verification status requires calling dc_contact_is_verified() !
SecurejoinJoined = 0x0200_0000,
SecurejoinJoined = 0x2000000,
/// contact added mannually by dc_create_contact(), this should be the largets origin as otherwise the user cannot modify the names
ManuallyCreated = 0x0400_0000,
ManuallyCreated = 0x4000000,
}
impl Default for Origin {
@@ -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,14 @@ fn dc_add_or_lookup_contacts_by_address_list(
}
};
let mut contact_ids = ContactIds::new();
info!(
context,
"dc_add_or_lookup_contacts_by_address raw={:?} addrs={:?}", addr_list_raw, addrs
);
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 +1562,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 +1573,7 @@ fn dc_add_or_lookup_contacts_by_address_list(
}
}
Ok(contact_ids)
Ok(())
}
/// Add contacts to database on receiving messages.
@@ -1563,6 +1591,10 @@ fn add_or_lookup_contact_by_addr(
.map(normalize_name)
.unwrap_or_default();
info!(
context,
"looking up addr={:?} display_name={:?}", addr, display_name_normalized
);
let (row_id, _modified) =
Contact::add_or_lookup(context, display_name_normalized, addr, origin)?;
ensure!(row_id > 0, "could not add contact: {:?}", addr);

View File

@@ -49,8 +49,8 @@ pub(crate) fn dc_truncate(buf: &str, approx_chars: usize, do_unwrap: bool) -> Co
/// - harmonize together while being different enough
/// (therefore, we cannot just use random rgb colors :)
const COLORS: [u32; 16] = [
0xe5_65_55, 0xf2_8c_48, 0x8e_85_ee, 0x76_c8_4d, 0x5b_b6_cc, 0x54_9c_dd, 0xd2_5c_99, 0xb3_78_00,
0xf2_30_30, 0x39_b2_49, 0xbb_24_3b, 0x96_40_78, 0x66_87_4f, 0x30_8a_b9, 0x12_7e_d0, 0xbe_45_0c,
0xe56555, 0xf28c48, 0x8e85ee, 0x76c84d, 0x5bb6cc, 0x549cdd, 0xd25c99, 0xb37800, 0xf23030,
0x39b249, 0xbb243b, 0x964078, 0x66874f, 0x308ab9, 0x127ed0, 0xbe450c,
];
pub(crate) fn dc_str_to_color(s: impl AsRef<str>) -> u32 {
@@ -59,7 +59,7 @@ pub(crate) fn dc_str_to_color(s: impl AsRef<str>) -> u32 {
let bytes = str_lower.as_bytes();
for (i, byte) in bytes.iter().enumerate() {
checksum += (i + 1) * *byte as usize;
checksum %= 0x00ff_ffff;
checksum %= 0xffffff;
}
let color_index = checksum % COLORS.len();

View File

@@ -139,12 +139,13 @@ fn dehtml_starttag_cb<B: std::io::BufRead>(
dehtml.add_text = AddText::YesPreserveLineEnds;
}
"a" => {
if let Some(href) = event
.html_attributes()
.filter_map(|attr| attr.ok())
.find(|attr| String::from_utf8_lossy(attr.key).trim().to_lowercase() == "href")
{
if let Some(href) = event.html_attributes().find(|attr| {
attr.as_ref()
.map(|a| String::from_utf8_lossy(a.key).trim().to_lowercase() == "href")
.unwrap_or_default()
}) {
let href = href
.unwrap()
.unescape_and_decode_value(reader)
.unwrap_or_default()
.to_lowercase();

View File

@@ -480,19 +480,19 @@ pub fn perform_sentbox_idle(context: &Context) {
.idle(context, use_network);
}
pub fn interrupt_inbox_idle(context: &Context) {
info!(context, "interrupt_inbox_idle called");
// we do not block on trying to obtain the thread lock
// because we don't know in which state the thread is.
// If it's currently fetching then we can not get the lock
// but we flag it for checking jobs so that idle will be skipped.
match context.inbox_thread.try_read() {
Ok(inbox_thread) => {
inbox_thread.interrupt_idle(context);
}
Err(err) => {
*context.perform_inbox_jobs_needed.write().unwrap() = true;
warn!(context, "could not interrupt idle: {}", err);
pub fn interrupt_inbox_idle(context: &Context, block: bool) {
info!(context, "interrupt_inbox_idle called blocking={}", block);
if block {
context.inbox_thread.read().unwrap().interrupt_idle(context);
} else {
match context.inbox_thread.try_read() {
Ok(inbox_thread) => {
inbox_thread.interrupt_idle(context);
}
Err(err) => {
*context.perform_inbox_jobs_needed.write().unwrap() = true;
warn!(context, "could not interrupt idle: {}", err);
}
}
}
}
@@ -604,7 +604,7 @@ pub fn maybe_network(context: &Context) {
}
interrupt_smtp_idle(context);
interrupt_inbox_idle(context);
interrupt_inbox_idle(context, true);
interrupt_mvbox_idle(context);
interrupt_sentbox_idle(context);
}
@@ -972,7 +972,7 @@ pub fn job_add(
).ok();
match thread {
Thread::Imap => interrupt_inbox_idle(context),
Thread::Imap => interrupt_inbox_idle(context, false),
Thread::Smtp => interrupt_smtp_idle(context),
Thread::Unknown => {}
}

View File

@@ -1,7 +1,7 @@
#![deny(clippy::correctness, missing_debug_implementations, clippy::all)]
// for now we hide warnings to not clutter/hide errors during "cargo clippy"
#![allow(clippy::cognitive_complexity, clippy::too_many_arguments)]
#![allow(clippy::match_bool)]
#![allow(clippy::unreadable_literal, clippy::match_bool)]
#![feature(ptr_wrapping_offset_from)]
#![feature(drain_filter)]

View File

@@ -8,8 +8,9 @@ macro_rules! info {
($ctx:expr, $msg:expr, $($args:expr),* $(,)?) => {{
let formatted = format!($msg, $($args),*);
let thread = ::std::thread::current();
let full = format!("{thid:?} {file}:{line}: {msg}",
let full = format!("{thid:?}/{thname} {file}:{line}: {msg}",
thid = thread.id(),
thname = thread.name().unwrap_or("unnamed"),
file = file!(),
line = line!(),
msg = &formatted);
@@ -25,8 +26,9 @@ macro_rules! warn {
($ctx:expr, $msg:expr, $($args:expr),* $(,)?) => {{
let formatted = format!($msg, $($args),*);
let thread = ::std::thread::current();
let full = format!("{thid:?} {file}:{line}: {msg}",
let full = format!("{thid:?}/{thname} {file}:{line}: {msg}",
thid = thread.id(),
thname = thread.name().unwrap_or("unnamed"),
file = file!(),
line = line!(),
msg = &formatted);

View File

@@ -720,7 +720,7 @@ pub fn get_msg_info(context: &Context, msg_id: MsgId) -> String {
return ret;
}
let rawtxt = rawtxt.unwrap_or_default();
let rawtxt = dc_truncate(rawtxt.trim(), 100_000, false);
let rawtxt = dc_truncate(rawtxt.trim(), 100000, false);
let fts = dc_timestamp_to_str(msg.get_timestamp());
ret += &format!("Sent: {}", fts);

View File

@@ -2,20 +2,17 @@
pub mod send;
use std::time::Duration;
use async_smtp::smtp::client::net::*;
use async_smtp::*;
use async_std::task;
use crate::constants::*;
use crate::context::Context;
use crate::events::Event;
use crate::login_param::{dc_build_tls, LoginParam};
use crate::oauth2::*;
/// SMTP write and read timeout in seconds.
const SMTP_TIMEOUT: u64 = 30;
#[derive(Debug, Fail)]
pub enum Error {
#[fail(display = "Bad parameters")]
@@ -24,12 +21,12 @@ pub enum Error {
InvalidLoginAddress {
address: String,
#[cause]
error: error::Error,
error: async_smtp::error::Error,
},
#[fail(display = "SMTP failed to connect: {:?}", _0)]
ConnectionFailure(#[cause] smtp::error::Error),
ConnectionFailure(#[cause] async_smtp::smtp::error::Error),
#[fail(display = "SMTP: failed to setup connection {:?}", _0)]
ConnectionSetupFailure(#[cause] smtp::error::Error),
ConnectionSetupFailure(#[cause] async_smtp::smtp::error::Error),
#[fail(display = "SMTP: oauth2 error {:?}", _0)]
Oauth2Error { address: String },
#[fail(display = "TLS error")]
@@ -47,7 +44,7 @@ pub type Result<T> = std::result::Result<T, Error>;
#[derive(Default, DebugStub)]
pub struct Smtp {
#[debug_stub(some = "SmtpTransport")]
transport: Option<smtp::SmtpTransport>,
transport: Option<async_smtp::smtp::SmtpTransport>,
/// Email address we are sending from.
from: Option<EmailAddress>,
}
@@ -60,25 +57,18 @@ impl Smtp {
/// Disconnect the SMTP transport and drop it entirely.
pub fn disconnect(&mut self) {
if let Some(mut transport) = self.transport.take() {
async_std::task::block_on(transport.close()).ok();
if let Some(ref mut transport) = self.transport.take() {
transport.close();
}
}
/// Check whether we are connected.
/// check whether we are connected
pub fn is_connected(&self) -> bool {
self.transport
.as_ref()
.map(|t| t.is_connected())
.unwrap_or_default()
self.transport.is_some()
}
/// Connect using the provided login params.
/// Connect using the provided login params
pub fn connect(&mut self, context: &Context, lp: &LoginParam) -> Result<()> {
async_std::task::block_on(self.inner_connect(context, lp))
}
async fn inner_connect(&mut self, context: &Context, lp: &LoginParam) -> Result<()> {
if self.is_connected() {
warn!(context, "SMTP already connected.");
return Ok(());
@@ -114,21 +104,21 @@ impl Smtp {
}
let user = &lp.send_user;
(
smtp::authentication::Credentials::new(
async_smtp::smtp::authentication::Credentials::new(
user.to_string(),
access_token.unwrap_or_default(),
),
vec![smtp::authentication::Mechanism::Xoauth2],
vec![async_smtp::smtp::authentication::Mechanism::Xoauth2],
)
} else {
// plain
let user = lp.send_user.clone();
let pw = lp.send_pw.clone();
(
smtp::authentication::Credentials::new(user, pw),
async_smtp::smtp::authentication::Credentials::new(user, pw),
vec![
smtp::authentication::Mechanism::Plain,
smtp::authentication::Mechanism::Login,
async_smtp::smtp::authentication::Mechanism::Plain,
async_smtp::smtp::authentication::Mechanism::Login,
],
)
};
@@ -136,31 +126,30 @@ impl Smtp {
let security = if 0
!= lp.server_flags & (DC_LP_SMTP_SOCKET_STARTTLS | DC_LP_SMTP_SOCKET_PLAIN) as i32
{
smtp::ClientSecurity::Opportunistic(tls_parameters)
async_smtp::smtp::ClientSecurity::Opportunistic(tls_parameters)
} else {
smtp::ClientSecurity::Wrapper(tls_parameters)
async_smtp::smtp::ClientSecurity::Wrapper(tls_parameters)
};
let client = smtp::SmtpClient::with_security((domain.as_str(), port), security)
.await
.map_err(Error::ConnectionSetupFailure)?;
let client = task::block_on(async_smtp::smtp::SmtpClient::with_security(
(domain.as_str(), port),
security,
))
.map_err(Error::ConnectionSetupFailure)?;
let client = client
.smtp_utf8(true)
.credentials(creds)
.authentication_mechanism(mechanism)
.connection_reuse(smtp::ConnectionReuseParameters::ReuseUnlimited)
.timeout(Some(Duration::from_secs(SMTP_TIMEOUT)));
.connection_reuse(async_smtp::smtp::ConnectionReuseParameters::ReuseUnlimited);
let mut trans = client.into_transport();
trans.connect().await.map_err(Error::ConnectionFailure)?;
task::block_on(trans.connect()).map_err(Error::ConnectionFailure)?;
self.transport = Some(trans);
context.call_cb(Event::SmtpConnected(format!(
"SMTP-LOGIN as {} ok",
lp.send_user,
)));
Ok(())
}
}

View File

@@ -1,11 +1,16 @@
//! # SMTP message sending
use std::time::Duration;
use super::Smtp;
use async_smtp::*;
use crate::context::Context;
use crate::events::Event;
/// SMTP send times out after 15 minutes
const SEND_TIMEOUT: u64 = 15 * 60;
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, Fail)]
@@ -51,15 +56,18 @@ impl Smtp {
format!("{}", job_id), // only used for internal logging
message,
);
if let Some(ref mut transport) = self.transport {
transport.send(mail).await.map_err(Error::SendError)?;
let res =
async_std::future::timeout(Duration::from_secs(SEND_TIMEOUT), transport.send(mail))
.await?
.map_err(Error::SendError);
context.call_cb(Event::SmtpMessageSent(format!(
"Message len={} was smtp-sent to {}",
message_len, recipients_display
)));
Ok(())
res.map(|_response| {
context.call_cb(Event::SmtpMessageSent(format!(
"Message len={} was smtp-sent to {}",
message_len, recipients_display
)));
})
} else {
warn!(
context,