Add more documentation

This commit is contained in:
link2xt
2023-02-13 17:09:58 +00:00
parent 7d2cca8633
commit ae19c9b331
20 changed files with 317 additions and 47 deletions

View File

@@ -5671,7 +5671,7 @@ void dc_event_unref(dc_event_t* event);
#define DC_EVENT_INCOMING_MSG 2005 #define DC_EVENT_INCOMING_MSG 2005
/** /**
* Downloading a bunch of messages just finished. This is an experimental * Downloading a bunch of messages just finished. This is an
* event to allow the UI to only show one notification per message bunch, * event to allow the UI to only show one notification per message bunch,
* instead of cluttering the user with many notifications. * instead of cluttering the user with many notifications.
* For each of the msg_ids, an additional #DC_EVENT_INCOMING_MSG event was emitted before. * For each of the msg_ids, an additional #DC_EVENT_INCOMING_MSG event was emitted before.

View File

@@ -161,6 +161,8 @@ impl Accounts {
} }
/// Migrate an existing account into this structure. /// Migrate an existing account into this structure.
///
/// Returns the ID of new account.
pub async fn migrate_account(&mut self, dbfile: PathBuf) -> Result<u32> { pub async fn migrate_account(&mut self, dbfile: PathBuf) -> Result<u32> {
let blobdir = Context::derive_blobdir(&dbfile); let blobdir = Context::derive_blobdir(&dbfile);
let walfile = Context::derive_walfile(&dbfile); let walfile = Context::derive_walfile(&dbfile);

View File

@@ -2075,8 +2075,7 @@ async fn prepare_msg_blob(context: &Context, msg: &mut Message) -> Result<()> {
Ok(()) Ok(())
} }
/// Prepares a message to be send out /// Prepares a message to be sent out.
/// - Checks if chat can be sent to
async fn prepare_msg_common( async fn prepare_msg_common(
context: &Context, context: &Context,
chat_id: ChatId, chat_id: ChatId,
@@ -2084,6 +2083,8 @@ async fn prepare_msg_common(
change_state_to: MessageState, change_state_to: MessageState,
) -> Result<MsgId> { ) -> Result<MsgId> {
let mut chat = Chat::load_from_db(context, chat_id).await?; let mut chat = Chat::load_from_db(context, chat_id).await?;
// Check if the chat can be sent to.
if let Some(reason) = chat.why_cant_send(context).await? { if let Some(reason) = chat.why_cant_send(context).await? {
bail!("cannot send to {}: {}", chat_id, reason); bail!("cannot send to {}: {}", chat_id, reason);
} }
@@ -2141,7 +2142,7 @@ pub async fn is_contact_in_chat(
Ok(exists) Ok(exists)
} }
/// Send a message defined by a dc_msg_t object to a chat. /// Sends a message object to a chat.
/// ///
/// Sends the event #DC_EVENT_MSGS_CHANGED on succcess. /// Sends the event #DC_EVENT_MSGS_CHANGED on succcess.
/// However, this does not imply, the message really reached the recipient - /// However, this does not imply, the message really reached the recipient -
@@ -3294,7 +3295,7 @@ pub async fn set_chat_name(context: &Context, chat_id: ChatId, new_name: &str) -
Ok(()) Ok(())
} }
/// Set a new profile image for the chat. /// Sets a new profile image for the chat.
/// ///
/// The profile image can only be set when you are a member of the /// The profile image can only be set when you are a member of the
/// chat. To remove the profile image pass an empty string for the /// chat. To remove the profile image pass an empty string for the

View File

@@ -1,7 +1,5 @@
//! # Key-value configuration management. //! # Key-value configuration management.
#![allow(missing_docs)]
use anyhow::{ensure, Context as _, Result}; use anyhow::{ensure, Context as _, Result};
use strum::{EnumProperty, IntoEnumIterator}; use strum::{EnumProperty, IntoEnumIterator};
use strum_macros::{AsRefStr, Display, EnumIter, EnumProperty, EnumString}; use strum_macros::{AsRefStr, Display, EnumIter, EnumProperty, EnumString};
@@ -195,6 +193,8 @@ pub enum Config {
/// Configured IMAP server security (e.g. TLS, STARTTLS). /// Configured IMAP server security (e.g. TLS, STARTTLS).
ConfiguredMailSecurity, ConfiguredMailSecurity,
/// How to check IMAP server TLS certificates.
ConfiguredImapCertificateChecks, ConfiguredImapCertificateChecks,
/// Configured SMTP server hostname. /// Configured SMTP server hostname.
@@ -208,14 +208,26 @@ pub enum Config {
/// Configured SMTP server port. /// Configured SMTP server port.
ConfiguredSendPort, ConfiguredSendPort,
/// How to check SMTP server TLS certificates.
ConfiguredSmtpCertificateChecks, ConfiguredSmtpCertificateChecks,
/// Whether OAuth 2 is used with configured provider. /// Whether OAuth 2 is used with configured provider.
ConfiguredServerFlags, ConfiguredServerFlags,
/// Configured SMTP server security (e.g. TLS, STARTTLS).
ConfiguredSendSecurity, ConfiguredSendSecurity,
/// Configured folder for incoming messages.
ConfiguredInboxFolder, ConfiguredInboxFolder,
/// Configured folder for chat messages.
ConfiguredMvboxFolder, ConfiguredMvboxFolder,
/// Configured "Sent" folder.
ConfiguredSentboxFolder, ConfiguredSentboxFolder,
/// Unix timestamp of the last successful configuration.
ConfiguredTimestamp, ConfiguredTimestamp,
/// ID of the configured provider from the provider database. /// ID of the configured provider from the provider database.
@@ -228,12 +240,15 @@ pub enum Config {
/// (`addr1@example.org addr2@exapmle.org addr3@example.org`) /// (`addr1@example.org addr2@exapmle.org addr3@example.org`)
SecondaryAddrs, SecondaryAddrs,
/// Read-only core version string.
#[strum(serialize = "sys.version")] #[strum(serialize = "sys.version")]
SysVersion, SysVersion,
/// Maximal recommended attachment size in bytes.
#[strum(serialize = "sys.msgsize_max_recommended")] #[strum(serialize = "sys.msgsize_max_recommended")]
SysMsgsizeMaxRecommended, SysMsgsizeMaxRecommended,
/// Space separated list of all config keys available.
#[strum(serialize = "sys.config_keys")] #[strum(serialize = "sys.config_keys")]
SysConfigKeys, SysConfigKeys,
@@ -419,6 +434,7 @@ impl Context {
Ok(()) Ok(())
} }
/// Set the given config to a boolean value.
pub async fn set_config_bool(&self, key: Config, value: bool) -> Result<()> { pub async fn set_config_bool(&self, key: Config, value: bool) -> Result<()> {
self.set_config(key, if value { Some("1") } else { Some("0") }) self.set_config(key, if value { Some("1") } else { Some("0") })
.await?; .await?;

View File

@@ -66,14 +66,20 @@ pub enum KeyGenType {
Ed25519 = 2, Ed25519 = 2,
} }
/// Video chat URL type.
#[derive( #[derive(
Debug, Default, Display, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive, FromSql, ToSql, Debug, Default, Display, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive, FromSql, ToSql,
)] )]
#[repr(i8)] #[repr(i8)]
pub enum VideochatType { pub enum VideochatType {
/// Unknown type.
#[default] #[default]
Unknown = 0, Unknown = 0,
/// [basicWebRTC](https://github.com/cracker0dks/basicwebrtc) instance.
BasicWebrtc = 1, BasicWebrtc = 1,
/// [Jitsi Meet](https://jitsi.org/jitsi-meet/) instance.
Jitsi = 2, Jitsi = 2,
} }
@@ -109,6 +115,7 @@ pub const DC_CHAT_ID_ALLDONE_HINT: ChatId = ChatId::new(7);
/// larger chat IDs are "real" chats, their messages are "real" messages. /// larger chat IDs are "real" chats, their messages are "real" messages.
pub const DC_CHAT_ID_LAST_SPECIAL: ChatId = ChatId::new(9); pub const DC_CHAT_ID_LAST_SPECIAL: ChatId = ChatId::new(9);
/// Chat type.
#[derive( #[derive(
Debug, Debug,
Default, Default,
@@ -127,11 +134,20 @@ pub const DC_CHAT_ID_LAST_SPECIAL: ChatId = ChatId::new(9);
)] )]
#[repr(u32)] #[repr(u32)]
pub enum Chattype { pub enum Chattype {
/// Undefined chat type.
#[default] #[default]
Undefined = 0, Undefined = 0,
/// 1:1 chat.
Single = 100, Single = 100,
/// Group chat.
Group = 120, Group = 120,
/// Mailing list.
Mailinglist = 140, Mailinglist = 140,
/// Broadcast list.
Broadcast = 160, Broadcast = 160,
} }

View File

@@ -1,7 +1,5 @@
//! # Events specification. //! # Events specification.
#![allow(missing_docs)]
use std::path::PathBuf; use std::path::PathBuf;
use async_channel::{self as channel, Receiver, Sender, TrySendError}; use async_channel::{self as channel, Receiver, Sender, TrySendError};
@@ -111,6 +109,7 @@ pub struct Event {
pub typ: EventType, pub typ: EventType,
} }
/// Event payload.
#[derive(Debug, Clone, PartialEq, Eq, Serialize)] #[derive(Debug, Clone, PartialEq, Eq, Serialize)]
pub enum EventType { pub enum EventType {
/// The library-user may write an informational string to the log. /// The library-user may write an informational string to the log.
@@ -171,17 +170,23 @@ pub enum EventType {
/// - Chats created, deleted or archived /// - Chats created, deleted or archived
/// - A draft has been set /// - A draft has been set
/// ///
/// `chat_id` is set if only a single chat is affected by the changes, otherwise 0.
/// `msg_id` is set if only a single message is affected by the changes, otherwise 0.
MsgsChanged { MsgsChanged {
/// Set if only a single chat is affected by the changes, otherwise 0.
chat_id: ChatId, chat_id: ChatId,
/// Set if only a single message is affected by the changes, otherwise 0.
msg_id: MsgId, msg_id: MsgId,
}, },
/// Reactions for the message changed. /// Reactions for the message changed.
ReactionsChanged { ReactionsChanged {
/// ID of the chat which the message belongs to.
chat_id: ChatId, chat_id: ChatId,
/// ID of the message for which reactions were changed.
msg_id: MsgId, msg_id: MsgId,
/// ID of the contact whose reaction set is changed.
contact_id: ContactId, contact_id: ContactId,
}, },
@@ -190,11 +195,16 @@ pub enum EventType {
/// ///
/// There is no extra #DC_EVENT_MSGS_CHANGED event send together with this event. /// There is no extra #DC_EVENT_MSGS_CHANGED event send together with this event.
IncomingMsg { IncomingMsg {
/// ID of the chat where the message is assigned.
chat_id: ChatId, chat_id: ChatId,
/// ID of the message.
msg_id: MsgId, msg_id: MsgId,
}, },
/// Downloading a bunch of messages just finished.
IncomingMsgBunch { IncomingMsgBunch {
/// List of incoming message IDs.
msg_ids: Vec<MsgId>, msg_ids: Vec<MsgId>,
}, },
@@ -205,21 +215,30 @@ pub enum EventType {
/// A single message is sent successfully. State changed from DC_STATE_OUT_PENDING to /// A single message is sent successfully. State changed from DC_STATE_OUT_PENDING to
/// DC_STATE_OUT_DELIVERED, see dc_msg_get_state(). /// DC_STATE_OUT_DELIVERED, see dc_msg_get_state().
MsgDelivered { MsgDelivered {
/// ID of the chat which the message belongs to.
chat_id: ChatId, chat_id: ChatId,
/// ID of the message that was successfully sent.
msg_id: MsgId, msg_id: MsgId,
}, },
/// A single message could not be sent. State changed from DC_STATE_OUT_PENDING or DC_STATE_OUT_DELIVERED to /// A single message could not be sent. State changed from DC_STATE_OUT_PENDING or DC_STATE_OUT_DELIVERED to
/// DC_STATE_OUT_FAILED, see dc_msg_get_state(). /// DC_STATE_OUT_FAILED, see dc_msg_get_state().
MsgFailed { MsgFailed {
/// ID of the chat which the message belongs to.
chat_id: ChatId, chat_id: ChatId,
/// ID of the message that could not be sent.
msg_id: MsgId, msg_id: MsgId,
}, },
/// A single message is read by the receiver. State changed from DC_STATE_OUT_DELIVERED to /// A single message is read by the receiver. State changed from DC_STATE_OUT_DELIVERED to
/// DC_STATE_OUT_MDN_RCVD, see dc_msg_get_state(). /// DC_STATE_OUT_MDN_RCVD, see dc_msg_get_state().
MsgRead { MsgRead {
/// ID of the chat which the message belongs to.
chat_id: ChatId, chat_id: ChatId,
/// ID of the message that was read.
msg_id: MsgId, msg_id: MsgId,
}, },
@@ -234,7 +253,10 @@ pub enum EventType {
/// Chat ephemeral timer changed. /// Chat ephemeral timer changed.
ChatEphemeralTimerModified { ChatEphemeralTimerModified {
/// Chat ID.
chat_id: ChatId, chat_id: ChatId,
/// New ephemeral timer value.
timer: EphemeralTimer, timer: EphemeralTimer,
}, },
@@ -281,15 +303,15 @@ pub enum EventType {
/// ///
/// These events are typically sent after a joiner has scanned the QR code /// These events are typically sent after a joiner has scanned the QR code
/// generated by dc_get_securejoin_qr(). /// generated by dc_get_securejoin_qr().
///
/// @param data1 (int) ID of the contact that wants to join.
/// @param data2 (int) Progress as:
/// 300=vg-/vc-request received, typically shown as "bob@addr joins".
/// 600=vg-/vc-request-with-auth received, vg-member-added/vc-contact-confirm sent, typically shown as "bob@addr verified".
/// 800=contact added to chat, shown as "bob@addr securely joined GROUP". Only for the verified-group-protocol.
/// 1000=Protocol finished for this contact.
SecurejoinInviterProgress { SecurejoinInviterProgress {
/// ID of the contact that wants to join.
contact_id: ContactId, contact_id: ContactId,
/// Progress as:
/// 300=vg-/vc-request received, typically shown as "bob@addr joins".
/// 600=vg-/vc-request-with-auth received, vg-member-added/vc-contact-confirm sent, typically shown as "bob@addr verified".
/// 800=contact added to chat, shown as "bob@addr securely joined GROUP". Only for the verified-group-protocol.
/// 1000=Protocol finished for this contact.
progress: usize, progress: usize,
}, },
@@ -297,12 +319,13 @@ pub enum EventType {
/// (Bob, the person who scans the QR code). /// (Bob, the person who scans the QR code).
/// The events are typically sent while dc_join_securejoin(), which /// The events are typically sent while dc_join_securejoin(), which
/// may take some time, is executed. /// may take some time, is executed.
/// @param data1 (int) ID of the inviting contact.
/// @param data2 (int) Progress as:
/// 400=vg-/vc-request-with-auth sent, typically shown as "alice@addr verified, introducing myself."
/// (Bob has verified alice and waits until Alice does the same for him)
SecurejoinJoinerProgress { SecurejoinJoinerProgress {
/// ID of the inviting contact.
contact_id: ContactId, contact_id: ContactId,
/// Progress as:
/// 400=vg-/vc-request-with-auth sent, typically shown as "alice@addr verified, introducing myself."
/// (Bob has verified alice and waits until Alice does the same for him)
progress: usize, progress: usize,
}, },
@@ -312,15 +335,21 @@ pub enum EventType {
/// dc_get_connectivity_html() for details. /// dc_get_connectivity_html() for details.
ConnectivityChanged, ConnectivityChanged,
/// The user's avatar changed.
SelfavatarChanged, SelfavatarChanged,
/// Webxdc status update received.
WebxdcStatusUpdate { WebxdcStatusUpdate {
/// Message ID.
msg_id: MsgId, msg_id: MsgId,
/// Status update ID.
status_update_serial: StatusUpdateSerial, status_update_serial: StatusUpdateSerial,
}, },
/// Inform that a message containing a webxdc instance has been deleted /// Inform that a message containing a webxdc instance has been deleted.
WebxdcInstanceDeleted { WebxdcInstanceDeleted {
/// ID of the deleted message.
msg_id: MsgId, msg_id: MsgId,
}, },
} }

View File

@@ -1,17 +1,18 @@
//! # List of email headers. //! # List of email headers.
#![allow(missing_docs)]
use mailparse::{MailHeader, MailHeaderMap}; use mailparse::{MailHeader, MailHeaderMap};
#[derive(Debug, Display, Clone, PartialEq, Eq, EnumVariantNames, IntoStaticStr)] #[derive(Debug, Display, Clone, PartialEq, Eq, EnumVariantNames, IntoStaticStr)]
#[strum(serialize_all = "kebab_case")] #[strum(serialize_all = "kebab_case")]
#[allow(missing_docs)]
pub enum HeaderDef { pub enum HeaderDef {
MessageId, MessageId,
Subject, Subject,
Date, Date,
From_, From_,
To, To,
/// Carbon copy.
Cc, Cc,
Disposition, Disposition,
@@ -34,11 +35,18 @@ pub enum HeaderDef {
/// header, so it can be used to ignore such messages. /// header, so it can be used to ignore such messages.
XMozillaDraftInfo, XMozillaDraftInfo,
/// Mailing list ID defined in [RFC 2919](https://tools.ietf.org/html/rfc2919).
ListId, ListId,
ListPost, ListPost,
References, References,
/// In-Reply-To header containing Message-ID of the parent message.
InReplyTo, InReplyTo,
/// Used to detect mailing lists if contains "list" value
/// as described in [RFC 3834](https://tools.ietf.org/html/rfc3834)
Precedence, Precedence,
ContentType, ContentType,
ContentId, ContentId,
ChatVersion, ChatVersion,
@@ -52,9 +60,14 @@ pub enum HeaderDef {
ChatGroupMemberRemoved, ChatGroupMemberRemoved,
ChatGroupMemberAdded, ChatGroupMemberAdded,
ChatContent, ChatContent,
/// Duration of the attached media file.
ChatDuration, ChatDuration,
ChatDispositionNotificationTo, ChatDispositionNotificationTo,
ChatWebrtcRoom, ChatWebrtcRoom,
/// [Autocrypt](https://autocrypt.org/) header.
Autocrypt, Autocrypt,
AutocryptSetupMessage, AutocryptSetupMessage,
SecureJoin, SecureJoin,
@@ -63,6 +76,8 @@ pub enum HeaderDef {
SecureJoinInvitenumber, SecureJoinInvitenumber,
SecureJoinAuth, SecureJoinAuth,
Sender, Sender,
/// Ephemeral message timer.
EphemeralTimer, EphemeralTimer,
Received, Received,
@@ -81,8 +96,12 @@ impl HeaderDef {
} }
} }
#[allow(missing_docs)]
pub trait HeaderDefMap { pub trait HeaderDefMap {
/// Returns requested header value if it exists.
fn get_header_value(&self, headerdef: HeaderDef) -> Option<String>; fn get_header_value(&self, headerdef: HeaderDef) -> Option<String>;
/// Returns requested header if it exists.
fn get_header(&self, headerdef: HeaderDef) -> Option<&MailHeader>; fn get_header(&self, headerdef: HeaderDef) -> Option<&MailHeader>;
} }

View File

@@ -1,4 +1,4 @@
//! # Delta Chat Core Library. //! # Delta Chat Core Library
#![recursion_limit = "256"] #![recursion_limit = "256"]
#![forbid(unsafe_code)] #![forbid(unsafe_code)]
@@ -111,7 +111,7 @@ pub mod tools;
pub mod accounts; pub mod accounts;
pub mod reaction; pub mod reaction;
/// if set imap/incoming and smtp/outgoing MIME messages will be printed /// If set IMAP/incoming and SMTP/outgoing MIME messages will be printed.
pub const DCC_MIME_DEBUG: &str = "DCC_MIME_DEBUG"; pub const DCC_MIME_DEBUG: &str = "DCC_MIME_DEBUG";
#[cfg(test)] #[cfg(test)]

View File

@@ -98,6 +98,8 @@ pub struct RenderedEmail {
/// Message ID (Message in the sense of Email) /// Message ID (Message in the sense of Email)
pub rfc724_mid: String, pub rfc724_mid: String,
/// Message subject.
pub subject: String, pub subject: String,
} }

View File

@@ -1,7 +1,5 @@
//! # MIME message parsing module. //! # MIME message parsing module.
#![allow(missing_docs)]
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::future::Future; use std::future::Future;
use std::pin::Pin; use std::pin::Pin;
@@ -130,11 +128,13 @@ pub(crate) enum MailinglistType {
None, None,
} }
/// System message type.
#[derive( #[derive(
Debug, Default, Display, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive, ToSql, FromSql, Debug, Default, Display, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive, ToSql, FromSql,
)] )]
#[repr(u32)] #[repr(u32)]
pub enum SystemMessage { pub enum SystemMessage {
/// Unknown type of system message.
#[default] #[default]
Unknown = 0, Unknown = 0,
@@ -152,8 +152,14 @@ pub enum SystemMessage {
/// Autocrypt Setup Message. /// Autocrypt Setup Message.
AutocryptSetupMessage = 6, AutocryptSetupMessage = 6,
/// Secure-join message.
SecurejoinMessage = 7, SecurejoinMessage = 7,
/// Location streaming is enabled.
LocationStreamingEnabled = 8, LocationStreamingEnabled = 8,
/// Location-only message.
LocationOnly = 9, LocationOnly = 9,
/// Chat ephemeral message timer is changed. /// Chat ephemeral message timer is changed.
@@ -1792,6 +1798,8 @@ pub struct Part {
/// Size of the MIME part in bytes. /// Size of the MIME part in bytes.
pub bytes: usize, pub bytes: usize,
/// Parameters.
pub param: Params, pub param: Params,
/// Attachment filename. /// Attachment filename.

View File

@@ -1,7 +1,5 @@
//! OAuth 2 module. //! OAuth 2 module.
#![allow(missing_docs)]
use std::collections::HashMap; use std::collections::HashMap;
use anyhow::Result; use anyhow::Result;
@@ -56,6 +54,8 @@ struct Response {
scope: Option<String>, scope: Option<String>,
} }
/// Returns URL that should be opened in the browser
/// if OAuth 2 is supported for this address.
pub async fn get_oauth2_url( pub async fn get_oauth2_url(
context: &Context, context: &Context,
addr: &str, addr: &str,
@@ -76,7 +76,7 @@ pub async fn get_oauth2_url(
} }
} }
pub async fn get_oauth2_access_token( pub(crate) async fn get_oauth2_access_token(
context: &Context, context: &Context,
addr: &str, addr: &str,
code: &str, code: &str,
@@ -228,7 +228,11 @@ pub async fn get_oauth2_access_token(
} }
} }
pub async fn get_oauth2_addr(context: &Context, addr: &str, code: &str) -> Result<Option<String>> { pub(crate) async fn get_oauth2_addr(
context: &Context,
addr: &str,
code: &str,
) -> Result<Option<String>> {
let socks5_enabled = context.get_config_bool(Config::Socks5Enabled).await?; let socks5_enabled = context.get_config_bool(Config::Socks5Enabled).await?;
let oauth2 = match Oauth2::from_address(context, addr, socks5_enabled).await { let oauth2 = match Oauth2::from_address(context, addr, socks5_enabled).await {
Some(o) => o, Some(o) => o,

View File

@@ -1,7 +1,5 @@
//! OpenPGP helper module using [rPGP facilities](https://github.com/rpgp/rpgp). //! OpenPGP helper module using [rPGP facilities](https://github.com/rpgp/rpgp).
#![allow(missing_docs)]
use std::collections::{BTreeMap, HashSet}; use std::collections::{BTreeMap, HashSet};
use std::io; use std::io;
use std::io::Cursor; use std::io::Cursor;
@@ -24,7 +22,10 @@ use crate::key::{DcKey, Fingerprint};
use crate::keyring::Keyring; use crate::keyring::Keyring;
use crate::tools::EmailAddress; use crate::tools::EmailAddress;
#[allow(missing_docs)]
pub const HEADER_AUTOCRYPT: &str = "autocrypt-prefer-encrypt"; pub const HEADER_AUTOCRYPT: &str = "autocrypt-prefer-encrypt";
#[allow(missing_docs)]
pub const HEADER_SETUPCODE: &str = "passphrase-begin"; pub const HEADER_SETUPCODE: &str = "passphrase-begin";
/// A wrapper for rPGP public key types /// A wrapper for rPGP public key types

119
src/qr.rs
View File

@@ -1,7 +1,5 @@
//! # QR code module. //! # QR code module.
#![allow(missing_docs)]
mod dclogin_scheme; mod dclogin_scheme;
use std::collections::BTreeMap; use std::collections::BTreeMap;
@@ -37,80 +35,190 @@ const SMTP_SCHEME: &str = "SMTP:";
const HTTP_SCHEME: &str = "http://"; const HTTP_SCHEME: &str = "http://";
const HTTPS_SCHEME: &str = "https://"; const HTTPS_SCHEME: &str = "https://";
/// Scanned QR code.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum Qr { pub enum Qr {
/// Ask the user whether to verify the contact.
///
/// If the user agrees, pass this QR code to [`crate::securejoin::join_securejoin`].
AskVerifyContact { AskVerifyContact {
/// ID of the contact.
contact_id: ContactId, contact_id: ContactId,
/// Fingerprint of the contact key as scanned from the QR code.
fingerprint: Fingerprint, fingerprint: Fingerprint,
/// Invite number.
invitenumber: String, invitenumber: String,
/// Authentication code.
authcode: String, authcode: String,
}, },
/// Ask the user whether to join the group.
AskVerifyGroup { AskVerifyGroup {
/// Group name.
grpname: String, grpname: String,
/// Group ID.
grpid: String, grpid: String,
/// ID of the contact.
contact_id: ContactId, contact_id: ContactId,
/// Fingerprint of the contact key as scanned from the QR code.
fingerprint: Fingerprint, fingerprint: Fingerprint,
/// Invite number.
invitenumber: String, invitenumber: String,
/// Authentication code.
authcode: String, authcode: String,
}, },
/// Contact fingerprint is verified.
///
/// Ask the user if they want to start chatting.
FprOk { FprOk {
/// Contact ID.
contact_id: ContactId, contact_id: ContactId,
}, },
/// Scanned fingerprint does not match the last seen fingerprint.
FprMismatch { FprMismatch {
/// Contact ID.
contact_id: Option<ContactId>, contact_id: Option<ContactId>,
}, },
/// The scanned QR code contains a fingerprint but no e-mail address.
FprWithoutAddr { FprWithoutAddr {
/// Key fingerprint.
fingerprint: String, fingerprint: String,
}, },
/// Ask the user if they want to create an account on the given domain.
Account { Account {
/// Server domain name.
domain: String, domain: String,
}, },
/// Ask the user if they want to use the given service for video chats.
WebrtcInstance { WebrtcInstance {
/// Server domain name.
domain: String, domain: String,
/// URL pattern for video chat rooms.
instance_pattern: String, instance_pattern: String,
}, },
/// Contact address is scanned.
///
/// Optionally, a draft message could be provided.
/// Ask the user if they want to start chatting.
Addr { Addr {
/// Contact ID.
contact_id: ContactId, contact_id: ContactId,
/// Draft message.
draft: Option<String>, draft: Option<String>,
}, },
/// URL scanned.
///
/// Ask the user if they want to open a browser or copy the URL to clipboard.
Url { Url {
/// URL.
url: String, url: String,
}, },
/// Text scanned.
///
/// Ask the user if they want to copy the text to clipboard.
Text { Text {
/// Scanned text.
text: String, text: String,
}, },
/// Ask the user if they want to withdraw their own QR code.
WithdrawVerifyContact { WithdrawVerifyContact {
/// Contact ID.
contact_id: ContactId, contact_id: ContactId,
/// Fingerprint of the contact key as scanned from the QR code.
fingerprint: Fingerprint, fingerprint: Fingerprint,
/// Invite number.
invitenumber: String, invitenumber: String,
/// Authentication code.
authcode: String, authcode: String,
}, },
/// Ask the user if they want to withdraw their own group invite QR code.
WithdrawVerifyGroup { WithdrawVerifyGroup {
/// Group name.
grpname: String, grpname: String,
/// Group ID.
grpid: String, grpid: String,
/// Contact ID.
contact_id: ContactId, contact_id: ContactId,
/// Fingerprint of the contact key as scanned from the QR code.
fingerprint: Fingerprint, fingerprint: Fingerprint,
/// Invite number.
invitenumber: String, invitenumber: String,
/// Authentication code.
authcode: String, authcode: String,
}, },
/// Ask the user if they want to revive their own QR code.
ReviveVerifyContact { ReviveVerifyContact {
/// Contact ID.
contact_id: ContactId, contact_id: ContactId,
/// Fingerprint of the contact key as scanned from the QR code.
fingerprint: Fingerprint, fingerprint: Fingerprint,
/// Invite number.
invitenumber: String, invitenumber: String,
/// Authentication code.
authcode: String, authcode: String,
}, },
/// Ask the user if they want to revive their own group invite QR code.
ReviveVerifyGroup { ReviveVerifyGroup {
/// Group name.
grpname: String, grpname: String,
/// Group ID.
grpid: String, grpid: String,
/// Contact ID.
contact_id: ContactId, contact_id: ContactId,
/// Fingerprint of the contact key as scanned from the QR code.
fingerprint: Fingerprint, fingerprint: Fingerprint,
/// Invite number.
invitenumber: String, invitenumber: String,
/// Authentication code.
authcode: String, authcode: String,
}, },
/// `dclogin:` scheme parameters. /// `dclogin:` scheme parameters.
///
/// Ask the user if they want to login with the email address.
Login { Login {
/// Email address.
address: String, address: String,
/// Login parameters.
options: LoginOptions, options: LoginOptions,
}, },
} }
@@ -119,7 +227,8 @@ fn starts_with_ignore_case(string: &str, pattern: &str) -> bool {
string.to_lowercase().starts_with(&pattern.to_lowercase()) string.to_lowercase().starts_with(&pattern.to_lowercase())
} }
/// Check a scanned QR code. /// Checks a scanned QR code.
///
/// The function should be called after a QR code is scanned. /// The function should be called after a QR code is scanned.
/// The function takes the raw text scanned and checks what can be done with it. /// The function takes the raw text scanned and checks what can be done with it.
pub async fn check_qr(context: &Context, qr: &str) -> Result<Qr> { pub async fn check_qr(context: &Context, qr: &str) -> Result<Qr> {
@@ -415,6 +524,7 @@ async fn set_account_from_qr(context: &Context, qr: &str) -> Result<()> {
} }
} }
/// Sets configuration values from a QR code.
pub async fn set_config_from_qr(context: &Context, qr: &str) -> Result<()> { pub async fn set_config_from_qr(context: &Context, qr: &str) -> Result<()> {
match check_qr(context, qr).await? { match check_qr(context, qr).await? {
Qr::Account { .. } => set_account_from_qr(context, qr).await?, Qr::Account { .. } => set_account_from_qr(context, qr).await?,
@@ -617,6 +727,9 @@ async fn decode_vcard(context: &Context, qr: &str) -> Result<Qr> {
} }
impl Qr { impl Qr {
/// Creates a new scanned QR code of a contact address.
///
/// May contain a message draft.
pub async fn from_address( pub async fn from_address(
context: &Context, context: &Context,
name: &str, name: &str,

View File

@@ -9,22 +9,53 @@ use crate::context::Context;
use crate::provider::Socket; use crate::provider::Socket;
use crate::{contact, login_param::CertificateChecks}; use crate::{contact, login_param::CertificateChecks};
/// Options for `dclogin:` scheme.
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub enum LoginOptions { pub enum LoginOptions {
/// Unsupported version.
UnsuportedVersion(u32), UnsuportedVersion(u32),
/// Version 1.
V1 { V1 {
/// IMAP server password.
///
/// Used for SMTP if separate SMTP password is not provided.
mail_pw: String, mail_pw: String,
/// IMAP host.
imap_host: Option<String>, imap_host: Option<String>,
/// IMAP port.
imap_port: Option<u16>, imap_port: Option<u16>,
/// IMAP username.
imap_username: Option<String>, imap_username: Option<String>,
/// IMAP password.
imap_password: Option<String>, imap_password: Option<String>,
/// IMAP socket security.
imap_security: Option<Socket>, imap_security: Option<Socket>,
/// IMAP certificate checks.
imap_certificate_checks: Option<CertificateChecks>, imap_certificate_checks: Option<CertificateChecks>,
/// SMTP host.
smtp_host: Option<String>, smtp_host: Option<String>,
/// SMTP port.
smtp_port: Option<u16>, smtp_port: Option<u16>,
/// SMTP username.
smtp_username: Option<String>, smtp_username: Option<String>,
/// SMTP password.
smtp_password: Option<String>, smtp_password: Option<String>,
/// SMTP socket security.
smtp_security: Option<Socket>, smtp_security: Option<Socket>,
/// SMTP certificate checks.
smtp_certificate_checks: Option<CertificateChecks>, smtp_certificate_checks: Option<CertificateChecks>,
}, },
} }

View File

@@ -1,4 +1,4 @@
#![allow(missing_docs)] //! # QR code generation module.
use anyhow::Result; use anyhow::Result;
use base64::Engine as _; use base64::Engine as _;
@@ -14,6 +14,10 @@ use crate::{
securejoin, stock_str, securejoin, stock_str,
}; };
/// Returns SVG of the QR code to join the group or verify contact.
///
/// If `chat_id` is `None`, returns verification QR code.
/// Otherwise, returns secure join QR code.
pub async fn get_securejoin_qr_svg(context: &Context, chat_id: Option<ChatId>) -> Result<String> { pub async fn get_securejoin_qr_svg(context: &Context, chat_id: Option<ChatId>) -> Result<String> {
if let Some(chat_id) = chat_id { if let Some(chat_id) = chat_id {
generate_join_group_qr_code(context, chat_id).await generate_join_group_qr_code(context, chat_id).await

View File

@@ -1,7 +1,5 @@
//! Internet Message Format reception pipeline. //! Internet Message Format reception pipeline.
#![allow(missing_docs)]
use std::cmp::min; use std::cmp::min;
use std::collections::HashSet; use std::collections::HashSet;
use std::convert::TryFrom; use std::convert::TryFrom;
@@ -48,8 +46,13 @@ use crate::{contact, imap};
/// all have the same chat_id, state and sort_timestamp. /// all have the same chat_id, state and sort_timestamp.
#[derive(Debug)] #[derive(Debug)]
pub struct ReceivedMsg { pub struct ReceivedMsg {
/// Chat the message is assigned to.
pub chat_id: ChatId, pub chat_id: ChatId,
/// Received message state.
pub state: MessageState, pub state: MessageState,
/// Message timestamp for sorting.
pub sort_timestamp: i64, pub sort_timestamp: i64,
/// IDs of inserted rows in messages table. /// IDs of inserted rows in messages table.

View File

@@ -1,7 +1,5 @@
//! # SQLite wrapper. //! # SQLite wrapper.
#![allow(missing_docs)]
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::convert::TryFrom; use std::convert::TryFrom;
use std::path::Path; use std::path::Path;
@@ -26,6 +24,7 @@ use crate::peerstate::{deduplicate_peerstates, Peerstate};
use crate::stock_str; use crate::stock_str;
use crate::tools::{delete_file, time}; use crate::tools::{delete_file, time};
#[allow(missing_docs)]
#[macro_export] #[macro_export]
macro_rules! paramsv { macro_rules! paramsv {
() => { () => {
@@ -36,6 +35,7 @@ macro_rules! paramsv {
}; };
} }
#[allow(missing_docs)]
#[macro_export] #[macro_export]
macro_rules! params_iterv { macro_rules! params_iterv {
($($param:expr),+ $(,)?) => { ($($param:expr),+ $(,)?) => {
@@ -55,16 +55,19 @@ pub struct Sql {
/// Database file path /// Database file path
pub(crate) dbfile: PathBuf, pub(crate) dbfile: PathBuf,
/// SQL connection pool.
pool: RwLock<Option<r2d2::Pool<r2d2_sqlite::SqliteConnectionManager>>>, pool: RwLock<Option<r2d2::Pool<r2d2_sqlite::SqliteConnectionManager>>>,
/// None if the database is not open, true if it is open with passphrase and false if it is /// None if the database is not open, true if it is open with passphrase and false if it is
/// open without a passphrase. /// open without a passphrase.
is_encrypted: RwLock<Option<bool>>, is_encrypted: RwLock<Option<bool>>,
/// Cache of `config` table.
pub(crate) config_cache: RwLock<HashMap<String, Option<String>>>, pub(crate) config_cache: RwLock<HashMap<String, Option<String>>>,
} }
impl Sql { impl Sql {
/// Creates new SQL database.
pub fn new(dbfile: PathBuf) -> Sql { pub fn new(dbfile: PathBuf) -> Sql {
Self { Self {
dbfile, dbfile,
@@ -244,6 +247,7 @@ impl Sql {
Ok(()) Ok(())
} }
/// Updates SQL schema to the latest version.
pub async fn run_migrations(&self, context: &Context) -> Result<()> { pub async fn run_migrations(&self, context: &Context) -> Result<()> {
// (1) update low-level database structure. // (1) update low-level database structure.
// this should be done before updates that use high-level objects that // this should be done before updates that use high-level objects that
@@ -388,6 +392,7 @@ impl Sql {
}) })
} }
/// Allocates a connection from the connection pool and returns it.
pub async fn get_conn( pub async fn get_conn(
&self, &self,
) -> Result<r2d2::PooledConnection<r2d2_sqlite::SqliteConnectionManager>> { ) -> Result<r2d2::PooledConnection<r2d2_sqlite::SqliteConnectionManager>> {
@@ -585,22 +590,26 @@ impl Sql {
Ok(value) Ok(value)
} }
/// Sets configuration for the given key to 32-bit signed integer value.
pub async fn set_raw_config_int(&self, key: &str, value: i32) -> Result<()> { pub async fn set_raw_config_int(&self, key: &str, value: i32) -> Result<()> {
self.set_raw_config(key, Some(&format!("{value}"))).await self.set_raw_config(key, Some(&format!("{value}"))).await
} }
/// Returns 32-bit signed integer configuration value for the given key.
pub async fn get_raw_config_int(&self, key: &str) -> Result<Option<i32>> { pub async fn get_raw_config_int(&self, key: &str) -> Result<Option<i32>> {
self.get_raw_config(key) self.get_raw_config(key)
.await .await
.map(|s| s.and_then(|s| s.parse().ok())) .map(|s| s.and_then(|s| s.parse().ok()))
} }
/// Returns 32-bit unsigned integer configuration value for the given key.
pub async fn get_raw_config_u32(&self, key: &str) -> Result<Option<u32>> { pub async fn get_raw_config_u32(&self, key: &str) -> Result<Option<u32>> {
self.get_raw_config(key) self.get_raw_config(key)
.await .await
.map(|s| s.and_then(|s| s.parse().ok())) .map(|s| s.and_then(|s| s.parse().ok()))
} }
/// Returns boolean configuration value for the given key.
pub async fn get_raw_config_bool(&self, key: &str) -> Result<bool> { pub async fn get_raw_config_bool(&self, key: &str) -> Result<bool> {
// Not the most obvious way to encode bool as string, but it is matter // Not the most obvious way to encode bool as string, but it is matter
// of backward compatibility. // of backward compatibility.
@@ -608,27 +617,32 @@ impl Sql {
Ok(res.unwrap_or_default() > 0) Ok(res.unwrap_or_default() > 0)
} }
/// Sets configuration for the given key to boolean value.
pub async fn set_raw_config_bool(&self, key: &str, value: bool) -> Result<()> { pub async fn set_raw_config_bool(&self, key: &str, value: bool) -> Result<()> {
let value = if value { Some("1") } else { None }; let value = if value { Some("1") } else { None };
self.set_raw_config(key, value).await self.set_raw_config(key, value).await
} }
/// Sets configuration for the given key to 64-bit signed integer value.
pub async fn set_raw_config_int64(&self, key: &str, value: i64) -> Result<()> { pub async fn set_raw_config_int64(&self, key: &str, value: i64) -> Result<()> {
self.set_raw_config(key, Some(&format!("{value}"))).await self.set_raw_config(key, Some(&format!("{value}"))).await
} }
/// Returns 64-bit signed integer configuration value for the given key.
pub async fn get_raw_config_int64(&self, key: &str) -> Result<Option<i64>> { pub async fn get_raw_config_int64(&self, key: &str) -> Result<Option<i64>> {
self.get_raw_config(key) self.get_raw_config(key)
.await .await
.map(|s| s.and_then(|r| r.parse().ok())) .map(|s| s.and_then(|r| r.parse().ok()))
} }
/// Returns configuration cache.
#[cfg(feature = "internals")] #[cfg(feature = "internals")]
pub fn config_cache(&self) -> &RwLock<HashMap<String, Option<String>>> { pub fn config_cache(&self) -> &RwLock<HashMap<String, Option<String>>> {
&self.config_cache &self.config_cache
} }
} }
/// Cleanup the account to restore some storage and optimize the database.
pub async fn housekeeping(context: &Context) -> Result<()> { pub async fn housekeeping(context: &Context) -> Result<()> {
if let Err(err) = remove_unused_files(context).await { if let Err(err) = remove_unused_files(context).await {
warn!( warn!(
@@ -687,6 +701,7 @@ pub async fn housekeeping(context: &Context) -> Result<()> {
Ok(()) Ok(())
} }
/// Enumerates used files in the blobdir and removes unused ones.
pub async fn remove_unused_files(context: &Context) -> Result<()> { pub async fn remove_unused_files(context: &Context) -> Result<()> {
let mut files_in_use = HashSet::new(); let mut files_in_use = HashSet::new();
let mut unreferenced_count = 0; let mut unreferenced_count = 0;

View File

@@ -1,7 +1,5 @@
//! Module to work with translatable stock strings. //! Module to work with translatable stock strings.
#![allow(missing_docs)]
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
@@ -21,6 +19,7 @@ use crate::message::{Message, Viewtype};
use crate::param::Param; use crate::param::Param;
use crate::tools::timestamp_to_str; use crate::tools::timestamp_to_str;
/// Storage for string translations.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct StockStrings { pub struct StockStrings {
/// Map from stock string ID to the translation. /// Map from stock string ID to the translation.
@@ -35,6 +34,7 @@ pub struct StockStrings {
/// See the `stock_*` methods on [Context] to use these. /// See the `stock_*` methods on [Context] to use these.
/// ///
/// [Context]: crate::context::Context /// [Context]: crate::context::Context
#[allow(missing_docs)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive, EnumProperty)] #[derive(Debug, Clone, Copy, PartialEq, Eq, FromPrimitive, ToPrimitive, EnumProperty)]
#[repr(u32)] #[repr(u32)]
pub enum StockMessage { pub enum StockMessage {
@@ -422,6 +422,7 @@ impl Default for StockStrings {
} }
impl StockStrings { impl StockStrings {
/// Creates a new translated string storage.
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
translated_stockstrings: Arc::new(RwLock::new(Default::default())), translated_stockstrings: Arc::new(RwLock::new(Default::default())),

View File

@@ -124,6 +124,7 @@ pub fn timestamp_to_str(wanted: i64) -> String {
} }
} }
/// Converts duration to string representation suitable for logs.
pub fn duration_to_str(duration: Duration) -> String { pub fn duration_to_str(duration: Duration) -> String {
let secs = duration.as_secs(); let secs = duration.as_secs();
let h = secs / 3600; let h = secs / 3600;
@@ -442,6 +443,7 @@ pub(crate) async fn write_file(
}) })
} }
/// Reads the file and returns its context as a byte vector.
pub async fn read_file(context: &Context, path: impl AsRef<Path>) -> Result<Vec<u8>> { pub async fn read_file(context: &Context, path: impl AsRef<Path>) -> Result<Vec<u8>> {
let path_abs = get_abs_path(context, &path); let path_abs = get_abs_path(context, &path);
@@ -530,7 +532,10 @@ pub(crate) fn time() -> i64 {
/// ``` /// ```
#[derive(Debug, PartialEq, Eq, Clone)] #[derive(Debug, PartialEq, Eq, Clone)]
pub struct EmailAddress { pub struct EmailAddress {
/// Local part of the email address.
pub local: String, pub local: String,
/// Email address domain.
pub domain: String, pub domain: String,
} }

View File

@@ -114,12 +114,12 @@ pub struct WebxdcInfo {
pub struct StatusUpdateSerial(u32); pub struct StatusUpdateSerial(u32);
impl StatusUpdateSerial { impl StatusUpdateSerial {
/// Create a new [MsgId]. /// Create a new [StatusUpdateSerial].
pub fn new(id: u32) -> StatusUpdateSerial { pub fn new(id: u32) -> StatusUpdateSerial {
StatusUpdateSerial(id) StatusUpdateSerial(id)
} }
/// Gets StatusUpdateId as untyped integer. /// Gets StatusUpdateSerial as untyped integer.
/// Avoid using this outside ffi. /// Avoid using this outside ffi.
pub fn to_u32(self) -> u32 { pub fn to_u32(self) -> u32 {
self.0 self.0