📄 xmpp.cxx
字号:
/* * xmpp.cxx * * Extensible Messaging and Presence Protocol (XMPP) Core * * Portable Windows Library * * Copyright (c) 2004 Reitek S.p.A. * * The contents of this file are subject to the Mozilla Public License * Version 1.0 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. * * The Original Code is Portable Windows Library. * * The Initial Developer of the Original Code is Post Increment * * Contributor(s): ______________________________________. * * $Log: xmpp.cxx,v $ * Revision 1.5 2004/05/09 07:23:50 rjongbloed * More work on XMPP, thanks Federico Pinna and Reitek S.p.A. * * Revision 1.4 2004/04/27 06:19:12 rjongbloed * Fixed GCC 3.4 warnings and improved crash avoidance with NULL pointers. * * Revision 1.3 2004/04/26 04:17:19 rjongbloed * Fixed GNU warnings * * Revision 1.2 2004/04/26 01:51:58 rjongbloed * More implementation of XMPP, thanks a lot to Federico Pinna & Reitek S.p.A. * * Revision 1.1 2004/04/22 12:31:00 rjongbloed * Added PNotifier extensions and XMPP (Jabber) support, * thanks to Federico Pinna and Reitek S.p.A. * * */#ifdef __GNUC__#pragma implementation "xmpp.h"#endif#include <ptlib.h>#include <ptclib/xmpp.h>#if P_EXPAT///////////////////////////////////////////////////////const PString XMPP::Language("xml:lang");const PString XMPP::Namespace("xmlns");const PString XMPP::MessageStanza("message");const PString XMPP::PresenceStanza("presence");const PString XMPP::IQStanza("iq");const PString XMPP::IQQuery("query");///////////////////////////////////////////////////////XMPP::JID::JID(const char * jid){ ParseJID(jid);}XMPP::JID::JID(const PString& jid){ ParseJID(jid);}XMPP::JID::JID(const PString& user, const PString& server, const PString& resource) : m_User(user), m_Server(server), m_Resource(resource), m_IsDirty(TRUE){ BuildJID();}PObject::Comparison XMPP::JID::Compare(const PObject & obj) const{ if (m_IsDirty) BuildJID(); if (PIsDescendant(&obj, XMPP::JID)) return m_JID.Compare((const PString&)((const XMPP::JID&)obj)); else if (PIsDescendant(&obj, PString)) return m_JID.Compare((const PString&)obj); PAssertAlways(PInvalidCast); return PObject::LessThan;}XMPP::JID& XMPP::JID::operator=(const PString & jid){ ParseJID(jid); return *this;}XMPP::JID::operator const PString&() const{ if (m_IsDirty) BuildJID(); return m_JID;}void XMPP::JID::SetUser(const PString& user){ m_IsDirty = TRUE; m_User = user;}void XMPP::JID::SetServer(const PString& server){ m_IsDirty = TRUE; m_Server = server;}void XMPP::JID::SetResource(const PString& resource){ m_IsDirty = TRUE; m_Resource = resource;}void XMPP::JID::PrintOn(ostream & strm) const{ strm << m_JID;}void XMPP::JID::ParseJID(const PString& jid){ m_User[0] = m_Server[0] = m_Resource[0] = 0; PINDEX i = jid.Find('@'); if (i == (jid.GetLength() - 1)) return; else if (i == P_MAX_INDEX) SetServer(jid); else { SetUser(jid.Left(i)); SetServer(jid.Mid(i + 1)); } i = m_Server.Find('/'); if (i != P_MAX_INDEX && i != 0) { SetResource(m_Server.Mid(i + 1)); SetServer(m_Server.Left(i)); } BuildJID();}void XMPP::JID::BuildJID() const{ if (m_User.IsEmpty()) m_JID = m_Server; else m_JID = m_User + "@" + m_Server; if (!m_Resource.IsEmpty()) m_JID += "/" + m_Resource; m_IsDirty = FALSE;}///////////////////////////////////////////////////////PObject::Comparison XMPP::BareJID::Compare(const PObject & obj) const{ if (m_IsDirty) BuildJID(); XMPP::BareJID that; if (PIsDescendant(&obj, XMPP::JID)) that = (const PString&)((const XMPP::JID&)obj); else if (PIsDescendant(&obj, PString)) that = (const PString&)obj; else { PAssertAlways(PInvalidCast); return PObject::LessThan; } return m_JID.Compare(that.m_JID);}XMPP::BareJID& XMPP::BareJID::operator=(const PString & jid){ ParseJID(jid); return *this;}///////////////////////////////////////////////////////XMPP::Stream::Stream(XMPP::Transport * transport) : m_Parser(new PXMLStreamParser){ if (transport) Open(transport);}XMPP::Stream::~Stream(){ delete m_Parser; Close();}BOOL XMPP::Stream::Close(){ if (IsOpen()) { OnClose(); return PIndirectChannel::Close(); } return FALSE;}BOOL XMPP::Stream::Write(const void * buf, PINDEX len){ PTRACE(5, "XMPP\tSND: " << (const char *)buf); return PIndirectChannel::Write(buf, len);}BOOL XMPP::Stream::Write(const PString& data){ return Write((const char *)data, data.GetLength());}BOOL XMPP::Stream::Write(const PXML& pdu){ PXMLElement * root = pdu.GetRootElement(); if (root == NULL) return FALSE; PStringStream os; root->Output(os, pdu, 0); return Write(os.GetPointer(), os.GetLength());}PXML * XMPP::Stream::Read(){ return m_Parser->Read(this);}void XMPP::Stream::Reset(){ delete m_Parser; m_Parser = new PXMLStreamParser;}///////////////////////////////////////////////////////XMPP::BaseStreamHandler::BaseStreamHandler() : PThread(0x1000, PThread::NoAutoDeleteThread), m_Stream(NULL), m_AutoReconnect(TRUE), m_ReconnectTimeout(1000){}XMPP::BaseStreamHandler::~BaseStreamHandler(){ Stop();}BOOL XMPP::BaseStreamHandler::Start(XMPP::Transport * transport){ if (m_Stream != NULL) Stop(); m_Stream = new XMPP::Stream(); m_Stream->OpenHandlers().Add(new PCREATE_NOTIFIER(OnOpen)); m_Stream->CloseHandlers().Add(new PCREATE_NOTIFIER(OnClose)); if (!transport->IsOpen() && !transport->Open()) return FALSE; if (m_Stream->Open(transport)) { if (IsSuspended()) Resume(); else Restart(); return TRUE; } return FALSE;}BOOL XMPP::BaseStreamHandler::Stop(const PString& _error){ if (m_Stream == NULL) return FALSE; if (!_error.IsEmpty()) { PString error = "<stream:error><"; error += _error; error += " xmlns='urn:ietf:params:xml:ns:xmpp-streams'/></stream:error>"; m_Stream->Write((const char *)error, error.GetLength()); } m_Stream->Close(); if (PThread::Current() != this) WaitForTermination(10000); delete m_Stream; m_Stream = NULL; return FALSE;}void XMPP::BaseStreamHandler::OnOpen(XMPP::Stream&, INT){}void XMPP::BaseStreamHandler::OnClose(XMPP::Stream&, INT){}void XMPP::BaseStreamHandler::SetAutoReconnect(BOOL b, long t){ m_AutoReconnect = b; m_ReconnectTimeout = t;}BOOL XMPP::BaseStreamHandler::Write(const void * buf, PINDEX len){ if (m_Stream == NULL) return FALSE; return m_Stream->Write(buf, len);}BOOL XMPP::BaseStreamHandler::Write(const PString& data){ if (m_Stream == NULL) return FALSE; return m_Stream->Write(data);}BOOL XMPP::BaseStreamHandler::Write(const PXML& pdu){ if (m_Stream == NULL) return FALSE; return m_Stream->Write(pdu);}void XMPP::BaseStreamHandler::OnElement(PXML& pdu){ m_ElementHandlers.Fire(pdu);}void XMPP::BaseStreamHandler::Main(){ PXML * pdu; for (;;) { if (!m_Stream || !m_Stream->IsOpen()) break; pdu = m_Stream->Read(); if (pdu != NULL) { if (PTrace::CanTrace(5)) { ostream& os = PTrace::Begin(5, __FILE__, __LINE__); os << "XMPP\tRCV: "; pdu->GetRootElement()->Output(os, *pdu, 0); os << PTrace::End; } OnElement(*pdu); } else if (m_Stream->GetErrorCode() != PChannel::Timeout) break; delete pdu; }}///////////////////////////////////////////////////////const PString XMPP::Stanza::ID("id");const PString XMPP::Stanza::From("from");const PString XMPP::Stanza::To("to");void XMPP::Stanza::SetID(const PString& id){ if (!id.IsEmpty()) PAssertNULL(rootElement)->SetAttribute(XMPP::Stanza::ID, id);}void XMPP::Stanza::SetFrom(const PString& from){ if (!from.IsEmpty()) PAssertNULL(rootElement)->SetAttribute(XMPP::Stanza::From, from);}void XMPP::Stanza::SetTo(const PString& to){ if (!to.IsEmpty()) PAssertNULL(rootElement)->SetAttribute(XMPP::Stanza::To, to);}PString XMPP::Stanza::GetID() const{ return PAssertNULL(rootElement)->GetAttribute(XMPP::Stanza::ID); }PString XMPP::Stanza::GetFrom() const{ return PAssertNULL(rootElement)->GetAttribute(XMPP::Stanza::From); }PString XMPP::Stanza::GetTo() const{ return PAssertNULL(rootElement)->GetAttribute(XMPP::Stanza::To); }PXMLElement * XMPP::Stanza::GetElement(const PString& name, PINDEX i){ if (PAssertNULL(rootElement) == 0) return 0; return rootElement->GetElement(name, i);}void XMPP::Stanza::AddElement(PXMLElement * elem){ if (elem == 0) return; if (PAssertNULL(rootElement) == 0) return; elem->SetParent(rootElement); rootElement->AddChild(elem);}PString XMPP::Stanza::GenerateID(){ static PAtomicInteger s_id; return PString(PString::Printf, "pdu_%d", (int)++s_id);}///////////////////////////////////////////////////////const PString XMPP::Message::Type("type");const PString XMPP::Message::Subject("subject");const PString XMPP::Message::Body("body");const PString XMPP::Message::Thread("thread");XMPP::Message::Message(){ SetRootElement(new PXMLElement(NULL, XMPP::MessageStanza)); PWaitAndSignal m(rootMutex); rootElement->SetAttribute(XMPP::Message::Type, "normal"); SetID(XMPP::Stanza::GenerateID());}XMPP::Message::Message(PXML& pdu){ if (XMPP::Message::IsValid(&pdu)) { PWaitAndSignal m(pdu.GetMutex()); PXMLElement * elem = pdu.GetRootElement(); if (elem != NULL) SetRootElement((PXMLElement *)elem->Clone(0)); }}XMPP::Message::Message(PXML * pdu){ if (XMPP::Message::IsValid(pdu)) { PWaitAndSignal m(PAssertNULL(pdu)->GetMutex()); PXMLElement * elem = pdu->GetRootElement(); if (elem != NULL) SetRootElement((PXMLElement *)elem->Clone(0)); }}BOOL XMPP::Message::IsValid() const{ return XMPP::Message::IsValid(this);}BOOL XMPP::Message::IsValid(const PXML * pdu){ PXMLElement * elem = PAssertNULL(pdu)->GetRootElement(); return elem != NULL && elem->GetName() == XMPP::MessageStanza;}XMPP::Message::MessageType XMPP::Message::GetType(PString * typeName) const{ PString t = PAssertNULL(rootElement)->GetAttribute(XMPP::Message::Type); if (typeName != NULL) *typeName = t; if (t *= "normal") return XMPP::Message::Normal; else if (t *= "chat") return XMPP::Message::Chat; else if (t *= "error") return XMPP::Message::Error; else if (t *= "groupchat") return XMPP::Message::GroupChat; else if (t *= "headline") return XMPP::Message::HeadLine; else return XMPP::Message::Unknown;}PString XMPP::Message::GetLanguage() const{ return PAssertNULL(rootElement)->GetAttribute(XMPP::Language);}PXMLElement * XMPP::Message::GetSubjectElement(const PString& lang){ if (PAssertNULL(rootElement) == NULL) return NULL; PXMLElement * dfltSubj = NULL; PINDEX i = 0; PXMLElement * subj; PString l; while ((subj = rootElement->GetElement(XMPP::Message::Subject, i++)) != NULL) { l = subj->GetAttribute(XMPP::Language); if (l == lang) return subj; else if (l.IsEmpty() && dfltSubj == NULL) dfltSubj = subj; } return dfltSubj;}PString XMPP::Message::GetSubject(const PString& lang){ PXMLElement * elem = GetSubjectElement(lang); return elem != NULL ? elem->GetData() : PString::Empty();}PXMLElement * XMPP::Message::GetBodyElement(const PString& lang){ if (PAssertNULL(rootElement) == NULL) return NULL; PXMLElement * dfltBody = NULL; PINDEX i = 0; PXMLElement * body; PString l; while ((body = rootElement->GetElement(XMPP::Message::Body, i++)) != NULL) { l = body->GetAttribute(XMPP::Language); if (l == lang) return body; else if (l.IsEmpty() && dfltBody == NULL) dfltBody = body; } return dfltBody;}PString XMPP::Message::GetBody(const PString& lang){ PXMLElement * elem = GetBodyElement(lang); return elem != NULL ? elem->GetData() : PString::Empty();}PString XMPP::Message::GetThread(){ PXMLElement * elem = PAssertNULL(rootElement)->GetElement(XMPP::Message::Thread); return elem != NULL ? elem->GetData() : PString::Empty();}void XMPP::Message::SetType(MessageType type){ switch (type) { case XMPP::Message::Normal: SetType("normal"); break; case XMPP::Message::Chat: SetType("chat"); break; case XMPP::Message::Error: SetType("error"); break; case XMPP::Message::GroupChat: SetType("groupchat"); break; case XMPP::Message::HeadLine: SetType("headline"); break; default : break; }}void XMPP::Message::SetType(const PString& type){ PAssertNULL(rootElement)->SetAttribute(XMPP::Message::Type, type);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -