Compare commits

..

2 Commits

Author SHA1 Message Date
B. Petersen
4187523311 add missing members receiving non-dc messages 2021-03-14 23:50:06 +01:00
B. Petersen
c6ad6cb0c9 add failing test for alias support 2021-03-14 23:50:05 +01:00
14 changed files with 227 additions and 365 deletions

1
.gitignore vendored
View File

@@ -1,6 +1,5 @@
/target
**/*.rs.bk
/build
# ignore vi temporaries
*~

View File

@@ -1,23 +1,22 @@
# Changelog
## 1.51.0
## UNRELEASED
- breaking change: You have to call `dc_stop_io()`/`dc_start_io()`
before/after `dc_imex(DC_IMEX_EXPORT_BACKUP)`:
fix race condition and db corruption
when a message was received during backup #2253
- breaking change: You have to call dc_stop_io()/dc_start_io() before/after EXPORT_BACKUP:
fix race condition and db corruption when a message was received during backup #2253
- save subject for messages: new api `dc_msg_get_subject()`,
when quoting, use the subject of the quoted message as the new subject,
instead of the last subject in the chat #2274 #2283
- save subject for messages:
new api `dc_msg_get_subject()`,
when quoting, use the subject of the quoted message as the new subject, instead of the
last subject in the chat
- new apis to get full or html message,
`dc_msg_has_html()` and `dc_get_msg_html()` #2125 #2151 #2264 #2279
`dc_msg_has_html()` and `dc_get_msg_html()` #2125 #2151
- new chat type and apis for the new mailing list support,
`DC_CHAT_TYPE_MAILINGLIST`, `dc_msg_get_real_chat_id()`,
`dc_msg_get_override_sender_name()` #1964 #2181 #2185 #2195 #2211 #2210 #2240
#2241 #2243 #2258 #2259 #2261 #2267 #2270 #2272 #2290
#2243
- new api `dc_decide_on_contact_request()`,
deprecated `dc_create_chat_by_msg_id()` and `dc_marknoticed_contact()` #1964
@@ -26,7 +25,7 @@
- new api `dc_get_chat_encrinfo()` #2186
- new api `dc_contact_get_status()`, returning the recent footer #2218 #2307
- new api `dc_contact_get_status()`, returning the recent footer #2218
- improve contact name update rules,
add api `dc_contact_get_auth_name()` #2206 #2212 #2225
@@ -39,9 +38,6 @@
- api removed: `dc_contact_get_first_name()` #2165 #2171
- improve compatibility with providers changing the Message-ID
(as Outlook.com) #2250 #2265
- implement Consistent Color Generation (XEP-0392),
that results in contact colors be be changed #2228 #2229 #2239
@@ -76,7 +72,7 @@
- enable strict TLS for known providers by default #2121
- improve and harden secure join #2154 #2161 #2251
- improve and harden secure join #2154 #2161
- update `dc_get_info()` to return more information #2156
@@ -104,24 +100,10 @@
- fix parsing quoted encoded words in From: header #2193 #2204
- fix import/export race condition #2250
- fix: exclude muted chats from notified-list #2269 #2275
- fix: update uid_next if the server rewind it #2288
- fix: return error on fingerprint mismatch on qr-scan #2295
- fix ci #2217 #2226 #2244 #2245 #2249 #2277 #2286
- fix ci #2217 #2226
- try harder on backup opening #2148
- trash messages more thoroughly #2273
- nicer logging #2284
- add CMakeLists.txt #2260
- switch to rust 1.50, update toolchains, deps #2150 #2155 #2165 #2107 #2262 #2271
- improve python bindings #2113 #2115 #2133 #2214
@@ -129,9 +111,7 @@
- improve documentation #2143 #2160 #2175 #2146
- refactorings #2110 #2136 #2135 #2168 #2178 #2189 #2190 #2198 #2197 #2201 #2196
#2200 #2230 #2262 #2203
- update provider-database #2299
#2200 #2230
## 1.50.0

4
Cargo.lock generated
View File

@@ -1063,7 +1063,7 @@ dependencies = [
[[package]]
name = "deltachat"
version = "1.51.0"
version = "1.51.0-alpha.0"
dependencies = [
"ansi_term 0.12.1",
"anyhow",
@@ -1141,7 +1141,7 @@ dependencies = [
[[package]]
name = "deltachat_ffi"
version = "1.51.0"
version = "1.51.0-alpha.0"
dependencies = [
"anyhow",
"async-std",

View File

@@ -1,6 +1,6 @@
[package]
name = "deltachat"
version = "1.51.0"
version = "1.51.0-alpha.0"
authors = ["Delta Chat Developers (ML) <delta@codespeak.net>"]
edition = "2018"
license = "MPL-2.0"

View File

@@ -12,9 +12,8 @@ WHEELHOUSEDIR=${2:?directory with pre-built wheels}
DOXYDOCDIR=${3:?directory where doxygen docs to be found}
SSHTARGET=ci@b1.delta.chat
# if CIRCLE_BRANCH is not set we are called for a tag with empty CIRCLE_BRANCH variable.
export BRANCH=${CIRCLE_BRANCH:master}
export BRANCH=${CIRCLE_BRANCH:?specify branch for uploading purposes}
export BUILDDIR=ci_builds/$REPONAME/$BRANCH/${CIRCLE_JOB:?jobname}/${CIRCLE_BUILD_NUM:?circle-build-number}/wheelhouse

View File

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

View File

@@ -1,10 +1,3 @@
1.51.0
------
- adapt python bindings and APIs to core51 release
(see CHANGELOG of https://github.com/deltachat/deltachat-core-rust/blob/1.51.0/CHANGELOG.md#1510
for more details on all core changes)
1.44.0
------

View File

@@ -2187,25 +2187,9 @@ class TestOnlineAccount:
chat12 = acfactory.get_accepted_chat(ac1, ac2)
ac1.set_config("selfstatus", "New status")
chat12.send_text("hi")
msg_received = ac2._evtracker.wait_next_incoming_message()
assert msg_received.text == "hi"
assert msg_received.get_sender_contact().status == "New status"
# Send a reply from ac2 to ac1 so ac1 can send a read receipt.
reply_msg = msg_received.chat.send_text("reply")
reply_msg_received = ac1._evtracker.wait_next_incoming_message()
assert reply_msg_received.text == "reply"
# Send read receipt from ac1 to ac2.
# It does not contain the signature.
ac1.mark_seen_messages([reply_msg_received])
ev = ac2._evtracker.get_matching("DC_EVENT_MSG_READ")
assert ev.data1 == reply_msg.chat.id
assert ev.data2 == reply_msg.id
assert reply_msg.is_out_mdn_received()
# Test that the status is not cleared as a result of receiving a read receipt.
assert msg_received.get_sender_contact().status == "New status"
msg = ac2._evtracker.wait_next_incoming_message()
assert msg.text == "hi"
assert msg.get_sender_contact().status == "New status"
ac1.set_config("selfstatus", "")
chat12.send_text("hello")

View File

@@ -237,18 +237,14 @@ pub(crate) async fn dc_receive_imf_inner(
}
// Always update the status, even if there is no footer, to allow removing the status.
//
// Ignore MDNs though, as they never contain the signature even if user has set it.
if mime_parser.mdn_reports.is_empty() {
if let Err(err) = contact::set_status(
context,
from_id,
mime_parser.footer.clone().unwrap_or_default(),
)
.await
{
warn!(context, "cannot update contact status: {}", err);
}
if let Err(err) = contact::set_status(
context,
from_id,
mime_parser.footer.clone().unwrap_or_default(),
)
.await
{
warn!(context, "cannot update contact status: {}", err);
}
// Get user-configured server deletion
@@ -1168,6 +1164,44 @@ async fn calc_sort_timestamp(
sort_timestamp
}
async fn update_member_list(
context: &Context,
chat_id: ChatId,
self_addr: String,
from_id: u32,
to_ids: &ContactIds,
) -> Result<()> {
if !chat::is_contact_in_chat(context, chat_id, DC_CONTACT_ID_SELF).await {
// Members could have been removed while we were
// absent. We can't use existing member list and need to
// start from scratch.
context
.sql
.execute(
"DELETE FROM chats_contacts WHERE chat_id=?;",
paramsv![chat_id],
)
.await?;
chat::add_to_chat_contacts_table(context, chat_id, DC_CONTACT_ID_SELF).await;
}
if from_id > DC_CONTACT_ID_LAST_SPECIAL
&& !Contact::addr_equals_contact(context, &self_addr, from_id as u32).await
&& !chat::is_contact_in_chat(context, chat_id, from_id).await
{
chat::add_to_chat_contacts_table(context, chat_id, from_id as u32).await;
}
for &to_id in to_ids.iter() {
info!(context, "adding to={:?} to chat id={}", to_id, chat_id);
if !Contact::addr_equals_contact(context, &self_addr, to_id).await
&& !chat::is_contact_in_chat(context, chat_id, to_id).await
{
chat::add_to_chat_contacts_table(context, chat_id, to_id).await;
}
}
Ok(())
}
/// This function tries to extract the group-id from the message and returns the
/// corresponding chat_id. If the chat does not exist, it is created.
/// If the message contains groups commands (name, profile image, changed members),
@@ -1201,6 +1235,11 @@ async fn create_or_lookup_group(
set_better_msg(mime_parser, &better_msg);
}
let self_addr = context
.get_config(Config::ConfiguredAddr)
.await
.unwrap_or_default();
let grpid = if let Some(grpid) = try_getting_grpid(mime_parser) {
grpid
} else {
@@ -1225,6 +1264,11 @@ async fn create_or_lookup_group(
// Otherwise, it could be a reply to an undecipherable
// group message that we previously assigned to a 1:1 chat.
if chat.typ == Chattype::Group {
// If we assign a non-dc-message to an existing chat,
// add missing contacts to the member list.
update_member_list(context, chat.id, self_addr, from_id, to_ids).await?;
context.emit_event(EventType::ChatModified(chat.id));
// Return immediately without attempting to execute group commands,
// as this message does not contain an explicit group-id header.
return Ok((chat.id, chat.blocked));
@@ -1328,10 +1372,6 @@ async fn create_or_lookup_group(
let group_explicitly_left = chat::is_group_explicitly_left(context, &grpid)
.await
.unwrap_or_default();
let self_addr = context
.get_config(Config::ConfiguredAddr)
.await
.unwrap_or_default();
if chat_id.is_unset()
&& !mime_parser.is_mailinglist_message()
@@ -1458,35 +1498,7 @@ async fn create_or_lookup_group(
// add members to group/check members
if recreate_member_list {
if !chat::is_contact_in_chat(context, chat_id, DC_CONTACT_ID_SELF).await {
// Members could have been removed while we were
// absent. We can't use existing member list and need to
// start from scratch.
context
.sql
.execute(
"DELETE FROM chats_contacts WHERE chat_id=?;",
paramsv![chat_id],
)
.await
.ok();
chat::add_to_chat_contacts_table(context, chat_id, DC_CONTACT_ID_SELF).await;
}
if from_id > DC_CONTACT_ID_LAST_SPECIAL
&& !Contact::addr_equals_contact(context, &self_addr, from_id as u32).await
&& !chat::is_contact_in_chat(context, chat_id, from_id).await
{
chat::add_to_chat_contacts_table(context, chat_id, from_id as u32).await;
}
for &to_id in to_ids.iter() {
info!(context, "adding to={:?} to chat id={}", to_id, chat_id);
if !Contact::addr_equals_contact(context, &self_addr, to_id).await
&& !chat::is_contact_in_chat(context, chat_id, to_id).await
{
chat::add_to_chat_contacts_table(context, chat_id, to_id).await;
}
}
update_member_list(context, chat_id, self_addr, from_id, to_ids).await?;
send_EVENT_CHAT_MODIFIED = true;
} else if let Some(contact_id) = removed_id {
chat::remove_from_chat_contacts_table(context, chat_id, contact_id).await;
@@ -2037,7 +2049,7 @@ fn dc_create_incoming_rfc724_mid(
mod tests {
use super::*;
use crate::chat::{get_chat_msgs, ChatItem, ChatVisibility};
use crate::chat::{get_chat_contacts, get_chat_msgs, ChatItem, ChatVisibility};
use crate::chatlist::Chatlist;
use crate::constants::{DC_CHAT_ID_DEADDROP, DC_CONTACT_ID_INFO, DC_GCL_NO_SPECIALS};
use crate::message::ContactRequestDecision::*;
@@ -3475,4 +3487,107 @@ YEAAAAAA!.
assert_eq!(chat.typ, Chattype::Single);
assert_eq!(msg.get_text().unwrap(), "private reply");
}
async fn test_alias() -> (TestContext, Chat) {
// Claire, a customer, sends a support request
// to the alias address <support@example.org> from a classic MUA.
// The alias expands to the supporters Alice and Bob.
// Check that Alice receives the message in a group chat.
let alice = TestContext::new_alice().await;
alice
.set_config(Config::ShowEmails, Some("2"))
.await
.unwrap();
dc_receive_imf(
&alice,
b"To: support@example.org\n\
From: claire@example.org\n\
Subject: i have a question\n\
Message-ID: <non-dc-1@example.org>\n\
Date: Sun, 14 Mar 2021 17:04:36 +0100\n\
Content-Type: text/plain\n\
\n\
hi support! what is the current version?",
"INBOX",
1,
false,
)
.await
.unwrap();
let msg = alice.get_last_msg().await;
assert_eq!(msg.get_subject(), "i have a question");
assert!(msg.get_text().unwrap().contains("hi support!"));
let chat = Chat::load_from_db(&alice, msg.chat_id).await.unwrap();
assert_eq!(chat.typ, Chattype::Group);
assert_eq!(get_chat_msgs(&alice, chat.id, 0, None).await.len(), 1);
assert_eq!(get_chat_contacts(&alice, chat.id).await.len(), 3);
(alice, chat)
}
#[async_std::test]
async fn test_alias_support_answer_from_nondc() {
let (alice, chat) = test_alias().await;
// Bob, the other supporter, answers with a classic MUA.
// Check that Alice gets the message in the same chat.
dc_receive_imf(
&alice,
b"To: support@example.org, claire@example.org\n\
From: bob@example.net\n\
Subject: =?utf-8?q?Re=3A_i_have_a_question?=\n\
References: <non-dc-1@example.org>\n\
In-Reply-To: <non-dc-1@example.org>\n\
Message-ID: <non-dc-2@example.net>\n\
Date: Sun, 14 Mar 2021 16:04:57 +0000\n\
Content-Type: text/plain\n\
\n\
hi claire, the version is 1.0, cheers bob",
"INBOX",
2,
false,
)
.await
.unwrap();
let msg = alice.get_last_msg().await;
assert_eq!(msg.get_subject(), "Re: i have a question");
assert!(msg.get_text().unwrap().contains("the version is 1.0"));
assert_eq!(msg.chat_id, chat.id);
assert_eq!(get_chat_contacts(&alice, chat.id).await.len(), 4);
}
#[async_std::test]
async fn test_alias_answer_from_dc() {
let (alice, chat) = test_alias().await;
// Bob, the other supporter, answers with Delta Chat.
// Check that Alice gets the message in the same chat.
dc_receive_imf(
&alice,
b"To: support@example.org, claire@example.org\n\
From: bob@example.net\n\
Subject: =?utf-8?q?Re=3A_i_have_a_question?=\n\
References: <Gr.af9e810c9b592927.gNm8dVdkZsH@example.net>\n\
In-Reply-To: <non-dc-1@example.org>\n\
Message-ID: <Gr.af9e810c9b592927.gNm8dVdkZsH@example.net>\n\
Date: Sun, 14 Mar 2021 16:04:57 +0000\n\
Chat-Version: 1.0\n\
Chat-Group-ID: af9e810c9b592927\n\
Chat-Group-Name: =?utf-8?q?i_have_a_question?=\n\
Chat-Disposition-Notification-To: bob@example.net\n\
Content-Type: text/plain\n\
\n\
hi claire, the version is 1.0, cheers bob",
"INBOX",
2,
false,
)
.await
.unwrap();
let msg = alice.get_last_msg().await;
assert_eq!(msg.get_subject(), "Re: i have a question");
assert!(msg.get_text().unwrap().contains("the version is 1.0"));
assert_eq!(msg.chat_id, chat.id); // FIXME: that fails
assert_eq!(get_chat_contacts(&alice, chat.id).await.len(), 4); // FIXME: that fails
}
}

View File

@@ -575,15 +575,6 @@ impl Imap {
// new messages is only one command, just as a SELECT command)
true
} else if let Some(uid_next) = mailbox.uid_next {
if uid_next < old_uid_next {
warn!(
context,
"The server illegally decreased the uid_next of folder {} from {} to {} without changing validity ({}), resyncing UIDs...",
folder, old_uid_next, uid_next, new_uid_validity,
);
set_uid_next(context, folder, uid_next).await?;
job::schedule_resync(context).await;
}
uid_next != old_uid_next // If uid_next changed, there are new emails
} else {
true // We have no uid_next and if in doubt, return true

View File

@@ -87,7 +87,7 @@ pub enum LotState {
QrFprOk = 210,
/// id=contact
QrFprMismatch = 220,
QrFprMissmatch = 220,
/// test1=formatted fingerprint
QrFprWithoutAddr = 230,

View File

@@ -296,35 +296,6 @@ static P_DUBBY_ORG: Lazy<Provider> = Lazy::new(|| Provider {
oauth2_authorizer: None,
});
// e.email.md: e.email
static P_E_EMAIL: Lazy<Provider> = Lazy::new(|| Provider {
id: "e.email",
status: Status::OK,
before_login_hint: "",
after_login_hint: "",
overview_page: "https://providers.delta.chat/e-email",
server: vec![
Server {
protocol: IMAP,
socket: SSL,
hostname: "mail.ecloud.global",
port: 993,
username_pattern: EMAIL,
},
Server {
protocol: SMTP,
socket: STARTTLS,
hostname: "mail.ecloud.global",
port: 587,
username_pattern: EMAIL,
},
],
config_defaults: None,
strict_tls: true,
max_smtp_rcpt_to: None,
oauth2_authorizer: None,
});
// espiv.net.md: espiv.net
static P_ESPIV_NET: Lazy<Provider> = Lazy::new(|| Provider {
id: "espiv.net",
@@ -366,29 +337,7 @@ static P_FASTMAIL: Lazy<Provider> = Lazy::new(|| Provider {
"You must create an app-specific password for Delta Chat before you can log in.",
after_login_hint: "",
overview_page: "https://providers.delta.chat/fastmail",
server: vec![
Server {
protocol: IMAP,
socket: SSL,
hostname: "imap.fastmail.com",
port: 993,
username_pattern: EMAIL,
},
Server {
protocol: SMTP,
socket: SSL,
hostname: "smtp.fastmail.com",
port: 465,
username_pattern: EMAIL,
},
Server {
protocol: SMTP,
socket: STARTTLS,
hostname: "smtp.fastmail.com",
port: 587,
username_pattern: EMAIL,
},
],
server: vec![],
config_defaults: None,
strict_tls: true,
max_smtp_rcpt_to: None,
@@ -444,22 +393,32 @@ static P_FIVE_CHAT: Lazy<Provider> = Lazy::new(|| Provider {
});
// freenet.de.md: freenet.de
static P_FREENET_DE: Lazy<Provider> = Lazy::new(|| {
Provider {
static P_FREENET_DE: Lazy<Provider> = Lazy::new(|| Provider {
id: "freenet.de",
status: Status::PREPARATION,
before_login_hint: "Um deine freenet.de E-Mail-Adresse mit Delta Chat zu benutzen, musst du erst auf der freenet.de-Webseite \"POP3/IMAP/SMTP\" aktivieren.",
status: Status::OK,
before_login_hint: "",
after_login_hint: "",
overview_page: "https://providers.delta.chat/freenet-de",
server: vec![
Server { protocol: IMAP, socket: SSL, hostname: "mx.freenet.de", port: 993, username_pattern: EMAIL },
Server { protocol: SMTP, socket: STARTTLS, hostname: "mx.freenet.de", port: 587, username_pattern: EMAIL },
Server {
protocol: IMAP,
socket: SSL,
hostname: "mx.freenet.de",
port: 993,
username_pattern: EMAIL,
},
Server {
protocol: SMTP,
socket: STARTTLS,
hostname: "mx.freenet.de",
port: 587,
username_pattern: EMAIL,
},
],
config_defaults: None,
strict_tls: true,
max_smtp_rcpt_to: None,
oauth2_authorizer: None,
}
});
// gmail.md: gmail.com, googlemail.com, google.com
@@ -579,20 +538,6 @@ static P_I_UA: Lazy<Provider> = Lazy::new(|| Provider {
oauth2_authorizer: None,
});
// i3.net.md: i3.net
static P_I3_NET: Lazy<Provider> = Lazy::new(|| Provider {
id: "i3.net",
status: Status::OK,
before_login_hint: "",
after_login_hint: "",
overview_page: "https://providers.delta.chat/i3-net",
server: vec![],
config_defaults: None,
strict_tls: true,
max_smtp_rcpt_to: None,
oauth2_authorizer: None,
});
// icloud.md: icloud.com, me.com, mac.com
static P_ICLOUD: Lazy<Provider> = Lazy::new(|| Provider {
id: "icloud",
@@ -679,124 +624,51 @@ static P_MAILBOX_ORG: Lazy<Provider> = Lazy::new(|| Provider {
oauth2_authorizer: None,
});
// mailo.com.md: mailo.com
static P_MAILO_COM: Lazy<Provider> = Lazy::new(|| Provider {
id: "mailo.com",
status: Status::OK,
before_login_hint: "",
after_login_hint: "",
overview_page: "https://providers.delta.chat/mailo-com",
server: vec![
Server {
protocol: IMAP,
socket: SSL,
hostname: "imap.mailo.com",
port: 993,
username_pattern: EMAIL,
},
Server {
protocol: SMTP,
socket: SSL,
hostname: "smtp.mailo.com",
port: 465,
username_pattern: EMAIL,
},
],
config_defaults: None,
strict_tls: true,
max_smtp_rcpt_to: None,
oauth2_authorizer: None,
});
// nauta.cu.md: nauta.cu
static P_NAUTA_CU: Lazy<Provider> = Lazy::new(|| Provider {
static P_NAUTA_CU: Lazy<Provider> = Lazy::new(|| {
Provider {
id: "nauta.cu",
status: Status::OK,
before_login_hint: "",
after_login_hint: "",
after_login_hint: "Atención - con nauta.cu, puede enviar mensajes sólo a un máximo de 20 personas a la vez. En grupos más grandes, no puede enviar mensajes o abandonar el grupo.",
overview_page: "https://providers.delta.chat/nauta-cu",
server: vec![
Server {
protocol: IMAP,
socket: STARTTLS,
hostname: "imap.nauta.cu",
port: 143,
username_pattern: EMAIL,
},
Server {
protocol: SMTP,
socket: STARTTLS,
hostname: "smtp.nauta.cu",
port: 25,
username_pattern: EMAIL,
},
Server { protocol: IMAP, socket: STARTTLS, hostname: "imap.nauta.cu", port: 143, username_pattern: EMAIL },
Server { protocol: SMTP, socket: STARTTLS, hostname: "smtp.nauta.cu", port: 25, username_pattern: EMAIL },
],
config_defaults: Some(vec![
ConfigDefault {
key: Config::DeleteServerAfter,
value: "1",
},
ConfigDefault {
key: Config::BccSelf,
value: "0",
},
ConfigDefault {
key: Config::SentboxWatch,
value: "0",
},
ConfigDefault {
key: Config::MvboxWatch,
value: "0",
},
ConfigDefault {
key: Config::MvboxMove,
value: "0",
},
ConfigDefault {
key: Config::E2eeEnabled,
value: "0",
},
ConfigDefault {
key: Config::MediaQuality,
value: "1",
},
ConfigDefault {
key: Config::FetchExistingMsgs,
value: "0",
},
ConfigDefault { key: Config::DeleteServerAfter, value: "1" },
ConfigDefault { key: Config::BccSelf, value: "0" },
ConfigDefault { key: Config::SentboxWatch, value: "0" },
ConfigDefault { key: Config::MvboxWatch, value: "0" },
ConfigDefault { key: Config::MvboxMove, value: "0" },
ConfigDefault { key: Config::E2eeEnabled, value: "0" },
ConfigDefault { key: Config::MediaQuality, value: "1" },
ConfigDefault { key: Config::FetchExistingMsgs, value: "0" },
]),
strict_tls: false,
max_smtp_rcpt_to: Some(20),
oauth2_authorizer: None,
}
});
// outlook.com.md: hotmail.com, outlook.com, office365.com, outlook.com.tr, live.com
static P_OUTLOOK_COM: Lazy<Provider> = Lazy::new(|| Provider {
static P_OUTLOOK_COM: Lazy<Provider> = Lazy::new(|| {
Provider {
id: "outlook.com",
status: Status::OK,
before_login_hint: "",
after_login_hint: "",
status: Status::BROKEN,
before_login_hint: "Outlook.com email addresses will not work as expected as these servers remove some important transport information. Hopefully sooner or later there will be a fix, for now we suggest to use another email address.",
after_login_hint: "Outlook.com email addresses will not work as expected as these servers remove some important transport information. Unencrypted 1-on-1 chats kind of work, but groups and encryption don't. Hopefully sooner or later there will be a fix, for now we suggest to use another email address.",
overview_page: "https://providers.delta.chat/outlook-com",
server: vec![
Server {
protocol: IMAP,
socket: SSL,
hostname: "outlook.office365.com",
port: 993,
username_pattern: EMAIL,
},
Server {
protocol: SMTP,
socket: STARTTLS,
hostname: "smtp.office365.com",
port: 587,
username_pattern: EMAIL,
},
Server { protocol: IMAP, socket: SSL, hostname: "imap-mail.outlook.com", port: 993, username_pattern: EMAIL },
Server { protocol: SMTP, socket: STARTTLS, hostname: "smtp-mail.outlook.com", port: 587, username_pattern: EMAIL },
],
config_defaults: None,
strict_tls: true,
max_smtp_rcpt_to: None,
oauth2_authorizer: None,
}
});
// posteo.md: posteo.de, posteo.af, posteo.at, posteo.be, posteo.ch, posteo.cl, posteo.co, posteo.co.uk, posteo.com.br, posteo.cr, posteo.cz, posteo.dk, posteo.ee, posteo.es, posteo.eu, posteo.fi, posteo.gl, posteo.gr, posteo.hn, posteo.hr, posteo.hu, posteo.ie, posteo.in, posteo.is, posteo.jp, posteo.la, posteo.li, posteo.lt, posteo.lu, posteo.me, posteo.mx, posteo.my, posteo.net, posteo.nl, posteo.no, posteo.nz, posteo.org, posteo.pe, posteo.pl, posteo.pm, posteo.pt, posteo.ro, posteo.ru, posteo.se, posteo.sg, posteo.si, posteo.tn, posteo.uk, posteo.us
@@ -1185,7 +1057,6 @@ pub(crate) static PROVIDER_DATA: Lazy<HashMap<&'static str, &'static Provider>>
("dismail.de", &*P_DISMAIL_DE),
("disroot.org", &*P_DISROOT),
("dubby.org", &*P_DUBBY_ORG),
("e.email", &*P_E_EMAIL),
("espiv.net", &*P_ESPIV_NET),
("example.com", &*P_EXAMPLE_COM),
("example.org", &*P_EXAMPLE_COM),
@@ -1210,7 +1081,6 @@ pub(crate) static PROVIDER_DATA: Lazy<HashMap<&'static str, &'static Provider>>
("hermes.radio", &*P_HERMES_RADIO),
("hey.com", &*P_HEY_COM),
("i.ua", &*P_I_UA),
("i3.net", &*P_I3_NET),
("icloud.com", &*P_ICLOUD),
("me.com", &*P_ICLOUD),
("mac.com", &*P_ICLOUD),
@@ -1222,7 +1092,6 @@ pub(crate) static PROVIDER_DATA: Lazy<HashMap<&'static str, &'static Provider>>
("list.ru", &*P_MAIL_RU),
("mailbox.org", &*P_MAILBOX_ORG),
("secure.mailbox.org", &*P_MAILBOX_ORG),
("mailo.com", &*P_MAILO_COM),
("nauta.cu", &*P_NAUTA_CU),
("hotmail.com", &*P_OUTLOOK_COM),
("outlook.com", &*P_OUTLOOK_COM),
@@ -1361,7 +1230,6 @@ pub(crate) static PROVIDER_IDS: Lazy<HashMap<&'static str, &'static Provider>> =
("dismail.de", &*P_DISMAIL_DE),
("disroot", &*P_DISROOT),
("dubby.org", &*P_DUBBY_ORG),
("e.email", &*P_E_EMAIL),
("espiv.net", &*P_ESPIV_NET),
("example.com", &*P_EXAMPLE_COM),
("fastmail", &*P_FASTMAIL),
@@ -1373,13 +1241,11 @@ pub(crate) static PROVIDER_IDS: Lazy<HashMap<&'static str, &'static Provider>> =
("hermes.radio", &*P_HERMES_RADIO),
("hey.com", &*P_HEY_COM),
("i.ua", &*P_I_UA),
("i3.net", &*P_I3_NET),
("icloud", &*P_ICLOUD),
("kolst.com", &*P_KOLST_COM),
("kontent.com", &*P_KONTENT_COM),
("mail.ru", &*P_MAIL_RU),
("mailbox.org", &*P_MAILBOX_ORG),
("mailo.com", &*P_MAILO_COM),
("nauta.cu", &*P_NAUTA_CU),
("outlook.com", &*P_OUTLOOK_COM),
("posteo", &*P_POSTEO),
@@ -1405,4 +1271,4 @@ pub(crate) static PROVIDER_IDS: Lazy<HashMap<&'static str, &'static Provider>> =
});
pub static PROVIDER_UPDATED: Lazy<chrono::NaiveDate> =
Lazy::new(|| chrono::NaiveDate::from_ymd(2021, 3, 18));
Lazy::new(|| chrono::NaiveDate::from_ymd(2021, 1, 8));

View File

@@ -175,7 +175,7 @@ if __name__ == "__main__":
"use crate::provider::Protocol::*;\n"
"use crate::provider::Socket::*;\n"
"use crate::provider::UsernamePattern::*;\n"
"use crate::provider::{Config, ConfigDefault, Oauth2Authorizer, Provider, Server, Status};\n"
"use crate::provider::*;\n"
"use std::collections::HashMap;\n\n"
"use once_cell::sync::Lazy;\n\n")

View File

@@ -72,7 +72,6 @@ pub async fn check_qr(context: &Context, qr: impl AsRef<str>) -> Lot {
/// scheme: `OPENPGP4FPR:FINGERPRINT#a=ADDR&n=NAME&i=INVITENUMBER&s=AUTH`
/// or: `OPENPGP4FPR:FINGERPRINT#a=ADDR&g=GROUPNAME&x=GROUPID&i=INVITENUMBER&s=AUTH`
/// or: `OPENPGP4FPR:FINGERPRINT#a=ADDR`
#[allow(clippy::indexing_slicing)]
async fn decode_openpgp(context: &Context, qr: &str) -> Lot {
let payload = &qr[OPENPGP4FPR_SCHEME.len()..];
@@ -170,14 +169,6 @@ async fn decode_openpgp(context: &Context, qr: &str) -> Lot {
.unwrap_or_default();
chat::add_info_msg(context, id, format!("{} verified.", peerstate.addr)).await;
} else if let Some(addr) = addr {
lot.state = LotState::QrFprMismatch;
lot.id = match Contact::lookup_id_by_addr(context, &addr, Origin::Unknown).await {
Ok(contact_id) => contact_id.unwrap_or_default(),
Err(err) => {
return format_err!("Error looking up contact {:?}: {}", addr, err).into()
}
};
} else {
lot.state = LotState::QrFprWithoutAddr;
lot.text1 = Some(fingerprint.to_string());
@@ -445,10 +436,7 @@ fn normalize_address(addr: &str) -> Result<String, Error> {
mod tests {
use super::*;
use crate::aheader::EncryptPreference;
use crate::key::DcKey;
use crate::peerstate::ToSave;
use crate::test_utils::{alice_keypair, TestContext};
use crate::test_utils::TestContext;
#[async_std::test]
async fn test_decode_http() {
@@ -637,59 +625,6 @@ mod tests {
assert_eq!(contact.get_name(), "");
}
#[async_std::test]
async fn test_decode_openpgp_fingerprint() {
let ctx = TestContext::new().await;
let contact_id = Contact::create(&ctx, "Alice", "alice@example.com")
.await
.expect("failed to create contact");
let pub_key = alice_keypair().public;
let peerstate = Peerstate {
addr: "alice@example.com".to_string(),
last_seen: 1,
last_seen_autocrypt: 1,
prefer_encrypt: EncryptPreference::Mutual,
public_key: Some(pub_key.clone()),
public_key_fingerprint: Some(pub_key.fingerprint()),
gossip_key: None,
gossip_timestamp: 0,
gossip_key_fingerprint: None,
verified_key: None,
verified_key_fingerprint: None,
to_save: Some(ToSave::All),
fingerprint_changed: false,
};
assert!(
peerstate.save_to_db(&ctx.ctx.sql, true).await.is_ok(),
"failed to save peerstate"
);
let res = check_qr(
&ctx.ctx,
"OPENPGP4FPR:1234567890123456789012345678901234567890#a=alice@example.com",
)
.await;
assert_eq!(res.get_state(), LotState::QrFprMismatch);
assert_eq!(res.get_id(), contact_id);
let res = check_qr(
&ctx.ctx,
format!("OPENPGP4FPR:{}#a=alice@example.com", pub_key.fingerprint()),
)
.await;
assert_eq!(res.get_state(), LotState::QrFprOk);
assert_eq!(res.get_id(), contact_id);
let res = check_qr(
&ctx.ctx,
"OPENPGP4FPR:1234567890123456789012345678901234567890#a=bob@example.org",
)
.await;
assert_eq!(res.get_state(), LotState::QrFprMismatch);
assert_eq!(res.get_id(), 0);
}
#[async_std::test]
async fn test_decode_openpgp_without_addr() {
let ctx = TestContext::new().await;