Introduce SecondaryAddrs config and make stuff work

This commit is contained in:
Hocuri
2022-04-13 10:03:49 +02:00
committed by holger krekel
parent 3ffc985968
commit 3b6fc9959f
16 changed files with 194 additions and 91 deletions

View File

@@ -18,7 +18,7 @@ use crate::constants::{
Blocked, Chattype, DC_CHAT_ID_ALLDONE_HINT, DC_CHAT_ID_ARCHIVED_LINK, DC_CHAT_ID_LAST_SPECIAL,
DC_CHAT_ID_TRASH, DC_GCM_ADDDAYMARKER, DC_GCM_INFO_ONLY, DC_RESEND_USER_AVATAR_DAYS,
};
use crate::contact::{addr_cmp, Contact, ContactId, Origin, VerifiedStatus};
use crate::contact::{Contact, ContactId, Origin, VerifiedStatus};
use crate::context::Context;
use crate::dc_receive_imf::ReceivedMsg;
use crate::dc_tools::{
@@ -1243,7 +1243,7 @@ impl Chat {
}
}
let from = context.get_configured_addr().await?;
let from = context.get_primary_self_addr().await?;
let new_rfc724_mid = {
let grpid = match self.typ {
Chattype::Group => Some(self.grpid.as_str()),
@@ -2023,7 +2023,7 @@ async fn create_send_msg_job(context: &Context, msg_id: MsgId) -> Result<Option<
let mut recipients = mimefactory.recipients();
let from = context.get_configured_addr().await?;
let from = context.get_primary_self_addr().await?;
let lowercase_from = from.to_lowercase();
// Send BCC to self if it is enabled and we are not going to
@@ -2690,8 +2690,8 @@ pub(crate) async fn add_contact_to_chat_ex(
context.sync_qr_code_tokens(Some(chat_id)).await?;
context.send_sync_msg().await?;
}
let self_addr = context.get_configured_addr().await.unwrap_or_default();
if addr_cmp(contact.get_addr(), &self_addr) {
if context.is_self_addr(contact.get_addr()).await? {
// ourself is added using ContactId::SELF, do not add this address explicitly.
// if SELF is not in the group, members cannot be added at all.
warn!(
@@ -3598,7 +3598,7 @@ mod tests {
#[async_std::test]
async fn test_add_contact_to_chat_ex_add_self() {
// Adding self to a contact should succeed, even though it's pointless.
let t = TestContext::new().await;
let t = TestContext::new_alice().await;
let chat_id = create_group_chat(&t, ProtectionStatus::Unprotected, "foo")
.await
.unwrap();

View File

@@ -6,6 +6,7 @@ use strum_macros::{AsRefStr, Display, EnumIter, EnumProperty, EnumString};
use crate::blob::BlobObject;
use crate::constants::DC_VERSION_STR;
use crate::contact::addr_normalize;
use crate::context::Context;
use crate::dc_tools::{dc_get_abs_path, improve_single_line_input};
use crate::events::EventType;
@@ -111,6 +112,7 @@ pub enum Config {
DeleteDeviceAfter,
SaveMimeHeaders,
/// The primary email address. Also see `SecondaryAddrs`.
ConfiguredAddr,
ConfiguredMailServer,
ConfiguredMailUser,
@@ -133,6 +135,10 @@ pub enum Config {
ConfiguredProvider,
Configured,
/// All secondary self addresses separated by spaces
/// (`addr1@example.org addr2@exapmle.org addr3@example.org`)
SecondaryAddrs,
#[strum(serialize = "sys.version")]
SysVersion,
@@ -226,12 +232,6 @@ impl Context {
Ok(self.get_config_int(key).await? != 0)
}
pub(crate) async fn get_configured_addr(&self) -> Result<String> {
self.get_config(Config::ConfiguredAddr)
.await?
.context("no address configured")
}
pub(crate) async fn should_watch_mvbox(&self) -> Result<bool> {
Ok(self.get_config_bool(Config::MvboxMove).await?
|| self.get_config_bool(Config::OnlyFetchMvbox).await?)
@@ -333,6 +333,70 @@ impl Context {
}
}
// Separate impl block for self address handling
impl Context {
/// determine whether the specified addr maps to the/a self addr
pub async fn is_self_addr(&self, addr: &str) -> Result<bool> {
let addr = addr_normalize(addr).to_lowercase();
// The addresses we get here are already normalized and lowercase TODO is this true?
Ok(
self.get_config(Config::ConfiguredAddr).await?.as_deref() == Some(&addr)
|| self.get_secondary_self_addrs().await?.contains(&addr),
)
}
/// Sets `primary_new` as the new primary self address and saves the old
/// primary address (if exists) as a secondary address.
pub(crate) async fn set_primary_self_addr(&self, primary_new: &str) -> Result<()> {
let primary_new = addr_normalize(primary_new).to_lowercase(); // TODO check if this might make problems
// Get all self addrs, including the old primary addr:
let mut secondary_new = self.get_all_self_addrs().await?;
// Remove the new primary addr in case it was a secondary addr before:
secondary_new.retain(|a| a != &primary_new);
self.set_config(
Config::SecondaryAddrs,
Some(secondary_new.join(" ").as_str()),
)
.await?;
self.set_config(Config::ConfiguredAddr, Some(&primary_new))
.await?;
Ok(())
}
/// Returns all primary and secondary self addresses.
pub async fn get_all_self_addrs(&self) -> Result<Vec<String>> {
let mut ret = Vec::new();
ret.extend(self.get_config(Config::ConfiguredAddr).await?.into_iter());
ret.extend(self.get_secondary_self_addrs().await?.into_iter());
Ok(ret)
}
/// Returns all secondary self addresses.
pub async fn get_secondary_self_addrs(&self) -> Result<Vec<String>> {
let secondary_addrs = self
.get_config(Config::SecondaryAddrs)
.await?
.unwrap_or_default();
Ok(secondary_addrs
.split_ascii_whitespace()
.map(|s| s.to_string())
.collect())
}
/// Returns the primary self address.
pub async fn get_primary_self_addr(&self) -> Result<String> {
self.get_config(Config::ConfiguredAddr)
.await?
.context("No self addr configured")
}
}
/// Returns all available configuration keys concated together.
fn get_config_keys_string() -> String {
let keys = Config::iter().fold(String::new(), |mut acc, key| {

View File

@@ -296,7 +296,7 @@ impl Contact {
.await?;
if contact_id == ContactId::SELF {
contact.name = stock_str::self_msg(context).await;
contact.addr = context.get_configured_addr().await.unwrap_or_default();
contact.addr = context.get_primary_self_addr().await.unwrap_or_default();
contact.status = context
.get_config(Config::Selfstatus)
.await?
@@ -398,6 +398,7 @@ impl Contact {
if context.is_self_addr(addr_normalized).await? {
return Ok(Some(ContactId::SELF));
}
let id = context
.sql
.query_get_value(
@@ -448,10 +449,7 @@ impl Contact {
let addr = addr_normalize(addr).to_string();
// during configuration process some chats are added and addr
// might not be configured yet
let addr_self = context.get_configured_addr().await.unwrap_or_default();
if addr_cmp(&addr, &addr_self) {
if context.is_self_addr(&addr).await? {
return Ok((ContactId::SELF, sth_modified));
}
@@ -686,7 +684,6 @@ impl Contact {
listflags: u32,
query: Option<impl AsRef<str>>,
) -> Result<Vec<ContactId>> {
let self_addr = context.get_configured_addr().await.unwrap_or_default();
let mut add_self = false;
let mut ret = Vec::new();
let flag_verified_only = (listflags & DC_GCL_VERIFIED_ONLY) != 0;
@@ -699,15 +696,13 @@ impl Contact {
.query_map(
"SELECT c.id FROM contacts c \
LEFT JOIN acpeerstates ps ON c.addr=ps.addr \
WHERE c.addr!=?1 \
AND c.id>?2 \
AND c.origin>=?3 \
WHERE c.id>?1 \
AND c.origin>=?2 \
AND c.blocked=0 \
AND (iif(c.name='',c.authname,c.name) LIKE ?4 OR c.addr LIKE ?5) \
AND (1=?6 OR LENGTH(ps.verified_key_fingerprint)!=0) \
AND (iif(c.name='',c.authname,c.name) LIKE ?3 OR c.addr LIKE ?4) \
AND (1=?5 OR LENGTH(ps.verified_key_fingerprint)!=0) \
ORDER BY LOWER(iif(c.name='',c.authname,c.name)||c.addr),c.id;",
paramsv![
self_addr,
ContactId::LAST_SPECIAL,
Origin::IncomingReplyTo,
s3str_like_cmd,
@@ -724,13 +719,17 @@ impl Contact {
)
.await?;
let self_name = context
.get_config(Config::Displayname)
.await?
.unwrap_or_default();
let self_name2 = stock_str::self_msg(context);
if let Some(query) = query {
let self_addr = context
.get_config(Config::ConfiguredAddr)
.await?
.unwrap_or_default();
let self_name = context
.get_config(Config::Displayname)
.await?
.unwrap_or_default();
let self_name2 = stock_str::self_msg(context);
if self_addr.contains(query.as_ref())
|| self_name.contains(query.as_ref())
|| self_name2.await.contains(query.as_ref())
@@ -747,12 +746,11 @@ impl Contact {
.sql
.query_map(
"SELECT id FROM contacts
WHERE addr!=?1
AND id>?2
AND origin>=?3
WHERE id>?1
AND origin>=?2
AND blocked=0
ORDER BY LOWER(iif(name='',authname,name)||addr),id;",
paramsv![self_addr, ContactId::LAST_SPECIAL, Origin::IncomingReplyTo],
paramsv![ContactId::LAST_SPECIAL, Origin::IncomingReplyTo],
|row| row.get::<_, ContactId>(0),
|ids| {
for id in ids {
@@ -1116,26 +1114,6 @@ impl Contact {
Ok(VerifiedStatus::Unverified)
}
pub async fn addr_equals_contact(
context: &Context,
addr: &str,
contact_id: ContactId,
) -> Result<bool> {
if addr.is_empty() {
return Ok(false);
}
let contact = Contact::load_from_db(context, contact_id).await?;
if !contact.addr.is_empty() {
let normalized_addr = addr_normalize(addr);
if contact.addr == normalized_addr {
return Ok(true);
}
}
Ok(false)
}
pub async fn get_real_cnt(context: &Context) -> Result<usize> {
if !context.sql.is_open().await {
return Ok(0);
@@ -1426,17 +1404,6 @@ fn cat_fingerprint(
}
}
impl Context {
/// determine whether the specified addr maps to the/a self addr
pub async fn is_self_addr(&self, addr: &str) -> Result<bool> {
if let Some(self_addr) = self.get_config(Config::ConfiguredAddr).await? {
Ok(addr_cmp(&self_addr, addr))
} else {
Ok(false)
}
}
}
pub fn addr_cmp(addr1: &str, addr2: &str) -> bool {
let norm1 = addr_normalize(addr1).to_lowercase();
let norm2 = addr_normalize(addr2).to_lowercase();
@@ -2163,4 +2130,49 @@ Hi."#;
Ok(())
}
#[async_std::test]
async fn test_self_addrs() -> Result<()> {
let alice = TestContext::new_alice().await;
assert!(alice.is_self_addr("alice@example.org").await?);
assert_eq!(alice.get_all_self_addrs().await?, vec!["alice@example.org"]);
assert!(!alice.is_self_addr("alice@alice.com").await?);
// Test adding a new (primary) self address
alice.set_primary_self_addr(" Alice@alice.com ").await?;
assert!(alice.is_self_addr("aliCe@example.org").await?);
assert!(alice.is_self_addr("alice@alice.com").await?);
assert_eq!(
alice.get_all_self_addrs().await?,
vec!["alice@alice.com", "alice@example.org"]
);
// Check that the entry is not duplicated
alice.set_primary_self_addr("alice@alice.com").await?;
assert_eq!(
alice.get_all_self_addrs().await?,
vec!["alice@alice.com", "alice@example.org"]
);
// Test switching back
alice.set_primary_self_addr("alice@example.org").await?;
assert_eq!(
alice.get_all_self_addrs().await?,
vec!["alice@example.org", "alice@alice.com"]
);
// Test setting a new primary self address, the previous self address
// should be kept as a secondary self address
alice.set_primary_self_addr("alice@alice.xyz").await?;
assert_eq!(
alice.get_all_self_addrs().await?,
vec!["alice@alice.xyz", "alice@example.org", "alice@alice.com"]
);
assert!(alice.is_self_addr("alice@example.org").await?);
assert!(alice.is_self_addr("alice@alice.com").await?);
assert!(alice.is_self_addr("Alice@alice.xyz").await?);
Ok(())
}
}

View File

@@ -336,6 +336,7 @@ impl Context {
let unset = "0";
let l = LoginParam::load_candidate_params(self).await?;
let l2 = LoginParam::load_configured_params(self).await?;
let secondary_addrs = self.get_secondary_self_addrs().await?.join(", ");
let displayname = self.get_config(Config::Displayname).await?;
let chats = get_chat_cnt(self).await? as usize;
let unblocked_msgs = message::get_unblocked_msg_cnt(self).await as usize;
@@ -420,6 +421,7 @@ impl Context {
res.insert("socks5_enabled", socks5_enabled.to_string());
res.insert("entered_account_settings", l.to_string());
res.insert("used_account_settings", l2.to_string());
res.insert("secondary_addrs", secondary_addrs);
res.insert(
"fetch_existing_msgs",
self.get_config_int(Config::FetchExistingMsgs)

View File

@@ -16,7 +16,7 @@ use crate::config::Config;
use crate::constants::{Blocked, Chattype, ShowEmails, DC_CHAT_ID_TRASH};
use crate::contact;
use crate::contact::{
addr_cmp, may_be_valid_addr, normalize_name, Contact, ContactId, Origin, VerifiedStatus,
may_be_valid_addr, normalize_name, Contact, ContactId, Origin, VerifiedStatus,
};
use crate::context::Context;
use crate::dc_tools::{dc_create_id, dc_extract_grpid_from_rfc724_mid, dc_smeared_time};
@@ -1415,7 +1415,17 @@ async fn create_or_lookup_group(
ProtectionStatus::Unprotected
};
let self_addr = context.get_configured_addr().await?;
async fn self_explicitly_added(
context: &Context,
mime_parser: &&mut MimeMessage,
) -> Result<bool> {
let ret = match mime_parser.get_header(HeaderDef::ChatGroupMemberAdded) {
Some(member_addr) => context.is_self_addr(member_addr).await?,
None => false,
};
Ok(ret)
}
if chat_id.is_none()
&& !mime_parser.is_mailinglist_message()
&& !grpid.is_empty()
@@ -1424,7 +1434,7 @@ async fn create_or_lookup_group(
&& mime_parser.get_header(HeaderDef::ChatGroupMemberRemoved).is_none()
// re-create explicitly left groups only if ourself is re-added
&& (!chat::is_group_explicitly_left(context, &grpid).await?
|| mime_parser.get_header(HeaderDef::ChatGroupMemberAdded).map_or(false, |member_addr| addr_cmp(&self_addr, member_addr)))
|| self_explicitly_added(context, &mime_parser).await?)
{
// Group does not exist but should be created.
if !allow_creation {
@@ -1456,7 +1466,7 @@ async fn create_or_lookup_group(
}
for &to_id in to_ids.iter() {
info!(context, "adding to={:?} to chat id={}", to_id, new_chat_id);
if !Contact::addr_equals_contact(context, &self_addr, to_id).await?
if to_id != ContactId::SELF
&& !chat::is_contact_in_chat(context, new_chat_id, to_id).await?
{
chat::add_to_chat_contacts_table(context, new_chat_id, to_id).await?;
@@ -1511,7 +1521,6 @@ async fn apply_group_changes(
return Ok(None);
}
let self_addr = context.get_configured_addr().await?;
let mut recreate_member_list = false;
let mut send_event_chat_modified = false;
@@ -1631,14 +1640,14 @@ async fn apply_group_changes(
}
}
if !from_id.is_special()
&& !Contact::addr_equals_contact(context, &self_addr, from_id).await?
&& from_id != ContactId::SELF
&& !chat::is_contact_in_chat(context, chat_id, from_id).await?
&& removed_id != Some(from_id)
{
chat::add_to_chat_contacts_table(context, chat_id, from_id).await?;
}
for &to_id in to_ids.iter() {
if !Contact::addr_equals_contact(context, &self_addr, to_id).await?
if to_id != ContactId::SELF
&& !chat::is_contact_in_chat(context, chat_id, to_id).await?
&& removed_id != Some(to_id)
{
@@ -1955,7 +1964,7 @@ async fn create_adhoc_group(
/// are hidden in BCC. This group ID is sent by DC in the messages sent to this chat,
/// so having the same ID prevents group split.
async fn create_adhoc_grp_id(context: &Context, member_ids: &[ContactId]) -> Result<String> {
let member_cs = context.get_configured_addr().await?.to_lowercase();
let member_cs = context.get_primary_self_addr().await?.to_lowercase();
let query = format!(
"SELECT addr FROM contacts WHERE id IN({}) AND id!=?",
sql::repeat_vars(member_ids.len())?

View File

@@ -28,7 +28,7 @@ impl EncryptHelper {
let prefer_encrypt =
EncryptPreference::from_i32(context.get_config_int(Config::E2eeEnabled).await?)
.unwrap_or_default();
let addr = context.get_configured_addr().await?;
let addr = context.get_primary_self_addr().await?;
let public_key = SignedPublicKey::load_self(context).await?;
Ok(EncryptHelper {
@@ -381,7 +381,7 @@ fn contains_report(mail: &ParsedMail<'_>) -> bool {
/// [Config::ConfiguredAddr] is configured, this address is returned.
// TODO, remove this once deltachat::key::Key no longer exists.
pub async fn ensure_secret_key_exists(context: &Context) -> Result<String> {
let self_addr = context.get_configured_addr().await?;
let self_addr = context.get_primary_self_addr().await?;
SignedPublicKey::load_self(context).await?;
Ok(self_addr)
}

View File

@@ -1206,10 +1206,26 @@ impl Imap {
.session
.as_mut()
.context("IMAP No Connection established")?;
let self_addr = context.get_configured_addr().await?;
let search_command = format!("FROM \"{}\"", self_addr);
// TODO probably requires a test if want to keep it as is:
let self_addrs = context
.get_all_self_addrs()
.await
.context("get_all_recipients() can't get self addrs")?;
if self_addrs.is_empty() {
bail!("get_all_recipients(): No self addresses");
}
let from_part = self_addrs
.iter()
.map(|a| format!(" FROM {}", a))
.collect::<String>();
let mut search_command = " OR".repeat(self_addrs.len() - 1);
search_command.push_str(&from_part);
let uids = session
.uid_search(search_command)
.uid_search(search_command.trim())
.await?
.into_iter()
.collect();

View File

@@ -351,7 +351,7 @@ async fn set_self_key(
}
};
let self_addr = context.get_configured_addr().await?;
let self_addr = context.get_primary_self_addr().await?;
let addr = EmailAddress::new(&self_addr)?;
let keypair = pgp::KeyPair {
addr,

View File

@@ -198,7 +198,7 @@ impl DcSecretKey for SignedSecretKey {
}
async fn generate_keypair(context: &Context) -> Result<KeyPair> {
let addr = context.get_configured_addr().await?;
let addr = context.get_primary_self_addr().await?;
let addr = EmailAddress::new(&addr)?;
let _guard = context.generating_key_mutex.lock().await;

View File

@@ -423,7 +423,7 @@ pub async fn delete_all(context: &Context) -> Result<()> {
pub async fn get_kml(context: &Context, chat_id: ChatId) -> Result<(String, u32)> {
let mut last_added_location_id = 0;
let self_addr = context.get_configured_addr().await?;
let self_addr = context.get_primary_self_addr().await?;
let (locations_send_begin, locations_send_until, locations_last_sent) = context.sql.query_row(
"SELECT locations_send_begin, locations_send_until, locations_last_sent FROM chats WHERE id=?;",

View File

@@ -256,8 +256,7 @@ impl LoginParam {
let prefix = "configured_";
let sql = &context.sql;
let key = format!("{}addr", prefix);
sql.set_raw_config(key, Some(&self.addr)).await?;
context.set_primary_self_addr(&self.addr).await?;
let key = format!("{}mail_server", prefix);
sql.set_raw_config(key, Some(&self.imap.server)).await?;

View File

@@ -133,7 +133,7 @@ impl<'a> MimeFactory<'a> {
) -> Result<MimeFactory<'a>> {
let chat = Chat::load_from_db(context, msg.chat_id).await?;
let from_addr = context.get_configured_addr().await?;
let from_addr = context.get_primary_self_addr().await?;
let config_displayname = context
.get_config(Config::Displayname)
.await?
@@ -233,7 +233,7 @@ impl<'a> MimeFactory<'a> {
ensure!(!msg.chat_id.is_special(), "Invalid chat id");
let contact = Contact::load_from_db(context, msg.from_id).await?;
let from_addr = context.get_configured_addr().await?;
let from_addr = context.get_primary_self_addr().await?;
let from_displayname = context
.get_config(Config::Displayname)
.await?
@@ -271,12 +271,13 @@ impl<'a> MimeFactory<'a> {
&self,
context: &Context,
) -> Result<Vec<(Option<Peerstate>, &str)>> {
let self_addr = context.get_configured_addr().await?;
let self_addrs = context.get_all_self_addrs().await?;
let mut res = Vec::new();
for (_, addr) in self
.recipients
.iter()
.filter(|(_, addr)| addr != &self_addr)
.filter(|(_, addr)| !self_addrs.contains(addr))
{
res.push((Peerstate::from_addr(context, addr).await?, addr.as_str()));
}

View File

@@ -449,7 +449,7 @@ impl Context {
// [======67%===== ]
// =============================================================================================
let domain = dc_tools::EmailAddress::new(&self.get_configured_addr().await?)?.domain;
let domain = dc_tools::EmailAddress::new(&self.get_primary_self_addr().await?)?.domain;
ret += &format!(
"<h3>{}</h3><ul>",
stock_str::storage_on_domain(self, domain).await

View File

@@ -66,7 +66,7 @@ pub async fn dc_get_securejoin_qr(context: &Context, group: Option<ChatId>) -> R
.is_none();
let invitenumber = token::lookup_or_new(context, Namespace::InviteNumber, group).await;
let auth = token::lookup_or_new(context, Namespace::Auth, group).await;
let self_addr = context.get_configured_addr().await?;
let self_addr = context.get_primary_self_addr().await?;
let self_name = context
.get_config(Config::Displayname)
.await?

View File

@@ -395,7 +395,7 @@ UPDATE chats SET protected=1, type=120 WHERE type=130;"#,
if dbversion < 71 {
info!(context, "[migration] v71");
if let Ok(addr) = context.get_configured_addr().await {
if let Ok(addr) = context.get_primary_self_addr().await {
if let Ok(domain) = addr.parse::<EmailAddress>().map(|email| email.domain) {
context
.set_config(

View File

@@ -407,7 +407,7 @@ impl TestContext {
.await
.unwrap_or_default()
.unwrap_or_default();
let addr = other.ctx.get_configured_addr().await.unwrap();
let addr = other.ctx.get_primary_self_addr().await.unwrap();
// MailinglistAddress is the lowest allowed origin, we'd prefer to not modify the
// origin when creating this contact.
let (contact_id, modified) =