diff options
Diffstat (limited to '')
| -rw-r--r-- | filamento/src/disco.rs | 1640 | ||||
| -rw-r--r-- | filamento/src/lib.rs | 3 | 
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)] | 
