mirror of
https://github.com/chatmail/core.git
synced 2026-04-28 19:06:35 +03:00
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:
141
src/chat.rs
141
src/chat.rs
@@ -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
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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(
|
||||
|
||||
217
src/ephemeral.rs
217
src/ephemeral.rs
@@ -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."
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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!(
|
||||
|
||||
@@ -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));
|
||||
};
|
||||
|
||||
20
src/sql.rs
20
src/sql.rs
@@ -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?;
|
||||
}
|
||||
|
||||
1347
src/stock.rs
1347
src/stock.rs
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user