aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar cel 🌸 <cel@bunny.garden>2025-03-28 19:25:33 +0000
committerLibravatar cel 🌸 <cel@bunny.garden>2025-03-28 21:12:02 +0000
commit7d122d244622c664a7f5d8d99efc739dba5e6a3d (patch)
tree58e33efd19298ec32dd4479b81226693406a6ada
parent97ef9274ac5e0e9aa6d6c842477051de80b9d82d (diff)
downloadluz-7d122d244622c664a7f5d8d99efc739dba5e6a3d.tar.gz
luz-7d122d244622c664a7f5d8d99efc739dba5e6a3d.tar.bz2
luz-7d122d244622c664a7f5d8d99efc739dba5e6a3d.zip
feat(filamento): disco features and identity categories according to registry
-rw-r--r--filamento/src/disco.rs1640
-rw-r--r--filamento/src/lib.rs3
2 files changed, 1643 insertions, 0 deletions
diff --git a/filamento/src/disco.rs b/filamento/src/disco.rs
new file mode 100644
index 0000000..233dd5f
--- /dev/null
+++ b/filamento/src/disco.rs
@@ -0,0 +1,1640 @@
+use stanza::xep_0030::info;
+
+pub use feature::Feature;
+pub use identity::Identity;
+
+pub struct Info {
+ node: Option<String>,
+ features: Vec<Feature>,
+ identities: Vec<Identity>,
+}
+
+mod feature {
+ // https://xmpp.org/registrar/disco-features.html
+ pub enum Feature {
+ DNSSRV,
+ FullUnicode,
+ GC1,
+ Activity,
+ Address,
+ Amp(Option<Amp>),
+ Bytestreams(Option<Bytestreams>),
+ Caps(CapsVersion),
+ ChatStates,
+ Commands,
+ Compress,
+ Disco(Disco),
+ FeatureNeg,
+ Geoloc,
+ HttpAuth,
+ HttpBind,
+ IBB,
+ Mood,
+ MUC(Option<MUC>),
+ Offline,
+ PubSub(PubSub),
+ RosterX,
+ SIPub,
+ SOAP(Option<SOAP>),
+ WaitingList(Option<WaitingList>),
+ XHTMLIM,
+ XDataLayout,
+ XDataValidate,
+ IPv6,
+ Client,
+ Component(Component),
+ Iq(Iq),
+ Server,
+ X(X),
+ MsgLog,
+ MsgOffline,
+ RosterDelimiter,
+ SSLC2S,
+ StringPrep,
+ XMPPBind,
+ XMPPE2E,
+ XMPPSASL(Option<XMPPSASL>),
+ XMPPSession,
+ XMPPStanzas,
+ XMPPStreams,
+ XMPPTLS(Option<XMPPTLS>),
+ RFC3264,
+ Archive(Archive),
+ Avatar(Avatar),
+ Delay,
+ Jingle(Jingle),
+ Ping,
+ Receipts,
+ SSN,
+ Time,
+ XMLLang,
+ VCardTemp,
+ Styling(i8),
+ SID(i8),
+ Unknown(String),
+ }
+
+ impl From<&str> for Feature {
+ fn from(value: &str) -> Self {
+ match value {
+ "dnssrv" => Self::DNSSRV,
+ "fullunicode" => Self::FullUnicode,
+ "gc-1.0" => Self::GC1,
+ "http://jabber.org/protocol/activity" => Self::Activity,
+ "http://jabber.org/protocol/address" => Self::Address,
+ "http://jabber.org/protocol/amp" => Self::Amp(None),
+ "http://jabber.org/protocol/amp#errors" => Self::Amp(Some(Amp::Errors)),
+ "http://jabber.org/protocol/amp?action=alert" => {
+ Self::Amp(Some(Amp::Action(AmpAction::Alert)))
+ }
+ "http://jabber.org/protocol/amp?action=drop" => {
+ Self::Amp(Some(Amp::Action(AmpAction::Drop)))
+ }
+ "http://jabber.org/protocol/amp?action=error" => {
+ Self::Amp(Some(Amp::Action(AmpAction::Error)))
+ }
+ "http://jabber.org/protocol/amp?action=notify" => {
+ Self::Amp(Some(Amp::Action(AmpAction::Notify)))
+ }
+ "http://jabber.org/protocol/amp?condition=deliver" => {
+ Self::Amp(Some(Amp::Condition(AmpCondition::Deliver)))
+ }
+ "http://jabber.org/protocol/amp?condition=expire-at" => {
+ Self::Amp(Some(Amp::Condition(AmpCondition::ExpireAt)))
+ }
+ "http://jabber.org/protocol/amp?condition=match-resource" => {
+ Self::Amp(Some(Amp::Condition(AmpCondition::MatchResource)))
+ }
+ "http://jabber.org/protocol/bytestreams" => Self::Bytestreams(None),
+ "http://jabber.org/protocol/bytestreams#udp" => {
+ Self::Bytestreams(Some(Bytestreams::UDP))
+ }
+ "http://jabber.org/protocol/caps" => Self::Caps(CapsVersion::One(None)),
+ "http://jabber.org/protocol/caps#optimize" => {
+ Self::Caps(CapsVersion::One(Some(CapsOne::Optimize)))
+ }
+ "http://jabber.org/protocol/chatstates" => Self::ChatStates,
+ "http://jabber.org/protocol/commands" => Self::Commands,
+ "http://jabber.org/protocol/compress" => Self::Compress,
+ "http://jabber.org/protocol/disco#info" => Self::Disco(Disco::Info),
+ "http://jabber.org/protocol/disco#items" => Self::Disco(Disco::Items),
+ "http://jabber.org/protocol/feature-neg" => Self::FeatureNeg,
+ "http://jabber.org/protocol/geoloc" => Self::Geoloc,
+ "http://jabber.org/protocol/http-auth" => Self::HttpAuth,
+ "http://jabber.org/protocol/httpbind" => Self::HttpBind,
+ "http://jabber.org/protocol/ibb" => Self::IBB,
+ "http://jabber.org/protocol/mood" => Self::Mood,
+ "http://jabber.org/protocol/muc" => Self::MUC(None),
+ "http://jabber.org/protocol/muc#admin" => Self::MUC(Some(MUC::Admin)),
+ "http://jabber.org/protocol/muc#owner" => Self::MUC(Some(MUC::Owner)),
+ "http://jabber.org/protocol/muc#register" => Self::MUC(Some(MUC::Register)),
+ "http://jabber.org/protocol/muc#roomconfig" => Self::MUC(Some(MUC::RoomConfig)),
+ "http://jabber.org/protocol/muc#roominfo" => Self::MUC(Some(MUC::RoomInfo)),
+ "http://jabber.org/protocol/muc#user" => Self::MUC(Some(MUC::User)),
+ "http://jabber.org/protocol/offline" => Self::Offline,
+ "http://jabber.org/protocol/pubsub#access-authorize" => {
+ Self::PubSub(PubSub::AccessAuthorize)
+ }
+ "http://jabber.org/protocol/pubsub#access-open" => Self::PubSub(PubSub::AccessOpen),
+ "http://jabber.org/protocol/pubsub#access-presence" => {
+ Self::PubSub(PubSub::AccessPresence)
+ }
+ "http://jabber.org/protocol/pubsub#access-roster" => {
+ Self::PubSub(PubSub::AccessRoster)
+ }
+ "http://jabber.org/protocol/pubsub#access-whitelist" => {
+ Self::PubSub(PubSub::AccessWhitelist)
+ }
+ "http://jabber.org/protocol/pubsub#auto-create" => Self::PubSub(PubSub::AutoCreate),
+ "http://jabber.org/protocol/pubsub#auto-subscribe" => {
+ Self::PubSub(PubSub::AutoSubscribe)
+ }
+ "http://jabber.org/protocol/pubsub#collections" => {
+ Self::PubSub(PubSub::Collections)
+ }
+ "http://jabber.org/protocol/pubsub#config-node" => Self::PubSub(PubSub::ConfigNode),
+ "http://jabber.org/protocol/pubsub#create-and-configure" => {
+ Self::PubSub(PubSub::CreateAndConfigure)
+ }
+ "http://jabber.org/protocol/pubsub#create-nodes" => {
+ Self::PubSub(PubSub::CreateNodes)
+ }
+ "http://jabber.org/protocol/pubsub#delete-any" => Self::PubSub(PubSub::DeleteAny),
+ "http://jabber.org/protocol/pubsub#delete-nodes" => {
+ Self::PubSub(PubSub::DeleteNodes)
+ }
+ "http://jabber.org/protocol/pubsub#filtered-notifications" => {
+ Self::PubSub(PubSub::FilteredNotifications)
+ }
+ "http://jabber.org/protocol/pubsub#get-pending" => Self::PubSub(PubSub::GetPending),
+ "http://jabber.org/protocol/pubsub#instant-nodes" => {
+ Self::PubSub(PubSub::InstantNodes)
+ }
+ "http://jabber.org/protocol/pubsub#item-ids" => Self::PubSub(PubSub::ItemIDs),
+ "http://jabber.org/protocol/pubsub#last-published" => {
+ Self::PubSub(PubSub::LastPublished)
+ }
+ "http://jabber.org/protocol/pubsub#leased-subscription" => {
+ Self::PubSub(PubSub::LeasedSubscription)
+ }
+ "http://jabber.org/protocol/pubsub#manage-subscription" => {
+ Self::PubSub(PubSub::ManageSubscription)
+ }
+ "http://jabber.org/protocol/pubsub#member-affiliation" => {
+ Self::PubSub(PubSub::MemberAffiliation)
+ }
+ "http://jabber.org/protocol/pubsub#meta-data" => Self::PubSub(PubSub::MetaData),
+ "http://jabber.org/protocol/pubsub#modify-affiliations" => {
+ Self::PubSub(PubSub::ModifyAffiliations)
+ }
+ "http://jabber.org/protocol/pubsub#multi-collection" => {
+ Self::PubSub(PubSub::MultiCollection)
+ }
+ "http://jabber.org/protocol/pubsub#multi-subscribe" => {
+ Self::PubSub(PubSub::MultiSubscribe)
+ }
+ "http://jabber.org/protocol/pubsub#outcast-affiliation" => {
+ Self::PubSub(PubSub::OutcastAffiliation)
+ }
+ "http://jabber.org/protocol/pubsub#persistent-items" => {
+ Self::PubSub(PubSub::PersistentItems)
+ }
+ "http://jabber.org/protocol/pubsub#presence-notifications" => {
+ Self::PubSub(PubSub::PresenceNotifications)
+ }
+ "http://jabber.org/protocol/pubsub#presence-subscribe" => {
+ Self::PubSub(PubSub::PresenceSubscribe)
+ }
+ "http://jabber.org/protocol/pubsub#publish" => Self::PubSub(PubSub::Publish),
+ "http://jabber.org/protocol/pubsub#publish-options" => {
+ Self::PubSub(PubSub::PublishOptions)
+ }
+ "http://jabber.org/protocol/pubsub#publisher-affiliation" => {
+ Self::PubSub(PubSub::PublisherAffiliation)
+ }
+ "http://jabber.org/protocol/pubsub#purge-nodes" => Self::PubSub(PubSub::PurgeNodes),
+ "http://jabber.org/protocol/pubsub#retract-items" => {
+ Self::PubSub(PubSub::RetractItems)
+ }
+ "http://jabber.org/protocol/pubsub#retrieve-affiliations" => {
+ Self::PubSub(PubSub::RetrieveAffiliations)
+ }
+ "http://jabber.org/protocol/pubsub#retrieve-default" => {
+ Self::PubSub(PubSub::RetrieveDefault)
+ }
+ "http://jabber.org/protocol/pubsub#retrieve-items" => {
+ Self::PubSub(PubSub::RetrieveItems)
+ }
+ "http://jabber.org/protocol/pubsub#retrieve-subscriptions" => {
+ Self::PubSub(PubSub::RetrieveSubscriptions)
+ }
+ "http://jabber.org/protocol/pubsub#subscribe" => Self::PubSub(PubSub::Subscribe),
+ "http://jabber.org/protocol/pubsub#subscription-options" => {
+ Self::PubSub(PubSub::SubscriptionOptions)
+ }
+ "http://jabber.org/protocol/pubsub#subscription-notifications" => {
+ Self::PubSub(PubSub::SubscriptionNotifications)
+ }
+ "http://jabber.org/protocol/rosterx" => Self::RosterX,
+ "http://jabber.org/protocol/sipub" => Self::SIPub,
+ "http://jabber.org/protocol/soap" => Self::SOAP(None),
+ "http://jabber.org/protocol/soap#fault" => Self::SOAP(Some(SOAP::Fault)),
+ "http://jabber.org/protocol/waitinglist" => Self::WaitingList(None),
+ "http://jabber.org/protocol/waitinglist/schemes/mailto" => {
+ Self::WaitingList(Some(WaitingList::Schemes(WaitingListSchemes::Mailto)))
+ }
+ "http://jabber.org/protocol/waitinglist/schemes/tel" => {
+ Self::WaitingList(Some(WaitingList::Schemes(WaitingListSchemes::Tel)))
+ }
+ "http://jabber.org/protocol/xhtml-im" => Self::XHTMLIM,
+ "http://jabber.org/protocol/xdata-layout" => Self::XDataLayout,
+ "http://jabber.org/protocol/xdata-validate" => Self::XDataValidate,
+ "ipv6" => Self::IPv6,
+ "jabber:client" => Self::Client,
+ "jabber:component:accept" => Self::Component(Component::Accept),
+ "jabber:component:connect" => Self::Component(Component::Connect),
+ "jabber:iq:auth" => Self::Iq(Iq::Auth),
+ "jabber:iq:gateway" => Self::Iq(Iq::Gateway),
+ "jabber:iq:last" => Self::Iq(Iq::Last),
+ "jabber:iq:oob" => Self::Iq(Iq::OOB),
+ "jabber:iq:privacy" => Self::Iq(Iq::Privacy),
+ "jabber:iq:private" => Self::Iq(Iq::Private),
+ "jabber:iq:register" => Self::Iq(Iq::Register),
+ "jabber:iq:roster" => Self::Iq(Iq::Roster),
+ "jabber:iq:rpc" => Self::Iq(Iq::RPC),
+ "jabber:iq:search" => Self::Iq(Iq::Search),
+ "jabber:iq:version" => Self::Iq(Iq::Version),
+ "jabber:server" => Self::Server,
+ "jabber:x:data" => Self::X(X::Data),
+ "jabber:x:encrypted" => Self::X(X::Encrypted),
+ "jabber:x:oob" => Self::X(X::OOB),
+ "jabber:x:signed" => Self::X(X::Signed),
+ "msglog" => Self::MsgLog,
+ "msgoffline" => Self::MsgOffline,
+ "muc_hidden" => Self::MUC(Some(MUC::Hidden)),
+ "muc_membersonly" => Self::MUC(Some(MUC::MembersOnly)),
+ "muc_moderated" => Self::MUC(Some(MUC::Moderated)),
+ "muc_nonanonymous" => Self::MUC(Some(MUC::NonAnonymous)),
+ "muc_open" => Self::MUC(Some(MUC::Open)),
+ "muc_passwordprotected" => Self::MUC(Some(MUC::PasswordProtected)),
+ "muc_persistent" => Self::MUC(Some(MUC::Persistent)),
+ "muc_public" => Self::MUC(Some(MUC::Public)),
+ "muc_rooms" => Self::MUC(Some(MUC::Rooms)),
+ "muc_semianonymous" => Self::MUC(Some(MUC::SemiAnonymous)),
+ "muc_temporary" => Self::MUC(Some(MUC::Temporary)),
+ "muc_unmoderated" => Self::MUC(Some(MUC::Unmoderated)),
+ "muc_unsecured" => Self::MUC(Some(MUC::Unsecured)),
+ "roster:delimiter" => Self::RosterDelimiter,
+ "sslc2s" => Self::SSLC2S,
+ "stringprep" => Self::StringPrep,
+ "urn:ietf:params:xml:ns:xmpp-bind" => Self::XMPPBind,
+ "urn:ietf:params:xml:ns:xmpp-e2e" => Self::XMPPE2E,
+ "urn:ietf:params:xml:ns:xmpp-sasl" => Self::XMPPSASL(None),
+ "urn:ietf:params:xml:ns:xmpp-sasl#c2s" => Self::XMPPSASL(Some(XMPPSASL::C2S)),
+ "urn:ietf:params:xml:ns:xmpp-sasl#s2s" => Self::XMPPSASL(Some(XMPPSASL::S2S)),
+ "urn:ietf:params:xml:ns:xmpp-session" => Self::XMPPSession,
+ "urn:ietf:params:xml:ns:xmpp-stanzas" => Self::XMPPStanzas,
+ "urn:ietf:params:xml:ns:xmpp-streams" => Self::XMPPStreams,
+ "urn:ietf:params:xml:ns:xmpp-tls" => Self::XMPPTLS(None),
+ "urn:ietf:params:xml:ns:xmpp-tls#c2s" => Self::XMPPTLS(Some(XMPPTLS::C2S)),
+ "urn:ietf:params:xml:ns:xmpp-tls#s2s" => Self::XMPPTLS(Some(XMPPTLS::S2S)),
+ "urn:ietf:rfc:3264" => Self::RFC3264,
+ "urn:xmpp:archive:auto" => Self::Archive(Archive::Auto),
+ "urn:xmpp:archive:manage" => Self::Archive(Archive::Manage),
+ "urn:xmpp:archive:manual" => Self::Archive(Archive::Manual),
+ "urn:xmpp:archive:pref" => Self::Archive(Archive::Pref),
+ "urn:xmpp:avatar:data" => Self::Avatar(Avatar::Data),
+ "urn:xmpp:avatar:metadata" => Self::Avatar(Avatar::Metadata),
+ "urn:xmpp:delay" => Self::Delay,
+ "urn:xmpp:jingle:apps:rtp:audio" => {
+ Self::Jingle(Jingle::Apps(JingleApps::RTP(JingleAppsRTP::Audio)))
+ }
+ "urn:xmpp:jingle:apps:rtp:video" => {
+ Self::Jingle(Jingle::Apps(JingleApps::RTP(JingleAppsRTP::Video)))
+ }
+ "urn:xmpp:ping" => Self::Ping,
+ "urn:xmpp:receipts" => Self::Receipts,
+ "urn:xmpp:ssn" => Self::SSN,
+ "urn:xmpp:time" => Self::Time,
+ "xmllang" => Self::XMLLang,
+ "vcard-temp" => Self::VCardTemp,
+ "urn:xmpp:styling:0" => Self::Styling(0),
+ "urn:xmpp:sid:0" => Self::SID(0),
+ "urn:xmpp:caps" => Self::Caps(CapsVersion::Two(None)),
+ "urn:xmpp:caps:optimize" => Self::Caps(CapsVersion::Two(Some(CapsTwo::Optimize))),
+ s => Self::Unknown(s.to_owned()),
+ }
+ }
+ }
+
+ impl ToString for Feature {
+ fn to_string(&self) -> String {
+ match self {
+ Feature::DNSSRV => "dnssrv".to_owned(),
+ Feature::FullUnicode => "fullunicode".to_owned(),
+ Feature::GC1 => "gc-1.0".to_owned(),
+ Feature::Activity => "http://jabber.org/protocol/activity".to_owned(),
+ Feature::Address => "http://jabber.org/protocol/address".to_owned(),
+ Feature::Amp(amp) => match amp {
+ Some(a) => a.to_string(),
+ None => "http://jabber.org/protocol/amp".to_owned(),
+ },
+ Feature::Bytestreams(byte_streams) => match byte_streams {
+ Some(b) => b.to_string(),
+ None => "http://jabber.org/protocol/bytestreams".to_owned(),
+ },
+ Feature::Caps(caps_version) => caps_version.to_string(),
+ Feature::ChatStates => "http://jabber.org/protocol/chatstates".to_owned(),
+ Feature::Commands => "http://jabber.org/protocol/commands".to_owned(),
+ Feature::Compress => "http://jabber.org/protocol/compress".to_owned(),
+ Feature::Disco(disco) => disco.to_string(),
+ Feature::FeatureNeg => "http://jabber.org/protocol/feature-neg".to_owned(),
+ Feature::Geoloc => "http://jabber.org/protocol/geoloc".to_owned(),
+ Feature::HttpAuth => "http://jabber.org/protocol/http-auth".to_owned(),
+ Feature::HttpBind => "http://jabber.org/protocol/httpbind".to_owned(),
+ Feature::IBB => "http://jabber.org/protocol/ibb".to_owned(),
+ Feature::Mood => "http://jabber.org/protocol/mood".to_owned(),
+ Feature::MUC(muc) => match muc {
+ Some(m) => m.to_string(),
+ None => "http://jabber.org/protocol/muc".to_owned(),
+ },
+ Feature::Offline => "http://jabber.org/protocol/offline".to_owned(),
+ Feature::PubSub(pub_sub) => pub_sub.to_string(),
+ Feature::RosterX => "http://jabber.org/protocol/rosterx".to_owned(),
+ Feature::SIPub => "http://jabber.org/protocol/sipub".to_owned(),
+ Feature::SOAP(soap) => match soap {
+ Some(s) => s.to_string(),
+ None => "http://jabber.org/protocol/soap".to_owned(),
+ },
+ Feature::WaitingList(waiting_list) => match waiting_list {
+ Some(w) => w.to_string(),
+ None => "http://jabber.org/protocol/waitinglist".to_owned(),
+ },
+ Feature::XHTMLIM => "http://jabber.org/protocol/xhtml-im".to_owned(),
+ Feature::XDataLayout => "http://jabber.org/protocol/xdata-layout".to_owned(),
+ Feature::XDataValidate => "http://jabber.org/protocol/xdata-validate".to_owned(),
+ Feature::IPv6 => "ipv6".to_owned(),
+ Feature::Client => "jabber:client".to_owned(),
+ Feature::Component(component) => component.to_string(),
+ Feature::Iq(iq) => iq.to_string(),
+ Feature::Server => "jabber:server".to_owned(),
+ Feature::X(x) => x.to_string(),
+ Feature::MsgLog => "msglog".to_owned(),
+ Feature::MsgOffline => "msgoffline".to_owned(),
+ Feature::RosterDelimiter => "roster:delimiter".to_owned(),
+ Feature::SSLC2S => "sslc2s".to_owned(),
+ Feature::StringPrep => "stringprep".to_owned(),
+ Feature::XMPPBind => "urn:ietf:params:xml:ns:xmpp-bind".to_owned(),
+ Feature::XMPPE2E => "urn:ietf:params:xml:ns:xmpp-e2e".to_owned(),
+ Feature::XMPPSASL(xmppsasl) => match xmppsasl {
+ Some(x) => x.to_string(),
+ None => "urn:ietf:params:xml:ns:xmpp-sasl".to_owned(),
+ },
+ Feature::XMPPSession => "urn:ietf:params:xml:ns:xmpp-session".to_owned(),
+ Feature::XMPPStanzas => "urn:ietf:params:xml:ns:xmpp-stanzas".to_owned(),
+ Feature::XMPPStreams => "urn:ietf:params:xml:ns:xmpp-streams".to_owned(),
+ Feature::XMPPTLS(xmpptls) => match xmpptls {
+ Some(x) => x.to_string(),
+ None => "urn:ietf:params:xml:ns:xmpp-tls".to_owned(),
+ },
+ Feature::RFC3264 => "urn:ietf:rfc:3264".to_owned(),
+ Feature::Archive(archive) => archive.to_string(),
+ Feature::Avatar(avatar) => avatar.to_string(),
+ Feature::Delay => "urn:xmpp:delay".to_owned(),
+ Feature::Jingle(jingle) => jingle.to_string(),
+ Feature::Ping => "urn:xmpp:ping".to_owned(),
+ Feature::Receipts => "urn:xmpp:receipts".to_owned(),
+ Feature::SSN => "urn:xmpp:ssn".to_owned(),
+ Feature::Time => "urn:xmpp:time".to_owned(),
+ Feature::XMLLang => "xmllang".to_owned(),
+ Feature::VCardTemp => "vcard-temp".to_owned(),
+ Feature::Styling(_) => "urn:xmpp:styling:0".to_owned(),
+ Feature::SID(_) => "urn:xmpp:sid:0".to_owned(),
+ Feature::Unknown(s) => s.to_owned(),
+ }
+ }
+ }
+
+ pub enum Amp {
+ Errors,
+ Action(AmpAction),
+ Condition(AmpCondition),
+ }
+
+ impl ToString for Amp {
+ fn to_string(&self) -> String {
+ match self {
+ Amp::Errors => "http://jabber.org/protocol/amp#errors".to_owned(),
+ Amp::Action(amp_action) => amp_action.to_string(),
+ Amp::Condition(amp_condition) => amp_condition.to_string(),
+ }
+ }
+ }
+
+ pub enum AmpAction {
+ Alert,
+ Drop,
+ Error,
+ Notify,
+ }
+
+ impl ToString for AmpAction {
+ fn to_string(&self) -> String {
+ match self {
+ AmpAction::Alert => "http://jabber.org/protocol/amp?action=alert",
+ AmpAction::Drop => "http://jabber.org/protocol/amp?action=drop",
+ AmpAction::Error => "http://jabber.org/protocol/amp?action=error",
+ AmpAction::Notify => "http://jabber.org/protocol/amp?action=notify",
+ }
+ .to_owned()
+ }
+ }
+
+ pub enum AmpCondition {
+ Deliver,
+ ExpireAt,
+ MatchResource,
+ }
+
+ impl ToString for AmpCondition {
+ fn to_string(&self) -> String {
+ match self {
+ AmpCondition::Deliver => "http://jabber.org/protocol/amp?condition=deliver",
+ AmpCondition::ExpireAt => "http://jabber.org/protocol/amp?condition=expire-at",
+ AmpCondition::MatchResource => {
+ "http://jabber.org/protocol/amp?condition=match-resource"
+ }
+ }
+ .to_owned()
+ }
+ }
+
+ pub enum Bytestreams {
+ UDP,
+ }
+
+ impl ToString for Bytestreams {
+ fn to_string(&self) -> String {
+ match self {
+ Bytestreams::UDP => "http://jabber.org/protocol/bytestreams#udp",
+ }
+ .to_owned()
+ }
+ }
+
+ pub enum CapsVersion {
+ One(Option<CapsOne>),
+ Two(Option<CapsTwo>),
+ }
+
+ impl ToString for CapsVersion {
+ fn to_string(&self) -> String {
+ match self {
+ CapsVersion::One(caps_one) => match caps_one {
+ Some(c) => c.to_string(),
+ None => "http://jabber.org/protocol/caps".to_owned(),
+ },
+ CapsVersion::Two(caps_two) => match caps_two {
+ Some(c) => c.to_string(),
+ None => "urn:xmpp:caps".to_owned(),
+ },
+ }
+ }
+ }
+
+ pub enum CapsOne {
+ Optimize,
+ }
+
+ impl ToString for CapsOne {
+ fn to_string(&self) -> String {
+ match self {
+ CapsOne::Optimize => "http://jabber.org/protocol/caps#optimize",
+ }
+ .to_string()
+ }
+ }
+
+ pub enum CapsTwo {
+ Optimize,
+ }
+
+ impl ToString for CapsTwo {
+ fn to_string(&self) -> String {
+ match self {
+ CapsTwo::Optimize => "urn:xmpp:caps:optimize",
+ }
+ .to_owned()
+ }
+ }
+
+ pub enum Disco {
+ Info,
+ Items,
+ }
+
+ impl ToString for Disco {
+ fn to_string(&self) -> String {
+ match self {
+ Disco::Info => "http://jabber.org/protocol/disco#info",
+ Disco::Items => "http://jabber.org/protocol/disco#items",
+ }
+ .to_owned()
+ }
+ }
+
+ pub enum MUC {
+ Admin,
+ Owner,
+ Register,
+ RoomConfig,
+ RoomInfo,
+ User,
+ Hidden,
+ MembersOnly,
+ Moderated,
+ NonAnonymous,
+ Open,
+ PasswordProtected,
+ Persistent,
+ Public,
+ Rooms,
+ SemiAnonymous,
+ Temporary,
+ Unmoderated,
+ Unsecured,
+ }
+
+ impl ToString for MUC {
+ fn to_string(&self) -> String {
+ match self {
+ MUC::Admin => "http://jabber.org/protocol/muc#admin",
+ MUC::Owner => "http://jabber.org/protocol/muc#owner",
+ MUC::Register => "http://jabber.org/protocol/muc#register",
+ MUC::RoomConfig => "http://jabber.org/protocol/muc#roomconfig",
+ MUC::RoomInfo => "http://jabber.org/protocol/muc#roominfo",
+ MUC::User => "http://jabber.org/protocol/muc#user",
+ MUC::Hidden => "muc_hidden",
+ MUC::MembersOnly => "muc_membersonly",
+ MUC::Moderated => "muc_moderated",
+ MUC::NonAnonymous => "muc_nonanonymous",
+ MUC::Open => "muc_open",
+ MUC::PasswordProtected => "muc_passwordprotected",
+ MUC::Persistent => "muc_persistent",
+ MUC::Public => "muc_public",
+ MUC::Rooms => "muc_rooms",
+ MUC::SemiAnonymous => "muc_semianonymous",
+ MUC::Temporary => "muc_temporary",
+ MUC::Unmoderated => "muc_unmoderated",
+ MUC::Unsecured => "muc_unsecured",
+ }
+ .to_owned()
+ }
+ }
+
+ pub enum PubSub {
+ AccessAuthorize,
+ AccessOpen,
+ AccessPresence,
+ AccessRoster,
+ AccessWhitelist,
+ AutoCreate,
+ AutoSubscribe,
+ Collections,
+ ConfigNode,
+ CreateAndConfigure,
+ CreateNodes,
+ DeleteAny,
+ DeleteNodes,
+ FilteredNotifications,
+ GetPending,
+ InstantNodes,
+ ItemIDs,
+ LastPublished,
+ LeasedSubscription,
+ ManageSubscription,
+ MemberAffiliation,
+ MetaData,
+ ModifyAffiliations,
+ MultiCollection,
+ MultiSubscribe,
+ OutcastAffiliation,
+ PersistentItems,
+ PresenceNotifications,
+ PresenceSubscribe,
+ Publish,
+ PublishOptions,
+ PublisherAffiliation,
+ PurgeNodes,
+ RetractItems,
+ RetrieveAffiliations,
+ RetrieveDefault,
+ RetrieveItems,
+ RetrieveSubscriptions,
+ Subscribe,
+ SubscriptionOptions,
+ SubscriptionNotifications,
+ }
+
+ impl ToString for PubSub {
+ fn to_string(&self) -> String {
+ match self {
+ PubSub::AccessAuthorize => "http://jabber.org/protocol/pubsub#access-authorize",
+ PubSub::AccessOpen => "http://jabber.org/protocol/pubsub#access-open",
+ PubSub::AccessPresence => "http://jabber.org/protocol/pubsub#access-presence",
+ PubSub::AccessRoster => "http://jabber.org/protocol/pubsub#access-roster",
+ PubSub::AccessWhitelist => "http://jabber.org/protocol/pubsub#access-whitelist",
+ PubSub::AutoCreate => "http://jabber.org/protocol/pubsub#auto-create",
+ PubSub::AutoSubscribe => "http://jabber.org/protocol/pubsub#auto-subscribe",
+ PubSub::Collections => "http://jabber.org/protocol/pubsub#collections",
+ PubSub::ConfigNode => "http://jabber.org/protocol/pubsub#config-node",
+ PubSub::CreateAndConfigure => {
+ "http://jabber.org/protocol/pubsub#create-and-configure"
+ }
+ PubSub::CreateNodes => "http://jabber.org/protocol/pubsub#create-nodes",
+ PubSub::DeleteAny => "http://jabber.org/protocol/pubsub#delete-any",
+ PubSub::DeleteNodes => "http://jabber.org/protocol/pubsub#delete-nodes",
+ PubSub::FilteredNotifications => {
+ "http://jabber.org/protocol/pubsub#filtered-notifications"
+ }
+ PubSub::GetPending => "http://jabber.org/protocol/pubsub#get-pending",
+ PubSub::InstantNodes => "http://jabber.org/protocol/pubsub#instant-nodes",
+ PubSub::ItemIDs => "http://jabber.org/protocol/pubsub#item-ids",
+ PubSub::LastPublished => "http://jabber.org/protocol/pubsub#last-published",
+ PubSub::LeasedSubscription => {
+ "http://jabber.org/protocol/pubsub#leased-subscription"
+ }
+ PubSub::ManageSubscription => {
+ "http://jabber.org/protocol/pubsub#manage-subscription"
+ }
+ PubSub::MemberAffiliation => "http://jabber.org/protocol/pubsub#member-affiliation",
+ PubSub::MetaData => "http://jabber.org/protocol/pubsub#meta-data",
+ PubSub::ModifyAffiliations => {
+ "http://jabber.org/protocol/pubsub#modify-affiliations"
+ }
+ PubSub::MultiCollection => "http://jabber.org/protocol/pubsub#multi-collection",
+ PubSub::MultiSubscribe => "http://jabber.org/protocol/pubsub#multi-subscribe",
+ PubSub::OutcastAffiliation => {
+ "http://jabber.org/protocol/pubsub#outcast-affiliation"
+ }
+ PubSub::PersistentItems => "http://jabber.org/protocol/pubsub#persistent-items",
+ PubSub::PresenceNotifications => {
+ "http://jabber.org/protocol/pubsub#presence-notifications"
+ }
+ PubSub::PresenceSubscribe => "http://jabber.org/protocol/pubsub#presence-subscribe",
+ PubSub::Publish => "http://jabber.org/protocol/pubsub#publish",
+ PubSub::PublishOptions => "http://jabber.org/protocol/pubsub#publish-options",
+ PubSub::PublisherAffiliation => {
+ "http://jabber.org/protocol/pubsub#publisher-affiliation"
+ }
+ PubSub::PurgeNodes => "http://jabber.org/protocol/pubsub#purge-nodes",
+ PubSub::RetractItems => "http://jabber.org/protocol/pubsub#retract-items",
+ PubSub::RetrieveAffiliations => {
+ "http://jabber.org/protocol/pubsub#retrieve-affiliations"
+ }
+ PubSub::RetrieveDefault => "http://jabber.org/protocol/pubsub#retrieve-default",
+ PubSub::RetrieveItems => "http://jabber.org/protocol/pubsub#retrieve-items",
+ PubSub::RetrieveSubscriptions => {
+ "http://jabber.org/protocol/pubsub#retrieve-subscriptions"
+ }
+ PubSub::Subscribe => "http://jabber.org/protocol/pubsub#subscribe",
+ PubSub::SubscriptionOptions => {
+ "http://jabber.org/protocol/pubsub#subscription-options"
+ }
+ PubSub::SubscriptionNotifications => {
+ "http://jabber.org/protocol/pubsub#subscription-notifications"
+ }
+ }
+ .to_owned()
+ }
+ }
+
+ pub enum SOAP {
+ Fault,
+ }
+
+ impl ToString for SOAP {
+ fn to_string(&self) -> String {
+ match self {
+ SOAP::Fault => "http://jabber.org/protocol/soap#fault",
+ }
+ .to_owned()
+ }
+ }
+
+ pub enum WaitingList {
+ Schemes(WaitingListSchemes),
+ }
+
+ impl ToString for WaitingList {
+ fn to_string(&self) -> String {
+ match self {
+ WaitingList::Schemes(waiting_list_schemes) => waiting_list_schemes.to_string(),
+ }
+ }
+ }
+
+ pub enum WaitingListSchemes {
+ Mailto,
+ Tel,
+ }
+
+ impl ToString for WaitingListSchemes {
+ fn to_string(&self) -> String {
+ match self {
+ WaitingListSchemes::Mailto => {
+ "http://jabber.org/protocol/waitinglist/schemes/mailto"
+ }
+ WaitingListSchemes::Tel => "http://jabber.org/protocol/waitinglist/schemes/tel",
+ }
+ .to_owned()
+ }
+ }
+
+ pub enum Component {
+ Accept,
+ Connect,
+ }
+
+ impl ToString for Component {
+ fn to_string(&self) -> String {
+ match self {
+ Component::Accept => "jabber:component:accept",
+ Component::Connect => "jabber:component:connect",
+ }
+ .to_owned()
+ }
+ }
+
+ pub enum Iq {
+ Auth,
+ Gateway,
+ Last,
+ OOB,
+ Privacy,
+ Private,
+ Register,
+ Roster,
+ RPC,
+ Search,
+ Version,
+ }
+
+ impl ToString for Iq {
+ fn to_string(&self) -> String {
+ match self {
+ Iq::Auth => "jabber:iq:auth",
+ Iq::Gateway => "jabber:iq:gateway",
+ Iq::Last => "jabber:iq:last",
+ Iq::OOB => "jabber:iq:oob",
+ Iq::Privacy => "jabber:iq:privacy",
+ Iq::Private => "jabber:iq:private",
+ Iq::Register => "jabber:iq:register",
+ Iq::Roster => "jabber:iq:roster",
+ Iq::RPC => "jabber:iq:rpc",
+ Iq::Search => "jabber:iq:search",
+ Iq::Version => "jabber:iq:version",
+ }
+ .to_owned()
+ }
+ }
+
+ pub enum X {
+ Data,
+ Encrypted,
+ OOB,
+ Signed,
+ }
+
+ impl ToString for X {
+ fn to_string(&self) -> String {
+ match self {
+ X::Data => "jabber:x:data",
+ X::Encrypted => "jabber:x:encrypted",
+ X::OOB => "jabber:x:oob",
+ X::Signed => "jabber:x:signed",
+ }
+ .to_owned()
+ }
+ }
+
+ pub enum XMPPSASL {
+ C2S,
+ S2S,
+ }
+
+ impl ToString for XMPPSASL {
+ fn to_string(&self) -> String {
+ match self {
+ XMPPSASL::C2S => "urn:ietf:params:xml:ns:xmpp-sasl#c2s",
+ XMPPSASL::S2S => "urn:ietf:params:xml:ns:xmpp-sasl#s2s",
+ }
+ .to_owned()
+ }
+ }
+
+ pub enum XMPPTLS {
+ C2S,
+ S2S,
+ }
+
+ impl ToString for XMPPTLS {
+ fn to_string(&self) -> String {
+ match self {
+ XMPPTLS::C2S => "urn:ietf:params:xml:ns:xmpp-tls#c2s",
+ XMPPTLS::S2S => "urn:ietf:params:xml:ns:xmpp-tls#s2s",
+ }
+ .to_owned()
+ }
+ }
+
+ pub enum Archive {
+ Auto,
+ Manage,
+ Manual,
+ Pref,
+ }
+
+ impl ToString for Archive {
+ fn to_string(&self) -> String {
+ match self {
+ Archive::Auto => "urn:xmpp:archive:auto",
+ Archive::Manage => "urn:xmpp:archive:manage",
+ Archive::Manual => "urn:xmpp:archive:manual",
+ Archive::Pref => "urn:xmpp:archive:pref",
+ }
+ .to_owned()
+ }
+ }
+
+ pub enum Avatar {
+ Data,
+ Metadata,
+ }
+
+ impl ToString for Avatar {
+ fn to_string(&self) -> String {
+ match self {
+ Avatar::Data => "urn:xmpp:avatar:data",
+ Avatar::Metadata => "urn:xmpp:avatar:metadata",
+ }
+ .to_owned()
+ }
+ }
+
+ pub enum Jingle {
+ Apps(JingleApps),
+ }
+
+ impl ToString for Jingle {
+ fn to_string(&self) -> String {
+ match self {
+ Jingle::Apps(jingle_apps) => jingle_apps.to_string(),
+ }
+ }
+ }
+
+ pub enum JingleApps {
+ RTP(JingleAppsRTP),
+ }
+
+ impl ToString for JingleApps {
+ fn to_string(&self) -> String {
+ match self {
+ JingleApps::RTP(jingle_apps_rtp) => jingle_apps_rtp.to_string(),
+ }
+ }
+ }
+
+ pub enum JingleAppsRTP {
+ Audio,
+ Video,
+ }
+
+ impl ToString for JingleAppsRTP {
+ fn to_string(&self) -> String {
+ match self {
+ JingleAppsRTP::Audio => "urn:xmpp:jingle:apps:rtp:audio",
+ JingleAppsRTP::Video => "urn:xmpp:jingle:apps:rtp:video",
+ }
+ .to_owned()
+ }
+ }
+}
+
+mod identity {
+ use stanza::xep_0030::info;
+
+ pub struct Identity {
+ name: Option<String>,
+ category: Category,
+ }
+
+ impl From<info::Identity> for Identity {
+ fn from(value: info::Identity) -> Self {
+ let category = Category::from_category_and_type(&value.category, &value.r#type);
+ Self {
+ name: value.name,
+ category,
+ }
+ }
+ }
+
+ // TODO: separate crate for disco registry
+
+ /// categories taken from [XMPP Disco Categories](https://xmpp.org/registrar/disco-categories.html)
+ pub enum Category {
+ Account(Account),
+ Auth(Auth),
+ Authz(Authz),
+ Automation(Automation),
+ Client(Client),
+ Collaboration(Collaboration),
+ Component(Component),
+ Conference(Conference),
+ Directory(Directory),
+ Gateway(Gateway),
+ Headline(Headline),
+ Hierarchy(Hierarchy),
+ Proxy(Proxy),
+ PubSub(PubSub),
+ Server(Server),
+ Store(Store),
+ Other { category: String, r#type: String },
+ }
+
+ impl ToString for Category {
+ fn to_string(&self) -> String {
+ match self {
+ Category::Account(_account) => "account",
+ Category::Auth(_auth) => "auth",
+ Category::Authz(_authz) => "authz",
+ Category::Automation(_automation) => "automation",
+ Category::Client(_client) => "client",
+ Category::Collaboration(_collaboration) => "collaboration",
+ Category::Component(_component) => "component",
+ Category::Conference(_conference) => "conference",
+ Category::Directory(_directory) => "directory",
+ Category::Gateway(_gateway) => "gateway",
+ Category::Headline(_headline) => "headline",
+ Category::Hierarchy(_hierarchy) => "hierarchy",
+ Category::Proxy(_proxy) => "proxy",
+ Category::PubSub(_pub_sub) => "pubsub",
+ Category::Server(_server) => "server",
+ Category::Store(_store) => "store",
+ Category::Other {
+ category,
+ r#type: _,
+ } => category,
+ }
+ .to_owned()
+ }
+ }
+
+ impl Category {
+ pub fn from_category_and_type(category: &str, r#type: &str) -> Self {
+ match category {
+ "account" => Self::Account(r#type.into()),
+ "auth" => Self::Auth(r#type.into()),
+ "authz" => Self::Authz(r#type.into()),
+ "automation" => Self::Automation(r#type.into()),
+ "client" => Self::Client(r#type.into()),
+ "collaboration" => Self::Collaboration(r#type.into()),
+ "component" => Self::Component(r#type.into()),
+ "conference" => Self::Conference(r#type.into()),
+ "directory" => Self::Directory(r#type.into()),
+ "gateway" => Self::Gateway(r#type.into()),
+ "headline" => Self::Headline(r#type.into()),
+ "hierarchy" => Self::Hierarchy(r#type.into()),
+ "proxy" => Self::Proxy(r#type.into()),
+ "pubsub" => Self::PubSub(r#type.into()),
+ "server" => Self::Server(r#type.into()),
+ "store" => Self::Store(r#type.into()),
+ s => Self::Other {
+ category: s.to_owned(),
+ r#type: r#type.to_owned(),
+ },
+ }
+ }
+
+ pub fn r#type(&self) -> String {
+ match self {
+ Category::Account(account) => account.to_string(),
+ Category::Auth(auth) => auth.to_string(),
+ Category::Authz(authz) => authz.to_string(),
+ Category::Automation(automation) => automation.to_string(),
+ Category::Client(client) => client.to_string(),
+ Category::Collaboration(collaboration) => collaboration.to_string(),
+ Category::Component(component) => component.to_string(),
+ Category::Conference(conference) => conference.to_string(),
+ Category::Directory(directory) => directory.to_string(),
+ Category::Gateway(gateway) => gateway.to_string(),
+ Category::Headline(headline) => headline.to_string(),
+ Category::Hierarchy(hierarchy) => hierarchy.to_string(),
+ Category::Proxy(proxy) => proxy.to_string(),
+ Category::PubSub(pub_sub) => pub_sub.to_string(),
+ Category::Server(server) => server.to_string(),
+ Category::Store(store) => store.to_string(),
+ Category::Other {
+ category: _,
+ r#type,
+ } => r#type.to_owned(),
+ }
+ }
+ }
+
+ pub enum Account {
+ Admin,
+ Anonymous,
+ Registered,
+ Other(String),
+ }
+
+ impl ToString for Account {
+ fn to_string(&self) -> String {
+ match self {
+ Account::Admin => "admin",
+ Account::Anonymous => "anonymous",
+ Account::Registered => "registered",
+ Account::Other(s) => s,
+ }
+ .to_owned()
+ }
+ }
+
+ impl From<&str> for Account {
+ fn from(value: &str) -> Self {
+ match value {
+ "admin" => Self::Admin,
+ "anonymous" => Self::Anonymous,
+ "registered" => Self::Registered,
+ s => Self::Other(s.to_string()),
+ }
+ }
+ }
+
+ pub enum Auth {
+ Cert,
+ Generic,
+ LDAP,
+ NTLM,
+ PAM,
+ Radius,
+ Other(String),
+ }
+
+ impl ToString for Auth {
+ fn to_string(&self) -> String {
+ match self {
+ Auth::Cert => "cert",
+ Auth::Generic => "generic",
+ Auth::LDAP => "ldap",
+ Auth::NTLM => "ntlm",
+ Auth::PAM => "pam",
+ Auth::Radius => "radius",
+ Auth::Other(s) => s,
+ }
+ .to_owned()
+ }
+ }
+
+ impl From<&str> for Auth {
+ fn from(value: &str) -> Self {
+ match value {
+ "cert" => Self::Cert,
+ "generic" => Self::Generic,
+ "ldap" => Self::LDAP,
+ "ntlm" => Self::NTLM,
+ "pam" => Self::PAM,
+ "radius" => Self::Radius,
+ s => Self::Other(s.to_owned()),
+ }
+ }
+ }
+
+ pub enum Authz {
+ Ephemeral,
+ Other(String),
+ }
+
+ impl ToString for Authz {
+ fn to_string(&self) -> String {
+ match self {
+ Authz::Ephemeral => "ephemeral",
+ Authz::Other(s) => s,
+ }
+ .to_owned()
+ }
+ }
+
+ impl From<&str> for Authz {
+ fn from(value: &str) -> Self {
+ match value {
+ "ephemeral" => Self::Ephemeral,
+ s => Self::Other(s.to_owned()),
+ }
+ }
+ }
+
+ pub enum Automation {
+ CommandList,
+ CommandNode,
+ RPC,
+ SOAP,
+ Translation,
+ Other(String),
+ }
+
+ impl ToString for Automation {
+ fn to_string(&self) -> String {
+ match self {
+ Automation::CommandList => "command-list",
+ Automation::CommandNode => "command-node",
+ Automation::RPC => "rpc",
+ Automation::SOAP => "soap",
+ Automation::Translation => "translation",
+ Automation::Other(s) => s,
+ }
+ .to_owned()
+ }
+ }
+
+ impl From<&str> for Automation {
+ fn from(value: &str) -> Self {
+ match value {
+ "command-list" => Self::CommandList,
+ "command-node" => Self::CommandNode,
+ "rpc" => Self::RPC,
+ "soap" => Self::SOAP,
+ "translation" => Self::Translation,
+ s => Self::Other(s.to_owned()),
+ }
+ }
+ }
+
+ pub enum Client {
+ Bot,
+ Console,
+ Game,
+ Handheld,
+ PC,
+ Phone,
+ SMS,
+ Tablet,
+ Web,
+ Other(String),
+ }
+
+ impl ToString for Client {
+ fn to_string(&self) -> String {
+ match self {
+ Client::Bot => "bot",
+ Client::Console => "console",
+ Client::Game => "game",
+ Client::Handheld => "handheld",
+ Client::PC => "pc",
+ Client::Phone => "phone",
+ Client::SMS => "sms",
+ Client::Tablet => "tablet",
+ Client::Web => "web",
+ Client::Other(s) => s,
+ }
+ .to_owned()
+ }
+ }
+
+ impl From<&str> for Client {
+ fn from(value: &str) -> Self {
+ match value {
+ "bot" => Self::Bot,
+ "console" => Self::Console,
+ "game" => Self::Game,
+ "handheld" => Self::Handheld,
+ "pc" => Self::PC,
+ "phone" => Self::Phone,
+ "sms" => Self::SMS,
+ "tablet" => Self::Tablet,
+ "web" => Self::Web,
+ s => Self::Other(s.to_owned()),
+ }
+ }
+ }
+
+ pub enum Collaboration {
+ Whiteboard,
+ Other(String),
+ }
+
+ impl ToString for Collaboration {
+ fn to_string(&self) -> String {
+ match self {
+ Collaboration::Whiteboard => "whiteboard",
+ Collaboration::Other(s) => s,
+ }
+ .to_owned()
+ }
+ }
+
+ impl From<&str> for Collaboration {
+ fn from(value: &str) -> Self {
+ match value {
+ "whiteboard" => Self::Whiteboard,
+ s => Self::Other(s.to_owned()),
+ }
+ }
+ }
+
+ pub enum Component {
+ Archive,
+ C2S,
+ Generic,
+ Load,
+ Log,
+ Presence,
+ Router,
+ S2S,
+ SM,
+ Stats,
+ Other(String),
+ }
+
+ impl ToString for Component {
+ fn to_string(&self) -> String {
+ match self {
+ Component::Archive => "archive",
+ Component::C2S => "c2s",
+ Component::Generic => "generic",
+ Component::Load => "load",
+ Component::Log => "log",
+ Component::Presence => "presence",
+ Component::Router => "router",
+ Component::S2S => "s2s",
+ Component::SM => "sm",
+ Component::Stats => "stats",
+ Component::Other(s) => s,
+ }
+ .to_owned()
+ }
+ }
+
+ impl From<&str> for Component {
+ fn from(value: &str) -> Self {
+ match value {
+ "archive" => Self::Archive,
+ "c2s" => Self::C2S,
+ "generic" => Self::Generic,
+ "load" => Self::Load,
+ "log" => Self::Log,
+ "presence" => Self::Presence,
+ "router" => Self::Router,
+ "s2s" => Self::S2S,
+ "sm" => Self::SM,
+ "stats" => Self::Stats,
+ s => Self::Other(s.to_owned()),
+ }
+ }
+ }
+
+ pub enum Conference {
+ IRC,
+ Text,
+ Other(String),
+ }
+
+ impl ToString for Conference {
+ fn to_string(&self) -> String {
+ match self {
+ Conference::IRC => "irc",
+ Conference::Text => "text",
+ Conference::Other(s) => s,
+ }
+ .to_owned()
+ }
+ }
+
+ impl From<&str> for Conference {
+ fn from(value: &str) -> Self {
+ match value {
+ "irc" => Self::IRC,
+ "text" => Self::Text,
+ s => Self::Other(s.to_owned()),
+ }
+ }
+ }
+
+ pub enum Directory {
+ Chatroom,
+ Group,
+ User,
+ WaitingList,
+ Other(String),
+ }
+
+ impl ToString for Directory {
+ fn to_string(&self) -> String {
+ match self {
+ Directory::Chatroom => "chatroom",
+ Directory::Group => "group",
+ Directory::User => "user",
+ Directory::WaitingList => "waiting-list",
+ Directory::Other(s) => s,
+ }
+ .to_string()
+ }
+ }
+
+ impl From<&str> for Directory {
+ fn from(value: &str) -> Self {
+ match value {
+ "chatroom" => Self::Chatroom,
+ "group" => Self::Group,
+ "user" => Self::User,
+ "waiting-list" => Self::WaitingList,
+ s => Self::Other(s.to_owned()),
+ }
+ }
+ }
+
+ pub enum Gateway {
+ Aim,
+ Discord,
+ Facebook,
+ GaduGadu,
+ HttpWS,
+ ICQ,
+ IRC,
+ LCS,
+ Mattermost,
+ MRIM,
+ MSN,
+ MySpaceIM,
+ OCS,
+ PSTN,
+ QQ,
+ Sametime,
+ Signal,
+ SIMPLE,
+ Skype,
+ SMS,
+ SMTP,
+ Steam,
+ Telegram,
+ Tlen,
+ Xfire,
+ XMPP,
+ Yahoo,
+ Other(String),
+ }
+
+ impl ToString for Gateway {
+ fn to_string(&self) -> String {
+ match self {
+ Gateway::Aim => "aim",
+ Gateway::Discord => "discord",
+ Gateway::Facebook => "facebook",
+ Gateway::GaduGadu => "gadu-gadu",
+ Gateway::HttpWS => "http-ws",
+ Gateway::ICQ => "icq",
+ Gateway::IRC => "irc",
+ Gateway::LCS => "lcs",
+ Gateway::Mattermost => "mattermost",
+ Gateway::MRIM => "mrim",
+ Gateway::MSN => "msn",
+ Gateway::MySpaceIM => "myspaceim",
+ Gateway::OCS => "ocs",
+ Gateway::PSTN => "pstn",
+ Gateway::QQ => "qq",
+ Gateway::Sametime => "sametime",
+ Gateway::Signal => "signal",
+ Gateway::SIMPLE => "simple",
+ Gateway::Skype => "skype",
+ Gateway::SMS => "sms",
+ Gateway::SMTP => "smtp",
+ Gateway::Steam => "steam",
+ Gateway::Telegram => "telegram",
+ Gateway::Tlen => "tlen",
+ Gateway::Xfire => "xfire",
+ Gateway::XMPP => "xmpp",
+ Gateway::Yahoo => "yahoo",
+ Gateway::Other(s) => s,
+ }
+ .to_owned()
+ }
+ }
+
+ impl From<&str> for Gateway {
+ fn from(value: &str) -> Self {
+ match value {
+ "aim" => Self::Aim,
+ "discord" => Self::Discord,
+ "facebook" => Self::Facebook,
+ "gadu-gadu" => Self::GaduGadu,
+ "http-ws" => Self::HttpWS,
+ "icq" => Self::ICQ,
+ "irc" => Self::IRC,
+ "lcs" => Self::LCS,
+ "mattermost" => Self::Mattermost,
+ "mrim" => Self::MRIM,
+ "msn" => Self::MSN,
+ "myspaceim" => Self::MySpaceIM,
+ "ocs" => Self::OCS,
+ "pstn" => Self::PSTN,
+ "qq" => Self::QQ,
+ "sametime" => Self::Sametime,
+ "signal" => Self::Signal,
+ "simple" => Self::SIMPLE,
+ "skype" => Self::Skype,
+ "sms" => Self::SMS,
+ "smtp" => Self::SMTP,
+ "steam" => Self::Steam,
+ "telegram" => Self::Telegram,
+ "tlen" => Self::Tlen,
+ "xfire" => Self::Xfire,
+ "xmpp" => Self::XMPP,
+ "yahoo" => Self::Yahoo,
+ s => Self::Other(s.to_owned()),
+ }
+ }
+ }
+
+ pub enum Headline {
+ NewMail,
+ RSS,
+ Weather,
+ Other(String),
+ }
+
+ impl ToString for Headline {
+ fn to_string(&self) -> String {
+ match self {
+ Headline::NewMail => "new-mail",
+ Headline::RSS => "rss",
+ Headline::Weather => "weather",
+ Headline::Other(s) => s,
+ }
+ .to_string()
+ }
+ }
+
+ impl From<&str> for Headline {
+ fn from(value: &str) -> Self {
+ match value {
+ "new-mail" => Self::NewMail,
+ "rss" => Self::RSS,
+ "weather" => Self::Weather,
+ s => Self::Other(s.to_owned()),
+ }
+ }
+ }
+
+ pub enum Hierarchy {
+ Branch,
+ Leaf,
+ Other(String),
+ }
+
+ impl ToString for Hierarchy {
+ fn to_string(&self) -> String {
+ match self {
+ Hierarchy::Branch => "branch",
+ Hierarchy::Leaf => "leaf",
+ Hierarchy::Other(s) => s,
+ }
+ .to_string()
+ }
+ }
+
+ impl From<&str> for Hierarchy {
+ fn from(value: &str) -> Self {
+ match value {
+ "branch" => Self::Branch,
+ "leaf" => Self::Leaf,
+ s => Self::Other(s.to_owned()),
+ }
+ }
+ }
+
+ pub enum Proxy {
+ Bytestreams,
+ Other(String),
+ }
+
+ impl ToString for Proxy {
+ fn to_string(&self) -> String {
+ match self {
+ Proxy::Bytestreams => "bytestreams",
+ Proxy::Other(s) => s,
+ }
+ .to_owned()
+ }
+ }
+
+ impl From<&str> for Proxy {
+ fn from(value: &str) -> Self {
+ match value {
+ "bytestreams" => Self::Bytestreams,
+ s => Self::Other(s.to_owned()),
+ }
+ }
+ }
+
+ pub enum PubSub {
+ Collection,
+ Leaf,
+ PEP,
+ Service,
+ // TODO: should there be other in each of these
+ Other(String),
+ }
+
+ impl ToString for PubSub {
+ fn to_string(&self) -> String {
+ match self {
+ PubSub::Collection => "collection",
+ PubSub::Leaf => "leaf",
+ PubSub::PEP => "pep",
+ PubSub::Service => "service",
+ PubSub::Other(s) => s,
+ }
+ .to_owned()
+ }
+ }
+
+ impl From<&str> for PubSub {
+ fn from(value: &str) -> Self {
+ match value {
+ "collection" => Self::Collection,
+ "leaf" => Self::Leaf,
+ "pep" => Self::PEP,
+ "service" => Self::Service,
+ s => Self::Other(s.to_owned()),
+ }
+ }
+ }
+
+ pub enum Server {
+ IM,
+ Other(String),
+ }
+
+ impl ToString for Server {
+ fn to_string(&self) -> String {
+ match self {
+ Server::IM => "im",
+ Server::Other(s) => s,
+ }
+ .to_string()
+ }
+ }
+
+ impl From<&str> for Server {
+ fn from(value: &str) -> Self {
+ match value {
+ "im" => Self::IM,
+ s => Self::Other(s.to_owned()),
+ }
+ }
+ }
+
+ pub enum Store {
+ Berkeley,
+ File,
+ Generic,
+ LDAP,
+ MySQL,
+ Oracle,
+ Postgres,
+ Other(String),
+ }
+
+ impl ToString for Store {
+ fn to_string(&self) -> String {
+ match self {
+ Store::Berkeley => "berkeley",
+ Store::File => "file",
+ Store::Generic => "generic",
+ Store::LDAP => "ldap",
+ Store::MySQL => "mysql",
+ Store::Oracle => "oracle",
+ Store::Postgres => "postgres",
+ Store::Other(s) => s,
+ }
+ .to_string()
+ }
+ }
+
+ impl From<&str> for Store {
+ fn from(value: &str) -> Self {
+ match value {
+ "berkeley" => Self::Berkeley,
+ "file" => Self::File,
+ "generic" => Self::Generic,
+ "ldap" => Self::LDAP,
+ "mysql" => Self::MySQL,
+ "oracle" => Self::Oracle,
+ "postgres" => Self::Postgres,
+ s => Self::Other(s.to_owned()),
+ }
+ }
+ }
+}
diff --git a/filamento/src/lib.rs b/filamento/src/lib.rs
index 89da1a3..bc946ae 100644
--- a/filamento/src/lib.rs
+++ b/filamento/src/lib.rs
@@ -36,6 +36,7 @@ use uuid::Uuid;
pub mod chat;
pub mod db;
+pub mod disco;
pub mod error;
mod logic;
pub mod presence;
@@ -97,6 +98,8 @@ pub enum Command {
/// send a message to a jid (any kind of jid that can receive a message, e.g. a user or a
/// chatroom). if disconnected, will be cached so when client connects, message will be sent.
SendMessage(JID, Body, oneshot::Sender<Result<(), WriteError>>),
+ /// disco info request
+ DiscoInfo(JID, oneshot::Sender<Result>),
}
#[derive(Debug, Clone)]