mirror of
https://github.com/chatmail/core.git
synced 2026-04-15 20:46:30 +03:00
Compare commits
2 Commits
py-1.51.0
...
alias-supp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4187523311 | ||
|
|
c6ad6cb0c9 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,6 +1,5 @@
|
||||
/target
|
||||
**/*.rs.bk
|
||||
/build
|
||||
|
||||
# ignore vi temporaries
|
||||
*~
|
||||
|
||||
46
CHANGELOG.md
46
CHANGELOG.md
@@ -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
4
Cargo.lock
generated
@@ -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",
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
------
|
||||
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -87,7 +87,7 @@ pub enum LotState {
|
||||
QrFprOk = 210,
|
||||
|
||||
/// id=contact
|
||||
QrFprMismatch = 220,
|
||||
QrFprMissmatch = 220,
|
||||
|
||||
/// test1=formatted fingerprint
|
||||
QrFprWithoutAddr = 230,
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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")
|
||||
|
||||
|
||||
67
src/qr.rs
67
src/qr.rs
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user