1
0
mirror of https://gitlab.com/xmpp-rs/xmpp-rs.git synced 2024-06-09 09:44:03 +02:00

Compare commits

..

No commits in common. "054447d1472d22a41d8a39baa56799f4142ebd4b" and "fb63ac8e50fe76af8f759619a7948ba786720c47" have entirely different histories.

21 changed files with 449 additions and 666 deletions

180
jid/src/inner.rs Normal file
View File

@ -0,0 +1,180 @@
// Copyright (c) 2023 Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#![deny(missing_docs)]
//! Provides a type for Jabber IDs.
//!
//! For usage, check the documentation on the `Jid` struct.
use crate::Error;
use core::num::NonZeroU16;
use memchr::memchr;
use std::borrow::Cow;
use std::str::FromStr;
use stringprep::{nameprep, nodeprep, resourceprep};
use crate::parts::{DomainRef, NodeRef, ResourceRef};
fn length_check(len: usize, error_empty: Error, error_too_long: Error) -> Result<(), Error> {
if len == 0 {
Err(error_empty)
} else if len > 1023 {
Err(error_too_long)
} else {
Ok(())
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub(crate) struct InnerJid {
pub(crate) normalized: String,
pub(crate) at: Option<NonZeroU16>,
pub(crate) slash: Option<NonZeroU16>,
}
impl InnerJid {
pub(crate) fn new(unnormalized: &str) -> Result<InnerJid, Error> {
let bytes = unnormalized.as_bytes();
let mut orig_at = memchr(b'@', bytes);
let mut orig_slash = memchr(b'/', bytes);
if orig_at.is_some() && orig_slash.is_some() && orig_at > orig_slash {
// This is part of the resource, not a node@domain separator.
orig_at = None;
}
let normalized = match (orig_at, orig_slash) {
(Some(at), Some(slash)) => {
let node = nodeprep(&unnormalized[..at]).map_err(|_| Error::NodePrep)?;
length_check(node.len(), Error::NodeEmpty, Error::NodeTooLong)?;
let domain = nameprep(&unnormalized[at + 1..slash]).map_err(|_| Error::NamePrep)?;
length_check(domain.len(), Error::DomainEmpty, Error::DomainTooLong)?;
let resource =
resourceprep(&unnormalized[slash + 1..]).map_err(|_| Error::ResourcePrep)?;
length_check(resource.len(), Error::ResourceEmpty, Error::ResourceTooLong)?;
orig_at = Some(node.len());
orig_slash = Some(node.len() + domain.len() + 1);
match (node, domain, resource) {
(Cow::Borrowed(_), Cow::Borrowed(_), Cow::Borrowed(_)) => {
unnormalized.to_string()
}
(node, domain, resource) => format!("{node}@{domain}/{resource}"),
}
}
(Some(at), None) => {
let node = nodeprep(&unnormalized[..at]).map_err(|_| Error::NodePrep)?;
length_check(node.len(), Error::NodeEmpty, Error::NodeTooLong)?;
let domain = nameprep(&unnormalized[at + 1..]).map_err(|_| Error::NamePrep)?;
length_check(domain.len(), Error::DomainEmpty, Error::DomainTooLong)?;
orig_at = Some(node.len());
match (node, domain) {
(Cow::Borrowed(_), Cow::Borrowed(_)) => unnormalized.to_string(),
(node, domain) => format!("{node}@{domain}"),
}
}
(None, Some(slash)) => {
let domain = nameprep(&unnormalized[..slash]).map_err(|_| Error::NamePrep)?;
length_check(domain.len(), Error::DomainEmpty, Error::DomainTooLong)?;
let resource =
resourceprep(&unnormalized[slash + 1..]).map_err(|_| Error::ResourcePrep)?;
length_check(resource.len(), Error::ResourceEmpty, Error::ResourceTooLong)?;
orig_slash = Some(domain.len());
match (domain, resource) {
(Cow::Borrowed(_), Cow::Borrowed(_)) => unnormalized.to_string(),
(domain, resource) => format!("{domain}/{resource}"),
}
}
(None, None) => {
let domain = nameprep(unnormalized).map_err(|_| Error::NamePrep)?;
length_check(domain.len(), Error::DomainEmpty, Error::DomainTooLong)?;
domain.into_owned()
}
};
Ok(InnerJid {
normalized,
at: orig_at.and_then(|x| NonZeroU16::new(x as u16)),
slash: orig_slash.and_then(|x| NonZeroU16::new(x as u16)),
})
}
pub(crate) fn node(&self) -> Option<&NodeRef> {
self.at.map(|at| {
let at = u16::from(at) as usize;
NodeRef::from_str_unchecked(&self.normalized[..at])
})
}
pub(crate) fn domain(&self) -> &DomainRef {
match (self.at, self.slash) {
(Some(at), Some(slash)) => {
let at = u16::from(at) as usize;
let slash = u16::from(slash) as usize;
DomainRef::from_str_unchecked(&self.normalized[at + 1..slash])
}
(Some(at), None) => {
let at = u16::from(at) as usize;
DomainRef::from_str_unchecked(&self.normalized[at + 1..])
}
(None, Some(slash)) => {
let slash = u16::from(slash) as usize;
DomainRef::from_str_unchecked(&self.normalized[..slash])
}
(None, None) => DomainRef::from_str_unchecked(&self.normalized),
}
}
pub(crate) fn resource(&self) -> Option<&ResourceRef> {
self.slash.map(|slash| {
let slash = u16::from(slash) as usize;
ResourceRef::from_str_unchecked(&self.normalized[slash + 1..])
})
}
#[inline(always)]
pub(crate) fn as_str(&self) -> &str {
self.normalized.as_str()
}
}
impl FromStr for InnerJid {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
InnerJid::new(s)
}
}
#[cfg(test)]
mod tests {
use super::*;
macro_rules! assert_size (
($t:ty, $sz:expr) => (
assert_eq!(::std::mem::size_of::<$t>(), $sz);
);
);
#[cfg(target_pointer_width = "32")]
#[test]
fn test_size() {
assert_size!(InnerJid, 16);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_size() {
assert_size!(InnerJid, 32);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -5,7 +5,7 @@ use std::str::FromStr;
use stringprep::{nameprep, nodeprep, resourceprep};
use crate::{BareJid, Error, Jid};
use crate::{BareJid, Error, InnerJid, Jid};
fn length_check(len: usize, error_empty: Error, error_too_long: Error) -> Result<(), Error> {
if len == 0 {
@ -250,18 +250,18 @@ impl DomainRef {
impl From<DomainPart> for BareJid {
fn from(other: DomainPart) -> Self {
BareJid {
inner: other.into(),
inner: InnerJid {
normalized: other.0,
at: None,
slash: None,
},
}
}
}
impl From<DomainPart> for Jid {
fn from(other: DomainPart) -> Self {
Jid {
normalized: other.0,
at: None,
slash: None,
}
Jid::Bare(other.into())
}
}

View File

@ -88,7 +88,7 @@ impl From<BindResponse> for FullJid {
impl From<BindResponse> for Jid {
fn from(bind: BindResponse) -> Jid {
Jid::from(bind.jid)
Jid::Full(bind.jid)
}
}

View File

@ -71,8 +71,8 @@ mod tests {
assert_size!(Enable, 0);
assert_size!(Disable, 0);
assert_size!(Private, 0);
assert_size!(Received, 140);
assert_size!(Sent, 140);
assert_size!(Received, 152);
assert_size!(Sent, 152);
}
#[cfg(target_pointer_width = "64")]
@ -81,8 +81,8 @@ mod tests {
assert_size!(Enable, 0);
assert_size!(Disable, 0);
assert_size!(Private, 0);
assert_size!(Received, 264);
assert_size!(Sent, 264);
assert_size!(Received, 288);
assert_size!(Sent, 288);
}
#[test]

View File

@ -40,13 +40,13 @@ mod tests {
#[cfg(target_pointer_width = "32")]
#[test]
fn test_size() {
assert_size!(Delay, 44);
assert_size!(Delay, 48);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_size() {
assert_size!(Delay, 72);
assert_size!(Delay, 80);
}
#[test]

View File

@ -248,7 +248,7 @@ mod tests {
assert_size!(DiscoInfoQuery, 12);
assert_size!(DiscoInfoResult, 48);
assert_size!(Item, 40);
assert_size!(Item, 44);
assert_size!(DiscoItemsQuery, 52);
assert_size!(DiscoItemsResult, 64);
}
@ -261,7 +261,7 @@ mod tests {
assert_size!(DiscoInfoQuery, 24);
assert_size!(DiscoInfoResult, 96);
assert_size!(Item, 80);
assert_size!(Item, 88);
assert_size!(DiscoItemsQuery, 104);
assert_size!(DiscoItemsResult, 128);
}

View File

@ -32,13 +32,13 @@ mod tests {
#[cfg(target_pointer_width = "32")]
#[test]
fn test_size() {
assert_size!(Forwarded, 140);
assert_size!(Forwarded, 152);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_size() {
assert_size!(Forwarded, 264);
assert_size!(Forwarded, 288);
}
#[test]

View File

@ -232,15 +232,15 @@ mod tests {
#[cfg(target_pointer_width = "32")]
#[test]
fn test_size() {
assert_size!(IqType, 92);
assert_size!(Iq, 156);
assert_size!(IqType, 96);
assert_size!(Iq, 148);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_size() {
assert_size!(IqType, 184);
assert_size!(Iq, 272);
assert_size!(IqType, 192);
assert_size!(Iq, 296);
}
#[test]

View File

@ -46,14 +46,14 @@ mod tests {
#[test]
fn test_size() {
assert_size!(JidPrepQuery, 12);
assert_size!(JidPrepResponse, 16);
assert_size!(JidPrepResponse, 20);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_size() {
assert_size!(JidPrepQuery, 24);
assert_size!(JidPrepResponse, 32);
assert_size!(JidPrepResponse, 40);
}
#[test]

View File

@ -692,7 +692,7 @@ mod tests {
assert_size!(Reason, 1);
assert_size!(ReasonElement, 16);
assert_size!(SessionId, 12);
assert_size!(Jingle, 104);
assert_size!(Jingle, 112);
}
#[cfg(target_pointer_width = "64")]
@ -711,7 +711,7 @@ mod tests {
assert_size!(Reason, 1);
assert_size!(ReasonElement, 32);
assert_size!(SessionId, 24);
assert_size!(Jingle, 208);
assert_size!(Jingle, 224);
}
#[test]

View File

@ -284,7 +284,7 @@ mod tests {
assert_size!(Mode, 1);
assert_size!(CandidateId, 12);
assert_size!(StreamId, 12);
assert_size!(Candidate, 56);
assert_size!(Candidate, 60);
assert_size!(TransportPayload, 16);
assert_size!(Transport, 44);
}
@ -296,7 +296,7 @@ mod tests {
assert_size!(Mode, 1);
assert_size!(CandidateId, 24);
assert_size!(StreamId, 24);
assert_size!(Candidate, 88);
assert_size!(Candidate, 96);
assert_size!(TransportPayload, 32);
assert_size!(Transport, 88);
}

View File

@ -166,7 +166,7 @@ mod tests {
fn test_size() {
assert_size!(QueryId, 12);
assert_size!(Query, 120);
assert_size!(Result_, 164);
assert_size!(Result_, 176);
assert_size!(Complete, 1);
assert_size!(Fin, 44);
}
@ -176,7 +176,7 @@ mod tests {
fn test_size() {
assert_size!(QueryId, 24);
assert_size!(Query, 240);
assert_size!(Result_, 312);
assert_size!(Result_, 336);
assert_size!(Complete, 1);
assert_size!(Fin, 88);
}

View File

@ -307,7 +307,7 @@ mod tests {
assert_size!(Body, 12);
assert_size!(Subject, 12);
assert_size!(Thread, 12);
assert_size!(Message, 96);
assert_size!(Message, 104);
}
#[cfg(target_pointer_width = "64")]
@ -317,7 +317,7 @@ mod tests {
assert_size!(Body, 24);
assert_size!(Subject, 24);
assert_size!(Thread, 24);
assert_size!(Message, 192);
assert_size!(Message, 208);
}
#[test]

View File

@ -379,7 +379,7 @@ mod tests {
fn test_size() {
assert_size!(Show, 1);
assert_size!(Type, 1);
assert_size!(Presence, 72);
assert_size!(Presence, 80);
}
#[cfg(target_pointer_width = "64")]
@ -387,7 +387,7 @@ mod tests {
fn test_size() {
assert_size!(Show, 1);
assert_size!(Type, 1);
assert_size!(Presence, 144);
assert_size!(Presence, 160);
}
#[test]

View File

@ -200,11 +200,11 @@ mod tests {
node: NodeName(String::from("foo")),
affiliations: vec![
Affiliation {
jid: Jid::from(BareJid::from_str("hamlet@denmark.lit").unwrap()),
jid: Jid::Bare(BareJid::from_str("hamlet@denmark.lit").unwrap()),
affiliation: AffiliationAttribute::Owner,
},
Affiliation {
jid: Jid::from(BareJid::from_str("polonius@denmark.lit").unwrap()),
jid: Jid::Bare(BareJid::from_str("polonius@denmark.lit").unwrap()),
affiliation: AffiliationAttribute::Outcast,
},
],
@ -335,22 +335,22 @@ mod tests {
node: NodeName(String::from("foo")),
subscriptions: vec![
SubscriptionElem {
jid: Jid::from(BareJid::from_str("hamlet@denmark.lit").unwrap()),
jid: Jid::Bare(BareJid::from_str("hamlet@denmark.lit").unwrap()),
subscription: Subscription::Subscribed,
subid: None,
},
SubscriptionElem {
jid: Jid::from(BareJid::from_str("polonius@denmark.lit").unwrap()),
jid: Jid::Bare(BareJid::from_str("polonius@denmark.lit").unwrap()),
subscription: Subscription::Unconfigured,
subid: None,
},
SubscriptionElem {
jid: Jid::from(BareJid::from_str("bernardo@denmark.lit").unwrap()),
jid: Jid::Bare(BareJid::from_str("bernardo@denmark.lit").unwrap()),
subscription: Subscription::Subscribed,
subid: Some(String::from("123-abc")),
},
SubscriptionElem {
jid: Jid::from(BareJid::from_str("bernardo@denmark.lit").unwrap()),
jid: Jid::Bare(BareJid::from_str("bernardo@denmark.lit").unwrap()),
subscription: Subscription::Subscribed,
subid: Some(String::from("004-yyy")),
},

View File

@ -319,7 +319,7 @@ mod tests {
fn test_size() {
assert_size!(ErrorType, 1);
assert_size!(DefinedCondition, 1);
assert_size!(StanzaError, 92);
assert_size!(StanzaError, 96);
}
#[cfg(target_pointer_width = "64")]
@ -327,7 +327,7 @@ mod tests {
fn test_size() {
assert_size!(ErrorType, 1);
assert_size!(DefinedCondition, 1);
assert_size!(StanzaError, 184);
assert_size!(StanzaError, 192);
}
#[test]

View File

@ -44,14 +44,14 @@ mod tests {
#[cfg(target_pointer_width = "32")]
#[test]
fn test_size() {
assert_size!(StanzaId, 24);
assert_size!(StanzaId, 32);
assert_size!(OriginId, 12);
}
#[cfg(target_pointer_width = "64")]
#[test]
fn test_size() {
assert_size!(StanzaId, 56);
assert_size!(StanzaId, 64);
assert_size!(OriginId, 24);
}

View File

@ -75,7 +75,7 @@ async fn main() -> Result<(), Option<()>> {
Event::RoomJoined(jid) => {
println!("Joined room {}.", jid);
client
.send_message(Jid::from(jid), MessageType::Groupchat, "en", "Hello world!")
.send_message(Jid::Bare(jid), MessageType::Groupchat, "en", "Hello world!")
.await;
}
Event::RoomLeft(jid) => {

View File

@ -25,8 +25,8 @@ pub async fn handle_message_chat<C: ServerConnector>(
for payload in &message.payloads {
if let Ok(_) = MucUser::try_from(payload.clone()) {
let event = match from.clone().try_into_full() {
Err(bare) => {
let event = match from.clone() {
Jid::Bare(bare) => {
// TODO: Can a service message be of type Chat/Normal and not Groupchat?
warn!("Received misformed MessageType::Chat in muc#user namespace from a bare JID.");
Event::ServiceMessage(
@ -36,7 +36,7 @@ pub async fn handle_message_chat<C: ServerConnector>(
time_info.clone(),
)
}
Ok(full) => Event::RoomPrivateMessage(
Jid::Full(full) => Event::RoomPrivateMessage(
message.id.clone(),
full.to_bare(),
full.resource().to_string(),

View File

@ -28,15 +28,17 @@ pub async fn handle_message_group_chat<C: ServerConnector>(
}
if let Some((_lang, body)) = message.get_best_body(langs) {
let event = match from.clone().try_into_full() {
Ok(full) => Event::RoomMessage(
let event = match from.clone() {
Jid::Full(full) => Event::RoomMessage(
message.id.clone(),
from.to_bare(),
full.resource().to_string(),
body.clone(),
time_info,
),
Err(bare) => Event::ServiceMessage(message.id.clone(), bare, body.clone(), time_info),
Jid::Bare(bare) => {
Event::ServiceMessage(message.id.clone(), bare, body.clone(), time_info)
}
};
events.push(event)
}