📄 xmpp_c2s.cxx
字号:
void XMPP::C2S::StreamHandler::OnSessionReleased(){ m_SessionReleasedHandlers.Fire(*this);}void XMPP::C2S::StreamHandler::OnElement(PXML& pdu){ switch (m_State) { case Null: HandleNullState(pdu); break; case RegStarted: HandleRegStartedState(pdu); break; case TLSStarted: HandleTLSStartedState(pdu); break;#if P_SASL2 case SASLStarted: HandleSASLStartedState(pdu); break;#endif case NonSASLStarted: HandleNonSASLStartedState(pdu); break; case StreamSent: HandleStreamSentState(pdu); break; case BindSent: HandleBindSentState(pdu); break; case SessionSent: HandleSessionSentState(pdu); break; case Established: HandleEstablishedState(pdu); break; default: // Error PAssertAlways(PLogicError); }}void XMPP::C2S::StreamHandler::HandleNullState(PXML& pdu){ if (pdu.GetRootElement()->GetName() != "stream:features") { Stop(); return; } /* This is what we are kind of expecting (more or less) <stream:features> <starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'> <required/> </starttls> <mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'> <mechanism>DIGEST-MD5</mechanism> <mechanism>PLAIN</mechanism> </mechanisms> </stream:features> */// PXMLElement * starttls = pdu.GetRootElement()->GetElement("starttls"); PStringSet ourMechSet; // We might have to negotiate the TLS first, but we set up the SASL phase now#if P_SASL2 PXMLElement * mechList = pdu.GetRootElement()->GetElement("mechanisms"); if (!mechList || !m_SASL.Init(m_JID.GetServer(), ourMechSet)) { // SASL initialisation failed, goodbye... Stop(); return; } PXMLElement * mech; PINDEX i = 0; while ((mech = mechList->GetElement("mechanism", i++)) != 0) { if (ourMechSet.Contains(mech->GetData())) // Hit break; } if (mech != NULL) m_Mechanism = mech->GetData();#endif // That's how it'll be once we support TLS /*if (starttls && (m_UseTLS || starttls->GetElement("required") != 0)) { // we must start the TLS nogotiation... SetState(XMPP::C2S::StreamHandler::TLSStarted); } else*/ StartAuthNegotiation();}void XMPP::C2S::StreamHandler::HandleRegStartedState(PXML& pdu){ PXMLElement * elem = pdu.GetRootElement(); if (elem->GetName() != "iq" || elem->GetAttribute("type") != "result") { Stop(); return; } m_NewAccount = FALSE; StartAuthNegotiation();}void XMPP::C2S::StreamHandler::HandleTLSStartedState(PXML& /*pdu*/){ PAssertAlways(PUnimplementedFunction);}#if P_SASL2void XMPP::C2S::StreamHandler::HandleSASLStartedState(PXML& pdu){ PString name = pdu.GetRootElement()->GetName(); if (name == "challenge") { PString input = pdu.GetRootElement()->GetData(); PString output; if (m_SASL.Negotiate(input, output) == PSASLClient::Fail) { Stop(); return; } PString response("<response xmlns='urn:ietf:params:xml:ns:xmpp-sasl'"); if (output.IsEmpty()) response += "/>"; else { response += ">"; response += output; response += "</response>"; } m_Stream->Write(response); } else if (name == "success") { m_SASL.End(); OnOpen(*m_Stream, 0); // open the inner stream (i.e. reset the parser) SetState(XMPP::C2S::StreamHandler::StreamSent); } else { Stop(); }}#endifvoid XMPP::C2S::StreamHandler::HandleNonSASLStartedState(PXML& pdu){ PXMLElement * elem = pdu.GetRootElement(); if (elem->GetName() != "iq" || elem->GetAttribute("type") != "result") { Stop(); return; } elem = elem->GetElement(XMPP::IQQuery); if (elem == NULL) { // Authentication succeded SetState(XMPP::C2S::StreamHandler::Established); } else { PString auth(PString::Printf, "<iq type='set' to='%s' id='auth2'>" "<query xmlns='jabber:iq:auth'>", (const char *)m_JID.GetServer()); PINDEX i = 0; PXMLElement * item; BOOL uid = FALSE, pwd = FALSE, digest = FALSE, res = FALSE; while ((item = (PXMLElement *)elem->GetElement(i++)) != NULL) { PString name = item->GetName(); if (name *= "username") uid = TRUE; else if (name *= "password") pwd = TRUE; else if (name *= "digest") digest = TRUE; else if (name *= "resource") res = TRUE; } if (uid) auth += "<username>" + m_JID.GetUser() + "</username>"; if (res) auth += "<resource>" + m_JID.GetResource() + "</resource>";#if P_SSL if (digest) { PMessageDigest::Result bin_digest; PMessageDigestSHA1::Encode(m_StreamID + m_Password, bin_digest); PString digest; const BYTE * data = bin_digest.GetPointer(); for (PINDEX i = 0, max = bin_digest.GetSize(); i < max ; i++) digest.sprintf("%02x", (unsigned)data[i]); auth += "<digest>" + digest + "</digest>"; } else #endif if (pwd) auth += "<password>" + m_Password + "</password>"; auth += "</query></iq>"; m_Stream->Write(auth); }}void XMPP::C2S::StreamHandler::HandleStreamSentState(PXML& pdu){ if (pdu.GetRootElement()->GetName() != "stream:features") { Stop(); return; } /* <stream:features> <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/> <session xmlns='urn:ietf:params:xml:ns:xmpp-session'/> </stream:features> */ m_HasBind = pdu.GetRootElement()->GetElement("bind") != NULL; m_HasSession = pdu.GetRootElement()->GetElement("session") != NULL; if (m_HasBind) { PString bind("<iq type='set' id='bind_1'>" "<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'"); if (m_JID.GetResource().IsEmpty()) bind += "/></iq>"; else { bind += "><resource>"; bind += m_JID.GetResource(); bind += "</resource></bind></iq>"; } m_Stream->Write(bind); SetState(XMPP::C2S::StreamHandler::BindSent); } else if (m_HasSession) HandleBindSentState(pdu); else SetState(XMPP::C2S::StreamHandler::Established);}void XMPP::C2S::StreamHandler::HandleBindSentState(PXML& pdu){ if (m_State == XMPP::C2S::StreamHandler::BindSent) { PXMLElement * elem = pdu.GetRootElement(); if (elem->GetName() != "iq" || elem->GetAttribute("type") != "result") { Stop(); return; } if ((elem = elem->GetElement("bind")) == NULL || (elem = elem->GetElement("jid")) == NULL) { Stop(); return; } PString jid = elem->GetData(); } if (m_HasSession) { PString session = "<iq id='sess_1' type='set'><session xmlns='urn:ietf:params:xml:ns:xmpp-session'/></iq>"; m_Stream->Write(session); SetState(XMPP::C2S::StreamHandler::SessionSent); } else SetState(XMPP::C2S::StreamHandler::Established);}void XMPP::C2S::StreamHandler::HandleSessionSentState(PXML& pdu){ PXMLElement * elem = pdu.GetRootElement(); if (elem->GetName() != "iq" || elem->GetAttribute("type") != "result") { Stop(); return; } SetState(XMPP::C2S::StreamHandler::Established);}void XMPP::C2S::StreamHandler::HandleEstablishedState(PXML& pdu){ PCaselessString name = pdu.GetRootElement()->GetName(); if (name == "stream:error") { OnError(pdu); Stop(); } else if (name == XMPP::MessageStanza) { XMPP::Message msg(pdu); if (msg.IsValid()) OnMessage(msg); else Stop("bad-format"); } else if (name == XMPP::PresenceStanza) { XMPP::Presence pre(pdu); if (pre.IsValid()) OnPresence(pre); else Stop("bad-format"); } else if (name == XMPP::IQStanza) { XMPP::IQ iq(pdu); if (iq.IsValid()) OnIQ(iq); else Stop("bad-format"); } else Stop("unsupported-stanza-type");}void XMPP::C2S::StreamHandler::OnError(PXML& pdu){ m_ErrorHandlers.Fire(pdu);}void XMPP::C2S::StreamHandler::OnMessage(XMPP::Message& pdu){ JID from = pdu.GetFrom(); /* Fire the generic message handles only if there isn't a notifier list for this particular originator or the list is empty */ if (!m_MessageSenderHandlers.Contains(from) || !m_MessageSenderHandlers[from].Fire(pdu)) m_MessageHandlers.Fire(pdu);}void XMPP::C2S::StreamHandler::OnPresence(XMPP::Presence& pdu){ m_PresenceHandlers.Fire(pdu);}void XMPP::C2S::StreamHandler::OnIQ(XMPP::IQ& pdu){ XMPP::IQ::IQType type = pdu.GetType(); XMPP::IQ * origMsg = NULL; if (type == XMPP::IQ::Result || type == XMPP::IQ::Error) { PString id = pdu.GetID(); m_PendingIQsLock.Wait(); for (PINDEX i = 0, max = m_PendingIQs.GetSize() ; i < max ; i++) if (((XMPP::IQ&)(m_PendingIQs[i])).GetID() == id) { origMsg = (XMPP::IQ *)m_PendingIQs.RemoveAt(i); pdu.SetOriginalMessage(origMsg); } m_PendingIQsLock.Signal(); } if (origMsg != NULL) origMsg->GetResponseHandlers().Fire(pdu); // Let's see if someone is registered to handle this namespace PXMLElement * query = (PXMLElement *)pdu.GetRootElement()->GetElement(0); PString xmlns = query != NULL ? query->GetAttribute(XMPP::Namespace) : PString::Empty(); if (!xmlns.IsEmpty() && m_IQNamespaceHandlers.Contains(xmlns)) m_IQNamespaceHandlers[xmlns].Fire(pdu); // Now the "normal" handlers m_IQHandlers.Fire(pdu); // If it was a set or a get and nobody took care of it, we send and error back if ((type == XMPP::IQ::Set || type == XMPP::IQ::Get) && !pdu.HasBeenProcessed()) { XMPP::IQ * error = pdu.BuildError("cancel", "feature-not-implemented"); Send(error); }}#endif // P_EXPAT// End of File ///////////////////////////////////////////////////////////////
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -