Strongly type stock strings

This changes the internal stock strings API to be more strongly typed,
ensuring that the caller can not construct the stock string in the
wrong way.

The old approach left it to the callers to figure out how a stock
string should be created, now each stock string has their specific
arguments and callers can not make mistakes.  In particular all the
subtleties and different ways of calling stock_system_msg() disappear.

This could not use a trait for stock strings, as this would not allow
having per-message typed arguments.  So we needed a type per message
with a custom method, only by convention this method is .stock_str().
The type is a enum without variants to avoid allowing someone to
create the type.

Sadly the fallback string and substitutions are still far away from
each other, but it is now only one place which needs to know how to
construct the string instead of many.
This commit is contained in:
Floris Bruynooghe
2021-02-07 15:52:30 +01:00
parent ad640e163c
commit 29f184b4c4
19 changed files with 1488 additions and 647 deletions

View File

@@ -1,6 +1,6 @@
//! # Chat module
use deltachat_derive::{FromSql, ToSql};
use std::borrow::Cow;
use std::convert::TryFrom;
use std::str::FromStr;
use std::time::{Duration, SystemTime};
@@ -8,6 +8,7 @@ use std::time::{Duration, SystemTime};
use anyhow::Context as _;
use anyhow::{bail, ensure, format_err, Error};
use async_std::path::{Path, PathBuf};
use deltachat_derive::{FromSql, ToSql};
use itertools::Itertools;
use num_traits::FromPrimitive;
use serde::{Deserialize, Serialize};
@@ -38,7 +39,11 @@ use crate::mimeparser::SystemMessage;
use crate::param::{Param, Params};
use crate::peerstate::{Peerstate, PeerstateVerifiedStatus};
use crate::sql;
use crate::stock::StockMessage;
use crate::stock::{
ArchivedChats, DeadDrop, DeviceMessages, E2eAvailable, E2ePreferred, EncrNone, MsgAddMember,
MsgDelMember, MsgGroupLeft, MsgGrpImgChanged, MsgGrpImgDeleted, MsgGrpName, NewGroupDraft,
SavedMessages, SelfDeletedMsgBody, VideochatInviteMsgBody,
};
/// An chat item, such as a message or a marker.
#[derive(Debug, Copy, Clone)]
@@ -396,12 +401,7 @@ impl ChatId {
if chat.is_self_talk() {
let mut msg = Message::new(Viewtype::Text);
msg.text = Some(
context
.stock_str(StockMessage::SelfDeletedMsgBody)
.await
.into(),
);
msg.text = Some(SelfDeletedMsgBody::stock_str(context).await.into());
add_device_msg(&context, None, Some(&mut msg)).await?;
}
@@ -659,23 +659,23 @@ impl ChatId {
let addr = contact.get_addr();
let peerstate = Peerstate::from_addr(context, addr).await?;
let stock_message = peerstate
let stock_message = match peerstate
.filter(|peerstate| {
peerstate
.peek_key(PeerstateVerifiedStatus::Unverified)
.is_some()
})
.map(|peerstate| match peerstate.prefer_encrypt {
EncryptPreference::Mutual => StockMessage::E2ePreferred,
EncryptPreference::NoPreference => StockMessage::E2eAvailable,
EncryptPreference::Reset => StockMessage::EncrNone,
})
.unwrap_or(StockMessage::EncrNone);
.map(|peerstate| peerstate.prefer_encrypt)
{
Some(EncryptPreference::Mutual) => E2ePreferred::stock_str(context).await,
Some(EncryptPreference::NoPreference) => E2eAvailable::stock_str(context).await,
Some(EncryptPreference::Reset) => EncrNone::stock_str(context).await,
None => EncrNone::stock_str(context).await,
};
if !ret.is_empty() {
ret.push('\n')
}
ret += &format!("{} {}", addr, context.stock_str(stock_message).await);
ret += &format!("{} {}", addr, stock_message);
}
Ok(ret)
@@ -793,9 +793,9 @@ impl Chat {
}
Ok(mut chat) => {
if chat.id.is_deaddrop() {
chat.name = context.stock_str(StockMessage::DeadDrop).await.into();
chat.name = DeadDrop::stock_str(context).await.into();
} else if chat.id.is_archived_link() {
let tempname = context.stock_str(StockMessage::ArchivedChats).await;
let tempname = ArchivedChats::stock_str(context).await;
let cnt = dc_get_archived_cnt(context).await;
chat.name = format!("{} ({})", tempname, cnt);
} else {
@@ -810,9 +810,9 @@ impl Chat {
chat.name = chat_name;
}
if chat.param.exists(Param::Selftalk) {
chat.name = context.stock_str(StockMessage::SavedMessages).await.into();
chat.name = SavedMessages::stock_str(context).await.into();
} else if chat.param.exists(Param::Devicetalk) {
chat.name = context.stock_str(StockMessage::DeviceMessages).await.into();
chat.name = DeviceMessages::stock_str(context).await.into();
}
}
Ok(chat)
@@ -1411,10 +1411,10 @@ pub(crate) async fn update_device_icon(context: &Context) -> Result<(), Error> {
async fn update_special_chat_name(
context: &Context,
contact_id: u32,
stock_id: StockMessage,
name: Cow<'static, str>,
) -> Result<(), Error> {
if let Ok((chat_id, _)) = lookup_by_contact_id(context, contact_id).await {
let name: String = context.stock_str(stock_id).await.into();
let name: String = name.into();
// the `!= name` condition avoids unneeded writes
context
.sql
@@ -1428,8 +1428,18 @@ async fn update_special_chat_name(
}
pub(crate) async fn update_special_chat_names(context: &Context) -> Result<(), Error> {
update_special_chat_name(context, DC_CONTACT_ID_DEVICE, StockMessage::DeviceMessages).await?;
update_special_chat_name(context, DC_CONTACT_ID_SELF, StockMessage::SavedMessages).await?;
update_special_chat_name(
context,
DC_CONTACT_ID_DEVICE,
DeviceMessages::stock_str(context).await,
)
.await?;
update_special_chat_name(
context,
DC_CONTACT_ID_SELF,
SavedMessages::stock_str(context).await,
)
.await?;
Ok(())
}
@@ -1812,12 +1822,9 @@ pub async fn send_videochat_invitation(context: &Context, chat_id: ChatId) -> Re
let mut msg = Message::new(Viewtype::VideochatInvitation);
msg.param.set(Param::WebrtcRoom, &instance);
msg.text = Some(
context
.stock_string_repl_str(
StockMessage::VideochatInviteMsgBody,
Message::parse_webrtc_instance(&instance).1,
)
.await,
VideochatInviteMsgBody::stock_str(context, Message::parse_webrtc_instance(&instance).1)
.await
.to_string(),
);
send_msg(context, chat_id, &mut msg).await
}
@@ -2154,9 +2161,9 @@ pub async fn create_group_chat(
let chat_name = improve_single_line_input(chat_name);
ensure!(!chat_name.is_empty(), "Invalid chat name");
let draft_txt = context
.stock_string_repl_str(StockMessage::NewGroupDraft, &chat_name)
.await;
let draft_txt = NewGroupDraft::stock_str(context, &chat_name)
.await
.to_string();
let grpid = dc_create_id();
context.sql.execute(
@@ -2334,14 +2341,9 @@ pub(crate) async fn add_contact_to_chat_ex(
if chat.param.get_int(Param::Unpromoted).unwrap_or_default() == 0 {
msg.viewtype = Viewtype::Text;
msg.text = Some(
context
.stock_system_msg(
StockMessage::MsgAddMember,
contact.get_addr(),
"",
DC_CONTACT_ID_SELF as u32,
)
.await,
MsgAddMember::stock_str(context, contact.get_addr(), DC_CONTACT_ID_SELF)
.await
.to_string(),
);
msg.param.set_cmd(SystemMessage::MemberAddedToGroup);
msg.param.set(Param::Arg, contact.get_addr());
@@ -2537,25 +2539,19 @@ pub async fn remove_contact_from_chat(
if contact.id == DC_CONTACT_ID_SELF {
set_group_explicitly_left(context, chat.grpid).await?;
msg.text = Some(
context
.stock_system_msg(
StockMessage::MsgGroupLeft,
"",
"",
DC_CONTACT_ID_SELF,
)
.await,
MsgGroupLeft::stock_str(context, DC_CONTACT_ID_SELF)
.await
.to_string(),
);
} else {
msg.text = Some(
context
.stock_system_msg(
StockMessage::MsgDelMember,
contact.get_addr(),
"",
DC_CONTACT_ID_SELF,
)
.await,
MsgDelMember::stock_str(
context,
contact.get_addr(),
DC_CONTACT_ID_SELF,
)
.await
.to_string(),
);
}
msg.param.set_cmd(SystemMessage::MemberRemovedFromGroup);
@@ -2651,14 +2647,9 @@ pub async fn set_chat_name(
if chat.is_promoted() && !chat.is_mailing_list() {
msg.viewtype = Viewtype::Text;
msg.text = Some(
context
.stock_system_msg(
StockMessage::MsgGrpName,
&chat.name,
&new_name,
DC_CONTACT_ID_SELF,
)
.await,
MsgGrpName::stock_str(context, &chat.name, &new_name, DC_CONTACT_ID_SELF)
.await
.to_string(),
);
msg.param.set_cmd(SystemMessage::GroupNameChanged);
if !chat.name.is_empty() {
@@ -2716,9 +2707,9 @@ pub async fn set_chat_profile_image(
chat.param.remove(Param::ProfileImage);
msg.param.remove(Param::Arg);
msg.text = Some(
context
.stock_system_msg(StockMessage::MsgGrpImgDeleted, "", "", DC_CONTACT_ID_SELF)
.await,
MsgGrpImgDeleted::stock_str(context, DC_CONTACT_ID_SELF)
.await
.to_string(),
);
} else {
let image_blob = match BlobObject::from_path(context, Path::new(new_image.as_ref())) {
@@ -2734,9 +2725,9 @@ pub async fn set_chat_profile_image(
chat.param.set(Param::ProfileImage, image_blob.as_name());
msg.param.set(Param::Arg, image_blob.as_name());
msg.text = Some(
context
.stock_system_msg(StockMessage::MsgGrpImgChanged, "", "", DC_CONTACT_ID_SELF)
.await,
MsgGrpImgChanged::stock_str(context, DC_CONTACT_ID_SELF)
.await
.to_string(),
);
}
chat.update_param(context).await?;
@@ -3215,7 +3206,7 @@ mod tests {
assert!(chat.visibility == ChatVisibility::Normal);
assert!(!chat.is_device_talk());
assert!(chat.can_send());
assert_eq!(chat.name, t.stock_str(StockMessage::SavedMessages).await);
assert_eq!(chat.name, SavedMessages::stock_str(&t).await);
assert!(chat.get_profile_image(&t).await.is_some());
}
@@ -3231,7 +3222,7 @@ mod tests {
assert!(chat.visibility == ChatVisibility::Normal);
assert!(!chat.is_device_talk());
assert!(!chat.can_send());
assert_eq!(chat.name, t.stock_str(StockMessage::DeadDrop).await);
assert_eq!(chat.name, DeadDrop::stock_str(&t).await);
}
#[async_std::test]
@@ -3308,7 +3299,7 @@ mod tests {
assert!(chat.is_device_talk());
assert!(!chat.is_self_talk());
assert!(!chat.can_send());
assert_eq!(chat.name, t.stock_str(StockMessage::DeviceMessages).await);
assert_eq!(chat.name, DeviceMessages::stock_str(&t).await);
assert!(chat.get_profile_image(&t).await.is_some());
// delete device message, make sure it is not added again

View File

@@ -14,7 +14,7 @@ use crate::context::Context;
use crate::ephemeral::delete_expired_messages;
use crate::lot::Lot;
use crate::message::{Message, MessageState, MsgId};
use crate::stock::StockMessage;
use crate::stock::NoMessages;
/// An object representing a single chatlist in memory.
///
@@ -385,12 +385,7 @@ impl Chatlist {
ret.text2 = None;
} else if lastmsg.is_none() || lastmsg.as_ref().unwrap().from_id == DC_CONTACT_ID_UNDEFINED
{
ret.text2 = Some(
context
.stock_str(StockMessage::NoMessages)
.await
.to_string(),
);
ret.text2 = Some(NoMessages::stock_str(context).await.to_string());
} else {
ret.fill(&mut lastmsg.unwrap(), chat, lastcontact.as_ref(), context)
.await;
@@ -445,6 +440,7 @@ mod tests {
use crate::chat::{create_group_chat, ProtectionStatus};
use crate::constants::Viewtype;
use crate::stock::StockMessage;
use crate::test_utils::TestContext;
#[async_std::test]

View File

@@ -3,6 +3,7 @@
use strum::{EnumProperty, IntoEnumIterator};
use strum_macros::{AsRefStr, Display, EnumIter, EnumProperty, EnumString};
use crate::blob::BlobObject;
use crate::chat::ChatId;
use crate::constants::DC_VERSION_STR;
use crate::context::Context;
@@ -11,11 +12,8 @@ use crate::events::EventType;
use crate::job;
use crate::message::MsgId;
use crate::mimefactory::RECOMMENDED_FILE_SIZE;
use crate::stock::StockMessage;
use crate::{
blob::BlobObject,
provider::{get_provider_by_id, Provider},
};
use crate::provider::{get_provider_by_id, Provider};
use crate::stock::StatusLine;
/// The available configuration keys.
#[derive(
@@ -175,7 +173,7 @@ impl Context {
// Default values
match key {
Config::Selfstatus => Some(self.stock_str(StockMessage::StatusLine).await.into_owned()),
Config::Selfstatus => Some(StatusLine::stock_str(self).await.into_owned()),
Config::ConfiguredInboxFolder => Some("INBOX".to_owned()),
_ => key.get_str("default").map(|s| s.to_string()),
}
@@ -260,7 +258,7 @@ impl Context {
}
}
Config::Selfstatus => {
let def = self.stock_str(StockMessage::StatusLine).await;
let def = StatusLine::stock_str(self).await;
let val = if value.is_none() || value.unwrap() == def {
None
} else {

View File

@@ -19,7 +19,7 @@ use crate::message::Message;
use crate::oauth2::dc_get_oauth2_addr;
use crate::provider::{Protocol, Socket, UsernamePattern};
use crate::smtp::Smtp;
use crate::stock::StockMessage;
use crate::stock::{ConfigurationFailed, ErrorNoNetwork};
use crate::{chat, e2ee, provider};
use crate::{config::Config, dc_tools::time};
use crate::{
@@ -127,12 +127,14 @@ impl Context {
self,
0,
Some(
self.stock_string_repl_str(
StockMessage::ConfigurationFailed,
// We are using Anyhow's .context() and to show the inner error, too, we need the {:#}:
ConfigurationFailed::stock_str(
self,
// We are using Anyhow's .context() and to show the
// inner error, too, we need the {:#}:
format!("{:#}", err),
)
.await
.to_string()
)
);
Err(err)
@@ -589,10 +591,7 @@ async fn nicer_configuration_error(context: &Context, errors: Vec<ConfigurationE
.iter()
.all(|e| e.msg.to_lowercase().contains("could not resolve"))
{
return context
.stock_str(StockMessage::ErrorNoNetwork)
.await
.to_string();
return ErrorNoNetwork::stock_str(context).await.to_string();
}
if errors.iter().all(|e| e.msg == first_err.msg) {

View File

@@ -25,7 +25,7 @@ use crate::message::MessageState;
use crate::mimeparser::AvatarAction;
use crate::param::{Param, Params};
use crate::peerstate::{Peerstate, PeerstateVerifiedStatus};
use crate::stock::StockMessage;
use crate::stock::{DeviceMessages, E2eAvailable, E2ePreferred, EncrNone, FingerPrints, SelfMsg};
/// An object representing a single contact in memory.
///
@@ -195,7 +195,7 @@ impl Contact {
)
.await?;
if contact_id == DC_CONTACT_ID_SELF {
res.name = context.stock_str(StockMessage::SelfMsg).await.to_string();
res.name = SelfMsg::stock_str(context).await.to_string();
res.addr = context
.get_config(Config::ConfiguredAddr)
.await
@@ -205,10 +205,7 @@ impl Contact {
.await
.unwrap_or_default();
} else if contact_id == DC_CONTACT_ID_DEVICE {
res.name = context
.stock_str(StockMessage::DeviceMessages)
.await
.to_string();
res.name = DeviceMessages::stock_str(context).await.to_string();
res.addr = DC_CONTACT_ID_DEVICE_ADDR.to_string();
}
Ok(res)
@@ -635,7 +632,7 @@ impl Contact {
.get_config(Config::Displayname)
.await
.unwrap_or_default();
let self_name2 = context.stock_str(StockMessage::SelfMsg);
let self_name2 = SelfMsg::stock_str(context);
if let Some(query) = query {
if self_addr.contains(query.as_ref())
@@ -729,15 +726,15 @@ impl Contact {
.is_some()
}) {
let stock_message = match peerstate.prefer_encrypt {
EncryptPreference::Mutual => StockMessage::E2ePreferred,
EncryptPreference::NoPreference => StockMessage::E2eAvailable,
EncryptPreference::Reset => StockMessage::EncrNone,
EncryptPreference::Mutual => E2ePreferred::stock_str(context).await,
EncryptPreference::NoPreference => E2eAvailable::stock_str(context).await,
EncryptPreference::Reset => EncrNone::stock_str(context).await,
};
ret += &format!(
"{}\n{}:",
context.stock_str(stock_message).await,
context.stock_str(StockMessage::FingerPrints).await
stock_message,
FingerPrints::stock_str(context).await
);
let fingerprint_self = SignedPublicKey::load_self(context)
@@ -770,7 +767,7 @@ impl Contact {
cat_fingerprint(&mut ret, &loginparam.addr, &fingerprint_self, "");
}
} else {
ret += &context.stock_str(StockMessage::EncrNone).await;
ret += &EncrNone::stock_str(context).await;
}
}
@@ -1510,7 +1507,7 @@ mod tests {
// check SELF
let contact = Contact::load_from_db(&t, DC_CONTACT_ID_SELF).await.unwrap();
assert_eq!(DC_CONTACT_ID_SELF, 1);
assert_eq!(contact.get_name(), t.stock_str(StockMessage::SelfMsg).await);
assert_eq!(contact.get_name(), SelfMsg::stock_str(&t).await);
assert_eq!(contact.get_addr(), ""); // we're not configured
assert!(!contact.is_blocked());
}

View File

@@ -26,7 +26,10 @@ use crate::mimeparser::{parse_message_ids, AvatarAction, MimeMessage, SystemMess
use crate::param::{Param, Params};
use crate::peerstate::{Peerstate, PeerstateKeyType, PeerstateVerifiedStatus};
use crate::securejoin::{self, handle_securejoin_handshake, observe_securejoin_on_other_device};
use crate::stock::StockMessage;
use crate::stock::{
MsgAddMember, MsgDelMember, MsgGroupLeft, MsgGrpImgChanged, MsgGrpImgDeleted, MsgGrpName,
MsgLocationEnabled, UnknownSenderForChat,
};
use crate::{contact, location};
// IndexSet is like HashSet but maintains order of insertion
@@ -1165,9 +1168,9 @@ async fn create_or_lookup_group(
let mut better_msg: String = From::from("");
if mime_parser.is_system_message == SystemMessage::LocationStreamingEnabled {
better_msg = context
.stock_system_msg(StockMessage::MsgLocationEnabled, "", "", from_id as u32)
.await;
better_msg = MsgLocationEnabled::stock_str_by(context, from_id)
.await
.to_string();
set_better_msg(mime_parser, &better_msg);
}
@@ -1231,48 +1234,38 @@ async fn create_or_lookup_group(
match removed_id {
Some(contact_id) => {
mime_parser.is_system_message = SystemMessage::MemberRemovedFromGroup;
better_msg = context
.stock_system_msg(
if contact_id == from_id as u32 {
StockMessage::MsgGroupLeft
} else {
StockMessage::MsgDelMember
},
&removed_addr,
"",
from_id as u32,
)
.await;
better_msg = if contact_id == from_id {
MsgGroupLeft::stock_str(context, from_id).await.to_string()
} else {
MsgDelMember::stock_str(context, &removed_addr, from_id)
.await
.to_string()
};
}
None => warn!(context, "removed {:?} has no contact_id", removed_addr),
}
} else {
let field = mime_parser.get(HeaderDef::ChatGroupMemberAdded).cloned();
if let Some(optional_field) = field {
if let Some(added_member) = field {
mime_parser.is_system_message = SystemMessage::MemberAddedToGroup;
better_msg = context
.stock_system_msg(
StockMessage::MsgAddMember,
&optional_field,
"",
from_id as u32,
)
.await;
X_MrAddToGrp = Some(optional_field);
better_msg = MsgAddMember::stock_str(context, &added_member, from_id)
.await
.to_string();
X_MrAddToGrp = Some(added_member);
} else if let Some(old_name) = mime_parser.get(HeaderDef::ChatGroupNameChanged) {
X_MrGrpNameChanged = true;
better_msg = context
.stock_system_msg(
StockMessage::MsgGrpName,
old_name,
if let Some(ref name) = grpname {
name
} else {
""
},
from_id as u32,
)
.await;
better_msg = MsgGrpName::stock_str(
context,
old_name,
if let Some(ref name) = grpname {
name
} else {
""
},
from_id as u32,
)
.await
.to_string();
mime_parser.is_system_message = SystemMessage::GroupNameChanged;
} else if let Some(value) = mime_parser.get(HeaderDef::ChatContent) {
if value == "group-avatar-changed" {
@@ -1280,17 +1273,14 @@ async fn create_or_lookup_group(
// this is just an explicit message containing the group-avatar,
// apart from that, the group-avatar is send along with various other messages
mime_parser.is_system_message = SystemMessage::GroupImageChanged;
better_msg = context
.stock_system_msg(
match avatar_action {
AvatarAction::Delete => StockMessage::MsgGrpImgDeleted,
AvatarAction::Change(_) => StockMessage::MsgGrpImgChanged,
},
"",
"",
from_id as u32,
)
.await
better_msg = match avatar_action {
AvatarAction::Delete => MsgGrpImgDeleted::stock_str(context, from_id)
.await
.to_string(),
AvatarAction::Change(_) => MsgGrpImgChanged::stock_str(context, from_id)
.await
.to_string(),
};
}
}
}
@@ -1308,7 +1298,7 @@ async fn create_or_lookup_group(
// but still show the message as part of the chat.
// After all, the sender has a reference/in-reply-to that
// points to this chat.
let s = context.stock_str(StockMessage::UnknownSenderForChat).await;
let s = UnknownSenderForChat::stock_str(context).await;
mime_parser.repl_msg_by_error(s.to_string());
}
@@ -1989,6 +1979,7 @@ mod tests {
use crate::constants::{DC_CONTACT_ID_INFO, DC_GCL_NO_SPECIALS};
use crate::message::ContactRequestDecision::*;
use crate::message::Message;
use crate::stock::FailedSendingTo;
use crate::test_utils::TestContext;
use crate::{
chat::{ChatItem, ChatVisibility},
@@ -2656,11 +2647,9 @@ mod tests {
assert_eq!(
last_msg.text,
Some(
t.stock_string_repl_str(
StockMessage::FailedSendingTo,
"assidhfaaspocwaeofi@gmail.com",
)
.await,
FailedSendingTo::stock_str(&t, "assidhfaaspocwaeofi@gmail.com")
.await
.to_string(),
)
);
assert_eq!(last_msg.from_id, DC_CONTACT_ID_INFO);

View File

@@ -22,7 +22,7 @@ use crate::context::Context;
use crate::events::EventType;
use crate::message::Message;
use crate::provider::get_provider_update_timestamp;
use crate::stock::StockMessage;
use crate::stock::{BadTimeMsgBody, UpdateReminderMsgBody};
/// Shortens a string to a specified length and adds "[...]" to the
/// end of the shortened string.
@@ -169,15 +169,15 @@ async fn maybe_warn_on_bad_time(context: &Context, now: i64, known_past_timestam
if now < known_past_timestamp {
let mut msg = Message::new(Viewtype::Text);
msg.text = Some(
context
.stock_string_repl_str(
StockMessage::BadTimeMsgBody,
Local
.timestamp(now, 0)
.format("%Y-%m-%d %H:%M:%S")
.to_string(),
)
.await,
BadTimeMsgBody::stock_str(
context,
Local
.timestamp(now, 0)
.format("%Y-%m-%d %H:%M:%S")
.to_string(),
)
.await
.to_string(),
);
add_device_msg_with_importance(
context,
@@ -201,12 +201,7 @@ async fn maybe_warn_on_bad_time(context: &Context, now: i64, known_past_timestam
async fn maybe_warn_on_outdated(context: &Context, now: i64, approx_compile_time: i64) {
if now > approx_compile_time + DC_OUTDATED_WARNING_DAYS * 24 * 60 * 60 {
let mut msg = Message::new(Viewtype::Text);
msg.text = Some(
context
.stock_str(StockMessage::UpdateReminderMsgBody)
.await
.into(),
);
msg.text = Some(UpdateReminderMsgBody::stock_str(context).await.into());
add_device_msg(
context,
Some(

View File

@@ -56,7 +56,15 @@
//! the database entries which are expired either according to their
//! ephemeral message timers or global `delete_server_after` setting.
use std::borrow::Cow;
use std::convert::{TryFrom, TryInto};
use std::num::ParseIntError;
use std::str::FromStr;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use anyhow::{ensure, Error};
use async_std::task;
use serde::{Deserialize, Serialize};
use crate::chat::{lookup_by_contact_id, send_msg, ChatId};
use crate::constants::{
@@ -68,13 +76,12 @@ use crate::events::EventType;
use crate::message::{Message, MessageState, MsgId};
use crate::mimeparser::SystemMessage;
use crate::sql;
use crate::stock::StockMessage;
use async_std::task;
use serde::{Deserialize, Serialize};
use std::convert::{TryFrom, TryInto};
use std::num::ParseIntError;
use std::str::FromStr;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
use crate::stock::{
MsgEphemeralTimerDay, MsgEphemeralTimerDays, MsgEphemeralTimerDisabled,
MsgEphemeralTimerEnabled, MsgEphemeralTimerHour, MsgEphemeralTimerHours,
MsgEphemeralTimerMinute, MsgEphemeralTimerMinutes, MsgEphemeralTimerWeek,
MsgEphemeralTimerWeeks,
};
#[derive(Debug, PartialEq, Eq, Copy, Clone, Serialize, Deserialize)]
pub enum Timer {
@@ -194,7 +201,11 @@ impl ChatId {
}
self.inner_set_ephemeral_timer(context, timer).await?;
let mut msg = Message::new(Viewtype::Text);
msg.text = Some(stock_ephemeral_timer_changed(context, timer, DC_CONTACT_ID_SELF).await);
msg.text = Some(
stock_ephemeral_timer_changed(context, timer, DC_CONTACT_ID_SELF)
.await
.to_string(),
);
msg.param.set_cmd(SystemMessage::EphemeralTimerChanged);
if let Err(err) = send_msg(context, self, &mut msg).await {
error!(
@@ -211,87 +222,48 @@ pub(crate) async fn stock_ephemeral_timer_changed(
context: &Context,
timer: Timer,
from_id: u32,
) -> String {
) -> Cow<'static, str> {
match timer {
Timer::Disabled => {
context
.stock_system_msg(
StockMessage::MsgEphemeralTimerDisabled,
timer.to_string(),
"",
Timer::Disabled => MsgEphemeralTimerDisabled::stock_str(context, from_id).await,
Timer::Enabled { duration } => match duration {
0..=59 => {
MsgEphemeralTimerEnabled::stock_str(context, timer.to_string(), from_id).await
}
60 => MsgEphemeralTimerMinute::stock_str(context, from_id).await,
61..=3599 => {
MsgEphemeralTimerMinutes::stock_str(
context,
format!("{}", (f64::from(duration) / 6.0).round() / 10.0),
from_id,
)
.await
}
Timer::Enabled { duration } => match duration {
0..=59 => {
context
.stock_system_msg(
StockMessage::MsgEphemeralTimerEnabled,
timer.to_string(),
"",
from_id,
)
.await
}
60 => {
context
.stock_system_msg(StockMessage::MsgEphemeralTimerMinute, "", "", from_id)
.await
}
61..=3599 => {
context
.stock_system_msg(
StockMessage::MsgEphemeralTimerMinutes,
format!("{}", (f64::from(duration) / 6.0).round() / 10.0),
"",
from_id,
)
.await
}
3600 => {
context
.stock_system_msg(StockMessage::MsgEphemeralTimerHour, "", "", from_id)
.await
}
3600 => MsgEphemeralTimerHour::stock_str(context, from_id).await,
3601..=86399 => {
context
.stock_system_msg(
StockMessage::MsgEphemeralTimerHours,
format!("{}", (f64::from(duration) / 360.0).round() / 10.0),
"",
from_id,
)
.await
}
86400 => {
context
.stock_system_msg(StockMessage::MsgEphemeralTimerDay, "", "", from_id)
.await
MsgEphemeralTimerHours::stock_str(
context,
format!("{}", (f64::from(duration) / 360.0).round() / 10.0),
from_id,
)
.await
}
86400 => MsgEphemeralTimerDay::stock_str(context, from_id).await,
86401..=604_799 => {
context
.stock_system_msg(
StockMessage::MsgEphemeralTimerDays,
format!("{}", (f64::from(duration) / 8640.0).round() / 10.0),
"",
from_id,
)
.await
}
604_800 => {
{ context.stock_system_msg(StockMessage::MsgEphemeralTimerWeek, "", "", from_id) }
.await
MsgEphemeralTimerDays::stock_str(
context,
format!("{}", (f64::from(duration) / 8640.0).round() / 10.0),
from_id,
)
.await
}
604_800 => MsgEphemeralTimerWeek::stock_str(context, from_id).await,
_ => {
context
.stock_system_msg(
StockMessage::MsgEphemeralTimerWeeks,
format!("{}", (f64::from(duration) / 60480.0).round() / 10.0),
"",
from_id,
)
.await
MsgEphemeralTimerWeeks::stock_str(
context,
format!("{}", (f64::from(duration) / 60480.0).round() / 10.0),
from_id,
)
.await
}
},
}
@@ -547,36 +519,67 @@ mod tests {
);
assert_eq!(
stock_ephemeral_timer_changed(&context, Timer::Disabled, 0).await,
"Message deletion timer is disabled."
stock_ephemeral_timer_changed(
&context,
Timer::Enabled { duration: 1 },
DC_CONTACT_ID_SELF
)
.await,
"Message deletion timer is set to 1 s by me."
);
assert_eq!(
stock_ephemeral_timer_changed(&context, Timer::Enabled { duration: 1 }, 0).await,
"Message deletion timer is set to 1 s."
stock_ephemeral_timer_changed(
&context,
Timer::Enabled { duration: 30 },
DC_CONTACT_ID_SELF
)
.await,
"Message deletion timer is set to 30 s by me."
);
assert_eq!(
stock_ephemeral_timer_changed(&context, Timer::Enabled { duration: 30 }, 0).await,
"Message deletion timer is set to 30 s."
stock_ephemeral_timer_changed(
&context,
Timer::Enabled { duration: 60 },
DC_CONTACT_ID_SELF
)
.await,
"Message deletion timer is set to 1 minute by me."
);
assert_eq!(
stock_ephemeral_timer_changed(&context, Timer::Enabled { duration: 60 }, 0).await,
"Message deletion timer is set to 1 minute."
stock_ephemeral_timer_changed(
&context,
Timer::Enabled { duration: 90 },
DC_CONTACT_ID_SELF
)
.await,
"Message deletion timer is set to 1.5 minutes by me."
);
assert_eq!(
stock_ephemeral_timer_changed(&context, Timer::Enabled { duration: 90 }, 0).await,
"Message deletion timer is set to 1.5 minutes."
stock_ephemeral_timer_changed(
&context,
Timer::Enabled { duration: 30 * 60 },
DC_CONTACT_ID_SELF
)
.await,
"Message deletion timer is set to 30 minutes by me."
);
assert_eq!(
stock_ephemeral_timer_changed(&context, Timer::Enabled { duration: 30 * 60 }, 0).await,
"Message deletion timer is set to 30 minutes."
stock_ephemeral_timer_changed(
&context,
Timer::Enabled { duration: 60 * 60 },
DC_CONTACT_ID_SELF
)
.await,
"Message deletion timer is set to 1 hour by me."
);
assert_eq!(
stock_ephemeral_timer_changed(&context, Timer::Enabled { duration: 60 * 60 }, 0).await,
"Message deletion timer is set to 1 hour."
);
assert_eq!(
stock_ephemeral_timer_changed(&context, Timer::Enabled { duration: 5400 }, 0).await,
"Message deletion timer is set to 1.5 hours."
stock_ephemeral_timer_changed(
&context,
Timer::Enabled { duration: 5400 },
DC_CONTACT_ID_SELF
)
.await,
"Message deletion timer is set to 1.5 hours by me."
);
assert_eq!(
stock_ephemeral_timer_changed(
@@ -584,10 +587,10 @@ mod tests {
Timer::Enabled {
duration: 2 * 60 * 60
},
0
DC_CONTACT_ID_SELF
)
.await,
"Message deletion timer is set to 2 hours."
"Message deletion timer is set to 2 hours by me."
);
assert_eq!(
stock_ephemeral_timer_changed(
@@ -595,10 +598,10 @@ mod tests {
Timer::Enabled {
duration: 24 * 60 * 60
},
0
DC_CONTACT_ID_SELF
)
.await,
"Message deletion timer is set to 1 day."
"Message deletion timer is set to 1 day by me."
);
assert_eq!(
stock_ephemeral_timer_changed(
@@ -606,10 +609,10 @@ mod tests {
Timer::Enabled {
duration: 2 * 24 * 60 * 60
},
0
DC_CONTACT_ID_SELF
)
.await,
"Message deletion timer is set to 2 days."
"Message deletion timer is set to 2 days by me."
);
assert_eq!(
stock_ephemeral_timer_changed(
@@ -617,10 +620,10 @@ mod tests {
Timer::Enabled {
duration: 7 * 24 * 60 * 60
},
0
DC_CONTACT_ID_SELF
)
.await,
"Message deletion timer is set to 1 week."
"Message deletion timer is set to 1 week by me."
);
assert_eq!(
stock_ephemeral_timer_changed(
@@ -628,10 +631,10 @@ mod tests {
Timer::Enabled {
duration: 4 * 7 * 24 * 60 * 60
},
0
DC_CONTACT_ID_SELF
)
.await,
"Message deletion timer is set to 4 weeks."
"Message deletion timer is set to 4 weeks by me."
);
}

View File

@@ -14,12 +14,17 @@ use async_std::channel::Receiver;
use async_std::prelude::*;
use num_traits::FromPrimitive;
use crate::chat;
use crate::config::Config;
use crate::constants::{
Chattype, ShowEmails, Viewtype, DC_CONTACT_ID_SELF, DC_FETCH_EXISTING_MSGS_COUNT,
DC_FOLDERS_CONFIGURED_VERSION, DC_LP_AUTH_OAUTH2,
};
use crate::context::Context;
use crate::dc_receive_imf::{from_field_to_contact_id, get_prefetch_parent_message};
use crate::dc_receive_imf::{
dc_receive_imf_inner, from_field_to_contact_id, get_prefetch_parent_message,
};
use crate::dc_tools::dc_extract_grpid_from_rfc724_mid;
use crate::events::EventType;
use crate::headerdef::{HeaderDef, HeaderDefMap};
use crate::job::{self, Action};
@@ -29,10 +34,8 @@ use crate::mimeparser;
use crate::oauth2::dc_get_oauth2_access_token;
use crate::param::Params;
use crate::provider::Socket;
use crate::{
chat, dc_tools::dc_extract_grpid_from_rfc724_mid, scheduler::InterruptInfo, stock::StockMessage,
};
use crate::{config::Config, dc_receive_imf::dc_receive_imf_inner};
use crate::scheduler::InterruptInfo;
use crate::stock::CannotLogin;
mod client;
mod idle;
@@ -252,9 +255,9 @@ impl Imap {
Err((err, _)) => {
let imap_user = self.config.lp.user.to_owned();
let message = context
.stock_string_repl_str(StockMessage::CannotLogin, &imap_user)
.await;
let message = CannotLogin::stock_str(context, &imap_user)
.await
.to_string();
warn!(context, "{} ({})", message, err);

View File

@@ -29,7 +29,7 @@ use crate::mimeparser::SystemMessage;
use crate::param::Param;
use crate::pgp;
use crate::sql::{self, Sql};
use crate::stock::StockMessage;
use crate::stock::{AcSetupMsgBody, AcSetupMsgSubject};
use ::pgp::types::KeyTrait;
use async_tar::Archive;
@@ -275,8 +275,8 @@ pub async fn render_setup_file(context: &Context, passphrase: &str) -> Result<St
);
let pgp_msg = encr.replace("-----BEGIN PGP MESSAGE-----", &replacement);
let msg_subj = context.stock_str(StockMessage::AcSetupMsgSubject).await;
let msg_body = context.stock_str(StockMessage::AcSetupMsgBody).await;
let msg_subj = AcSetupMsgSubject::stock_str(context).await;
let msg_body = AcSetupMsgBody::stock_str(context).await;
let msg_body_html = msg_body.replace("\r", "").replace("\n", "<br>");
Ok(format!(
concat!(
@@ -902,8 +902,11 @@ where
#[cfg(test)]
mod tests {
use super::*;
use crate::pgp::{split_armored_data, HEADER_AUTOCRYPT, HEADER_SETUPCODE};
use crate::stock::StockMessage;
use crate::test_utils::{alice_keypair, TestContext};
use ::pgp::armor::BlockType;
#[async_std::test]

View File

@@ -14,7 +14,7 @@ use crate::job::{self, Job};
use crate::message::{Message, MsgId};
use crate::mimeparser::SystemMessage;
use crate::param::Params;
use crate::stock::StockMessage;
use crate::stock::{MsgLocationDisabled, MsgLocationEnabled};
/// Location record
#[derive(Debug, Clone, Default)]
@@ -212,19 +212,13 @@ pub async fn send_locations_to_chat(context: &Context, chat_id: ChatId, seconds:
{
if 0 != seconds && !is_sending_locations_before {
let mut msg = Message::new(Viewtype::Text);
msg.text = Some(
context
.stock_system_msg(StockMessage::MsgLocationEnabled, "", "", 0)
.await,
);
msg.text = Some(MsgLocationEnabled::stock_str(context).await.to_string());
msg.param.set_cmd(SystemMessage::LocationStreamingEnabled);
chat::send_msg(context, chat_id, &mut msg)
.await
.unwrap_or_default();
} else if 0 == seconds && is_sending_locations_before {
let stock_str = context
.stock_system_msg(StockMessage::MsgLocationDisabled, "", "", 0)
.await;
let stock_str = MsgLocationDisabled::stock_str(context).await;
chat::add_info_msg(context, chat_id, stock_str).await;
}
context.emit_event(EventType::ChatModified(chat_id));
@@ -716,9 +710,7 @@ pub(crate) async fn job_maybe_send_locations_ended(
paramsv![chat_id],
).await);
let stock_str = context
.stock_system_msg(StockMessage::MsgLocationDisabled, "", "", 0)
.await;
let stock_str = MsgLocationDisabled::stock_str(context).await;
chat::add_info_msg(context, chat_id, stock_str).await;
context.emit_event(EventType::ChatModified(chat_id));
}

View File

@@ -26,7 +26,10 @@ use crate::lot::{Lot, LotState, Meaning};
use crate::mimeparser::{FailureReport, SystemMessage};
use crate::param::{Param, Params};
use crate::pgp::split_armored_data;
use crate::stock::StockMessage;
use crate::stock::{
AcSetupMsgSubject, Audio, Draft, FailedSendingTo, File, Gif, Image, Location, ReplyNoun,
SelfMsg, Sticker, Video, VideochatInvitation, VoiceMessage,
};
use std::collections::BTreeMap;
// In practice, the user additionally cuts the string themselves
@@ -1055,26 +1058,14 @@ impl Lot {
context: &Context,
) {
if msg.state == MessageState::OutDraft {
self.text1 = Some(
context
.stock_str(StockMessage::Draft)
.await
.to_owned()
.into(),
);
self.text1 = Some(Draft::stock_str(context).await.to_owned().into());
self.text1_meaning = Meaning::Text1Draft;
} else if msg.from_id == DC_CONTACT_ID_SELF {
if msg.is_info() || chat.is_self_talk() {
self.text1 = None;
self.text1_meaning = Meaning::None;
} else {
self.text1 = Some(
context
.stock_str(StockMessage::SelfMsg)
.await
.to_owned()
.into(),
);
self.text1 = Some(SelfMsg::stock_str(context).await.to_owned().into());
self.text1_meaning = Meaning::Text1Self;
}
} else {
@@ -1107,10 +1098,7 @@ impl Lot {
.await;
if text2.is_empty() && msg.quoted_text().is_some() {
text2 = context
.stock_str(StockMessage::ReplyNoun)
.await
.into_owned()
text2 = ReplyNoun::stock_str(context).await.into_owned()
}
self.text2 = Some(text2);
@@ -1562,21 +1550,15 @@ pub async fn get_summarytext_by_raw(
) -> String {
let mut append_text = true;
let prefix = match viewtype {
Viewtype::Image => context.stock_str(StockMessage::Image).await.into_owned(),
Viewtype::Gif => context.stock_str(StockMessage::Gif).await.into_owned(),
Viewtype::Sticker => context.stock_str(StockMessage::Sticker).await.into_owned(),
Viewtype::Video => context.stock_str(StockMessage::Video).await.into_owned(),
Viewtype::Voice => context
.stock_str(StockMessage::VoiceMessage)
.await
.into_owned(),
Viewtype::Image => Image::stock_str(context).await.into_owned(),
Viewtype::Gif => Gif::stock_str(context).await.into_owned(),
Viewtype::Sticker => Sticker::stock_str(context).await.into_owned(),
Viewtype::Video => Video::stock_str(context).await.into_owned(),
Viewtype::Voice => VoiceMessage::stock_str(context).await.into_owned(),
Viewtype::Audio | Viewtype::File => {
if param.get_cmd() == SystemMessage::AutocryptSetupMessage {
append_text = false;
context
.stock_str(StockMessage::AcSetupMsgSubject)
.await
.to_string()
AcSetupMsgSubject::stock_str(context).await.to_string()
} else {
let file_name: String = param
.get_path(Param::File, context)
@@ -1586,29 +1568,24 @@ pub async fn get_summarytext_by_raw(
.map(|fname| fname.to_string_lossy().into_owned())
})
.unwrap_or_else(|| String::from("ErrFileName"));
let label = context
.stock_str(if viewtype == Viewtype::Audio {
StockMessage::Audio
} else {
StockMessage::File
})
.await;
let label = if viewtype == Viewtype::Audio {
Audio::stock_str(context).await
} else {
File::stock_str(context).await
};
format!("{} {}", label, file_name)
}
}
Viewtype::VideochatInvitation => {
append_text = false;
context
.stock_str(StockMessage::VideochatInvitation)
.await
.into_owned()
VideochatInvitation::stock_str(context).await.into_owned()
}
_ => {
if param.get_cmd() != SystemMessage::LocationOnly {
"".to_string()
} else {
append_text = false;
context.stock_str(StockMessage::Location).await.to_string()
Location::stock_str(context).await.to_string()
}
}
};
@@ -1865,13 +1842,9 @@ async fn ndn_maybe_add_info_msg(
Error::msg("ndn_maybe_add_info_msg: Contact ID not found")
})?;
let contact = Contact::load_from_db(context, contact_id).await?;
// Tell the user which of the recipients failed if we know that (because in a group, this might otherwise be unclear)
let text = context
.stock_string_repl_str(
StockMessage::FailedSendingTo,
contact.get_display_name(),
)
.await;
// Tell the user which of the recipients failed if we know that (because in
// a group, this might otherwise be unclear)
let text = FailedSendingTo::stock_str(context, contact.get_display_name()).await;
chat::add_info_msg(context, chat_id, text).await;
context.emit_event(EventType::ChatModified(chat_id));
}

View File

@@ -21,7 +21,10 @@ use crate::mimeparser::SystemMessage;
use crate::param::Param;
use crate::peerstate::{Peerstate, PeerstateVerifiedStatus};
use crate::simplify::escape_message_footer_marks;
use crate::stock::StockMessage;
use crate::stock::{
AcSetupMsgBody, AcSetupMsgSubject, EncryptedMsg, ReadRcpt, ReadRcptMailBody, StatusLine,
SubjectForNewContact,
};
use std::convert::TryInto;
// attachments of 25 mb brutto should work on the majority of providers
@@ -139,10 +142,7 @@ impl<'a, 'b> MimeFactory<'a, 'b> {
)
.await?;
let default_str = context
.stock_str(StockMessage::StatusLine)
.await
.to_string();
let default_str = StatusLine::stock_str(context).await.to_string();
let factory = MimeFactory {
from_addr,
from_displayname,
@@ -180,10 +180,7 @@ impl<'a, 'b> MimeFactory<'a, 'b> {
.get_config(Config::Displayname)
.await
.unwrap_or_default();
let default_str = context
.stock_str(StockMessage::StatusLine)
.await
.to_string();
let default_str = StatusLine::stock_str(context).await.to_string();
let selfstatus = context
.get_config(Config::Selfstatus)
.await
@@ -345,8 +342,7 @@ impl<'a, 'b> MimeFactory<'a, 'b> {
match self.loaded {
Loaded::Message { ref chat } => {
if self.msg.param.get_cmd() == SystemMessage::AutocryptSetupMessage {
self.context
.stock_str(StockMessage::AcSetupMsgSubject)
AcSetupMsgSubject::stock_str(self.context)
.await
.into_owned()
} else if chat.typ == Chattype::Group {
@@ -390,21 +386,14 @@ impl<'a, 'b> MimeFactory<'a, 'b> {
.unwrap_or_default(),
};
self.context
.stock_string_repl_str(
StockMessage::SubjectForNewContact,
self_name,
)
SubjectForNewContact::stock_str(self.context, self_name)
.await
.to_string()
}
}
}
}
Loaded::MDN { .. } => self
.context
.stock_str(StockMessage::ReadRcpt)
.await
.into_owned(),
Loaded::MDN { .. } => ReadRcpt::stock_str(self.context).await.into_owned(),
}
}
@@ -808,12 +797,7 @@ impl<'a, 'b> MimeFactory<'a, 'b> {
unprotected_headers
.push(Header::new("Autocrypt-Setup-Message".into(), "v1".into()));
placeholdertext = Some(
self.context
.stock_str(StockMessage::AcSetupMsgBody)
.await
.to_string(),
);
placeholdertext = Some(AcSetupMsgBody::stock_str(self.context).await.to_string());
}
SystemMessage::SecurejoinMessage => {
let msg = &self.msg;
@@ -1071,17 +1055,11 @@ impl<'a, 'b> MimeFactory<'a, 'b> {
.get_int(Param::GuaranteeE2ee)
.unwrap_or_default()
{
self.context
.stock_str(StockMessage::EncryptedMsg)
.await
.into_owned()
EncryptedMsg::stock_str(self.context).await.into_owned()
} else {
self.msg.get_summarytext(self.context, 32).await
};
let p2 = self
.context
.stock_string_repl_str(StockMessage::ReadRcptMailBody, p1)
.await;
let p2 = ReadRcptMailBody::stock_str(self.context, p1).await;
let message_text = format!("{}\r\n", p2);
message = message.child(
PartBuilder::new()

View File

@@ -3,10 +3,12 @@ use std::future::Future;
use std::pin::Pin;
use anyhow::{bail, Result};
use charset::Charset;
use deltachat_derive::{FromSql, ToSql};
use lettre_email::mime::{self, Mime};
use mailparse::{addrparse_header, DispositionType, MailHeader, MailHeaderMap, SingleInfo};
use once_cell::sync::Lazy;
use percent_encoding::percent_decode_str;
use crate::aheader::Aheader;
use crate::blob::BlobObject;
@@ -25,9 +27,7 @@ use crate::message;
use crate::param::{Param, Params};
use crate::peerstate::Peerstate;
use crate::simplify::simplify;
use crate::stock::StockMessage;
use charset::Charset;
use percent_encoding::percent_decode_str;
use crate::stock::CantDecryptMsgBody;
/// A parsed MIME message.
///
@@ -629,7 +629,7 @@ impl MimeMessage {
// we currently do not try to decrypt non-autocrypt messages
// at all. If we see an encrypted part, we set
// decrypting_failed.
let msg_body = context.stock_str(StockMessage::CantDecryptMsgBody).await;
let msg_body = CantDecryptMsgBody::stock_str(context).await;
let txt = format!("[{}]", msg_body);
let part = Part {

View File

@@ -13,7 +13,7 @@ use crate::context::Context;
use crate::events::EventType;
use crate::key::{DcKey, Fingerprint, SignedPublicKey};
use crate::sql::Sql;
use crate::stock::StockMessage;
use crate::stock::ContactSetupChanged;
#[derive(Debug)]
pub enum PeerstateKeyType {
@@ -281,9 +281,7 @@ impl<'a> Peerstate<'a> {
.await
.unwrap_or_default();
let msg = context
.stock_string_repl_str(StockMessage::ContactSetupChanged, self.addr.clone())
.await;
let msg = ContactSetupChanged::stock_str(context, self.addr.clone()).await;
chat::add_info_msg(context, contact_chat_id, msg).await;
emit_event!(context, EventType::ChatModified(contact_chat_id));

View File

@@ -23,7 +23,7 @@ use crate::param::Param;
use crate::peerstate::{Peerstate, PeerstateKeyType, PeerstateVerifiedStatus, ToSave};
use crate::qr::check_qr;
use crate::sql;
use crate::stock::StockMessage;
use crate::stock::{ContactNotVerified, ContactVerified};
use crate::token;
mod bobstate;
@@ -822,10 +822,8 @@ async fn secure_connection_established(context: &Context, contact_chat_id: ChatI
} else {
"?"
};
let msg = context
.stock_string_repl_str(StockMessage::ContactVerified, addr)
.await;
chat::add_info_msg(context, contact_chat_id, &msg).await;
let msg = ContactVerified::stock_str(context, addr).await;
chat::add_info_msg(context, contact_chat_id, msg).await;
emit_event!(context, EventType::ChatModified(contact_chat_id));
info!(context, "StockMessage::ContactVerified posted to 1:1 chat");
}
@@ -837,16 +835,15 @@ async fn could_not_establish_secure_connection(
) {
let contact_id = chat_id_2_contact_id(context, contact_chat_id).await;
let contact = Contact::get_by_id(context, contact_id).await;
let msg = context
.stock_string_repl_str(
StockMessage::ContactNotVerified,
if let Ok(ref contact) = contact {
contact.get_addr()
} else {
"?"
},
)
.await;
let msg = ContactNotVerified::stock_str(
context,
if let Ok(ref contact) = contact {
contact.get_addr()
} else {
"?"
},
)
.await;
chat::add_info_msg(context, contact_chat_id, &msg).await;
error!(

View File

@@ -13,7 +13,7 @@ use crate::events::EventType;
use crate::login_param::{dc_build_tls, CertificateChecks, LoginParam, ServerLoginParam};
use crate::oauth2::dc_get_oauth2_access_token;
use crate::provider::Socket;
use crate::stock::StockMessage;
use crate::stock::ServerResponse;
/// SMTP write and read timeout in seconds.
const SMTP_TIMEOUT: u64 = 30;
@@ -111,13 +111,13 @@ impl Smtp {
)
.await;
if let Err(ref err) = res {
let message = context
.stock_string_repl_str2(
StockMessage::ServerResponse,
format!("SMTP {}:{}", lp.smtp.server, lp.smtp.port),
err.to_string(),
)
.await;
let message = ServerResponse::stock_str(
context,
format!("SMTP {}:{}", lp.smtp.server, lp.smtp.port),
err.to_string(),
)
.await
.to_string();
context.emit_event(EventType::ErrorNetwork(message));
};

View File

@@ -10,22 +10,19 @@ use std::time::Duration;
use anyhow::format_err;
use rusqlite::{Connection, Error as SqlError, OpenFlags};
use crate::chat::add_device_msg;
use crate::chat::{add_device_msg, update_device_icon, update_saved_messages_icon};
use crate::config::Config;
use crate::config::Config::DeleteServerAfter;
use crate::constants::{ShowEmails, DC_CHAT_ID_TRASH};
use crate::constants::{ShowEmails, Viewtype, DC_CHAT_ID_TRASH};
use crate::context::Context;
use crate::dc_tools::{dc_delete_file, time, EmailAddress};
use crate::ephemeral::start_ephemeral_timers;
use crate::imap;
use crate::message::Message;
use crate::param::{Param, Params};
use crate::peerstate::Peerstate;
use crate::provider::get_provider_by_domain;
use crate::stock::StockMessage;
use crate::{
chat::{update_device_icon, update_saved_messages_icon},
config::Config,
};
use crate::{constants::Viewtype, message::Message};
use crate::stock::DeleteServerTurnedOff;
#[macro_export]
macro_rules! paramsv {
@@ -1544,12 +1541,7 @@ CREATE INDEX devmsglabels_index1 ON devmsglabels (label);
// So, for people who have delete_server enabled, disable it and add a hint to the devicechat:
if context.get_config_delete_server_after().await.is_some() {
let mut msg = Message::new(Viewtype::Text);
msg.text = Some(
context
.stock_str(StockMessage::DeleteServerTurnedOff)
.await
.into(),
);
msg.text = Some(DeleteServerTurnedOff::stock_str(context).await.into());
add_device_msg(context, None, Some(&mut msg)).await?;
context.set_config(DeleteServerAfter, Some("0")).await?;
}

File diff suppressed because it is too large Load Diff