/// A contact could not be updated. #[derive(Debug, thiserror::Error)] pub(crate) enum ContactUpdateError { /// Contact could not be updated because the identity does not match. #[error("Identity mismatch: Expected {expected} but got {actual}")]
IdentityMismatch { expected: ThreemaId, actual: ThreemaId },
/// Contact could not be updated because the public key does not match. #[error("Public key mismatch")]
PublicKeyMismatch,
}
#[derive(Debug)] pub(crate) enum CommunicationPermission { /// Communication with this contact is allowed.
Allow,
/// Communication with this contact is disallowed due to it being explicitly blocked.
BlockExplicit,
/// Communication with this contact is disallowed due to it being implicitly blocked by the _block /// unknown_ setting. /// /// Note: This is purely informational, i.e. when encountering this, the behaviour must be the same as for /// [`CommunicationPermission::BlockExplicit`]. Communication would be allowed after the contact has been /// explicitly added or both the user and the contact are in a group not marked as _left_.
BlockUnknown,
}
/// All protocol relevant data associated to a contact with the following exclusions: /// /// - _contact-defined_ profile picture /// - _user-defined_ profile picture //- // IMPORTANT: When touching these, always make sure to update [`ContactUpdate`] and // `ContactUpdate::apply_to` accordingly. #[derive(Debug, Clone)] pubstruct Contact { /// Threema ID of the contact. pub identity: ThreemaId,
/// Public key of the contact. pub public_key: PublicKey,
/// Unix-ish timestamp in milliseconds when the contact has been created (added) locally. pub created_at: u64,
/// First name of the contact. pub first_name: Option<String>,
/// Last name of the contact. pub last_name: Option<String>,
/// Nickname of the contact (without `~` prefix). /// /// IMPORTANT: Do not provide the Threema ID as a fallback! pub nickname: Option<String>,
/// Verification level of the contact. pub verification_level: protobuf_contact::VerificationLevel,
/// Threema Work verification level of the contact. pub work_verification_level: protobuf_contact::WorkVerificationLevel,
/// Identity type of the contact. pub identity_type: protobuf_contact::IdentityType,
/// Acquaintance level of the contact. pub acquaintance_level: protobuf_contact::AcquaintanceLevel,
/// Activity state of the contact. pub activity_state: protobuf_contact::ActivityState,
/// Features available for the contact. pub feature_mask: FeatureMask,
/// _Read_ receipt policy override for this contact. pub read_receipt_policy_override: Option<protobuf::d2d_sync::ReadReceiptPolicy>,
/// Typing indicator policy override for this contact. pub typing_indicator_policy_override: Option<protobuf::d2d_sync::TypingIndicatorPolicy>,
/// Notification trigger policy for the contact. pub notification_trigger_policy_override:
Option<protobuf_contact::notification_trigger_policy_override::Policy>,
/// Notification sound policy for the contact. pub notification_sound_policy_override: Option<protobuf::d2d_sync::NotificationSoundPolicy>,
/// Conversation category of the contact. pub conversation_category: protobuf::d2d_sync::ConversationCategory,
/// Conversation visibility of the contact. pub conversation_visibility: protobuf::d2d_sync::ConversationVisibility,
}
/// All protocol relevant data associated to create a contact with the following exclusions: /// /// - _contact-defined_ profile picture /// - _user-defined_ profile picture pubtype ContactInit = Contact;
// Special contacts cannot be blocked if predefined_contact.is_some_and(|contact| contact.special) { return Ok(CommunicationPermission::Allow);
}
// Check if the user explicitly blocked the contact if contact_provider.is_explicitly_blocked(inner.identity)? { return Ok(CommunicationPermission::BlockExplicit);
}
// Check if the user wants to block _unknown_ identities. if !settings_provider.block_unknown_identities()? { return Ok(CommunicationPermission::Allow);
}
// Predefined contacts should not be implicitly blocked if predefined_contact.is_some() { return Ok(CommunicationPermission::Allow);
}
Ok(match &self {
ContactOrInit::NewContact(_) => { // The contact does not exist and block unknown is active
CommunicationPermission::BlockUnknown
},
ContactOrInit::ExistingContact(inner) => { // Check if the contact has acquaintance level _direct_ if inner.acquaintance_level == protobuf_contact::AcquaintanceLevel::Direct { return Ok(CommunicationPermission::Allow);
}
// Check if the user and the contact are part of an active group if contact_provider.is_member_of_active_group(inner.identity)? {
CommunicationPermission::Allow
} else {
CommunicationPermission::BlockUnknown
}
},
})
}
}
/// All protocol relevant data associated to update a contact with the following exclusions: /// /// - _contact-defined_ profile picture /// - _user-defined_ profile picture /// /// Note: This may only include changes to a contact. #[derive(Debug, Clone, PartialEq)] pubstruct ContactUpdate { /// Threema ID of the contact. pub identity: ThreemaId,
/// First name of the contact. pub first_name: Delta<String>,
/// Last name of the contact. pub last_name: Delta<String>,
/// Nickname of the contact (without `~` prefix). /// /// IMPORTANT: Do not provide the Threema ID as a fallback! pub nickname: Delta<String>,
/// Verification level of the contact. pub verification_level: Option<protobuf_contact::VerificationLevel>,
/// Threema Work verification level of the contact. pub work_verification_level: Option<protobuf_contact::WorkVerificationLevel>,
/// Identity type of the contact. pub identity_type: Option<protobuf_contact::IdentityType>,
/// Acquaintance level of the contact. pub acquaintance_level: Option<protobuf_contact::AcquaintanceLevel>,
/// Activity state of the contact. pub activity_state: Option<protobuf_contact::ActivityState>,
/// Features available for the contact. pub feature_mask: Option<FeatureMask>,
/// _Read_ receipt policy override for this contact. pub read_receipt_policy_override: Delta<protobuf::d2d_sync::ReadReceiptPolicy>,
/// Typing indicator policy override for this contact. pub typing_indicator_policy_override: Delta<protobuf::d2d_sync::TypingIndicatorPolicy>,
/// Notification trigger policy for the contact. pub notification_trigger_policy_override:
Delta<protobuf_contact::notification_trigger_policy_override::Policy>,
/// Notification sound policy for the contact. pub notification_sound_policy_override: Delta<protobuf::d2d_sync::NotificationSoundPolicy>,
/// Conversation category of the contact. pub conversation_category: Option<protobuf::d2d_sync::ConversationCategory>,
/// Conversation visibility of the contact. pub conversation_visibility: Option<protobuf::d2d_sync::ConversationVisibility>,
}
pub(crate) fn has_changes(&self) -> bool { self != &Self::default(self.identity)
}
} impl TryApply<ContactUpdate> for Contact { type Error = ContactUpdateError;
/// Try applying the contact update to the contact. /// /// # Errors /// /// Returns [`ContactUpdateError`] if the identity mismatches. fn try_apply(&mutself, value: ContactUpdate) -> Result<(), Self::Error> { // Unpacking here, so we can't miss updating this function when a new field is being added let ContactUpdate {
identity,
first_name,
last_name,
nickname,
verification_level,
work_verification_level,
identity_type,
acquaintance_level,
activity_state,
feature_mask,
sync_state,
read_receipt_policy_override,
typing_indicator_policy_override,
notification_trigger_policy_override,
notification_sound_policy_override,
conversation_category,
conversation_visibility,
} = value;
// Ensure the identity equals before updating if identity != self.identity { return Err(ContactUpdateError::IdentityMismatch {
expected: self.identity,
actual: identity,
});
}
/// A predefined contact that does not need to be fetched from the directory. /// /// It is automatically elevated to the highest verification level. #[derive(Debug, Clone)] pubstruct PredefinedContact { /// Threema ID of the predefined contact. pub identity: ThreemaId,
/// Whether the predefined contact is marked as a _special contact_. pub special: bool,
/// Public key of the predefined contact. pub public_key: PublicKey,
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.