diff --git a/deltachat-ffi/deltachat.h b/deltachat-ffi/deltachat.h index 507fbe76c..e457ecf11 100644 --- a/deltachat-ffi/deltachat.h +++ b/deltachat-ffi/deltachat.h @@ -1159,7 +1159,7 @@ uint32_t dc_add_device_msg (dc_context_t* context, const char* /** * Check if a device-message with a given label was ever added. - * Device-messages can be added dc_add_device_msg(). + * Device-messages can be added with dc_add_device_msg(). * * @memberof dc_context_t * @param context The context object. diff --git a/src/chat.rs b/src/chat.rs index 6d23b2048..0f5c1553e 100644 --- a/src/chat.rs +++ b/src/chat.rs @@ -1,7 +1,5 @@ //! # Chat module. -#![allow(missing_docs)] - use std::collections::HashMap; use std::convert::{TryFrom, TryInto}; use std::fmt; @@ -60,6 +58,7 @@ pub enum ChatItem { }, } +/// Chat protection status. #[derive( Debug, Display, @@ -77,7 +76,12 @@ pub enum ChatItem { )] #[repr(u32)] pub enum ProtectionStatus { + /// Chat is not protected. Unprotected = 0, + + /// Chat is protected. + /// + /// All members of the chat must be verified. Protected = 1, } @@ -295,7 +299,7 @@ impl ChatId { Ok(chat_id) } - pub async fn set_selfavatar_timestamp(self, context: &Context, timestamp: i64) -> Result<()> { + async fn set_selfavatar_timestamp(self, context: &Context, timestamp: i64) -> Result<()> { context .sql .execute( @@ -680,6 +684,7 @@ impl ChatId { Ok(()) } + /// Returns ID of the draft message, if there is one. async fn get_draft_msg_id(self, context: &Context) -> Result> { let msg_id: Option = context .sql @@ -691,6 +696,7 @@ impl ChatId { Ok(msg_id) } + /// Returns draft message, if there is one. pub async fn get_draft(self, context: &Context) -> Result> { if self.is_special() { return Ok(None); @@ -704,7 +710,7 @@ impl ChatId { } } - /// Delete draft message in specified chat, if there is one. + /// Deletes draft message, if there is one. /// /// Returns `true`, if message was deleted, `false` otherwise. async fn maybe_delete_draft(self, context: &Context) -> Result { @@ -826,6 +832,7 @@ impl ChatId { Ok(count) } + /// Returns the number of fresh messages in the chat. pub async fn get_fresh_msg_cnt(self, context: &Context) -> Result { // this function is typically used to show a badge counter beside _each_ chatlist item. // to make this as fast as possible, esp. on older devices, we added an combined index over the rows used for querying. @@ -892,7 +899,7 @@ impl ChatId { Ok(promoted) } - // Returns true if chat is a saved messages chat. + /// Returns true if chat is a saved messages chat. pub async fn is_self_talk(self, context: &Context) -> Result { Ok(self.get_param(context).await?.exists(Param::Selftalk)) } @@ -1130,15 +1137,29 @@ pub struct Chat { /// Chat type, e.g. 1:1 chat, group chat, mailing list. pub typ: Chattype, + + /// Chat name. pub name: String, + + /// Whether the chat is archived or pinned. pub visibility: ChatVisibility, /// Group ID. pub grpid: String, + + /// Whether the chat is blocked, unblocked or a contact request. pub(crate) blocked: Blocked, + + /// Additional chat parameters stored in the database. pub param: Params, + + /// If location streaming is enabled in the chat. is_sending_locations: bool, + + /// Duration of the chat being muted. pub mute_duration: MuteDuration, + + /// If the chat is protected (verified). protected: ProtectionStatus, } @@ -1258,7 +1279,7 @@ impl Chat { } } - pub async fn update_param(&mut self, context: &Context) -> Result<()> { + pub(crate) async fn update_param(&mut self, context: &Context) -> Result<()> { context .sql .execute( @@ -1314,6 +1335,10 @@ impl Chat { Ok(None) } + /// Returns chat avatar color. + /// + /// For 1:1 chats, the color is calculated from the contact's address. + /// For group chats the color is calculated from the chat name. pub async fn get_color(&self, context: &Context) -> Result { let mut color = 0; @@ -1360,6 +1385,7 @@ impl Chat { }) } + /// Returns chat visibilitiy, e.g. whether it is archived or pinned. pub fn get_visibility(&self) -> ChatVisibility { self.visibility } @@ -1372,10 +1398,12 @@ impl Chat { self.blocked == Blocked::Request } + /// Returns true if the chat is not promoted. pub fn is_unpromoted(&self) -> bool { self.param.get_bool(Param::Unpromoted).unwrap_or_default() } + /// Returns true if the chat is promoted. pub fn is_promoted(&self) -> bool { !self.is_unpromoted() } @@ -1390,6 +1418,7 @@ impl Chat { self.is_sending_locations } + /// Returns true if the chat is currently muted. pub fn is_muted(&self) -> bool { match self.mute_duration { MuteDuration::NotMuted => false, @@ -1974,6 +2003,7 @@ impl ChatIdBlocked { } } +/// Prepares a message for sending. pub async fn prepare_msg(context: &Context, chat_id: ChatId, msg: &mut Message) -> Result { ensure!( !chat_id.is_special(), @@ -2331,6 +2361,9 @@ async fn create_send_msg_job(context: &Context, msg_id: MsgId) -> Result, @@ -2706,10 +2745,14 @@ pub async fn get_chat_media( #[derive(Debug, Clone, PartialEq, Eq)] #[repr(i32)] pub enum Direction { + /// Search forward. Forward = 1, + + /// Search backward. Backward = -1, } +/// Searches next/previous message based on the given message and list of types. pub async fn get_next_media( context: &Context, curr_msg_id: MsgId, @@ -3400,6 +3443,9 @@ pub async fn forward_msgs(context: &Context, msg_ids: &[MsgId], chat_id: ChatId) Ok(()) } +/// Resends given messages with the same Message-ID. +/// +/// This is primarily intended to make existing webxdcs available to new chat members. pub async fn resend_msgs(context: &Context, msg_ids: &[MsgId]) -> Result<()> { let mut chat_id = None; let mut msgs: Vec = Vec::new(); @@ -3598,6 +3644,7 @@ pub async fn add_device_msg( add_device_msg_with_importance(context, label, msg, false).await } +/// Returns true if device message with a given label was ever added to the device chat. pub async fn was_device_msg_ever_added(context: &Context, label: &str) -> Result { ensure!(!label.is_empty(), "empty label"); let exists = context diff --git a/src/config.rs b/src/config.rs index 40aa43f16..52a25a05b 100644 --- a/src/config.rs +++ b/src/config.rs @@ -103,18 +103,26 @@ pub enum Config { /// Own avatar filename. Selfavatar, + /// Send BCC copy to self. + /// + /// Should be enabled for multidevice setups. #[strum(props(default = "1"))] BccSelf, + /// True if encryption is preferred according to Autocrypt standard. #[strum(props(default = "1"))] E2eeEnabled, + /// True if Message Delivery Notifications (read receipts) should + /// be sent and requested. #[strum(props(default = "1"))] MdnsEnabled, + /// True if "Sent" folder should be watched for changes. #[strum(props(default = "0"))] SentboxWatch, + /// True if chat messages should be moved to a separate folder. #[strum(props(default = "1"))] MvboxMove, @@ -125,9 +133,11 @@ pub enum Config { #[strum(props(default = "0"))] OnlyFetchMvbox, + /// Whether to show classic emails or only chat messages. #[strum(props(default = "0"))] // also change ShowEmails.default() on changes ShowEmails, + /// Quality of the media files to send. #[strum(props(default = "0"))] // also change MediaQuality.default() on changes MediaQuality, @@ -142,6 +152,7 @@ pub enum Config { #[strum(props(default = "1"))] FetchedExistingMsgs, + /// Type of the OpenPGP key to generate. #[strum(props(default = "0"))] KeyGenType, @@ -164,7 +175,9 @@ pub enum Config { #[strum(props(default = "0"))] DeleteDeviceAfter, + /// Save raw MIME messages with headers in the database if true. SaveMimeHeaders, + /// The primary email address. Also see `SecondaryAddrs`. ConfiguredAddr, @@ -196,6 +209,8 @@ pub enum Config { /// Configured SMTP server port. ConfiguredSendPort, ConfiguredSmtpCertificateChecks, + + /// Whether OAuth 2 is used with configured provider. ConfiguredServerFlags, ConfiguredSendSecurity, ConfiguredE2EEEnabled, @@ -203,7 +218,11 @@ pub enum Config { ConfiguredMvboxFolder, ConfiguredSentboxFolder, ConfiguredTimestamp, + + /// ID of the configured provider from the provider database. ConfiguredProvider, + + /// True if account is configured. Configured, /// All secondary self addresses separated by spaces @@ -219,6 +238,7 @@ pub enum Config { #[strum(serialize = "sys.config_keys")] SysConfigKeys, + /// True if it is a bot account. Bot, /// Whether we send a warning if the password is wrong (set to false when we send a warning @@ -293,28 +313,33 @@ impl Context { } } + /// Returns 32-bit signed integer configuration value for the given key. pub async fn get_config_int(&self, key: Config) -> Result { self.get_config(key) .await .map(|s: Option| s.and_then(|s| s.parse().ok()).unwrap_or_default()) } + /// Returns 64-bit signed integer configuration value for the given key. pub async fn get_config_i64(&self, key: Config) -> Result { self.get_config(key) .await .map(|s: Option| s.and_then(|s| s.parse().ok()).unwrap_or_default()) } + /// Returns 64-bit unsigned integer configuration value for the given key. pub async fn get_config_u64(&self, key: Config) -> Result { self.get_config(key) .await .map(|s: Option| s.and_then(|s| s.parse().ok()).unwrap_or_default()) } + /// Returns boolean configuration value for the given key. pub async fn get_config_bool(&self, key: Config) -> Result { Ok(self.get_config_int(key).await? != 0) } + /// Returns true if movebox ("DeltaChat" folder) should be watched. pub(crate) async fn should_watch_mvbox(&self) -> Result { Ok(self.get_config_bool(Config::MvboxMove).await? || self.get_config_bool(Config::OnlyFetchMvbox).await?) diff --git a/src/context.rs b/src/context.rs index 3f8866259..c672a1171 100644 --- a/src/context.rs +++ b/src/context.rs @@ -1,7 +1,5 @@ //! Context module. -#![allow(missing_docs)] - use std::collections::{BTreeMap, HashMap}; use std::ffi::OsString; use std::ops::Deref; diff --git a/src/html.rs b/src/html.rs index 20bb046c9..87b27acb3 100644 --- a/src/html.rs +++ b/src/html.rs @@ -240,7 +240,7 @@ fn mimepart_to_data_url(mail: &mailparse::ParsedMail<'_>) -> Result { } impl MsgId { - /// Get HTML from a message-id. + /// Get HTML by database message id. /// This requires `mime_headers` field to be set for the message; /// this is the case at least when `Message.has_html()` returns true /// (we do not save raw mime unconditionally in the database to save space). diff --git a/src/imex.rs b/src/imex.rs index bcedd8b99..cbe91658d 100644 --- a/src/imex.rs +++ b/src/imex.rs @@ -1,7 +1,5 @@ //! # Import/export module. -#![allow(missing_docs)] - use std::any::Any; use std::ffi::OsStr; use std::path::{Path, PathBuf}; @@ -38,6 +36,7 @@ use crate::{e2ee, tools}; const DBFILE_BACKUP_NAME: &str = "dc_database_backup.sqlite"; const BLOBS_BACKUP_NAME: &str = "blobs_backup"; +/// Import/export command. #[derive(Debug, Display, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)] #[repr(u32)] pub enum ImexMode { @@ -220,6 +219,7 @@ pub async fn render_setup_file(context: &Context, passphrase: &str) -> Result String { let mut random_val: u16; let mut rng = thread_rng(); @@ -258,6 +258,10 @@ async fn maybe_add_bcc_self_device_msg(context: &Context) -> Result<()> { Ok(()) } +/// Continue key transfer via Autocrypt Setup Message. +/// +/// `msg_id` is the ID of the received Autocrypt Setup Message. +/// `setup_code` is the code entered by the user. pub async fn continue_key_transfer( context: &Context, msg_id: MsgId, diff --git a/src/message.rs b/src/message.rs index 1b1a1118c..9962a6cbe 100644 --- a/src/message.rs +++ b/src/message.rs @@ -244,12 +244,18 @@ pub struct Message { /// ID of the first contact in the `To:` header. pub(crate) to_id: ContactId, + + /// ID of the chat message belongs to. pub(crate) chat_id: ChatId, + + /// Type of the message. pub(crate) viewtype: Viewtype, /// State of the message. pub(crate) state: MessageState, pub(crate) download_state: DownloadState, + + /// Whether the message is hidden. pub(crate) hidden: bool, pub(crate) timestamp_sort: i64, pub(crate) timestamp_sent: i64, @@ -257,8 +263,14 @@ pub struct Message { pub(crate) ephemeral_timer: EphemeralTimer, pub(crate) ephemeral_timestamp: i64, pub(crate) text: Option, + + /// Message subject. pub(crate) subject: String, + + /// `Message-ID` header value. pub(crate) rfc724_mid: String, + + /// `In-Reply-To` header value. pub(crate) in_reply_to: Option, pub(crate) is_dc_message: MessengerMessage, pub(crate) mime_modified: bool, diff --git a/src/mimeparser.rs b/src/mimeparser.rs index d428fc080..3728a44d5 100644 --- a/src/mimeparser.rs +++ b/src/mimeparser.rs @@ -49,12 +49,18 @@ use crate::{location, tools}; /// using the [MimeMessage::from_bytes] constructor. #[derive(Debug)] pub struct MimeMessage { + /// Parsed MIME parts. pub parts: Vec, + + /// Message headers. header: HashMap, /// Addresses are normalized and lowercased: pub recipients: Vec, + + /// `From:` address. pub from: SingleInfo, + /// Whether the From address was repeated in the signed part /// (and we know that the signer intended to send from this address) pub from_is_signed: bool, @@ -72,6 +78,8 @@ pub struct MimeMessage { /// The set of mail recipient addresses for which gossip headers were applied, regardless of /// whether they modified any peerstates. pub gossiped_addr: HashSet, + + /// True if the message is a forwarded message. pub is_forwarded: bool, pub is_system_message: SystemMessage, pub location_kml: Option, @@ -128,10 +136,20 @@ pub(crate) enum MailinglistType { #[repr(u32)] pub enum SystemMessage { Unknown = 0, + + /// Group name changed. GroupNameChanged = 2, + + /// Group avatar changed. GroupImageChanged = 3, + + /// Member was added to the group. MemberAddedToGroup = 4, + + /// Member was removed from the group. MemberRemovedFromGroup = 5, + + /// Autocrypt Setup Message. AutocryptSetupMessage = 6, SecurejoinMessage = 7, LocationStreamingEnabled = 8, @@ -140,20 +158,22 @@ pub enum SystemMessage { /// Chat ephemeral message timer is changed. EphemeralTimerChanged = 10, - // Chat protection state changed + /// Chat protection is enabled. ChatProtectionEnabled = 11, + + /// Chat protection is disabled. ChatProtectionDisabled = 12, /// Self-sent-message that contains only json used for multi-device-sync; /// if possible, we attach that to other messages as for locations. MultiDeviceSync = 20, - // Sync message that contains a json payload - // sent to the other webxdc instances - // These messages are not shown in the chat. + /// Sync message that contains a json payload + /// sent to the other webxdc instances + /// These messages are not shown in the chat. WebxdcStatusUpdate = 30, - // Webxdc info added with `info` set in `send_webxdc_status_update()`. + /// Webxdc info added with `info` set in `send_webxdc_status_update()`. WebxdcInfoMessage = 32, } @@ -1764,16 +1784,32 @@ fn is_known(key: &str) -> bool { ) } +/// Parsed MIME part. #[derive(Debug, Default, Clone)] pub struct Part { + /// Type of the MIME part determining how it should be displayed. pub typ: Viewtype, + + /// MIME type. pub mimetype: Option, + + /// Message text to be displayed in the chat. pub msg: String, + + /// Message text to be displayed in message info. pub msg_raw: Option, + + /// Size of the MIME part in bytes. pub bytes: usize, pub param: Params, + + /// Attachment filename. pub(crate) org_filename: Option, + + /// An error detected during parsing. pub error: Option, + + /// True if conversion from HTML to plaintext failed. pub(crate) dehtml_failed: bool, /// the part is a child or a descendant of multipart/related. diff --git a/src/plaintext.rs b/src/plaintext.rs index 13dd1ac7c..e50311677 100644 --- a/src/plaintext.rs +++ b/src/plaintext.rs @@ -1,13 +1,13 @@ //! Handle plain text together with some attributes. -#![allow(missing_docs)] - use once_cell::sync::Lazy; use crate::simplify::split_lines; +/// Plaintext message body together with format=flowed attributes. #[derive(Debug)] pub struct PlainText { + /// The text itself. pub text: String, /// Text may "flowed" as defined in [RFC 2646](https://tools.ietf.org/html/rfc2646). diff --git a/src/provider.rs b/src/provider.rs index 01153f4c2..fcf26852f 100644 --- a/src/provider.rs +++ b/src/provider.rs @@ -1,7 +1,5 @@ //! [Provider database](https://providers.delta.chat/) module. -#![allow(missing_docs)] - mod data; use anyhow::Result; @@ -12,27 +10,46 @@ use crate::config::Config; use crate::context::Context; use crate::provider::data::{PROVIDER_DATA, PROVIDER_IDS, PROVIDER_UPDATED}; +/// Provider status according to manual testing. #[derive(Debug, Display, Copy, Clone, PartialEq, Eq, FromPrimitive, ToPrimitive)] #[repr(u8)] pub enum Status { + /// Provider is known to be working with Delta Chat. Ok = 1, + + /// Provider works with Delta Chat, but requires some preparation, + /// such as changing the settings in the web interface. Preparation = 2, + + /// Provider is known not to work with Delta Chat. Broken = 3, } +/// Server protocol. #[derive(Debug, Display, PartialEq, Eq, Copy, Clone, FromPrimitive, ToPrimitive)] #[repr(u8)] pub enum Protocol { + /// SMTP protocol. Smtp = 1, + + /// IMAP protocol. Imap = 2, } +/// Socket security. #[derive(Debug, Display, PartialEq, Eq, Copy, Clone, FromPrimitive, ToPrimitive)] #[repr(u8)] pub enum Socket { + /// Unspecified socket security, select automatically. Automatic = 0, + + /// TLS connection. Ssl = 1, + + /// STARTTLS connection. Starttls = 2, + + /// No TLS, plaintext connection. Plain = 3, } @@ -42,47 +59,89 @@ impl Default for Socket { } } +/// Pattern used to construct login usernames from email addresses. #[derive(Debug, PartialEq, Eq, Clone)] #[repr(u8)] pub enum UsernamePattern { + /// Whole email is used as username. Email = 1, + + /// Part of address before `@` is used as username. Emaillocalpart = 2, } +/// Type of OAuth 2 authorization. #[derive(Debug, PartialEq, Eq)] #[repr(u8)] pub enum Oauth2Authorizer { + /// Yandex. Yandex = 1, + + /// Gmail. Gmail = 2, } +/// Email server endpoint. #[derive(Debug, Clone, PartialEq, Eq)] pub struct Server { + /// Server protocol, e.g. SMTP or IMAP. pub protocol: Protocol, + + /// Port security, e.g. TLS or STARTTLS. pub socket: Socket, + + /// Server host. pub hostname: &'static str, + + /// Server port. pub port: u16, + + /// Pattern used to construct login usernames from email addresses. pub username_pattern: UsernamePattern, } +/// Pair of key and value for default configuration. #[derive(Debug, PartialEq, Eq)] pub struct ConfigDefault { + /// Configuration variable name. pub key: Config, + + /// Configuration variable value. pub value: &'static str, } +/// Provider database entry. #[derive(Debug, PartialEq, Eq)] pub struct Provider { /// Unique ID, corresponding to provider database filename. pub id: &'static str, + + /// Provider status according to manual testing. pub status: Status, + + /// Hint to be shown to the user on the login screen. pub before_login_hint: &'static str, + + /// Hint to be added to the device chat after provider configuration. pub after_login_hint: &'static str, + + /// URL of the page with provider overview. pub overview_page: &'static str, + + /// List of provider servers. pub server: Vec, + + /// Default configuration values to set when provider is configured. pub config_defaults: Option>, + + /// True if provider is known to use use proper, + /// not self-signed certificates. pub strict_tls: bool, + + /// Maximum number of recipients the provider allows to send a single email to. pub max_smtp_rcpt_to: Option, + + /// Type of OAuth 2 authorization if provider supports it. pub oauth2_authorizer: Option, } @@ -175,6 +234,7 @@ pub async fn get_provider_by_mx(context: &Context, domain: &str) -> Option<&'sta None } +/// Returns a provider with the given ID from the database. pub fn get_provider_by_id(id: &str) -> Option<&'static Provider> { if let Some(provider) = PROVIDER_IDS.get(id) { Some(provider) @@ -183,7 +243,7 @@ pub fn get_provider_by_id(id: &str) -> Option<&'static Provider> { } } -// returns update timestamp in seconds, UTC, compatible for comparison with time() and database times +/// Returns update timestamp as a unix timestamp compatible for comparison with time() and database times. pub fn get_provider_update_timestamp() -> i64 { NaiveDateTime::new(*PROVIDER_UPDATED, NaiveTime::from_hms_opt(0, 0, 0).unwrap()) .timestamp_millis() diff --git a/src/scheduler/connectivity.rs b/src/scheduler/connectivity.rs index 745f0b9e6..54d8b1d42 100644 --- a/src/scheduler/connectivity.rs +++ b/src/scheduler/connectivity.rs @@ -1,5 +1,3 @@ -#![allow(missing_docs)] - use core::fmt; use std::{ops::Deref, sync::Arc}; @@ -538,6 +536,7 @@ impl Context { Ok(ret) } + /// Returns true if all background work is done. pub async fn all_work_done(&self) -> bool { let lock = self.scheduler.read().await; let stores: Vec<_> = match &*lock { diff --git a/src/securejoin.rs b/src/securejoin.rs index 834436136..de9edcf21 100644 --- a/src/securejoin.rs +++ b/src/securejoin.rs @@ -1,7 +1,5 @@ //! Verified contact protocol implementation as [specified by countermitm project](https://countermitm.readthedocs.io/en/stable/new.html#setup-contact-protocol). -#![allow(missing_docs)] - use std::convert::TryFrom; use anyhow::{bail, Context as _, Error, Result}; @@ -35,6 +33,7 @@ use qrinvite::QrInvite; use crate::token::Namespace; +/// Set of characters to percent-encode in email addresses and names. pub const NON_ALPHANUMERIC_WITHOUT_DOT: &AsciiSet = &NON_ALPHANUMERIC.remove(b'.'); macro_rules! inviter_progress {