mirror of
https://github.com/chatmail/core.git
synced 2026-04-17 21:46:35 +03:00
Add missing documentation to the message module
This commit is contained in:
112
src/message.rs
112
src/message.rs
@@ -1,7 +1,5 @@
|
||||
//! # Messages and their identifiers.
|
||||
|
||||
#![allow(missing_docs)]
|
||||
|
||||
use std::collections::BTreeSet;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
@@ -237,11 +235,18 @@ impl Default for MessengerMessage {
|
||||
/// If you want an update, you have to recreate the object.
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||
pub struct Message {
|
||||
/// Message ID.
|
||||
pub(crate) id: MsgId,
|
||||
|
||||
/// `From:` contact ID.
|
||||
pub(crate) from_id: ContactId,
|
||||
|
||||
/// ID of the first contact in the `To:` header.
|
||||
pub(crate) to_id: ContactId,
|
||||
pub(crate) chat_id: ChatId,
|
||||
pub(crate) viewtype: Viewtype,
|
||||
|
||||
/// State of the message.
|
||||
pub(crate) state: MessageState,
|
||||
pub(crate) download_state: DownloadState,
|
||||
pub(crate) hidden: bool,
|
||||
@@ -263,6 +268,7 @@ pub struct Message {
|
||||
}
|
||||
|
||||
impl Message {
|
||||
/// Creates a new message with given view type.
|
||||
pub fn new(viewtype: Viewtype) -> Self {
|
||||
Message {
|
||||
viewtype,
|
||||
@@ -270,6 +276,7 @@ impl Message {
|
||||
}
|
||||
}
|
||||
|
||||
/// Loads message with given ID from the database.
|
||||
pub async fn load_from_db(context: &Context, id: MsgId) -> Result<Message> {
|
||||
ensure!(
|
||||
!id.is_special(),
|
||||
@@ -366,6 +373,12 @@ impl Message {
|
||||
Ok(msg)
|
||||
}
|
||||
|
||||
/// Returns the MIME type of an attached file if it exists.
|
||||
///
|
||||
/// If the MIME type is not known, the function guesses the MIME type
|
||||
/// from the extension. `application/octet-stream` is used as a fallback
|
||||
/// if MIME type is not known, but `None` is only returned if no file
|
||||
/// is attached.
|
||||
pub fn get_filemime(&self) -> Option<String> {
|
||||
if let Some(m) = self.param.get(Param::MimeType) {
|
||||
return Some(m.to_string());
|
||||
@@ -380,11 +393,12 @@ impl Message {
|
||||
None
|
||||
}
|
||||
|
||||
/// Returns the full path to the file associated with a message.
|
||||
pub fn get_file(&self, context: &Context) -> Option<PathBuf> {
|
||||
self.param.get_path(Param::File, context).unwrap_or(None)
|
||||
}
|
||||
|
||||
pub async fn try_calc_and_set_dimensions(&mut self, context: &Context) -> Result<()> {
|
||||
pub(crate) async fn try_calc_and_set_dimensions(&mut self, context: &Context) -> Result<()> {
|
||||
if self.viewtype.has_file() {
|
||||
let file_param = self.param.get_path(Param::File, context)?;
|
||||
if let Some(path_and_filename) = file_param {
|
||||
@@ -442,6 +456,8 @@ impl Message {
|
||||
self.param.set_float(Param::SetLongitude, longitude);
|
||||
}
|
||||
|
||||
/// Returns the message timestamp for display in the UI
|
||||
/// as a unix timestamp in seconds.
|
||||
pub fn get_timestamp(&self) -> i64 {
|
||||
if 0 != self.timestamp_sent {
|
||||
self.timestamp_sent
|
||||
@@ -450,10 +466,12 @@ impl Message {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the message ID.
|
||||
pub fn get_id(&self) -> MsgId {
|
||||
self.id
|
||||
}
|
||||
|
||||
/// Returns the ID of the contact who wrote the message.
|
||||
pub fn get_from_id(&self) -> ContactId {
|
||||
self.from_id
|
||||
}
|
||||
@@ -463,30 +481,40 @@ impl Message {
|
||||
self.chat_id
|
||||
}
|
||||
|
||||
/// Returns the type of the message.
|
||||
pub fn get_viewtype(&self) -> Viewtype {
|
||||
self.viewtype
|
||||
}
|
||||
|
||||
/// Returns the state of the message.
|
||||
pub fn get_state(&self) -> MessageState {
|
||||
self.state
|
||||
}
|
||||
|
||||
/// Returns the message receive time as a unix timestamp in seconds.
|
||||
pub fn get_received_timestamp(&self) -> i64 {
|
||||
self.timestamp_rcvd
|
||||
}
|
||||
|
||||
/// Returns the timestamp of the message for sorting.
|
||||
pub fn get_sort_timestamp(&self) -> i64 {
|
||||
self.timestamp_sort
|
||||
}
|
||||
|
||||
/// Returns the text of the message.
|
||||
pub fn get_text(&self) -> Option<String> {
|
||||
self.text.as_ref().map(|s| s.to_string())
|
||||
}
|
||||
|
||||
/// Returns message subject.
|
||||
pub fn get_subject(&self) -> &str {
|
||||
&self.subject
|
||||
}
|
||||
|
||||
/// Returns base file name without the path.
|
||||
/// The base file name includes the extension.
|
||||
///
|
||||
/// To get the full path, use [`Self::get_file()`].
|
||||
pub fn get_filename(&self) -> Option<String> {
|
||||
self.param
|
||||
.get(Param::File)
|
||||
@@ -503,18 +531,22 @@ impl Message {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns width of associated image or video file.
|
||||
pub fn get_width(&self) -> i32 {
|
||||
self.param.get_int(Param::Width).unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Returns height of associated image or video file.
|
||||
pub fn get_height(&self) -> i32 {
|
||||
self.param.get_int(Param::Height).unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Returns duration of associated audio or video file.
|
||||
pub fn get_duration(&self) -> i32 {
|
||||
self.param.get_int(Param::Duration).unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Returns true if padlock indicating message encryption should be displayed in the UI.
|
||||
pub fn get_showpadlock(&self) -> bool {
|
||||
self.param.get_int(Param::GuaranteeE2ee).unwrap_or_default() != 0
|
||||
}
|
||||
@@ -524,10 +556,12 @@ impl Message {
|
||||
self.param.get_bool(Param::Bot).unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Return the ephemeral timer duration for a message.
|
||||
pub fn get_ephemeral_timer(&self) -> EphemeralTimer {
|
||||
self.ephemeral_timer
|
||||
}
|
||||
|
||||
/// Returns the timestamp of the epehemeral message removal.
|
||||
pub fn get_ephemeral_timestamp(&self) -> i64 {
|
||||
self.ephemeral_timestamp
|
||||
}
|
||||
@@ -565,6 +599,7 @@ impl Message {
|
||||
// C-data in the Java code (i.e. a `long` storing a C pointer)
|
||||
// - We can't make a param `SenderDisplayname` for messages as sometimes the display name of a contact changes, and we want to show
|
||||
// the same display name over all messages from the same sender.
|
||||
/// Returns the name that should be shown over the message instead of the contact display ame.
|
||||
pub fn get_override_sender_name(&self) -> Option<String> {
|
||||
self.param
|
||||
.get(Param::OverrideSenderDisplayname)
|
||||
@@ -573,11 +608,15 @@ impl Message {
|
||||
|
||||
// Exposing this function over the ffi instead of get_override_sender_name() would mean that at least Android Java code has
|
||||
// to handle raw C-data (as it is done for msg_get_summary())
|
||||
pub fn get_sender_name(&self, contact: &Contact) -> String {
|
||||
pub(crate) fn get_sender_name(&self, contact: &Contact) -> String {
|
||||
self.get_override_sender_name()
|
||||
.unwrap_or_else(|| contact.get_display_name().to_string())
|
||||
}
|
||||
|
||||
/// Returns true if a message has a deviating timestamp.
|
||||
///
|
||||
/// A message has a deviating timestamp when it is sent on
|
||||
/// another day as received/sorted by.
|
||||
pub fn has_deviating_timestamp(&self) -> bool {
|
||||
let cnv_to_local = gm2local_offset();
|
||||
let sort_timestamp = self.get_sort_timestamp() + cnv_to_local;
|
||||
@@ -586,14 +625,18 @@ impl Message {
|
||||
sort_timestamp / 86400 != send_timestamp / 86400
|
||||
}
|
||||
|
||||
/// Returns true if the message was successfully delivered to the outgoing server or even
|
||||
/// received a read receipt.
|
||||
pub fn is_sent(&self) -> bool {
|
||||
self.state >= MessageState::OutDelivered
|
||||
}
|
||||
|
||||
/// Returns true if the message is a forwarded message.
|
||||
pub fn is_forwarded(&self) -> bool {
|
||||
0 != self.param.get_int(Param::Forwarded).unwrap_or_default()
|
||||
}
|
||||
|
||||
/// Returns true if the message is an informational message.
|
||||
pub fn is_info(&self) -> bool {
|
||||
let cmd = self.param.get_cmd();
|
||||
self.from_id == ContactId::INFO
|
||||
@@ -601,10 +644,12 @@ impl Message {
|
||||
|| cmd != SystemMessage::Unknown && cmd != SystemMessage::AutocryptSetupMessage
|
||||
}
|
||||
|
||||
/// Returns the type of an informational message.
|
||||
pub fn get_info_type(&self) -> SystemMessage {
|
||||
self.param.get_cmd()
|
||||
}
|
||||
|
||||
/// Returns true if the message is a system message.
|
||||
pub fn is_system_message(&self) -> bool {
|
||||
let cmd = self.param.get_cmd();
|
||||
cmd != SystemMessage::Unknown
|
||||
@@ -622,6 +667,7 @@ impl Message {
|
||||
self.viewtype.has_file() && self.state == MessageState::OutPreparing
|
||||
}
|
||||
|
||||
/// Returns true if the message is an Autocrypt Setup Message.
|
||||
pub fn is_setupmessage(&self) -> bool {
|
||||
if self.viewtype != Viewtype::File {
|
||||
return false;
|
||||
@@ -630,6 +676,9 @@ impl Message {
|
||||
self.param.get_cmd() == SystemMessage::AutocryptSetupMessage
|
||||
}
|
||||
|
||||
/// Returns the first characters of the setup code.
|
||||
///
|
||||
/// This is used to pre-fill the first entry field of the setup code.
|
||||
pub async fn get_setupcodebegin(&self, context: &Context) -> Option<String> {
|
||||
if !self.is_setupmessage() {
|
||||
return None;
|
||||
@@ -650,7 +699,7 @@ impl Message {
|
||||
|
||||
// add room to a webrtc_instance as defined by the corresponding config-value;
|
||||
// the result may still be prefixed by the type
|
||||
pub fn create_webrtc_instance(instance: &str, room: &str) -> String {
|
||||
pub(crate) fn create_webrtc_instance(instance: &str, room: &str) -> String {
|
||||
let (videochat_type, mut url) = Message::parse_webrtc_instance(instance);
|
||||
|
||||
// make sure, there is a scheme in the url
|
||||
@@ -707,6 +756,7 @@ impl Message {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns videochat URL if the message is a videochat invitation.
|
||||
pub fn get_videochat_url(&self) -> Option<String> {
|
||||
if self.viewtype == Viewtype::VideochatInvitation {
|
||||
if let Some(instance) = self.param.get(Param::WebrtcRoom) {
|
||||
@@ -716,6 +766,7 @@ impl Message {
|
||||
None
|
||||
}
|
||||
|
||||
/// Returns videochat type if the message is a videochat invitation.
|
||||
pub fn get_videochat_type(&self) -> Option<VideochatType> {
|
||||
if self.viewtype == Viewtype::VideochatInvitation {
|
||||
if let Some(instance) = self.param.get(Param::WebrtcRoom) {
|
||||
@@ -725,10 +776,16 @@ impl Message {
|
||||
None
|
||||
}
|
||||
|
||||
/// Sets or unsets message text.
|
||||
pub fn set_text(&mut self, text: Option<String>) {
|
||||
self.text = text;
|
||||
}
|
||||
|
||||
/// Sets the file associated with a message.
|
||||
///
|
||||
/// This function does not use the file or check if it exists,
|
||||
/// the file will only be used when the message is prepared
|
||||
/// for sending.
|
||||
pub fn set_file(&mut self, file: impl ToString, filemime: Option<&str>) {
|
||||
self.param.set(Param::File, file);
|
||||
if let Some(filemime) = filemime {
|
||||
@@ -746,11 +803,13 @@ impl Message {
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the dimensions of associated image or video file.
|
||||
pub fn set_dimension(&mut self, width: i32, height: i32) {
|
||||
self.param.set_int(Param::Width, width);
|
||||
self.param.set_int(Param::Height, height);
|
||||
}
|
||||
|
||||
/// Sets the duration of associated audio or video file.
|
||||
pub fn set_duration(&mut self, duration: i32) {
|
||||
self.param.set_int(Param::Duration, duration);
|
||||
}
|
||||
@@ -760,6 +819,8 @@ impl Message {
|
||||
self.param.set_int(Param::Reaction, 1);
|
||||
}
|
||||
|
||||
/// Changes the message width, height or duration,
|
||||
/// and stores it into the database.
|
||||
pub async fn latefiling_mediasize(
|
||||
&mut self,
|
||||
context: &Context,
|
||||
@@ -824,10 +885,12 @@ impl Message {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns quoted message text, if any.
|
||||
pub fn quoted_text(&self) -> Option<String> {
|
||||
self.param.get(Param::Quote).map(|s| s.to_string())
|
||||
}
|
||||
|
||||
/// Returns quoted message, if any.
|
||||
pub async fn quoted_message(&self, context: &Context) -> Result<Option<Message>> {
|
||||
if self.param.get(Param::Quote).is_some() && !self.is_forwarded() {
|
||||
return self.parent(context).await;
|
||||
@@ -835,6 +898,10 @@ impl Message {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
/// Returns parent message according to the `In-Reply-To` header
|
||||
/// if it exists in the database and is not trashed.
|
||||
///
|
||||
/// `References` header is not taken into account.
|
||||
pub async fn parent(&self, context: &Context) -> Result<Option<Message>> {
|
||||
if let Some(in_reply_to) = &self.in_reply_to {
|
||||
if let Some(msg_id) = rfc724_mid_exists(context, in_reply_to).await? {
|
||||
@@ -855,6 +922,7 @@ impl Message {
|
||||
self.param.set_int(Param::ForcePlaintext, 1);
|
||||
}
|
||||
|
||||
/// Updates `param` column of the message in the database without changing other columns.
|
||||
pub async fn update_param(&self, context: &Context) -> Result<()> {
|
||||
context
|
||||
.sql
|
||||
@@ -894,6 +962,9 @@ impl Message {
|
||||
}
|
||||
}
|
||||
|
||||
/// State of the message.
|
||||
/// For incoming messages, stores the information on whether the message was read or not.
|
||||
/// For outgoing message, the message could be pending, already delivered or confirmed.
|
||||
#[derive(
|
||||
Debug,
|
||||
Clone,
|
||||
@@ -911,6 +982,7 @@ impl Message {
|
||||
)]
|
||||
#[repr(u32)]
|
||||
pub enum MessageState {
|
||||
/// Undefined message state.
|
||||
Undefined = 0,
|
||||
|
||||
/// Incoming *fresh* message. Fresh messages are neither noticed
|
||||
@@ -981,6 +1053,7 @@ impl std::fmt::Display for MessageState {
|
||||
}
|
||||
|
||||
impl MessageState {
|
||||
/// Returns true if the message can transition to `OutFailed` state from the current state.
|
||||
pub fn can_fail(self) -> bool {
|
||||
use MessageState::*;
|
||||
matches!(
|
||||
@@ -988,6 +1061,8 @@ impl MessageState {
|
||||
OutPreparing | OutPending | OutDelivered | OutMdnRcvd // OutMdnRcvd can still fail because it could be a group message and only some recipients failed.
|
||||
)
|
||||
}
|
||||
|
||||
/// Returns true for any outgoing message states.
|
||||
pub fn is_outgoing(self) -> bool {
|
||||
use MessageState::*;
|
||||
matches!(
|
||||
@@ -997,6 +1072,7 @@ impl MessageState {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns detailed message information in a multi-line text form.
|
||||
pub async fn get_msg_info(context: &Context, msg_id: MsgId) -> Result<String> {
|
||||
let msg = Message::load_from_db(context, msg_id).await?;
|
||||
let rawtxt: Option<String> = context
|
||||
@@ -1161,7 +1237,7 @@ pub async fn get_msg_info(context: &Context, msg_id: MsgId) -> Result<String> {
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
pub fn guess_msgtype_from_suffix(path: &Path) -> Option<(Viewtype, &str)> {
|
||||
pub(crate) fn guess_msgtype_from_suffix(path: &Path) -> Option<(Viewtype, &str)> {
|
||||
let extension: &str = &path.extension()?.to_str()?.to_lowercase();
|
||||
let info = match extension {
|
||||
// before using viewtype other than Viewtype::File,
|
||||
@@ -1274,6 +1350,9 @@ pub async fn get_mime_headers(context: &Context, msg_id: MsgId) -> Result<Vec<u8
|
||||
Ok(headers)
|
||||
}
|
||||
|
||||
/// Deletes requested messages
|
||||
/// by moving them to the trash chat
|
||||
/// and scheduling for deletion on IMAP.
|
||||
pub async fn delete_msgs(context: &Context, msg_ids: &[MsgId]) -> Result<()> {
|
||||
for msg_id in msg_ids.iter() {
|
||||
let msg = Message::load_from_db(context, *msg_id).await?;
|
||||
@@ -1321,6 +1400,7 @@ async fn delete_poi_location(context: &Context, location_id: u32) -> Result<()>
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Marks requested messages as seen.
|
||||
pub async fn markseen_msgs(context: &Context, msg_ids: Vec<MsgId>) -> Result<()> {
|
||||
if msg_ids.is_empty() {
|
||||
return Ok(());
|
||||
@@ -1453,7 +1533,8 @@ pub(crate) async fn update_msg_state(
|
||||
|
||||
// Context functions to work with messages
|
||||
|
||||
pub async fn exists(context: &Context, msg_id: MsgId) -> Result<bool> {
|
||||
/// Returns true if given message ID exists in the database and is not trashed.
|
||||
pub(crate) async fn exists(context: &Context, msg_id: MsgId) -> Result<bool> {
|
||||
if msg_id.is_special() {
|
||||
return Ok(false);
|
||||
}
|
||||
@@ -1470,7 +1551,7 @@ pub async fn exists(context: &Context, msg_id: MsgId) -> Result<bool> {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn set_msg_failed(context: &Context, msg_id: MsgId, error: &str) {
|
||||
pub(crate) async fn set_msg_failed(context: &Context, msg_id: MsgId, error: &str) {
|
||||
if let Ok(mut msg) = Message::load_from_db(context, msg_id).await {
|
||||
if msg.state.can_fail() {
|
||||
msg.state = MessageState::OutFailed;
|
||||
@@ -1716,6 +1797,20 @@ pub async fn get_request_msg_cnt(context: &Context) -> usize {
|
||||
}
|
||||
}
|
||||
|
||||
/// Estimates the number of messages that will be deleted
|
||||
/// by the options `delete_device_after` or `delete_server_after`.
|
||||
/// This is typically used to show the estimated impact to the user
|
||||
/// before actually enabling deletion of old messages.
|
||||
///
|
||||
/// If `from_server` is true,
|
||||
/// estimate deletion count for server,
|
||||
/// otherwise estimate deletion count for device.
|
||||
///
|
||||
/// Count messages older than the given number of `seconds`.
|
||||
///
|
||||
/// Returns the number of messages that are older than the given number of seconds.
|
||||
/// This includes e-mails downloaded due to the `show_emails` option.
|
||||
/// Messages in the "saved messages" folder are not counted as they will not be deleted automatically.
|
||||
pub async fn estimate_deletion_cnt(
|
||||
context: &Context,
|
||||
from_server: bool,
|
||||
@@ -1804,6 +1899,7 @@ pub(crate) async fn rfc724_mid_exists(
|
||||
)]
|
||||
#[repr(u32)]
|
||||
pub enum Viewtype {
|
||||
/// Unknown message type.
|
||||
Unknown = 0,
|
||||
|
||||
/// Text message.
|
||||
|
||||
Reference in New Issue
Block a user