diff --git a/Cargo.toml b/Cargo.toml index 848c54c..25f07e8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,8 +14,10 @@ futures = "^0.3" lazy_static = "^1.4" log = "^0.4" tokio = "^1.20" -tokio-xmpp = { version = "^3.2", default-features = false, features = ["tls-rust"] } -xmpp-parsers = { version = "^0.19", features = ["component"] } +tokio-xmpp = { version = "^3.5", default-features = false, features = ["tls-rust"] } +xmpp-parsers = { version = "*", features = ["component"] } +minidom = { version = "*" } +jid = { version = "*" } [dev-dependencies] syntect = "5.0" diff --git a/src/handlers/mod.rs b/src/handlers/mod.rs index d0b491e..31ad39f 100644 --- a/src/handlers/mod.rs +++ b/src/handlers/mod.rs @@ -96,22 +96,24 @@ async fn handle_iq_ping( // Pinging a participant. The resource needs to be currently joined. if let Jid::Full(participant) = to.clone() { // TODO: Reply from participant if joined and nick is correct - let bare = BareJid::from(to.clone()); - if let Some(room) = rooms.get(&bare) && - room.is_joined(&participant) && - let Some(occupant) = room.occupants.get(&participant.resource) { - if occupant.contains(&from) { - let success = success.clone().with_from(Jid::Full(participant)); - component.send_stanza(success).await?; - return Ok(()); - } + let bare = BareJid::from(to.clone().to_bare()); + let nick = participant.resource_str(); + if let Some(room) = rooms.get(&bare) + && room.is_joined(&participant) + && let Some(occupant) = room.occupants.get(nick) + { + if occupant.contains(&from) { + let success = success.clone().with_from(Jid::Full(participant)); + component.send_stanza(success).await?; + return Ok(()); + } - return Ok(()); - } + return Ok(()); + } } else if let Jid::Bare(to) = to.clone() { // Pinging the component - if to.node.is_none() { - let domain = BareJid::from_str(&to.domain).unwrap(); + if to.node().is_none() { + let domain = BareJid::from_str(to.domain_str()).unwrap(); let success = success.clone().with_from(Jid::Bare(domain)); component.send_stanza(success).await?; // Pinging a room. User is required to have an affiliation other than none if @@ -130,7 +132,7 @@ async fn handle_iq_ping( StanzaError { type_: ErrorType::Modify, defined_condition: DefinedCondition::NotAcceptable, - by: Some(Jid::Bare(BareJid::from(to.clone()))), + by: Some(Jid::Bare(BareJid::from(to.to_bare()))), texts: BTreeMap::new(), other: None, }, diff --git a/src/handlers/presence.rs b/src/handlers/presence.rs index fc8d957..5192593 100644 --- a/src/handlers/presence.rs +++ b/src/handlers/presence.rs @@ -88,7 +88,7 @@ async fn handle_presence_full_available( .unwrap() .unwrap(); let participant: FullJid = presence.to.clone().map(FullJid::try_from).unwrap().unwrap(); - let roomjid: BareJid = BareJid::from(participant.clone()); + let roomjid: BareJid = BareJid::from(participant.to_bare()); let muc = presence .payloads @@ -172,7 +172,7 @@ async fn handle_presence_full_unavailable( .unwrap() .unwrap(); let participant: FullJid = presence.to.clone().map(FullJid::try_from).unwrap().unwrap(); - let roomjid: BareJid = BareJid::from(participant.clone()); + let roomjid: BareJid = BareJid::from(participant.to_bare()); let error = Presence::new(PresenceType::Error) .with_from(participant.clone()) diff --git a/src/main.rs b/src/main.rs index 69fb3df..33b0421 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,7 +14,7 @@ // along with this program. If not, see . #![feature(let_chains)] -#![feature(once_cell)] +#![feature(lazy_cell)] // Maybe change that someday? #![allow(clippy::result_large_err)] diff --git a/src/occupant.rs b/src/occupant.rs index a476609..097fa09 100644 --- a/src/occupant.rs +++ b/src/occupant.rs @@ -37,8 +37,8 @@ impl Occupant { let participant = presence.to.clone().map(FullJid::try_from).unwrap().unwrap(); let session = Session::try_from(presence)?; Ok(Occupant { - real: BareJid::from(session.real().clone()), - nick: participant.resource.clone(), + real: BareJid::from(session.real().to_bare()), + nick: participant.resource_str().to_string(), participant, sessions: vec![session], }) @@ -64,7 +64,7 @@ impl Occupant { /// Add a new session to the occupant pub fn add_session(&mut self, presence: PresenceFull) -> Result<(), Error> { let new_session = Session::try_from(presence)?; - if BareJid::from(new_session.real().clone()) != self.real { + if BareJid::from(new_session.real().to_bare()) != self.real { return Err(Error::MismatchJids( Jid::from(self.real.clone()), Jid::from(new_session.real().clone()), diff --git a/src/room.rs b/src/room.rs index e94ac51..0b62f61 100644 --- a/src/room.rs +++ b/src/room.rs @@ -311,13 +311,13 @@ impl Room { presence: PresenceFull, ) -> Result<(), Error> { let new_session = Session::try_from(presence)?; - let new_nick = new_session.participant().resource.clone(); + let new_nick = new_session.participant().resource_str().to_string(); let realjid = new_session.real().clone(); // Ensure nick isn't already assigned self.occupants.iter().try_for_each(|(nick, occupant)| { let new_nick = new_nick.as_str(); - if new_nick == nick && occupant.real != BareJid::from(realjid.clone()) { + if new_nick == nick && occupant.real != BareJid::from(realjid.to_bare()) { return Err(Error::NickAlreadyAssigned(String::from(new_nick))); } Ok(()) @@ -407,15 +407,15 @@ impl Room { joined_session: Session, new_session: Session, ) -> Result<(), Error> { - let oldnick = &joined_session.participant().resource; - let newnick = &new_session.participant().resource; - let bare = BareJid::from(new_session.real().clone()); + let oldnick = joined_session.participant().resource_str(); + let newnick = new_session.participant().resource_str(); + let bare = BareJid::from(new_session.real().to_bare()); let mut merge = false; for (nick, occupant) in self.occupants.iter_mut() { if nick == newnick { if occupant.real != bare { - return Err(Error::NickAlreadyAssigned(newnick.clone())); + return Err(Error::NickAlreadyAssigned(String::from(newnick))); } else { merge = true; break; @@ -430,7 +430,7 @@ impl Room { self.get_occupant(&joined_session)?, joined_session.presence.clone(), BroadcastPresence::Leave, - Some(&**newnick), + Some(&String::from(newnick)), ) .await?; @@ -533,7 +533,8 @@ impl Room { ) -> Result<(), Error> { let session = Session::try_from(presence)?; // If occupant doesn't exist, ignore. - if let Some(mut occupant) = self.occupants.remove(&session.participant().resource) { + let nick = session.participant().resource_str(); + if let Some(mut occupant) = self.occupants.remove(nick) { self.broadcast_presence( component, &occupant, @@ -547,7 +548,7 @@ impl Room { if occupant.iter().len() > 0 { let _ = self .occupants - .insert(session.participant().resource.clone(), occupant); + .insert(session.participant().resource_str().to_string(), occupant); } } else { // TODO: Error @@ -590,7 +591,10 @@ impl Room { /// . /// Fetch a mutable reference to the occupant associated with the requesting realjid. pub fn get_mut_occupant(&mut self, session: &Session) -> Result<&mut Occupant, Error> { - if let Some(occupant) = self.occupants.get_mut(&session.participant().resource) { + if let Some(occupant) = self + .occupants + .get_mut(&session.participant().resource_str().to_string()) + { if occupant.contains(session.real()) { Ok(occupant) } else { @@ -598,7 +602,7 @@ impl Room { } } else { Err(Error::ParticipantNotFound( - session.participant().resource.clone(), + session.participant().resource_str().to_string(), )) } } @@ -631,11 +635,11 @@ mod tests { async fn broadcast_presence_resync() { let roomjid = BareJid::from_str("room@muc").unwrap(); let realjid1 = FullJid::from_str("foo@bar/qxx").unwrap(); - let participant1 = roomjid.clone().with_resource(String::from("nick1")); + let participant1 = roomjid.clone().with_resource_str("nick1").unwrap(); let realjid2 = FullJid::from_str("qxx@foo/bar").unwrap(); - let participant2 = roomjid.clone().with_resource(String::from("nick2")); + let participant2 = roomjid.clone().with_resource_str("nick2").unwrap(); let realjid3 = FullJid::from_str("bar@qxx/foo").unwrap(); - let participant3 = roomjid.clone().with_resource(String::from("nick3")); + let participant3 = roomjid.clone().with_resource_str("nick3").unwrap(); let presence1 = PresenceFull::try_from( Presence::new(PresenceType::None) @@ -662,16 +666,16 @@ mod tests { room.occupants = BTreeMap::new(); room.occupants.insert( - participant1.resource.clone(), + participant1.resource_str().to_string(), Occupant::new(presence1).unwrap(), ); room.occupants.insert( - participant2.resource.clone(), + participant2.resource_str().to_string(), Occupant::new(presence2).unwrap(), ); let occupant3 = Occupant::new(presence3.clone()).unwrap(); room.occupants - .insert(participant3.resource.clone(), occupant3.clone()); + .insert(participant3.resource_str().to_string(), occupant3.clone()); let self_item = MucItem::try_from( r#""# @@ -730,11 +734,11 @@ mod tests { async fn broadcast_presence_update() { let roomjid = BareJid::from_str("room@muc").unwrap(); let realjid1 = FullJid::from_str("foo@bar/qxx").unwrap(); - let participant1 = roomjid.clone().with_resource(String::from("nick1")); + let participant1 = roomjid.clone().with_resource_str("nick1").unwrap(); let realjid2 = FullJid::from_str("qxx@foo/bar").unwrap(); - let participant2 = roomjid.clone().with_resource(String::from("nick2")); + let participant2 = roomjid.clone().with_resource_str("nick2").unwrap(); let realjid3 = FullJid::from_str("bar@qxx/foo").unwrap(); - let participant3 = roomjid.clone().with_resource(String::from("nick3")); + let participant3 = roomjid.clone().with_resource_str("nick3").unwrap(); let presence1 = PresenceFull::try_from( Presence::new(PresenceType::None) @@ -761,16 +765,16 @@ mod tests { room.occupants = BTreeMap::new(); room.occupants.insert( - participant1.resource.clone(), + participant1.resource_str().to_string(), Occupant::new(presence1).unwrap(), ); room.occupants.insert( - participant2.resource.clone(), + participant2.resource_str().to_string(), Occupant::new(presence2).unwrap(), ); let occupant3 = Occupant::new(presence3.clone()).unwrap(); room.occupants - .insert(participant3.resource.clone(), occupant3.clone()); + .insert(participant3.resource_str().to_string(), occupant3.clone()); // BroadcastPresence::Update let mut component = TestComponent::new(vec![]); @@ -812,11 +816,11 @@ mod tests { async fn broadcast_presence_join() { let roomjid = BareJid::from_str("room@muc").unwrap(); let realjid1 = FullJid::from_str("foo@bar/qxx").unwrap(); - let participant1 = roomjid.clone().with_resource(String::from("nick1")); + let participant1 = roomjid.clone().with_resource_str("nick1").unwrap(); let realjid2 = FullJid::from_str("qxx@foo/bar").unwrap(); - let participant2 = roomjid.clone().with_resource(String::from("nick2")); + let participant2 = roomjid.clone().with_resource_str("nick2").unwrap(); let realjid3 = FullJid::from_str("bar@qxx/foo").unwrap(); - let participant3 = roomjid.clone().with_resource(String::from("nick3")); + let participant3 = roomjid.clone().with_resource_str("nick3").unwrap(); let presence1 = PresenceFull::try_from( Presence::new(PresenceType::None) @@ -843,16 +847,16 @@ mod tests { room.occupants = BTreeMap::new(); room.occupants.insert( - participant1.resource.clone(), + participant1.resource_str().to_string(), Occupant::new(presence1.clone()).unwrap(), ); room.occupants.insert( - participant2.resource.clone(), + participant2.resource_str().to_string(), Occupant::new(presence2.clone()).unwrap(), ); let occupant3 = Occupant::new(presence3.clone()).unwrap(); room.occupants - .insert(participant3.resource.clone(), occupant3.clone()); + .insert(participant3.resource_str().to_string(), occupant3.clone()); let self_item = MucItem::try_from( r#""# @@ -1049,7 +1053,7 @@ mod tests { } // Sessions not joined to the room, even from the same barejid, should be rejected - let louise_full3 = LOUISE_BARE.clone().with_resource("othernick"); + let louise_full3 = LOUISE_BARE.clone().with_resource_str("othernick").unwrap(); let presence2 = PresenceFull::try_from( Presence::new(PresenceType::None) .with_from(Jid::Full(louise_full3)) diff --git a/src/tests/iq.rs b/src/tests/iq.rs index b6fecce..716fb60 100644 --- a/src/tests/iq.rs +++ b/src/tests/iq.rs @@ -15,7 +15,7 @@ use crate::component::TestComponent; use crate::handlers::handle_stanza; use crate::room::Room; -use crate::tests::templates::{COMPONENT_JID, LOUISE_FULL1, LOUISE_ROOM1_PART}; +use crate::tests::templates::{COMPONENT_JID, LOUISE_FULL1, LOUISE_ROOM1_PART, ROOM1_BARE}; use std::collections::{BTreeMap, HashMap}; use std::str::FromStr; @@ -119,8 +119,8 @@ async fn self_ping_answer() { #[tokio::test] async fn self_ping_participant_non_existing() { let realjid1 = Jid::Full(FullJid::from_str("foo@bar/qxx").unwrap()); - let roomjid = COMPONENT_JID.clone().with_node("room"); - let participant1 = roomjid.clone().with_resource("nick1"); + let roomjid = ROOM1_BARE.clone(); + let participant1 = roomjid.with_resource_str("nick1").unwrap(); let ping: Element = Iq { from: Some(realjid1.clone()), @@ -154,7 +154,7 @@ async fn self_ping_participant_non_existing() { #[tokio::test] async fn ping_room() { let realjid1 = Jid::Full(FullJid::from_str("foo@bar/qxx").unwrap()); - let roomjid = COMPONENT_JID.clone().with_node("room"); + let roomjid = ROOM1_BARE.clone(); let ping: Element = Iq { from: Some(realjid1.clone()), diff --git a/src/tests/presence_msn.rs b/src/tests/presence_msn.rs index 4d13578..110b9ca 100644 --- a/src/tests/presence_msn.rs +++ b/src/tests/presence_msn.rs @@ -116,7 +116,7 @@ async fn join() { assert_eq!(room.occupants.len(), 1); assert_eq!( room.occupants - .get(&LOUISE_ROOM1_PART.resource) + .get(LOUISE_ROOM1_PART.resource_str()) .unwrap() .sessions .len(), diff --git a/src/tests/templates.rs b/src/tests/templates.rs index 1b99cbd..1758c63 100644 --- a/src/tests/templates.rs +++ b/src/tests/templates.rs @@ -17,6 +17,7 @@ use crate::occupant::Occupant; use crate::presence::PresenceFull; use crate::room::Room; use crate::session::Nick; +use jid::{DomainPart, NodePart}; use std::str::FromStr; use std::sync::LazyLock; use xmpp_parsers::{ @@ -24,57 +25,61 @@ use xmpp_parsers::{ BareJid, FullJid, }; +const COMPONENT_DOMAIN_PART: LazyLock = + LazyLock::new(|| DomainPart::new("commons.social").unwrap()); pub const COMPONENT_JID: LazyLock = - LazyLock::new(|| BareJid::from_str("commons.social").unwrap()); -pub const ROOM1_BARE: LazyLock = - LazyLock::new(|| COMPONENT_JID.clone().with_node("direct-action")); + LazyLock::new(|| BareJid::from_parts(None, &COMPONENT_DOMAIN_PART)); +pub const ROOM1_BARE: LazyLock = LazyLock::new(|| { + let node = NodePart::new("direct-action").unwrap(); + BareJid::from_parts(Some(&node), &COMPONENT_DOMAIN_PART) +}); /// https://en.wikipedia.org/wiki/Louise_Michel pub const LOUISE_BARE: LazyLock = LazyLock::new(|| BareJid::from_str("louise@example.net").unwrap()); pub const LOUISE_FULL1: LazyLock = - LazyLock::new(|| LOUISE_BARE.clone().with_resource("commune")); + LazyLock::new(|| LOUISE_BARE.with_resource_str("commune").unwrap()); pub const LOUISE_FULL2: LazyLock = - LazyLock::new(|| LOUISE_BARE.clone().with_resource("desktop")); + LazyLock::new(|| LOUISE_BARE.with_resource_str("desktop").unwrap()); pub const LOUISE_NICK: &'static str = "louise"; pub const LOUISE_NICK2: &'static str = "louise_"; pub const LOUISE_ROOM1_PART: LazyLock = - LazyLock::new(|| ROOM1_BARE.clone().with_resource(LOUISE_NICK)); + LazyLock::new(|| ROOM1_BARE.with_resource_str(LOUISE_NICK).unwrap()); pub const LOUISE_ROOM1_PART2: LazyLock = - LazyLock::new(|| ROOM1_BARE.clone().with_resource(LOUISE_NICK2)); + LazyLock::new(|| ROOM1_BARE.with_resource_str(LOUISE_NICK2).unwrap()); /// https://en.wikipedia.org/wiki/Kanno_Sugako pub const SUGAKO_BARE: LazyLock = LazyLock::new(|| BareJid::from_str("すがこ@example.net").unwrap()); pub const SUGAKO_FULL1: LazyLock = - LazyLock::new(|| SUGAKO_BARE.clone().with_resource("desktop")); + LazyLock::new(|| SUGAKO_BARE.with_resource_str("desktop").unwrap()); pub const SUGAKO_FULL2: LazyLock = - LazyLock::new(|| SUGAKO_BARE.clone().with_resource("mobile")); + LazyLock::new(|| SUGAKO_BARE.with_resource_str("mobile").unwrap()); pub const SUGAKO_NICK: &'static str = "すがこ"; pub const SUGAKO_ROOM1_PART: LazyLock = - LazyLock::new(|| ROOM1_BARE.clone().with_resource(SUGAKO_NICK)); + LazyLock::new(|| ROOM1_BARE.with_resource_str(SUGAKO_NICK).unwrap()); /// https://en.wikipedia.org/wiki/Rosa_Luxemburg pub const ROSA_BARE: LazyLock = LazyLock::new(|| BareJid::from_str("rosa@example.net").unwrap()); pub const ROSA_FULL1: LazyLock = - LazyLock::new(|| ROSA_BARE.clone().with_resource("desktop")); + LazyLock::new(|| ROSA_BARE.with_resource_str("desktop").unwrap()); pub const ROSA_FULL2: LazyLock = - LazyLock::new(|| ROSA_BARE.clone().with_resource("mobile")); + LazyLock::new(|| ROSA_BARE.with_resource_str("mobile").unwrap()); pub const ROSA_NICK: &'static str = "rosa"; pub const ROSA_ROOM1_PART: LazyLock = - LazyLock::new(|| ROOM1_BARE.clone().with_resource(ROSA_NICK)); + LazyLock::new(|| ROOM1_BARE.with_resource_str(ROSA_NICK).unwrap()); /// https://en.wikipedia.org/wiki/Peter_Kropotkin pub const PETER_BARE: LazyLock = LazyLock::new(|| BareJid::from_str("peter@example.net").unwrap()); pub const PETER_FULL1: LazyLock = - LazyLock::new(|| PETER_BARE.clone().with_resource("desktop")); + LazyLock::new(|| PETER_BARE.with_resource_str("desktop").unwrap()); pub const PETER_FULL2: LazyLock = - LazyLock::new(|| PETER_BARE.clone().with_resource("mobile")); + LazyLock::new(|| PETER_BARE.with_resource_str("mobile").unwrap()); pub const PETER_NICK: &'static str = "peter"; pub const PETER_ROOM1_PART: LazyLock = - LazyLock::new(|| ROOM1_BARE.clone().with_resource(PETER_NICK)); + LazyLock::new(|| ROOM1_BARE.with_resource_str(PETER_NICK).unwrap()); pub fn one_participant_room(roomjid: BareJid) -> Room { let mut room = Room::new(roomjid.clone()); @@ -113,7 +118,7 @@ pub async fn new_room>(roomjid: BareJid, occupants: Vec<(N, Vec