diff options
Diffstat (limited to 'kopete/protocols/jabber/jingle/libjingle/talk/xmpp')
27 files changed, 4941 insertions, 0 deletions
diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/Makefile.am b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/Makefile.am new file mode 100644 index 00000000..527f7053 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/Makefile.am @@ -0,0 +1,34 @@ +## Does not compile with final +KDE_OPTIONS = nofinal + +libcricketxmpp_la_SOURCES = constants.cc \ + jid.cc \ + saslmechanism.cc \ + xmppclient.cc \ + xmppengineimpl.cc \ + xmppengineimpl_iq.cc \ + xmpplogintask.cc \ + xmppstanzaparser.cc \ + xmpptask.cc + +noinst_HEADERS = asyncsocket.h \ + prexmppauth.h \ + saslhandler.h \ + xmpplogintask.h \ + jid.h \ + saslmechanism.h \ + xmppclient.h \ + xmpppassword.h \ + constants.h \ + saslplainmechanism.h \ + xmppclientsettings.h \ + xmppstanzaparser.h \ + xmppengine.h \ + xmpptask.h \ + plainsaslhandler.h \ + saslcookiemechanism.h \ + xmppengineimpl.h + + +AM_CPPFLAGS = -DPOSIX -I$(srcdir)/../.. +noinst_LTLIBRARIES = libcricketxmpp.la diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/asyncsocket.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/asyncsocket.h new file mode 100644 index 00000000..fd91929b --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/asyncsocket.h @@ -0,0 +1,85 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _ASYNCSOCKET_H_ +#define _ASYNCSOCKET_H_ + +#include "talk/base/sigslot.h" + +namespace cricket { + class SocketAddress; +} + +namespace buzz { + +class AsyncSocket { +public: + enum State { + STATE_CLOSED = 0, //!< Socket is not open. + STATE_CLOSING, //!< Socket is closing but can have buffered data + STATE_CONNECTING, //!< In the process of + STATE_OPEN, //!< Socket is connected +#if defined(FEATURE_ENABLE_SSL) + STATE_TLS_CONNECTING, //!< Establishing TLS connection + STATE_TLS_OPEN, //!< TLS connected +#endif + }; + + enum Error { + ERROR_NONE = 0, //!< No error + ERROR_WINSOCK, //!< Winsock error + ERROR_DNS, //!< Couldn't resolve host name + ERROR_WRONGSTATE, //!< Call made while socket is in the wrong state +#if defined(FEATURE_ENABLE_SSL) + ERROR_SSL, //!< Something went wrong with OpenSSL +#endif + }; + + virtual ~AsyncSocket() {} + virtual State state() = 0; + virtual Error error() = 0; + + virtual bool Connect(const cricket::SocketAddress& addr) = 0; + virtual bool Read(char * data, size_t len, size_t* len_read) = 0; + virtual bool Write(const char * data, size_t len) = 0; + virtual bool Close() = 0; +#if defined(FEATURE_ENABLE_SSL) + // We allow matching any passed domain. + // If both names are passed as empty, we do not require a match. + virtual bool StartTls(const std::string & domainname) = 0; +#endif + + sigslot::signal0<> SignalConnected; + sigslot::signal0<> SignalSSLConnected; + sigslot::signal0<> SignalClosed; + sigslot::signal0<> SignalRead; + sigslot::signal0<> SignalError; +}; + +} + +#endif diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/constants.cc b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/constants.cc new file mode 100644 index 00000000..b2c833f7 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/constants.cc @@ -0,0 +1,331 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <string> +#include "talk/base/basicdefs.h" +#include "talk/xmllite/xmlconstants.h" +#include "talk/xmllite/xmlelement.h" +#include "talk/xmllite/qname.h" +#include "talk/xmpp/jid.h" +#include "talk/xmpp/constants.h" +namespace buzz { + +const Jid JID_EMPTY(STR_EMPTY); + +const std::string & Constants::ns_client() { + static const std::string ns_client_("jabber:client"); + return ns_client_; +} + +const std::string & Constants::ns_server() { + static const std::string ns_server_("jabber:server"); + return ns_server_; +} + +const std::string & Constants::ns_stream() { + static const std::string ns_stream_("http://etherx.jabber.org/streams"); + return ns_stream_; +} + +const std::string & Constants::ns_xstream() { + static const std::string ns_xstream_("urn:ietf:params:xml:ns:xmpp-streams"); + return ns_xstream_; +} + +const std::string & Constants::ns_tls() { + static const std::string ns_tls_("urn:ietf:params:xml:ns:xmpp-tls"); + return ns_tls_; +} + +const std::string & Constants::ns_sasl() { + static const std::string ns_sasl_("urn:ietf:params:xml:ns:xmpp-sasl"); + return ns_sasl_; +} + +const std::string & Constants::ns_bind() { + static const std::string ns_bind_("urn:ietf:params:xml:ns:xmpp-bind"); + return ns_bind_; +} + +const std::string & Constants::ns_dialback() { + static const std::string ns_dialback_("jabber:server:dialback"); + return ns_dialback_; +} + +const std::string & Constants::ns_session() { + static const std::string ns_session_("urn:ietf:params:xml:ns:xmpp-session"); + return ns_session_; +} + +const std::string & Constants::ns_stanza() { + static const std::string ns_stanza_("urn:ietf:params:xml:ns:xmpp-stanzas"); + return ns_stanza_; +} + +const std::string & Constants::ns_privacy() { + static const std::string ns_privacy_("jabber:iq:privacy"); + return ns_privacy_; +} + +const std::string & Constants::ns_roster() { + static const std::string ns_roster_("jabber:iq:roster"); + return ns_roster_; +} + +const std::string & Constants::ns_vcard() { + static const std::string ns_vcard_("vcard-temp"); + return ns_vcard_; +} + +const std::string & Constants::str_client() { + static const std::string str_client_("client"); + return str_client_; +} + +const std::string & Constants::str_server() { + static const std::string str_server_("server"); + return str_server_; +} + +const std::string & Constants::str_stream() { + static const std::string str_stream_("stream"); + return str_stream_; +} + +const std::string STR_GET("get"); +const std::string STR_SET("set"); +const std::string STR_RESULT("result"); +const std::string STR_ERROR("error"); + +const std::string STR_FROM("from"); +const std::string STR_TO("to"); +const std::string STR_BOTH("both"); +const std::string STR_REMOVE("remove"); + +const std::string STR_UNAVAILABLE("unavailable"); +const std::string STR_INVISIBLE("invisible"); + +const std::string STR_GOOGLE_COM("google.com"); +const std::string STR_GMAIL_COM("gmail.com"); +const std::string STR_GOOGLEMAIL_COM("googlemail.com"); +const std::string STR_DEFAULT_DOMAIN("default.talk.google.com"); +const std::string STR_X("x"); + +const QName QN_STREAM_STREAM(true, NS_STREAM, STR_STREAM); +const QName QN_STREAM_FEATURES(true, NS_STREAM, "features"); +const QName QN_STREAM_ERROR(true, NS_STREAM, "error"); + +const QName QN_XSTREAM_BAD_FORMAT(true, NS_XSTREAM, "bad-format"); +const QName QN_XSTREAM_BAD_NAMESPACE_PREFIX(true, NS_XSTREAM, "bad-namespace-prefix"); +const QName QN_XSTREAM_CONFLICT(true, NS_XSTREAM, "conflict"); +const QName QN_XSTREAM_CONNECTION_TIMEOUT(true, NS_XSTREAM, "connection-timeout"); +const QName QN_XSTREAM_HOST_GONE(true, NS_XSTREAM, "host-gone"); +const QName QN_XSTREAM_HOST_UNKNOWN(true, NS_XSTREAM, "host-unknown"); +const QName QN_XSTREAM_IMPROPER_ADDRESSIING(true, NS_XSTREAM, "improper-addressing"); +const QName QN_XSTREAM_INTERNAL_SERVER_ERROR(true, NS_XSTREAM, "internal-server-error"); +const QName QN_XSTREAM_INVALID_FROM(true, NS_XSTREAM, "invalid-from"); +const QName QN_XSTREAM_INVALID_ID(true, NS_XSTREAM, "invalid-id"); +const QName QN_XSTREAM_INVALID_NAMESPACE(true, NS_XSTREAM, "invalid-namespace"); +const QName QN_XSTREAM_INVALID_XML(true, NS_XSTREAM, "invalid-xml"); +const QName QN_XSTREAM_NOT_AUTHORIZED(true, NS_XSTREAM, "not-authorized"); +const QName QN_XSTREAM_POLICY_VIOLATION(true, NS_XSTREAM, "policy-violation"); +const QName QN_XSTREAM_REMOTE_CONNECTION_FAILED(true, NS_XSTREAM, "remote-connection-failed"); +const QName QN_XSTREAM_RESOURCE_CONSTRAINT(true, NS_XSTREAM, "resource-constraint"); +const QName QN_XSTREAM_RESTRICTED_XML(true, NS_XSTREAM, "restricted-xml"); +const QName QN_XSTREAM_SEE_OTHER_HOST(true, NS_XSTREAM, "see-other-host"); +const QName QN_XSTREAM_SYSTEM_SHUTDOWN(true, NS_XSTREAM, "system-shutdown"); +const QName QN_XSTREAM_UNDEFINED_CONDITION(true, NS_XSTREAM, "undefined-condition"); +const QName QN_XSTREAM_UNSUPPORTED_ENCODING(true, NS_XSTREAM, "unsupported-encoding"); +const QName QN_XSTREAM_UNSUPPORTED_STANZA_TYPE(true, NS_XSTREAM, "unsupported-stanza-type"); +const QName QN_XSTREAM_UNSUPPORTED_VERSION(true, NS_XSTREAM, "unsupported-version"); +const QName QN_XSTREAM_XML_NOT_WELL_FORMED(true, NS_XSTREAM, "xml-not-well-formed"); +const QName QN_XSTREAM_TEXT(true, NS_XSTREAM, "text"); + +const QName QN_TLS_STARTTLS(true, NS_TLS, "starttls"); +const QName QN_TLS_REQUIRED(true, NS_TLS, "required"); +const QName QN_TLS_PROCEED(true, NS_TLS, "proceed"); +const QName QN_TLS_FAILURE(true, NS_TLS, "failure"); + +const QName QN_SASL_MECHANISMS(true, NS_SASL, "mechanisms"); +const QName QN_SASL_MECHANISM(true, NS_SASL, "mechanism"); +const QName QN_SASL_AUTH(true, NS_SASL, "auth"); +const QName QN_SASL_CHALLENGE(true, NS_SASL, "challenge"); +const QName QN_SASL_RESPONSE(true, NS_SASL, "response"); +const QName QN_SASL_ABORT(true, NS_SASL, "abort"); +const QName QN_SASL_SUCCESS(true, NS_SASL, "success"); +const QName QN_SASL_FAILURE(true, NS_SASL, "failure"); +const QName QN_SASL_ABORTED(true, NS_SASL, "aborted"); +const QName QN_SASL_INCORRECT_ENCODING(true, NS_SASL, "incorrect-encoding"); +const QName QN_SASL_INVALID_AUTHZID(true, NS_SASL, "invalid-authzid"); +const QName QN_SASL_INVALID_MECHANISM(true, NS_SASL, "invalid-mechanism"); +const QName QN_SASL_MECHANISM_TOO_WEAK(true, NS_SASL, "mechanism-too-weak"); +const QName QN_SASL_NOT_AUTHORIZED(true, NS_SASL, "not-authorized"); +const QName QN_SASL_TEMPORARY_AUTH_FAILURE(true, NS_SASL, "temporary-auth-failure"); + +const QName QN_DIALBACK_RESULT(true, NS_DIALBACK, "result"); +const QName QN_DIALBACK_VERIFY(true, NS_DIALBACK, "verify"); + +const QName QN_STANZA_BAD_REQUEST(true, NS_STANZA, "bad-request"); +const QName QN_STANZA_CONFLICT(true, NS_STANZA, "conflict"); +const QName QN_STANZA_FEATURE_NOT_IMPLEMENTED(true, NS_STANZA, "feature-not-implemented"); +const QName QN_STANZA_FORBIDDEN(true, NS_STANZA, "forbidden"); +const QName QN_STANZA_GONE(true, NS_STANZA, "gone"); +const QName QN_STANZA_INTERNAL_SERVER_ERROR(true, NS_STANZA, "internal-server-error"); +const QName QN_STANZA_ITEM_NOT_FOUND(true, NS_STANZA, "item-not-found"); +const QName QN_STANZA_JID_MALFORMED(true, NS_STANZA, "jid-malformed"); +const QName QN_STANZA_NOT_ACCEPTABLE(true, NS_STANZA, "not-acceptable"); +const QName QN_STANZA_NOT_ALLOWED(true, NS_STANZA, "not-allowed"); +const QName QN_STANZA_PAYMENT_REQUIRED(true, NS_STANZA, "payment-required"); +const QName QN_STANZA_RECIPIENT_UNAVAILABLE(true, NS_STANZA, "recipient-unavailable"); +const QName QN_STANZA_REDIRECT(true, NS_STANZA, "redirect"); +const QName QN_STANZA_REGISTRATION_REQUIRED(true, NS_STANZA, "registration-required"); +const QName QN_STANZA_REMOTE_SERVER_NOT_FOUND(true, NS_STANZA, "remote-server-not-found"); +const QName QN_STANZA_REMOTE_SERVER_TIMEOUT(true, NS_STANZA, "remote-server-timeout"); +const QName QN_STANZA_RESOURCE_CONSTRAINT(true, NS_STANZA, "resource-constraint"); +const QName QN_STANZA_SERVICE_UNAVAILABLE(true, NS_STANZA, "service-unavailable"); +const QName QN_STANZA_SUBSCRIPTION_REQUIRED(true, NS_STANZA, "subscription-required"); +const QName QN_STANZA_UNDEFINED_CONDITION(true, NS_STANZA, "undefined-condition"); +const QName QN_STANZA_UNEXPECTED_REQUEST(true, NS_STANZA, "unexpected-request"); +const QName QN_STANZA_TEXT(true, NS_STANZA, "text"); + +const QName QN_BIND_BIND(true, NS_BIND, "bind"); +const QName QN_BIND_RESOURCE(true, NS_BIND, "resource"); +const QName QN_BIND_JID(true, NS_BIND, "jid"); + +const QName QN_MESSAGE(true, NS_CLIENT, "message"); +const QName QN_BODY(true, NS_CLIENT, "body"); +const QName QN_SUBJECT(true, NS_CLIENT, "subject"); +const QName QN_THREAD(true, NS_CLIENT, "thread"); +const QName QN_PRESENCE(true, NS_CLIENT, "presence"); +const QName QN_SHOW(true, NS_CLIENT, "show"); +const QName QN_STATUS(true, NS_CLIENT, "status"); +const QName QN_LANG(true, NS_CLIENT, "lang"); +const QName QN_PRIORITY(true, NS_CLIENT, "priority"); +const QName QN_IQ(true, NS_CLIENT, "iq"); +const QName QN_ERROR(true, NS_CLIENT, "error"); + +const QName QN_SERVER_MESSAGE(true, NS_SERVER, "message"); +const QName QN_SERVER_BODY(true, NS_SERVER, "body"); +const QName QN_SERVER_SUBJECT(true, NS_SERVER, "subject"); +const QName QN_SERVER_THREAD(true, NS_SERVER, "thread"); +const QName QN_SERVER_PRESENCE(true, NS_SERVER, "presence"); +const QName QN_SERVER_SHOW(true, NS_SERVER, "show"); +const QName QN_SERVER_STATUS(true, NS_SERVER, "status"); +const QName QN_SERVER_LANG(true, NS_SERVER, "lang"); +const QName QN_SERVER_PRIORITY(true, NS_SERVER, "priority"); +const QName QN_SERVER_IQ(true, NS_SERVER, "iq"); +const QName QN_SERVER_ERROR(true, NS_SERVER, "error"); + +const QName QN_SESSION_SESSION(true, NS_SESSION, "session"); + +const QName QN_PRIVACY_QUERY(true, NS_PRIVACY, "query"); +const QName QN_PRIVACY_ACTIVE(true, NS_PRIVACY, "active"); +const QName QN_PRIVACY_DEFAULT(true, NS_PRIVACY, "default"); +const QName QN_PRIVACY_LIST(true, NS_PRIVACY, "list"); +const QName QN_PRIVACY_ITEM(true, NS_PRIVACY, "item"); +const QName QN_PRIVACY_IQ(true, NS_PRIVACY, "iq"); +const QName QN_PRIVACY_MESSAGE(true, NS_PRIVACY, "message"); +const QName QN_PRIVACY_PRESENCE_IN(true, NS_PRIVACY, "presence-in"); +const QName QN_PRIVACY_PRESENCE_OUT(true, NS_PRIVACY, "presence-out"); + +const QName QN_ROSTER_QUERY(true, NS_ROSTER, "query"); +const QName QN_ROSTER_ITEM(true, NS_ROSTER, "item"); +const QName QN_ROSTER_GROUP(true, NS_ROSTER, "group"); + +const QName QN_VCARD_QUERY(true, NS_VCARD, "vCard"); +const QName QN_VCARD_FN(true, NS_VCARD, "FN"); + +const QName QN_XML_LANG(true, NS_XML, "lang"); + +const std::string STR_TYPE("type"); +const std::string STR_ID("id"); +const std::string STR_NAME("name"); +const std::string STR_JID("jid"); +const std::string STR_SUBSCRIPTION("subscription"); +const std::string STR_ASK("ask"); + +const QName QN_ENCODING(true, STR_EMPTY, STR_ENCODING); +const QName QN_VERSION(true, STR_EMPTY, STR_VERSION); +const QName QN_TO(true, STR_EMPTY, "to"); +const QName QN_FROM(true, STR_EMPTY, "from"); +const QName QN_TYPE(true, STR_EMPTY, "type"); +const QName QN_ID(true, STR_EMPTY, "id"); +const QName QN_CODE(true, STR_EMPTY, "code"); +const QName QN_NAME(true, STR_EMPTY, "name"); +const QName QN_VALUE(true, STR_EMPTY, "value"); +const QName QN_ACTION(true, STR_EMPTY, "action"); +const QName QN_ORDER(true, STR_EMPTY, "order"); +const QName QN_MECHANISM(true, STR_EMPTY, "mechanism"); +const QName QN_ASK(true, STR_EMPTY, "ask"); +const QName QN_JID(true, STR_EMPTY, "jid"); +const QName QN_SUBSCRIPTION(true, STR_EMPTY, "subscription"); +const QName QN_SOURCE(true, STR_EMPTY, "source"); + +const QName QN_XMLNS_CLIENT(true, NS_XMLNS, STR_CLIENT); +const QName QN_XMLNS_SERVER(true, NS_XMLNS, STR_SERVER); +const QName QN_XMLNS_STREAM(true, NS_XMLNS, STR_STREAM); + +// Presence +const std::string STR_SHOW_AWAY("away"); +const std::string STR_SHOW_CHAT("chat"); +const std::string STR_SHOW_DND("dnd"); +const std::string STR_SHOW_XA("xa"); + +// Subscription +const std::string STR_SUBSCRIBE("subscribe"); +const std::string STR_SUBSCRIBED("subscribed"); +const std::string STR_UNSUBSCRIBE("unsubscribe"); +const std::string STR_UNSUBSCRIBED("unsubscribed"); + + +// JEP 0030 +const QName QN_NODE(true, STR_EMPTY, "node"); +const QName QN_CATEGORY(true, STR_EMPTY, "category"); +const QName QN_VAR(true, STR_EMPTY, "var"); +const std::string NS_DISCO_INFO("http://jabber.org/protocol/disco#info"); +const std::string NS_DISCO_ITEMS("http://jabber.org/protocol/disco#items"); +const QName QN_DISCO_INFO_QUERY(true, NS_DISCO_INFO, "query"); +const QName QN_DISCO_IDENTITY(true, NS_DISCO_INFO, "identity"); +const QName QN_DISCO_FEATURE(true, NS_DISCO_INFO, "feature"); + +const QName QN_DISCO_ITEMS_QUERY(true, NS_DISCO_ITEMS, "query"); +const QName QN_DISCO_ITEM(true, NS_DISCO_ITEMS, "item"); + + +// JEP 0115 +const std::string NS_CAPS("http://jabber.org/protocol/caps"); +const QName QN_CAPS_C(true, NS_CAPS, "c"); +const QName QN_VER(true, STR_EMPTY, "ver"); +const QName QN_EXT(true, STR_EMPTY, "ext"); + +// JEP 0091 Delayed Delivery +const std::string kNSDelay("jabber:x:delay"); +const QName kQnDelayX(true, kNSDelay, "x"); +const QName kQnStamp(true, STR_EMPTY, "stamp"); + + +} diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/constants.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/constants.h new file mode 100644 index 00000000..b05af965 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/constants.h @@ -0,0 +1,300 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _CRICKET_XMPP_XMPPLIB_BUZZ_CONSTANTS_H_ +#define _CRICKET_XMPP_XMPPLIB_BUZZ_CONSTANTS_H_ + +#include <string> +#include "talk/xmllite/qname.h" +#include "talk/xmpp/jid.h" + + +#define NS_CLIENT Constants::ns_client() +#define NS_SERVER Constants::ns_server() +#define NS_STREAM Constants::ns_stream() +#define NS_XSTREAM Constants::ns_xstream() +#define NS_TLS Constants::ns_tls() +#define NS_SASL Constants::ns_sasl() +#define NS_BIND Constants::ns_bind() +#define NS_DIALBACK Constants::ns_dialback() +#define NS_SESSION Constants::ns_session() +#define NS_STANZA Constants::ns_stanza() +#define NS_PRIVACY Constants::ns_privacy() +#define NS_ROSTER Constants::ns_roster() +#define NS_VCARD Constants::ns_vcard() +#define STR_CLIENT Constants::str_client() +#define STR_SERVER Constants::str_server() +#define STR_STREAM Constants::str_stream() + +namespace buzz { + +extern const Jid JID_EMPTY; + +class Constants { + public: + static const std::string & ns_client(); + static const std::string & ns_server(); + static const std::string & ns_stream(); + static const std::string & ns_xstream(); + static const std::string & ns_tls(); + static const std::string & ns_sasl(); + static const std::string & ns_bind(); + static const std::string & ns_dialback(); + static const std::string & ns_session(); + static const std::string & ns_stanza(); + static const std::string & ns_privacy(); + static const std::string & ns_roster(); + static const std::string & ns_vcard(); + + static const std::string & str_client(); + static const std::string & str_server(); + static const std::string & str_stream(); +}; + +extern const std::string STR_GET; +extern const std::string STR_SET; +extern const std::string STR_RESULT; +extern const std::string STR_ERROR; + +extern const std::string STR_FROM; +extern const std::string STR_TO; +extern const std::string STR_BOTH; +extern const std::string STR_REMOVE; + +extern const std::string STR_MESSAGE; +extern const std::string STR_BODY; +extern const std::string STR_PRESENCE; +extern const std::string STR_STATUS; +extern const std::string STR_SHOW; +extern const std::string STR_PRIOIRTY; +extern const std::string STR_IQ; + +extern const std::string STR_TYPE; +extern const std::string STR_NAME; +extern const std::string STR_ID; +extern const std::string STR_JID; +extern const std::string STR_SUBSCRIPTION; +extern const std::string STR_ASK; +extern const std::string STR_X; +extern const std::string STR_GOOGLE_COM; +extern const std::string STR_GMAIL_COM; +extern const std::string STR_GOOGLEMAIL_COM; +extern const std::string STR_DEFAULT_DOMAIN; + +extern const std::string STR_UNAVAILABLE; +extern const std::string STR_INVISIBLE; + +extern const QName QN_STREAM_STREAM; +extern const QName QN_STREAM_FEATURES; +extern const QName QN_STREAM_ERROR; + +extern const QName QN_XSTREAM_BAD_FORMAT; +extern const QName QN_XSTREAM_BAD_NAMESPACE_PREFIX; +extern const QName QN_XSTREAM_CONFLICT; +extern const QName QN_XSTREAM_CONNECTION_TIMEOUT; +extern const QName QN_XSTREAM_HOST_GONE; +extern const QName QN_XSTREAM_HOST_UNKNOWN; +extern const QName QN_XSTREAM_IMPROPER_ADDRESSIING; +extern const QName QN_XSTREAM_INTERNAL_SERVER_ERROR; +extern const QName QN_XSTREAM_INVALID_FROM; +extern const QName QN_XSTREAM_INVALID_ID; +extern const QName QN_XSTREAM_INVALID_NAMESPACE; +extern const QName QN_XSTREAM_INVALID_XML; +extern const QName QN_XSTREAM_NOT_AUTHORIZED; +extern const QName QN_XSTREAM_POLICY_VIOLATION; +extern const QName QN_XSTREAM_REMOTE_CONNECTION_FAILED; +extern const QName QN_XSTREAM_RESOURCE_CONSTRAINT; +extern const QName QN_XSTREAM_RESTRICTED_XML; +extern const QName QN_XSTREAM_SEE_OTHER_HOST; +extern const QName QN_XSTREAM_SYSTEM_SHUTDOWN; +extern const QName QN_XSTREAM_UNDEFINED_CONDITION; +extern const QName QN_XSTREAM_UNSUPPORTED_ENCODING; +extern const QName QN_XSTREAM_UNSUPPORTED_STANZA_TYPE; +extern const QName QN_XSTREAM_UNSUPPORTED_VERSION; +extern const QName QN_XSTREAM_XML_NOT_WELL_FORMED; +extern const QName QN_XSTREAM_TEXT; + +extern const QName QN_TLS_STARTTLS; +extern const QName QN_TLS_REQUIRED; +extern const QName QN_TLS_PROCEED; +extern const QName QN_TLS_FAILURE; + +extern const QName QN_SASL_MECHANISMS; +extern const QName QN_SASL_MECHANISM; +extern const QName QN_SASL_AUTH; +extern const QName QN_SASL_CHALLENGE; +extern const QName QN_SASL_RESPONSE; +extern const QName QN_SASL_ABORT; +extern const QName QN_SASL_SUCCESS; +extern const QName QN_SASL_FAILURE; +extern const QName QN_SASL_ABORTED; +extern const QName QN_SASL_INCORRECT_ENCODING; +extern const QName QN_SASL_INVALID_AUTHZID; +extern const QName QN_SASL_INVALID_MECHANISM; +extern const QName QN_SASL_MECHANISM_TOO_WEAK; +extern const QName QN_SASL_NOT_AUTHORIZED; +extern const QName QN_SASL_TEMPORARY_AUTH_FAILURE; + +extern const QName QN_DIALBACK_RESULT; +extern const QName QN_DIALBACK_VERIFY; + +extern const QName QN_STANZA_BAD_REQUEST; +extern const QName QN_STANZA_CONFLICT; +extern const QName QN_STANZA_FEATURE_NOT_IMPLEMENTED; +extern const QName QN_STANZA_FORBIDDEN; +extern const QName QN_STANZA_GONE; +extern const QName QN_STANZA_INTERNAL_SERVER_ERROR; +extern const QName QN_STANZA_ITEM_NOT_FOUND; +extern const QName QN_STANZA_JID_MALFORMED; +extern const QName QN_STANZA_NOT_ACCEPTABLE; +extern const QName QN_STANZA_NOT_ALLOWED; +extern const QName QN_STANZA_PAYMENT_REQUIRED; +extern const QName QN_STANZA_RECIPIENT_UNAVAILABLE; +extern const QName QN_STANZA_REDIRECT; +extern const QName QN_STANZA_REGISTRATION_REQUIRED; +extern const QName QN_STANZA_REMOTE_SERVER_NOT_FOUND; +extern const QName QN_STANZA_REMOTE_SERVER_TIMEOUT; +extern const QName QN_STANZA_RESOURCE_CONSTRAINT; +extern const QName QN_STANZA_SERVICE_UNAVAILABLE; +extern const QName QN_STANZA_SUBSCRIPTION_REQUIRED; +extern const QName QN_STANZA_UNDEFINED_CONDITION; +extern const QName QN_STANZA_UNEXPECTED_REQUEST; +extern const QName QN_STANZA_TEXT; + +extern const QName QN_BIND_BIND; +extern const QName QN_BIND_RESOURCE; +extern const QName QN_BIND_JID; + +extern const QName QN_MESSAGE; +extern const QName QN_BODY; +extern const QName QN_SUBJECT; +extern const QName QN_THREAD; +extern const QName QN_PRESENCE; +extern const QName QN_SHOW; +extern const QName QN_STATUS; +extern const QName QN_LANG; +extern const QName QN_PRIORITY; +extern const QName QN_IQ; +extern const QName QN_ERROR; + +extern const QName QN_SERVER_MESSAGE; +extern const QName QN_SERVER_BODY; +extern const QName QN_SERVER_SUBJECT; +extern const QName QN_SERVER_THREAD; +extern const QName QN_SERVER_PRESENCE; +extern const QName QN_SERVER_SHOW; +extern const QName QN_SERVER_STATUS; +extern const QName QN_SERVER_LANG; +extern const QName QN_SERVER_PRIORITY; +extern const QName QN_SERVER_IQ; +extern const QName QN_SERVER_ERROR; + +extern const QName QN_SESSION_SESSION; + +extern const QName QN_PRIVACY_QUERY; +extern const QName QN_PRIVACY_ACTIVE; +extern const QName QN_PRIVACY_DEFAULT; +extern const QName QN_PRIVACY_LIST; +extern const QName QN_PRIVACY_ITEM; +extern const QName QN_PRIVACY_IQ; +extern const QName QN_PRIVACY_MESSAGE; +extern const QName QN_PRIVACY_PRESENCE_IN; +extern const QName QN_PRIVACY_PRESENCE_OUT; + +extern const QName QN_ROSTER_QUERY; +extern const QName QN_ROSTER_ITEM; +extern const QName QN_ROSTER_GROUP; + +extern const QName QN_VCARD_QUERY; +extern const QName QN_VCARD_FN; + +extern const QName QN_XML_LANG; + +extern const QName QN_ENCODING; +extern const QName QN_VERSION; +extern const QName QN_TO; +extern const QName QN_FROM; +extern const QName QN_TYPE; +extern const QName QN_ID; +extern const QName QN_CODE; +extern const QName QN_NAME; +extern const QName QN_VALUE; +extern const QName QN_ACTION; +extern const QName QN_ORDER; +extern const QName QN_MECHANISM; +extern const QName QN_ASK; +extern const QName QN_JID; +extern const QName QN_SUBSCRIPTION; + + +extern const QName QN_XMLNS_CLIENT; +extern const QName QN_XMLNS_SERVER; +extern const QName QN_XMLNS_STREAM; + +// Presence +extern const std::string STR_SHOW_AWAY; +extern const std::string STR_SHOW_CHAT; +extern const std::string STR_SHOW_DND; +extern const std::string STR_SHOW_XA; + +// Subscription +extern const std::string STR_SUBSCRIBE; +extern const std::string STR_SUBSCRIBED; +extern const std::string STR_UNSUBSCRIBE; +extern const std::string STR_UNSUBSCRIBED; + + +// JEP 0030 +extern const QName QN_NODE; +extern const QName QN_CATEGORY; +extern const QName QN_VAR; +extern const std::string NS_DISCO_INFO; +extern const std::string NS_DISCO_ITEMS; + +extern const QName QN_DISCO_INFO_QUERY; +extern const QName QN_DISCO_IDENTITY; +extern const QName QN_DISCO_FEATURE; + +extern const QName QN_DISCO_ITEMS_QUERY; +extern const QName QN_DISCO_ITEM; + + +// JEP 0115 +extern const std::string NS_CAPS; +extern const QName QN_CAPS_C; +extern const QName QN_VER; +extern const QName QN_EXT; + + +// JEP 0091 Delayed Delivery +extern const std::string kNSDelay; +extern const QName kQnDelayX; +extern const QName kQnStamp; + +} + +#endif // _CRICKET_XMPP_XMPPLIB_BUZZ_CONSTANTS_H_ diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/jid.cc b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/jid.cc new file mode 100644 index 00000000..b742e03a --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/jid.cc @@ -0,0 +1,477 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +extern "C" { +#include <ctype.h> +} +#include <string> +#include "talk/xmpp/jid.h" +#include "talk/xmpp/constants.h" +#include "talk/base/common.h" +#include <algorithm> + +#define new TRACK_NEW + +namespace buzz { + +static int AsciiToLower(int x) { + return (x <= 'Z' && x >= 'A') ? (x + ('a' - 'A')) : x; +} + +Jid::Jid() : data_(NULL) { +} + +Jid::Jid(bool is_special, const std::string & special) { + data_ = is_special ? new Data(special, STR_EMPTY, STR_EMPTY) : NULL; +} + +Jid::Jid(const std::string & jid_string) { + if (jid_string == STR_EMPTY) { + data_ = NULL; + return; + } + + // First find the slash and slice of that part + size_t slash = jid_string.find('/'); + std::string resource_name = (slash == std::string::npos ? STR_EMPTY : + jid_string.substr(slash + 1)); + + // Now look for the node + std::string node_name; + size_t at = jid_string.find('@'); + size_t domain_begin; + if (at < slash && at != std::string::npos) { + node_name = jid_string.substr(0, at); + domain_begin = at + 1; + } else { + domain_begin = 0; + } + + // Now take what is left as the domain + size_t domain_length = + ( slash == std::string::npos + ? jid_string.length() - domain_begin + : slash - domain_begin); + + // avoid allocating these constants repeatedly + std::string domain_name; + + if (domain_length == 9 && jid_string.find("gmail.com", domain_begin) == domain_begin) { + domain_name = STR_GMAIL_COM; + } + else if (domain_length == 14 && jid_string.find("googlemail.com", domain_begin) == domain_begin) { + domain_name = STR_GOOGLEMAIL_COM; + } + else if (domain_length == 10 && jid_string.find("google.com", domain_begin) == domain_begin) { + domain_name = STR_GOOGLE_COM; + } + else { + domain_name = jid_string.substr(domain_begin, domain_length); + } + + // If the domain is empty we have a non-valid jid and we should empty + // everything else out + if (domain_name.empty()) { + data_ = NULL; + return; + } + + bool valid_node; + std::string validated_node = prepNode(node_name, + node_name.begin(), node_name.end(), &valid_node); + bool valid_domain; + std::string validated_domain = prepDomain(domain_name, + domain_name.begin(), domain_name.end(), &valid_domain); + bool valid_resource; + std::string validated_resource = prepResource(resource_name, + resource_name.begin(), resource_name.end(), &valid_resource); + + if (!valid_node || !valid_domain || !valid_resource) { + data_ = NULL; + return; + } + + data_ = new Data(validated_node, validated_domain, validated_resource); +} + +Jid::Jid(const std::string & node_name, + const std::string & domain_name, + const std::string & resource_name) { + if (domain_name.empty()) { + data_ = NULL; + return; + } + + bool valid_node; + std::string validated_node = prepNode(node_name, + node_name.begin(), node_name.end(), &valid_node); + bool valid_domain; + std::string validated_domain = prepDomain(domain_name, + domain_name.begin(), domain_name.end(), &valid_domain); + bool valid_resource; + std::string validated_resource = prepResource(resource_name, + resource_name.begin(), resource_name.end(), &valid_resource); + + if (!valid_node || !valid_domain || !valid_resource) { + data_ = NULL; + return; + } + + data_ = new Data(validated_node, validated_domain, validated_resource); +} + +std::string Jid::Str() const { + if (!IsValid()) + return STR_EMPTY; + + std::string ret; + + if (!data_->node_name_.empty()) + ret = data_->node_name_ + "@"; + + ASSERT(data_->domain_name_ != STR_EMPTY); + ret += data_->domain_name_; + + if (!data_->resource_name_.empty()) + ret += "/" + data_->resource_name_; + + return ret; +} + +bool +Jid::IsValid() const { + return data_ != NULL && !data_->domain_name_.empty(); +} + +bool +Jid::IsBare() const { + return IsValid() && + data_->resource_name_.empty(); +} + +bool +Jid::IsFull() const { + return IsValid() && + !data_->resource_name_.empty(); +} + +Jid +Jid::BareJid() const { + if (!IsValid()) + return Jid(); + if (!IsFull()) + return *this; + return Jid(data_->node_name_, data_->domain_name_, STR_EMPTY); +} + +#if 0 +void +Jid::set_node(const std::string & node_name) { + data_->node_name_ = node_name; +} +void +Jid::set_domain(const std::string & domain_name) { + data_->domain_name_ = domain_name; +} +void +Jid::set_resource(const std::string & res_name) { + data_->resource_name_ = res_name; +} +#endif + +bool +Jid::BareEquals(const Jid & other) const { + return (other.data_ == data_ || + data_ != NULL && + other.data_ != NULL && + other.data_->node_name_ == data_->node_name_ && + other.data_->domain_name_ == data_->domain_name_); +} + +bool +Jid::operator==(const Jid & other) const { + return (other.data_ == data_ || + data_ != NULL && + other.data_ != NULL && + other.data_->node_name_ == data_->node_name_ && + other.data_->domain_name_ == data_->domain_name_ && + other.data_->resource_name_ == data_->resource_name_); +} + +int +Jid::Compare(const Jid & other) const { + if (other.data_ == data_) + return 0; + if (data_ == NULL) + return -1; + if (other.data_ == NULL) + return 1; + + int compare_result; + compare_result = data_->node_name_.compare(other.data_->node_name_); + if (0 != compare_result) + return compare_result; + compare_result = data_->domain_name_.compare(other.data_->domain_name_); + if (0 != compare_result) + return compare_result; + compare_result = data_->resource_name_.compare(other.data_->resource_name_); + return compare_result; +} + + +// --- JID parsing code: --- + +// Checks and normalizes the node part of a JID. +std::string +Jid::prepNode(const std::string str, std::string::const_iterator start, + std::string::const_iterator end, bool *valid) { + *valid = false; + std::string result; + + for (std::string::const_iterator i = start; i < end; i++) { + bool char_valid = true; + char ch = *i; + if (ch <= 0x7F) { + result += prepNodeAscii(ch, &char_valid); + } + else { + // TODO: implement the correct stringprep protocol for these + result += tolower(ch); + } + if (!char_valid) { + return STR_EMPTY; + } + } + + if (result.length() > 1023) { + return STR_EMPTY; + } + *valid = true; + return result; +} + + +// Returns the appropriate mapping for an ASCII character in a node. +char +Jid::prepNodeAscii(char ch, bool *valid) { + *valid = true; + switch (ch) { + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': + case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': + case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': + case 'V': case 'W': case 'X': case 'Y': case 'Z': + return (char)(ch + ('a' - 'A')); + + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: + case 0x06: case 0x07: case 0x08: case 0x09: case 0x0A: case 0x0B: + case 0x0C: case 0x0D: case 0x0E: case 0x0F: case 0x10: case 0x11: + case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: + case ' ': case '&': case '/': case ':': case '<': case '>': case '@': + case '\"': case '\'': + case 0x7F: + *valid = false; + return 0; + + default: + return ch; + } +} + + +// Checks and normalizes the resource part of a JID. +std::string +Jid::prepResource(const std::string str, std::string::const_iterator start, + std::string::const_iterator end, bool *valid) { + *valid = false; + std::string result; + + for (std::string::const_iterator i = start; i < end; i++) { + bool char_valid = true; + char ch = *i; + if (ch <= 0x7F) { + result += prepResourceAscii(ch, &char_valid); + } + else { + // TODO: implement the correct stringprep protocol for these + result += ch; + } + } + + if (result.length() > 1023) { + return STR_EMPTY; + } + *valid = true; + return result; +} + +// Returns the appropriate mapping for an ASCII character in a resource. +char +Jid::prepResourceAscii(char ch, bool *valid) { + *valid = true; + switch (ch) { + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: + case 0x06: case 0x07: case 0x08: case 0x09: case 0x0A: case 0x0B: + case 0x0C: case 0x0D: case 0x0E: case 0x0F: case 0x10: case 0x11: + case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: + case 0x7F: + *valid = false; + return 0; + + default: + return ch; + } +} + +// Checks and normalizes the domain part of a JID. +std::string +Jid::prepDomain(const std::string str, std::string::const_iterator start, + std::string::const_iterator end, bool *valid) { + *valid = false; + std::string result; + + // TODO: if the domain contains a ':', then we should parse it + // as an IPv6 address rather than giving an error about illegal domain. + prepDomain(str, start, end, &result, valid); + if (!*valid) { + return STR_EMPTY; + } + + if (result.length() > 1023) { + return STR_EMPTY; + } + *valid = true; + return result; +} + + +// Checks and normalizes an IDNA domain. +void +Jid::prepDomain(const std::string str, std::string::const_iterator start, + std::string::const_iterator end, std::string *buf, bool *valid) { + *valid = false; + std::string::const_iterator last = start; + for (std::string::const_iterator i = start; i < end; i++) { + bool label_valid = true; + char ch = *i; + switch (ch) { + case 0x002E: +#if 0 // FIX: This isn't UTF-8-aware. + case 0x3002: + case 0xFF0E: + case 0xFF61: +#endif + prepDomainLabel(str, last, i, buf, &label_valid); + *buf += '.'; + last = i + 1; + break; + } + if (!label_valid) { + return; + } + } + prepDomainLabel(str, last, end, buf, valid); +} + +// Checks and normalizes a domain label. +void +Jid::prepDomainLabel(const std::string str, std::string::const_iterator start, + std::string::const_iterator end, std::string *buf, bool *valid) { + *valid = false; + + int startLen = buf->length(); + for (std::string::const_iterator i = start; i < end; i++) { + bool char_valid = true; + char ch = *i; + if (ch <= 0x7F) { + *buf += prepDomainLabelAscii(ch, &char_valid); + } + else { + // TODO: implement ToASCII for these + *buf += ch; + } + if (!char_valid) { + return; + } + } + + int count = buf->length() - startLen; + if (count == 0) { + return; + } + else if (count > 63) { + return; + } + + // Is this check needed? See comment in prepDomainLabelAscii. + if ((*buf)[startLen] == '-') { + return; + } + if ((*buf)[buf->length() - 1] == '-') { + return; + } + *valid = true; +} + + +// Returns the appropriate mapping for an ASCII character in a domain label. +char +Jid::prepDomainLabelAscii(char ch, bool *valid) { + *valid = true; + // TODO: A literal reading of the spec seems to say that we do + // not need to check for these illegal characters (an "internationalized + // domain label" runs ToASCII with UseSTD3... set to false). But that + // can't be right. We should at least be checking that there are no '/' + // or '@' characters in the domain. Perhaps we should see what others + // do in this case. + + switch (ch) { + case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': + case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': + case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U': + case 'V': case 'W': case 'X': case 'Y': case 'Z': + return (char)(ch + ('a' - 'A')); + + case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: + case 0x06: case 0x07: case 0x08: case 0x09: case 0x0A: case 0x0B: + case 0x0C: case 0x0D: case 0x0E: case 0x0F: case 0x10: case 0x11: + case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: + case 0x1E: case 0x1F: case 0x20: case 0x21: case 0x22: case 0x23: + case 0x24: case 0x25: case 0x26: case 0x27: case 0x28: case 0x29: + case 0x2A: case 0x2B: case 0x2C: case 0x2E: case 0x2F: case 0x3A: + case 0x3B: case 0x3C: case 0x3D: case 0x3E: case 0x3F: case 0x40: + case 0x5B: case 0x5C: case 0x5D: case 0x5E: case 0x5F: case 0x60: + case 0x7B: case 0x7C: case 0x7D: case 0x7E: case 0x7F: + *valid = false; + return 0; + + default: + return ch; + } +} + +} diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/jid.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/jid.h new file mode 100644 index 00000000..ae7944bf --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/jid.h @@ -0,0 +1,144 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _jid_h_ +#define _jid_h_ + +#include <string> +#include "talk/xmllite/xmlconstants.h" + +namespace buzz { + +//! The Jid class encapsulates and provides parsing help for Jids +//! A Jid consists of three parts. The node, the domain and the resource. +//! +//! node@domain/resource +//! +//! The node and resource are both optional. A valid jid is defined to have +//! a domain. A bare jid is defined to not have a resource and a full jid +//! *does* have a resource. +class Jid { +public: + explicit Jid(); + explicit Jid(const std::string & jid_string); + explicit Jid(const std::string & node_name, + const std::string & domain_name, + const std::string & resource_name); + explicit Jid(bool special, const std::string & special_string); + Jid(const Jid & jid) : data_(jid.data_) { + if (data_ != NULL) { + data_->AddRef(); + } + } + Jid & operator=(const Jid & jid) { + if (jid.data_ != NULL) { + jid.data_->AddRef(); + } + if (data_ != NULL) { + data_->Release(); + } + data_ = jid.data_; + return *this; + } + ~Jid() { + if (data_ != NULL) { + data_->Release(); + } + } + + + const std::string & node() const { return !data_ ? STR_EMPTY : data_->node_name_; } + // void set_node(const std::string & node_name); + const std::string & domain() const { return !data_ ? STR_EMPTY : data_->domain_name_; } + // void set_domain(const std::string & domain_name); + const std::string & resource() const { return !data_ ? STR_EMPTY : data_->resource_name_; } + // void set_resource(const std::string & res_name); + + std::string Str() const; + Jid BareJid() const; + + bool IsValid() const; + bool IsBare() const; + bool IsFull() const; + + bool BareEquals(const Jid & other) const; + + bool operator==(const Jid & other) const; + bool operator!=(const Jid & other) const { return !operator==(other); } + + bool operator<(const Jid & other) const { return Compare(other) < 0; }; + bool operator>(const Jid & other) const { return Compare(other) > 0; }; + + int Compare(const Jid & other) const; + + +private: + + static std::string prepNode(const std::string str, + std::string::const_iterator start, std::string::const_iterator end, + bool *valid); + static char prepNodeAscii(char ch, bool *valid); + static std::string prepResource(const std::string str, + std::string::const_iterator start, std::string::const_iterator end, + bool *valid); + static char prepResourceAscii(char ch, bool *valid); + static std::string prepDomain(const std::string str, + std::string::const_iterator start, std::string::const_iterator end, + bool *valid); + static void prepDomain(const std::string str, + std::string::const_iterator start, std::string::const_iterator end, + std::string *buf, bool *valid); + static void prepDomainLabel(const std::string str, + std::string::const_iterator start, std::string::const_iterator end, + std::string *buf, bool *valid); + static char prepDomainLabelAscii(char ch, bool *valid); + + class Data { + public: + Data() : refcount_(1) {} + Data(const std::string & node, const std::string &domain, const std::string & resource) : + node_name_(node), + domain_name_(domain), + resource_name_(resource), + refcount_(1) {} + const std::string node_name_; + const std::string domain_name_; + const std::string resource_name_; + + void AddRef() { refcount_++; } + void Release() { if (!--refcount_) delete this; } + private: + int refcount_; + }; + + Data * data_; +}; + +} + + + +#endif diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/plainsaslhandler.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/plainsaslhandler.h new file mode 100644 index 00000000..659820f5 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/plainsaslhandler.h @@ -0,0 +1,80 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PLAINSASLHANDLER_H_ +#define _PLAINSASLHANDLER_H_ + +#include "talk/xmpp/saslhandler.h" +#include <algorithm> + +namespace buzz { + +class PlainSaslHandler : public SaslHandler { +public: + PlainSaslHandler(const Jid & jid, const XmppPassword & password) : + jid_(jid), password_(password) {} + + virtual ~PlainSaslHandler() {} + + // Should pick the best method according to this handler + // returns the empty string if none are suitable + virtual std::string ChooseBestSaslMechanism(const std::vector<std::string> & mechanisms, bool encrypted) { + + // Do not send @google.com passwords unencrypted + if (!encrypted && jid_.domain() == "google.com") { + return ""; + } + + std::vector<std::string>::const_iterator it = std::find(mechanisms.begin(), mechanisms.end(), "PLAIN"); + if (it == mechanisms.end()) { + return ""; + } + else { + return "PLAIN"; + } + } + + // Creates a SaslMechanism for the given mechanism name (you own it + // once you get it). If not handled, return NULL. + virtual SaslMechanism * CreateSaslMechanism(const std::string & mechanism) { + if (mechanism == "PLAIN") { + return new SaslPlainMechanism(jid_, password_); + } + return NULL; + } + +private: + Jid jid_; + XmppPassword password_; + +}; + + +} + +#endif + diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/prexmppauth.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/prexmppauth.h new file mode 100644 index 00000000..8d2aa9d4 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/prexmppauth.h @@ -0,0 +1,85 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PREXMPPAUTH_H_ +#define _PREXMPPAUTH_H_ + +#include "talk/base/sigslot.h" +#include "talk/xmpp/saslhandler.h" +#include "talk/xmpp/xmpppassword.h" + +namespace cricket { + class SocketAddress; +} + +namespace buzz { + +class Jid; +class SaslMechanism; + +class CaptchaChallenge { + public: + CaptchaChallenge() : captcha_needed_(false) {} + CaptchaChallenge(const std::string& token, const std::string& url) + : captcha_needed_(true), captcha_token_(token), captcha_image_url_(url) { + } + + bool captcha_needed() const { return captcha_needed_; } + const std::string& captcha_token() const { return captcha_token_; } + + // This url is relative to the gaia server. Once we have better tools + // for cracking URLs, we should probably make this a full URL + const std::string& captcha_image_url() const { return captcha_image_url_; } + + private: + bool captcha_needed_; + std::string captcha_token_; + std::string captcha_image_url_; +}; + +class PreXmppAuth : public SaslHandler { +public: + virtual ~PreXmppAuth() {} + + virtual void StartPreXmppAuth( + const Jid & jid, + const cricket::SocketAddress & server, + const XmppPassword & pass, + const std::string & auth_cookie) = 0; + + sigslot::signal0<> SignalAuthDone; + + virtual bool IsAuthDone() = 0; + virtual bool IsAuthorized() = 0; + virtual bool HadError() = 0; + virtual CaptchaChallenge GetCaptchaChallenge() = 0; + virtual std::string GetAuthCookie() = 0; +}; + +} + +#endif diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslcookiemechanism.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslcookiemechanism.h new file mode 100644 index 00000000..a6630d90 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslcookiemechanism.h @@ -0,0 +1,67 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _SASLCOOKIEMECHANISM_H_ +#define _SASLCOOKIEMECHANISM_H_ + +#include "talk/xmpp/saslmechanism.h" +#include "talk/xmllite/xmlelement.h" +#include "talk/xmpp/constants.h" + +namespace buzz { + +class SaslCookieMechanism : public SaslMechanism { + +public: + SaslCookieMechanism(const std::string & mechanism, const std::string & username, const std::string & cookie) : + mechanism_(mechanism), username_(username), cookie_(cookie) {} + + virtual std::string GetMechanismName() { return mechanism_; } + + virtual XmlElement * StartSaslAuth() { + // send initial request + XmlElement * el = new XmlElement(QN_SASL_AUTH, true); + el->AddAttr(QN_MECHANISM, mechanism_); + + std::string credential; + credential.append("\0", 1); + credential.append(username_); + credential.append("\0", 1); + credential.append(cookie_); + el->AddText(Base64Encode(credential)); + return el; + } + +private: + std::string mechanism_; + std::string username_; + std::string cookie_; +}; + +} + +#endif diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslhandler.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslhandler.h new file mode 100644 index 00000000..b57d3baf --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslhandler.h @@ -0,0 +1,59 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _SASLHANDLER_H_ +#define _SASLHANDLER_H_ + +#include <string> + +namespace buzz { + +class XmlElement; +class SaslMechanism; + +// Creates mechanisms to deal with a given mechanism +class SaslHandler { + +public: + + // Intended to be subclassed + virtual ~SaslHandler() {} + + // Should pick the best method according to this handler + // returns the empty string if none are suitable + virtual std::string ChooseBestSaslMechanism(const std::vector<std::string> & mechanisms, bool encrypted) = 0; + + // Creates a SaslMechanism for the given mechanism name (you own it + // once you get it). + // If not handled, return NULL. + virtual SaslMechanism * CreateSaslMechanism(const std::string & mechanism) = 0; +}; + +} + +#endif + diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslmechanism.cc b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslmechanism.cc new file mode 100644 index 00000000..092df104 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslmechanism.cc @@ -0,0 +1,68 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "talk/base/base64.h" +#include "talk/xmllite/xmlelement.h" +#include "talk/xmpp/constants.h" +#include "talk/xmpp/saslmechanism.h" + +namespace buzz { + +XmlElement * +SaslMechanism::StartSaslAuth() { + return new XmlElement(QN_SASL_AUTH, true); +} + +XmlElement * +SaslMechanism::HandleSaslChallenge(const XmlElement * challenge) { + return new XmlElement(QN_SASL_ABORT, true); +} + +void +SaslMechanism::HandleSaslSuccess(const XmlElement * success) { +} + +void +SaslMechanism::HandleSaslFailure(const XmlElement * failure) { +} + +std::string +SaslMechanism::Base64Encode(const std::string & plain) { + return Base64::encode(plain); +} + +std::string +SaslMechanism::Base64Decode(const std::string & encoded) { + return Base64::decode(encoded); +} + +std::string +SaslMechanism::Base64EncodeFromArray(const char * plain, size_t length) { + return Base64::encodeFromArray(plain, length); +} + +} diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslmechanism.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslmechanism.h new file mode 100644 index 00000000..f2e5adce --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslmechanism.h @@ -0,0 +1,74 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _SASLMECHANISM_H_ +#define _SASLMECHANISM_H_ + +#include <string> + +namespace buzz { + +class XmlElement; + + +// Defines a mechnanism to do SASL authentication. +// Subclass instances should have a self-contained way to present +// credentials. +class SaslMechanism { + +public: + + // Intended to be subclassed + virtual ~SaslMechanism() {} + + // Should return the name of the SASL mechanism, e.g., "PLAIN" + virtual std::string GetMechanismName() = 0; + + // Should generate the initial "auth" request. Default is just <auth/>. + virtual XmlElement * StartSaslAuth(); + + // Should respond to a SASL "<challenge>" request. Default is + // to abort (for mechanisms that do not do challenge-response) + virtual XmlElement * HandleSaslChallenge(const XmlElement * challenge); + + // Notification of a SASL "<success>". Sometimes information + // is passed on success. + virtual void HandleSaslSuccess(const XmlElement * success); + + // Notification of a SASL "<failure>". Sometimes information + // for the user is passed on failure. + virtual void HandleSaslFailure(const XmlElement * failure); + +protected: + static std::string Base64Encode(const std::string & plain); + static std::string Base64Decode(const std::string & encoded); + static std::string Base64EncodeFromArray(const char * plain, size_t length); +}; + +} + +#endif diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslplainmechanism.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslplainmechanism.h new file mode 100644 index 00000000..7e0b0562 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/saslplainmechanism.h @@ -0,0 +1,65 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _SASLPLAINMECHANISM_H_ +#define _SASLPLAINMECHANISM_H_ + +#include "talk/xmpp/saslmechanism.h" +#include "talk/xmpp/xmpppassword.h" + +namespace buzz { + +class SaslPlainMechanism : public SaslMechanism { + +public: + SaslPlainMechanism(const buzz::Jid user_jid, const XmppPassword & password) : + user_jid_(user_jid), password_(password) {} + + virtual std::string GetMechanismName() { return "PLAIN"; } + + virtual XmlElement * StartSaslAuth() { + // send initial request + XmlElement * el = new XmlElement(QN_SASL_AUTH, true); + el->AddAttr(QN_MECHANISM, "PLAIN"); + + FormatXmppPassword credential; + credential.Append("\0", 1); + credential.Append(user_jid_.Str()); + credential.Append("\0", 1); + credential.Append(&password_); + el->AddText(Base64EncodeFromArray(credential.GetData(), credential.GetLength())); + return el; + } + +private: + Jid user_jid_; + XmppPassword password_; +}; + +} + +#endif diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppclient.cc b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppclient.cc new file mode 100644 index 00000000..959b6f88 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppclient.cc @@ -0,0 +1,372 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "xmppclient.h" +#include "xmpptask.h" +#include "talk/xmpp/constants.h" +#include "talk/base/sigslot.h" +#include "talk/xmpp/saslplainmechanism.h" +#include "talk/xmpp/prexmppauth.h" +#include "talk/base/scoped_ptr.h" +#include "talk/xmpp/plainsaslhandler.h" + +namespace buzz { + +Task * +XmppClient::GetParent(int code) { + if (code == XMPP_CLIENT_TASK_CODE) + return this; + else + return Task::GetParent(code); +} + +class XmppClient::Private : + public sigslot::has_slots<>, + public XmppSessionHandler, + public XmppOutputHandler { +public: + + Private(XmppClient * client) : + client_(client), + socket_(NULL), + engine_(NULL), + proxy_port_(0), + pre_engine_error_(XmppEngine::ERROR_NONE), + signal_closed_(false) {} + + // the owner + XmppClient * const client_; + + // the two main objects + scoped_ptr<AsyncSocket> socket_; + scoped_ptr<XmppEngine> engine_; + scoped_ptr<PreXmppAuth> pre_auth_; + XmppPassword pass_; + std::string auth_cookie_; + cricket::SocketAddress server_; + std::string proxy_host_; + int proxy_port_; + XmppEngine::Error pre_engine_error_; + CaptchaChallenge captcha_challenge_; + bool signal_closed_; + + // implementations of interfaces + void OnStateChange(int state); + void WriteOutput(const char * bytes, size_t len); + void StartTls(const std::string & domainname); + void CloseConnection(); + + // slots for socket signals + void OnSocketConnected(); + void OnSocketRead(); + void OnSocketClosed(); +}; + +XmppReturnStatus +XmppClient::Connect(const XmppClientSettings & settings, AsyncSocket * socket, PreXmppAuth * pre_auth) { + if (socket == NULL) + return XMPP_RETURN_BADARGUMENT; + if (d_->socket_.get() != NULL) + return XMPP_RETURN_BADSTATE; + + d_->socket_.reset(socket); + + d_->socket_->SignalConnected.connect(d_.get(), &Private::OnSocketConnected); + d_->socket_->SignalRead.connect(d_.get(), &Private::OnSocketRead); + d_->socket_->SignalClosed.connect(d_.get(), &Private::OnSocketClosed); + + d_->engine_.reset(XmppEngine::Create()); + d_->engine_->SetSessionHandler(d_.get()); + d_->engine_->SetOutputHandler(d_.get()); + d_->engine_->SetUser(buzz::Jid(settings.user(), settings.host(), STR_EMPTY)); + if (!settings.resource().empty()) { + d_->engine_->SetRequestedResource(settings.resource()); + } + d_->engine_->SetUseTls(settings.use_tls()); + + + d_->pass_ = settings.pass(); + d_->auth_cookie_ = settings.auth_cookie(); + d_->server_ = settings.server(); + d_->proxy_host_ = settings.proxy_host(); + d_->proxy_port_ = settings.proxy_port(); + d_->pre_auth_.reset(pre_auth); + + return XMPP_RETURN_OK; +} + +XmppEngine::State +XmppClient::GetState() { + if (d_->engine_.get() == NULL) + return XmppEngine::STATE_NONE; + return d_->engine_->GetState(); +} + +XmppEngine::Error +XmppClient::GetError() { + if (d_->engine_.get() == NULL) + return XmppEngine::ERROR_NONE; + if (d_->pre_engine_error_ != XmppEngine::ERROR_NONE) + return d_->pre_engine_error_; + return d_->engine_->GetError(); +} + +CaptchaChallenge XmppClient::GetCaptchaChallenge() { + if (d_->engine_.get() == NULL) + return CaptchaChallenge(); + return d_->captcha_challenge_; +} + +std::string +XmppClient::GetAuthCookie() { + if (d_->engine_.get() == NULL) + return ""; + return d_->auth_cookie_; +} + +static void +ForgetPassword(std::string & to_erase) { + size_t len = to_erase.size(); + for (size_t i = 0; i < len; i++) { + // get rid of characters + to_erase[i] = 'x'; + } + // get rid of length + to_erase.erase(); +} + +int +XmppClient::ProcessStart() { + if (d_->pre_auth_.get()) { + d_->pre_auth_->SignalAuthDone.connect(this, &XmppClient::OnAuthDone); + d_->pre_auth_->StartPreXmppAuth( + d_->engine_->GetUser(), d_->server_, d_->pass_, d_->auth_cookie_); + d_->pass_.Clear(); // done with this; + return STATE_PRE_XMPP_LOGIN; + } + else { + d_->engine_->SetSaslHandler(new PlainSaslHandler( + d_->engine_->GetUser(), d_->pass_)); + d_->pass_.Clear(); // done with this; + return STATE_START_XMPP_LOGIN; + } +} + +void +XmppClient::OnAuthDone() { + Wake(); +} + +int +XmppClient::ProcessCookieLogin() { + // Don't know how this could happen, but crash reports show it as NULL + if (!d_->pre_auth_.get()) { + d_->pre_engine_error_ = XmppEngine::ERROR_AUTH; + EnsureClosed(); + return STATE_ERROR; + } + + // Wait until pre authentication is done is done + if (!d_->pre_auth_->IsAuthDone()) + return STATE_BLOCKED; + + if (!d_->pre_auth_->IsAuthorized()) { + // maybe split out a case when gaia is down? + if (d_->pre_auth_->HadError()) { + d_->pre_engine_error_ = XmppEngine::ERROR_AUTH; + } + else { + d_->pre_engine_error_ = XmppEngine::ERROR_UNAUTHORIZED; + d_->captcha_challenge_ = d_->pre_auth_->GetCaptchaChallenge(); + } + d_->pre_auth_.reset(NULL); // done with this + EnsureClosed(); + return STATE_ERROR; + } + + // Save auth cookie as a result + d_->auth_cookie_ = d_->pre_auth_->GetAuthCookie(); + + // transfer ownership of pre_auth_ to engine + d_->engine_->SetSaslHandler(d_->pre_auth_.release()); + + return STATE_START_XMPP_LOGIN; +} + +int +XmppClient::ProcessStartXmppLogin() { + // Done with pre-connect tasks - connect! + if (!d_->socket_->Connect(d_->server_)) { + EnsureClosed(); + return STATE_ERROR; + } + + return STATE_RESPONSE; +} + +int +XmppClient::ProcessResponse() { + // Hang around while we are connected. + if (!delivering_signal_ && (d_->engine_.get() == NULL || + d_->engine_->GetState() == XmppEngine::STATE_CLOSED)) + return STATE_DONE; + return STATE_BLOCKED; +} + +XmppReturnStatus +XmppClient::Disconnect() { + if (d_->socket_.get() == NULL) + return XMPP_RETURN_BADSTATE; + d_->engine_->Disconnect(); + return XMPP_RETURN_OK; +} + +XmppClient::XmppClient(Task * parent) : Task(parent), + delivering_signal_(false) { + d_.reset(new Private(this)); +} + +XmppClient::~XmppClient() {} + +const Jid & +XmppClient::jid() { + return d_->engine_->FullJid(); +} + + +std::string +XmppClient::NextId() { + return d_->engine_->NextId(); +} + +XmppReturnStatus +XmppClient::SendStanza(const XmlElement * stanza) { + return d_->engine_->SendStanza(stanza); +} + +XmppReturnStatus +XmppClient::SendStanzaError(const XmlElement * old_stanza, XmppStanzaError xse, const std::string & message) { + return d_->engine_->SendStanzaError(old_stanza, xse, message); +} + +XmppReturnStatus +XmppClient::SendRaw(const std::string & text) { + return d_->engine_->SendRaw(text); +} + +XmppEngine* +XmppClient::engine() { + return d_->engine_.get(); +} + +void +XmppClient::Private::OnSocketConnected() { + engine_->Connect(); +} + +void +XmppClient::Private::OnSocketRead() { + char bytes[4096]; + size_t bytes_read; + for (;;) { + if (!socket_->Read(bytes, sizeof(bytes), &bytes_read)) { + // TODO: deal with error information + return; + } + + if (bytes_read == 0) + return; + +//#ifdef _DEBUG + client_->SignalLogInput(bytes, bytes_read); +//#endif + + engine_->HandleInput(bytes, bytes_read); + } +} + +void +XmppClient::Private::OnSocketClosed() { + engine_->ConnectionClosed(); +} + +void +XmppClient::Private::OnStateChange(int state) { + if (state == XmppEngine::STATE_CLOSED) { + client_->EnsureClosed(); + } + else { + client_->SignalStateChange((XmppEngine::State)state); + } + client_->Wake(); +} + +void +XmppClient::Private::WriteOutput(const char * bytes, size_t len) { + +//#ifdef _DEBUG + client_->SignalLogOutput(bytes, len); +//#endif + + socket_->Write(bytes, len); + // TODO: deal with error information +} + +void +XmppClient::Private::StartTls(const std::string & domain) { +#if defined(FEATURE_ENABLE_SSL) + socket_->StartTls(domain); +#endif +} + +void +XmppClient::Private::CloseConnection() { + socket_->Close(); +} + +void +XmppClient::AddXmppTask(XmppTask * task, XmppEngine::HandlerLevel level) { + d_->engine_->AddStanzaHandler(task, level); +} + +void +XmppClient::RemoveXmppTask(XmppTask * task) { + d_->engine_->RemoveStanzaHandler(task); +} + +void +XmppClient::EnsureClosed() { + if (!d_->signal_closed_) { + d_->signal_closed_ = true; + delivering_signal_ = true; + SignalStateChange(XmppEngine::STATE_CLOSED); + delivering_signal_ = false; + } +} + + +} diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppclient.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppclient.h new file mode 100644 index 00000000..f8b4798c --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppclient.h @@ -0,0 +1,157 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _XMPPCLIENT_H_ +#define _XMPPCLIENT_H_ + +#include <string> +#include "talk/base/basicdefs.h" +#include "talk/base/sigslot.h" +#include "talk/xmpp/xmppengine.h" +#include "talk/xmpp/asyncsocket.h" +#include "talk/xmpp/xmppclientsettings.h" +#include "talk/base/task.h" + +namespace buzz { + +class XmppTask; +class PreXmppAuth; +class CaptchaChallenge; + +// Just some non-colliding number. Could have picked "1". +#define XMPP_CLIENT_TASK_CODE 0x366c1e47 + +///////////////////////////////////////////////////////////////////// +// +// XMPPCLIENT +// +///////////////////////////////////////////////////////////////////// +// +// See Task first. XmppClient is a parent task for XmppTasks. +// +// XmppClient is a task which is designed to be the parent task for +// all tasks that depend on a single Xmpp connection. If you want to, +// for example, listen for subscription requests forever, then your +// listener should be a task that is a child of the XmppClient that owns +// the connection you are using. XmppClient has all the utility methods +// that basically drill through to XmppEngine. +// +// XmppClient is just a wrapper for XmppEngine, and if I were writing it +// all over again, I would make XmppClient == XmppEngine. Why? +// XmppEngine needs tasks too, for example it has an XmppLoginTask which +// should just be the same kind of Task instead of an XmppEngine specific +// thing. It would help do certain things like GAIA auth cleaner. +// +///////////////////////////////////////////////////////////////////// + +class XmppClient : public Task, public sigslot::has_slots<> +{ +public: + XmppClient(Task * parent); + ~XmppClient(); + + XmppReturnStatus Connect(const XmppClientSettings & settings, + AsyncSocket * socket, + PreXmppAuth * preauth); + + virtual Task * GetParent(int code); + virtual int ProcessStart(); + virtual int ProcessResponse(); + XmppReturnStatus Disconnect(); + const Jid & jid(); + + sigslot::signal1<XmppEngine::State> SignalStateChange; + XmppEngine::State GetState(); + XmppEngine::Error GetError(); + + // When there is an authentication error, we may have captcha info + // that the user can use to unlock their account + CaptchaChallenge GetCaptchaChallenge(); + + // When authentication is successful, this returns the service cookie + // (if we used GAIA authentication) + std::string GetAuthCookie(); + + std::string NextId(); + XmppReturnStatus SendStanza(const XmlElement *stanza); + XmppReturnStatus SendRaw(const std::string & text); + XmppReturnStatus SendStanzaError(const XmlElement * pelOriginal, + XmppStanzaError code, + const std::string & text); + + XmppEngine* engine(); + + sigslot::signal2<const char *, int> SignalLogInput; + sigslot::signal2<const char *, int> SignalLogOutput; + +private: + friend class XmppTask; + + void OnAuthDone(); + + // managed tasks and dispatching + void AddXmppTask(XmppTask *, XmppEngine::HandlerLevel); + void RemoveXmppTask(XmppTask *); + + sigslot::signal0<> SignalDisconnected; + +private: + // Internal state management + enum { + STATE_PRE_XMPP_LOGIN = STATE_NEXT, + STATE_START_XMPP_LOGIN = STATE_NEXT + 1, + }; + int Process(int state) { + switch (state) { + case STATE_PRE_XMPP_LOGIN: return ProcessCookieLogin(); + case STATE_START_XMPP_LOGIN: return ProcessStartXmppLogin(); + default: return Task::Process(state); + } + } + + std::string GetStateName(int state) const { + switch (state) { + case STATE_PRE_XMPP_LOGIN: return "PRE_XMPP_LOGIN"; + case STATE_START_XMPP_LOGIN: return "START_XMPP_LOGIN"; + default: return Task::GetStateName(state); + } + } + + int ProcessCookieLogin(); + int ProcessStartXmppLogin(); + void EnsureClosed(); + + class Private; + friend class Private; + scoped_ptr<Private> d_; + + bool delivering_signal_; +}; + +} + +#endif diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppclientsettings.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppclientsettings.h new file mode 100644 index 00000000..9795682b --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppclientsettings.h @@ -0,0 +1,94 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _XMPPCLIENTSETTINGS_H_ +#define _XMPPCLIENTSETTINGS_H_ + +#include "talk/p2p/base/port.h" +#include "talk/xmpp/xmpppassword.h" + +namespace buzz { + +class XmppClientSettings { +public: + XmppClientSettings() : + use_tls_(false), use_cookie_auth_(false), protocol_(cricket::PROTO_TCP), + proxy_(cricket::PROXY_NONE), proxy_port_(80), use_proxy_auth_(false) {} + + void set_user(const std::string & user) { user_ = user; } + void set_host(const std::string & host) { host_ = host; } + void set_pass(const XmppPassword & pass) { pass_ = pass; } + void set_auth_cookie(const std::string & cookie) { auth_cookie_ = cookie; } + void set_resource(const std::string & resource) { resource_ = resource; } + void set_use_tls(bool use_tls) { use_tls_ = use_tls; } + void set_server(const cricket::SocketAddress & server) { + server_ = server; + } + void set_protocol(cricket::ProtocolType protocol) { protocol_ = protocol; } + void set_proxy(cricket::ProxyType f) { proxy_ = f; } + void set_proxy_host(const std::string & host) { proxy_host_ = host; } + void set_proxy_port(int port) { proxy_port_ = port; }; + void set_use_proxy_auth(bool f) { use_proxy_auth_ = f; } + void set_proxy_user(const std::string & user) { proxy_user_ = user; } + void set_proxy_pass(const XmppPassword & pass) { proxy_pass_ = pass; } + + const std::string & user() const { return user_; } + const std::string & host() const { return host_; } + const XmppPassword & pass() const { return pass_; } + const std::string & auth_cookie() const { return auth_cookie_; } + const std::string & resource() const { return resource_; } + bool use_tls() const { return use_tls_; } + const cricket::SocketAddress & server() const { return server_; } + cricket::ProtocolType protocol() const { return protocol_; } + cricket::ProxyType proxy() const { return proxy_; } + const std::string & proxy_host() const { return proxy_host_; } + int proxy_port() const { return proxy_port_; } + bool use_proxy_auth() const { return use_proxy_auth_; } + const std::string & proxy_user() const { return proxy_user_; } + const XmppPassword & proxy_pass() const { return proxy_pass_; } + +private: + std::string user_; + std::string host_; + XmppPassword pass_; + std::string auth_cookie_; + std::string resource_; + bool use_tls_; + bool use_cookie_auth_; + cricket::SocketAddress server_; + cricket::ProtocolType protocol_; + cricket::ProxyType proxy_; + std::string proxy_host_; + int proxy_port_; + bool use_proxy_auth_; + std::string proxy_user_; + XmppPassword proxy_pass_; +}; + +} + +#endif diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppengine.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppengine.h new file mode 100644 index 00000000..ef8f2ea8 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppengine.h @@ -0,0 +1,332 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _xmppengine_h_ +#define _xmppengine_h_ + +// also part of the API +#include "talk/xmpp/jid.h" +#include "talk/xmllite/qname.h" +#include "talk/xmllite/xmlelement.h" + + +namespace buzz { + +class XmppEngine; +class SaslHandler; +typedef void * XmppIqCookie; + +//! XMPP stanza error codes. +//! Used in XmppEngine.SendStanzaError(). +enum XmppStanzaError { + XSE_BAD_REQUEST, + XSE_CONFLICT, + XSE_FEATURE_NOT_IMPLEMENTED, + XSE_FORBIDDEN, + XSE_GONE, + XSE_INTERNAL_SERVER_ERROR, + XSE_ITEM_NOT_FOUND, + XSE_JID_MALFORMED, + XSE_NOT_ACCEPTABLE, + XSE_NOT_ALLOWED, + XSE_PAYMENT_REQUIRED, + XSE_RECIPIENT_UNAVAILABLE, + XSE_REDIRECT, + XSE_REGISTRATION_REQUIRED, + XSE_SERVER_NOT_FOUND, + XSE_SERVER_TIMEOUT, + XSE_RESOURCE_CONSTRAINT, + XSE_SERVICE_UNAVAILABLE, + XSE_SUBSCRIPTION_REQUIRED, + XSE_UNDEFINED_CONDITION, + XSE_UNEXPECTED_REQUEST, +}; + +// XmppReturnStatus +// This is used by API functions to synchronously return status. +enum XmppReturnStatus { + XMPP_RETURN_OK, + XMPP_RETURN_BADARGUMENT, + XMPP_RETURN_BADSTATE, + XMPP_RETURN_PENDING, + XMPP_RETURN_UNEXPECTED, + XMPP_RETURN_NOTYETIMPLEMENTED, +}; + +//! Callback for socket output for an XmppEngine connection. +//! Register via XmppEngine.SetOutputHandler. An XmppEngine +//! can call back to this handler while it is processing +//! Connect, SendStanza, SendIq, Disconnect, or HandleInput. +class XmppOutputHandler { +public: + + //! Deliver the specified bytes to the XMPP socket. + virtual void WriteOutput(const char * bytes, size_t len) = 0; + + //! Initiate TLS encryption on the socket. + //! The implementation must verify that the SSL + //! certificate matches the given domainname. + virtual void StartTls(const std::string & domainname) = 0; + + //! Called when engine wants the connecton closed. + virtual void CloseConnection() = 0; +}; + +//! Callback to deliver engine state change notifications +//! to the object managing the engine. +class XmppSessionHandler { +public: + //! Called when engine changes state. Argument is new state. + virtual void OnStateChange(int state) = 0; +}; + +//! Callback to deliver stanzas to an Xmpp application module. +//! Register via XmppEngine.SetDefaultSessionHandler or via +//! XmppEngine.AddSessionHAndler. +class XmppStanzaHandler { +public: + + //! Process the given stanza. + //! The handler must return true if it has handled the stanza. + //! A false return value causes the stanza to be passed on to + //! the next registered handler. + virtual bool HandleStanza(const XmlElement * stanza) = 0; +}; + +//! Callback to deliver iq responses (results and errors). +//! Register while sending an iq via XmppEngine.SendIq. +//! Iq responses are routed to matching XmppIqHandlers in preference +//! to sending to any registered SessionHandlers. +class XmppIqHandler { +public: + //! Called to handle the iq response. + //! The response may be either a result or an error, and will have + //! an 'id' that matches the request and a 'from' that matches the + //! 'to' of the request. Called no more than once; once this is + //! called, the handler is automatically unregistered. + virtual void IqResponse(XmppIqCookie cookie, const XmlElement * pelStanza) = 0; +}; + +//! The XMPP connection engine. +//! This engine implements the client side of the 'core' XMPP protocol. +//! To use it, register an XmppOutputHandler to handle socket output +//! and pass socket input to HandleInput. Then application code can +//! set up the connection with a user, password, and other settings, +//! and then call Connect() to initiate the connection. +//! An application can listen for events and receive stanzas by +//! registering an XmppStanzaHandler via AddStanzaHandler(). +class XmppEngine { +public: + static XmppEngine * Create(); + virtual ~XmppEngine() {} + + //! Error codes. See GetError(). + enum Error { + ERROR_NONE = 0, //!< No error + ERROR_XML, //!< Malformed XML or encoding error + ERROR_STREAM, //!< XMPP stream error - see GetStreamError() + ERROR_VERSION, //!< XMPP version error + ERROR_UNAUTHORIZED, //!< User is not authorized (rejected credentials) + ERROR_TLS, //!< TLS could not be negotiated + ERROR_AUTH, //!< Authentication could not be negotiated + ERROR_BIND, //!< Resource or session binding could not be negotiated + ERROR_CONNECTION_CLOSED,//!< Connection closed by output handler. + ERROR_DOCUMENT_CLOSED, //!< Closed by </stream:stream> + ERROR_SOCKET, //!< Socket error + }; + + //! States. See GetState(). + enum State { + STATE_NONE = 0, //!< Nonexistent state + STATE_START, //!< Initial state. + STATE_OPENING, //!< Exchanging stream headers, authenticating and so on. + STATE_OPEN, //!< Authenticated and bound. + STATE_CLOSED, //!< Session closed, possibly due to error. + }; + + // SOCKET INPUT AND OUTPUT ------------------------------------------------ + + //! Registers the handler for socket output + virtual XmppReturnStatus SetOutputHandler(XmppOutputHandler *pxoh) = 0; + + //! Provides socket input to the engine + virtual XmppReturnStatus HandleInput(const char * bytes, size_t len) = 0; + + //! Advises the engine that the socket has closed + virtual XmppReturnStatus ConnectionClosed() = 0; + + // SESSION SETUP --------------------------------------------------------- + + //! Indicates the (bare) JID for the user to use. + virtual XmppReturnStatus SetUser(const Jid & jid)= 0; + + //! Get the login (bare) JID. + virtual const Jid & GetUser() = 0; + + //! Provides different methods for credentials for login. + //! Takes ownership of this object; deletes when login is done + virtual XmppReturnStatus SetSaslHandler(SaslHandler * h) = 0; + + //! Sets whether TLS will be used within the connection (default true). + virtual XmppReturnStatus SetUseTls(bool useTls) = 0; + + //! Sets an alternate domain from which we allows TLS certificates. + //! This is for use in the case where a we want to allow a proxy to + //! serve up its own certificate rather than one owned by the underlying + //! domain. + virtual XmppReturnStatus SetTlsServerDomain(const std::string & proxy_domain) = 0; + + //! Gets whether TLS will be used within the connection. + virtual bool GetUseTls() = 0; + + //! Sets the request resource name, if any (optional). + //! Note that the resource name may be overridden by the server; after + //! binding, the actual resource name is available as part of FullJid(). + virtual XmppReturnStatus SetRequestedResource(const std::string& resource) = 0; + + //! Gets the request resource name. + virtual const std::string & GetRequestedResource() = 0; + + // SESSION MANAGEMENT --------------------------------------------------- + + //! Set callback for state changes. + virtual XmppReturnStatus SetSessionHandler(XmppSessionHandler* handler) = 0; + + //! Initiates the XMPP connection. + //! After supplying connection settings, call this once to initiate, + //! (optionally) encrypt, authenticate, and bind the connection. + virtual XmppReturnStatus Connect() = 0; + + //! The current engine state. + virtual State GetState() = 0; + + //! Returns true if the connection is encrypted (under TLS) + virtual bool IsEncrypted() = 0; + + //! The error code. + //! Consult this after XmppOutputHandler.OnClose(). + virtual Error GetError() = 0; + + //! The stream:error stanza, when the error is XMPP_ERROR_STREAM. + //! Notice the stanza returned is owned by the XmppEngine and + //! is deleted when the engine is destroyed. + virtual const XmlElement * GetStreamError() = 0; + + //! Closes down the connection. + //! Sends CloseConnection to output, and disconnects and registered + //! session handlers. After Disconnect completes, it is guaranteed + //! that no further callbacks will be made. + virtual XmppReturnStatus Disconnect() = 0; + + // APPLICATION USE ------------------------------------------------------- + + enum HandlerLevel { + HL_NONE = 0, + HL_PEEK, //!< Sees messages before all other processing; cannot abort + HL_SINGLE, //!< Watches for a single message, e.g., by id and sender + HL_SENDER, //!< Watches for a type of message from a specific sender + HL_TYPE, //!< Watches a type of message, e.g., all groupchat msgs + HL_ALL, //!< Watches all messages - gets last shot + HL_COUNT, //!< Count of handler levels + }; + + //! Adds a listener for session events. + //! Stanza delivery is chained to session handlers; the first to + //! return 'true' is the last to get each stanza. + virtual XmppReturnStatus AddStanzaHandler(XmppStanzaHandler* handler, HandlerLevel level = HL_PEEK) = 0; + + //! Removes a listener for session events. + virtual XmppReturnStatus RemoveStanzaHandler(XmppStanzaHandler* handler) = 0; + + //! Sends a stanza to the server. + virtual XmppReturnStatus SendStanza(const XmlElement * pelStanza) = 0; + + //! Sends raw text to the server + virtual XmppReturnStatus SendRaw(const std::string & text) = 0; + + //! Sends an iq to the server, and registers a callback for the result. + //! Returns the cookie passed to the result handler. + virtual XmppReturnStatus SendIq(const XmlElement* pelStanza, + XmppIqHandler* iq_handler, + XmppIqCookie* cookie) = 0; + + //! Unregisters an iq callback handler given its cookie. + //! No callback will come to this handler after it's unregistered. + virtual XmppReturnStatus RemoveIqHandler(XmppIqCookie cookie, + XmppIqHandler** iq_handler) = 0; + + + //! Forms and sends an error in response to the given stanza. + //! Swaps to and from, sets type to "error", and adds error information + //! based on the passed code. Text is optional and may be STR_EMPTY. + virtual XmppReturnStatus SendStanzaError(const XmlElement * pelOriginal, + XmppStanzaError code, + const std::string & text) = 0; + + //! The fullly bound JID. + //! This JID is only valid after binding has succeeded. If the value + //! is JID_NULL, the binding has not succeeded. + virtual const Jid & FullJid() = 0; + + //! The next unused iq id for this connection. + //! Call this when building iq stanzas, to ensure that each iq + //! gets its own unique id. + virtual std::string NextId() = 0; + +}; + +} + + +// Move these to a better location + +#define XMPP_FAILED(x) \ + ( (x) == buzz::XMPP_RETURN_OK ? false : true) \ + + +#define XMPP_SUCCEEDED(x) \ + ( (x) == buzz::XMPP_RETURN_OK ? true : false) \ + +#define IFR(x) \ + do { \ + xmpp_status = (x); \ + if (XMPP_FAILED(xmpp_status)) { \ + return xmpp_status; \ + } \ + } while (false) \ + + +#define IFC(x) \ + do { \ + xmpp_status = (x); \ + if (XMPP_FAILED(xmpp_status)) { \ + goto Cleanup; \ + } \ + } while (false) \ + + +#endif diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppengineimpl.cc b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppengineimpl.cc new file mode 100644 index 00000000..173d711b --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppengineimpl.cc @@ -0,0 +1,480 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define TRACK_ARRAY_ALLOC_PROBLEM + +#include <vector> +#include <sstream> +#include <algorithm> +#include "talk/xmllite/xmlelement.h" +#include "talk/base/common.h" +#include "talk/xmpp/xmppengineimpl.h" +#include "talk/xmpp/xmpplogintask.h" +#include "talk/xmpp/constants.h" +#include "talk/xmllite/xmlprinter.h" +#include "talk/xmpp/saslhandler.h" +// #include "buzz/saslmechanism.h" + +#define new TRACK_NEW + +namespace buzz { + +static const std::string XMPP_CLIENT_NAMESPACES[] = { + "stream", "http://etherx.jabber.org/streams", + "", "jabber:client", +}; + +static const size_t XMPP_CLIENT_NAMESPACES_LEN = 4; + +XmppEngine * XmppEngine::Create() { + return new XmppEngineImpl(); +} + + +XmppEngineImpl::XmppEngineImpl() : + stanzaParseHandler_(this), + stanzaParser_(&stanzaParseHandler_), + engine_entered_(0), + user_jid_(JID_EMPTY), + password_(), + requested_resource_(STR_EMPTY), + tls_needed_(true), + login_task_(new XmppLoginTask(this)), + next_id_(0), + bound_jid_(JID_EMPTY), + state_(STATE_START), + encrypted_(false), + error_code_(ERROR_NONE), + stream_error_(NULL), + raised_reset_(false), + output_handler_(NULL), + session_handler_(NULL), + iq_entries_(new IqEntryVector()), + output_(new std::stringstream()), + sasl_handler_(NULL) { + for (int i = 0; i < HL_COUNT; i+= 1) { + stanza_handlers_[i].reset(new StanzaHandlerVector()); + } +} + +XmppEngineImpl::~XmppEngineImpl() { + DeleteIqCookies(); +} + +XmppReturnStatus +XmppEngineImpl::SetOutputHandler(XmppOutputHandler* output_handler) { + if (state_ != STATE_START) + return XMPP_RETURN_BADSTATE; + + output_handler_ = output_handler; + + return XMPP_RETURN_OK; +} + +XmppReturnStatus +XmppEngineImpl::SetSessionHandler(XmppSessionHandler* session_handler) { + if (state_ != STATE_START) + return XMPP_RETURN_BADSTATE; + + session_handler_ = session_handler; + + return XMPP_RETURN_OK; +} + +XmppReturnStatus +XmppEngineImpl::HandleInput(const char * bytes, size_t len) { + if (state_ < STATE_OPENING || state_ > STATE_OPEN) + return XMPP_RETURN_BADSTATE; + + EnterExit ee(this); + + stanzaParser_.Parse(bytes, len, false); + + return XMPP_RETURN_OK; +} + +XmppReturnStatus +XmppEngineImpl::ConnectionClosed() { + if (state_ != STATE_CLOSED) { + EnterExit ee(this); + // If told that connection closed and not already closed, + // then connection was unpexectedly dropped. + SignalError(ERROR_CONNECTION_CLOSED); + } + return XMPP_RETURN_OK; +} + +XmppReturnStatus +XmppEngineImpl::SetUseTls(bool useTls) { + if (state_ != STATE_START) + return XMPP_RETURN_BADSTATE; + + tls_needed_ = useTls; + + return XMPP_RETURN_OK; +} + +XmppReturnStatus +XmppEngineImpl::SetTlsServerDomain(const std::string & tls_server_domain) { + if (state_ != STATE_START) + return XMPP_RETURN_BADSTATE; + + tls_server_domain_= tls_server_domain; + + return XMPP_RETURN_OK; +} + +bool +XmppEngineImpl::GetUseTls() { + return tls_needed_; +} + +XmppReturnStatus +XmppEngineImpl::SetUser(const Jid & jid) { + if (state_ != STATE_START) + return XMPP_RETURN_BADSTATE; + + user_jid_ = jid; + + return XMPP_RETURN_OK; +} + +const Jid & +XmppEngineImpl::GetUser() { + return user_jid_; +} + +XmppReturnStatus +XmppEngineImpl::SetSaslHandler(SaslHandler * sasl_handler) { + if (state_ != STATE_START) + return XMPP_RETURN_BADSTATE; + + sasl_handler_.reset(sasl_handler); + return XMPP_RETURN_OK; +} + +XmppReturnStatus +XmppEngineImpl::SetRequestedResource(const std::string & resource) { + if (state_ != STATE_START) + return XMPP_RETURN_BADSTATE; + + requested_resource_ = resource; + + return XMPP_RETURN_OK; +} + +const std::string & +XmppEngineImpl::GetRequestedResource() { + return requested_resource_; +} + +XmppReturnStatus +XmppEngineImpl::AddStanzaHandler(XmppStanzaHandler * stanza_handler, + XmppEngine::HandlerLevel level) { + if (state_ == STATE_CLOSED) + return XMPP_RETURN_BADSTATE; + + stanza_handlers_[level]->push_back(stanza_handler); + + return XMPP_RETURN_OK; +} + +XmppReturnStatus +XmppEngineImpl::RemoveStanzaHandler(XmppStanzaHandler * stanza_handler) { + + bool found = false; + + for (int level = 0; level < HL_COUNT; level += 1) { + StanzaHandlerVector::iterator new_end = + std::remove(stanza_handlers_[level]->begin(), + stanza_handlers_[level]->end(), + stanza_handler); + + if (new_end != stanza_handlers_[level]->end()) { + stanza_handlers_[level]->erase(new_end, stanza_handlers_[level]->end()); + found = true; + } + } + + if (!found) { + return XMPP_RETURN_BADARGUMENT; + } + + return XMPP_RETURN_OK; +} + +XmppReturnStatus +XmppEngineImpl::Connect() { + if (state_ != STATE_START) + return XMPP_RETURN_BADSTATE; + + EnterExit ee(this); + + // get the login task started + state_ = STATE_OPENING; + if (login_task_.get()) { + login_task_->IncomingStanza(NULL, false); + if (login_task_->IsDone()) + login_task_.reset(); + } + + return XMPP_RETURN_OK; +} + +XmppReturnStatus +XmppEngineImpl::SendStanza(const XmlElement * element) { + if (state_ == STATE_CLOSED) + return XMPP_RETURN_BADSTATE; + + EnterExit ee(this); + + if (login_task_.get()) { + // still handshaking - then outbound stanzas are queued + login_task_->OutgoingStanza(element); + } else { + // handshake done - send straight through + InternalSendStanza(element); + } + + return XMPP_RETURN_OK; +} + +XmppReturnStatus +XmppEngineImpl::SendRaw(const std::string & text) { + if (state_ == STATE_CLOSED || login_task_.get()) + return XMPP_RETURN_BADSTATE; + + EnterExit ee(this); + + (*output_) << text; + + return XMPP_RETURN_OK; +} + +std::string +XmppEngineImpl::NextId() { + std::stringstream ss; + ss << next_id_++; + return ss.str(); +} + +XmppReturnStatus +XmppEngineImpl::Disconnect() { + + if (state_ != STATE_CLOSED) { + EnterExit ee(this); + if (state_ == STATE_OPEN) + *output_ << "</stream:stream>"; + state_ = STATE_CLOSED; + } + + return XMPP_RETURN_OK; +} + +void +XmppEngineImpl::IncomingStart(const XmlElement * pelStart) { + if (HasError() || raised_reset_) + return; + + if (login_task_.get()) { + // start-stream should go to login task + login_task_->IncomingStanza(pelStart, true); + if (login_task_->IsDone()) + login_task_.reset(); + } + else { + // if not logging in, it's an error to see a start + SignalError(ERROR_XML); + } +} + +void +XmppEngineImpl::IncomingStanza(const XmlElement * stanza) { + if (HasError() || raised_reset_) + return; + + if (stanza->Name() == QN_STREAM_ERROR) { + // Explicit XMPP stream error + SignalStreamError(stanza); + } else if (login_task_.get()) { + // Handle login handshake + login_task_->IncomingStanza(stanza, false); + if (login_task_->IsDone()) + login_task_.reset(); + } else if (HandleIqResponse(stanza)) { + // iq is handled by above call + } else { + // give every "peek" handler a shot at all stanzas + for (size_t i = 0; i < stanza_handlers_[HL_PEEK]->size(); i += 1) { + (*stanza_handlers_[HL_PEEK])[i]->HandleStanza(stanza); + } + + // give other handlers a shot in precedence order, stopping after handled + for (int level = HL_SINGLE; level <= HL_ALL; level += 1) { + for (size_t i = 0; i < stanza_handlers_[level]->size(); i += 1) { + if ((*stanza_handlers_[level])[i]->HandleStanza(stanza)) + goto Handled; + } + } + + // If nobody wants to handle a stanza then send back an error. + // Only do this for IQ stanzas as messages should probably just be dropped + // and presence stanzas should certainly be dropped. + std::string type = stanza->Attr(QN_TYPE); + if (stanza->Name() == QN_IQ && + !(type == "error" || type == "result")) { + SendStanzaError(stanza, XSE_FEATURE_NOT_IMPLEMENTED, STR_EMPTY); + } + } + Handled: + ; // handled - we're done +} + +void +XmppEngineImpl::IncomingEnd(bool isError) { + if (HasError() || raised_reset_) + return; + + SignalError(isError ? ERROR_XML : ERROR_DOCUMENT_CLOSED); +} + +void +XmppEngineImpl::InternalSendStart(const std::string & to) { + // send stream-beginning + // note, we put a \r\n at tne end fo the first line to cause non-XMPP + // line-oriented servers (e.g., Apache) to reveal themselves more quickly. + *output_ << "<stream:stream to=\"" << to << "\" version=\"1.0\" " + "xmlns:stream=\"http://etherx.jabber.org/streams\" " + "xmlns=\"jabber:client\">\r\n"; +} + +void +XmppEngineImpl::InternalSendStanza(const XmlElement * element) { + // It should really never be necessary to set a FROM attribute on a stanza. + // It is implied by the bind on the stream and if you get it wrong + // (by flipping from/to on a message?) the server will close the stream. + ASSERT(!element->HasAttr(QN_FROM)); + + // TODO: consider caching the XmlPrinter + XmlPrinter::PrintXml(output_.get(), element, + XMPP_CLIENT_NAMESPACES, XMPP_CLIENT_NAMESPACES_LEN); +} + +std::string +XmppEngineImpl::ChooseBestSaslMechanism(const std::vector<std::string> & mechanisms, bool encrypted) { + return sasl_handler_->ChooseBestSaslMechanism(mechanisms, encrypted); +} + +SaslMechanism * +XmppEngineImpl::GetSaslMechanism(const std::string & name) { + return sasl_handler_->CreateSaslMechanism(name); +} + +void +XmppEngineImpl::SignalBound(const Jid & fullJid) { + if (state_ == STATE_OPENING) { + bound_jid_ = fullJid; + state_ = STATE_OPEN; + } +} + +void +XmppEngineImpl::SignalStreamError(const XmlElement * pelStreamError) { + if (state_ != STATE_CLOSED) { + stream_error_.reset(new XmlElement(*pelStreamError)); + SignalError(ERROR_STREAM); + } +} + +void +XmppEngineImpl::SignalError(Error errorCode) { + if (state_ != STATE_CLOSED) { + error_code_ = errorCode; + state_ = STATE_CLOSED; + } +} + +bool +XmppEngineImpl::HasError() { + return error_code_ != ERROR_NONE; +} + +void +XmppEngineImpl::StartTls(const std::string & domain) { + if (output_handler_) { + output_handler_->StartTls( + tls_server_domain_.empty() ? domain : tls_server_domain_); + encrypted_ = true; + } +} + +XmppEngineImpl::EnterExit::EnterExit(XmppEngineImpl* engine) + : engine_(engine), + state_(engine->state_), + error_(engine->error_code_) { + engine->engine_entered_ += 1; +} + +XmppEngineImpl::EnterExit::~EnterExit() { + XmppEngineImpl* engine = engine_; + + engine->engine_entered_ -= 1; + + bool closing = (engine->state_ != state_ && + engine->state_ == STATE_CLOSED); + bool flushing = closing || (engine->engine_entered_ == 0); + + if (engine->output_handler_ && flushing) { + std::string output = engine->output_->str(); + if (output.length() > 0) + engine->output_handler_->WriteOutput(output.c_str(), output.length()); + engine->output_->str(""); + + if (closing) { + engine->output_handler_->CloseConnection(); + engine->output_handler_ = 0; + } + } + + if (engine->engine_entered_) + return; + + if (engine->raised_reset_) { + engine->stanzaParser_.Reset(); + engine->raised_reset_ = false; + } + + if (engine->session_handler_) { + if (engine->state_ != state_) + engine->session_handler_->OnStateChange(engine->state_); + // Note: Handling of OnStateChange(CLOSED) should allow for the + // deletion of the engine, so no members should be accessed + // after this line. + } +} + +} diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppengineimpl.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppengineimpl.h new file mode 100644 index 00000000..c36f168c --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppengineimpl.h @@ -0,0 +1,262 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _xmppengineimpl_h_ +#define _xmppengineimpl_h_ + +#include <sstream> +#include "talk/xmpp/xmppengine.h" +#include "talk/xmpp/xmppstanzaparser.h" + +namespace buzz { + +class XmppLoginTask; +class XmppEngine; +class XmppIqEntry; +class SaslHandler; +class SaslMechanism; + + +//! The XMPP connection engine. +//! This engine implements the client side of the 'core' XMPP protocol. +//! To use it, register an XmppOutputHandler to handle socket output +//! and pass socket input to HandleInput. Then application code can +//! set up the connection with a user, password, and other settings, +//! and then call Connect() to initiate the connection. +//! An application can listen for events and receive stanzas by +//! registering an XmppStanzaHandler via AddStanzaHandler(). +class XmppEngineImpl : public XmppEngine { +public: + XmppEngineImpl(); + virtual ~XmppEngineImpl(); + + // SOCKET INPUT AND OUTPUT ------------------------------------------------ + + //! Registers the handler for socket output + virtual XmppReturnStatus SetOutputHandler(XmppOutputHandler *pxoh); + + //! Provides socket input to the engine + virtual XmppReturnStatus HandleInput(const char * bytes, size_t len); + + //! Advises the engine that the socket has closed + virtual XmppReturnStatus ConnectionClosed(); + + // SESSION SETUP --------------------------------------------------------- + + //! Indicates the (bare) JID for the user to use. + virtual XmppReturnStatus SetUser(const Jid & jid); + + //! Get the login (bare) JID. + virtual const Jid & GetUser(); + + //! Indicates the autentication to use. Takes ownership of the object. + virtual XmppReturnStatus SetSaslHandler(SaslHandler * sasl_handler); + + //! Sets whether TLS will be used within the connection (default true). + virtual XmppReturnStatus SetUseTls(bool useTls); + + //! Sets an alternate domain from which we allows TLS certificates. + //! This is for use in the case where a we want to allow a proxy to + //! serve up its own certificate rather than one owned by the underlying + //! domain. + virtual XmppReturnStatus SetTlsServerDomain(const std::string & proxy_domain); + + //! Gets whether TLS will be used within the connection. + virtual bool GetUseTls(); + + //! Sets the request resource name, if any (optional). + //! Note that the resource name may be overridden by the server; after + //! binding, the actual resource name is available as part of FullJid(). + virtual XmppReturnStatus SetRequestedResource(const std::string& resource); + + //! Gets the request resource name. + virtual const std::string & GetRequestedResource(); + + // SESSION MANAGEMENT --------------------------------------------------- + + //! Set callback for state changes. + virtual XmppReturnStatus SetSessionHandler(XmppSessionHandler* handler); + + //! Initiates the XMPP connection. + //! After supplying connection settings, call this once to initiate, + //! (optionally) encrypt, authenticate, and bind the connection. + virtual XmppReturnStatus Connect(); + + //! The current engine state. + virtual State GetState() { return state_; } + + //! Returns true if the connection is encrypted (under TLS) + virtual bool IsEncrypted() { return encrypted_; } + + //! The error code. + //! Consult this after XmppOutputHandler.OnClose(). + virtual Error GetError() { return error_code_; } + + //! The stream:error stanza, when the error is XMPP_ERROR_STREAM. + //! Notice the stanza returned is owned by the XmppEngine and + //! is deleted when the engine is destroyed. + virtual const XmlElement * GetStreamError() { return stream_error_.get(); } + + //! Closes down the connection. + //! Sends CloseConnection to output, and disconnects and registered + //! session handlers. After Disconnect completes, it is guaranteed + //! that no further callbacks will be made. + virtual XmppReturnStatus Disconnect(); + + // APPLICATION USE ------------------------------------------------------- + + //! Adds a listener for session events. + //! Stanza delivery is chained to session handlers; the first to + //! return 'true' is the last to get each stanza. + virtual XmppReturnStatus AddStanzaHandler(XmppStanzaHandler* handler, + XmppEngine::HandlerLevel level); + + //! Removes a listener for session events. + virtual XmppReturnStatus RemoveStanzaHandler(XmppStanzaHandler* handler); + + //! Sends a stanza to the server. + virtual XmppReturnStatus SendStanza(const XmlElement * pelStanza); + + //! Sends raw text to the server + virtual XmppReturnStatus SendRaw(const std::string & text); + + //! Sends an iq to the server, and registers a callback for the result. + //! Returns the cookie passed to the result handler. + virtual XmppReturnStatus SendIq(const XmlElement* pelStanza, + XmppIqHandler* iq_handler, + XmppIqCookie* cookie); + + //! Unregisters an iq callback handler given its cookie. + //! No callback will come to this handler after it's unregistered. + virtual XmppReturnStatus RemoveIqHandler(XmppIqCookie cookie, + XmppIqHandler** iq_handler); + + //! Forms and sends an error in response to the given stanza. + //! Swaps to and from, sets type to "error", and adds error information + //! based on the passed code. Text is optional and may be STR_EMPTY. + virtual XmppReturnStatus SendStanzaError(const XmlElement * pelOriginal, + XmppStanzaError code, + const std::string & text); + + //! The fullly bound JID. + //! This JID is only valid after binding has succeeded. If the value + //! is JID_NULL, the binding has not succeeded. + virtual const Jid & FullJid() { return bound_jid_; } + + //! The next unused iq id for this connection. + //! Call this when building iq stanzas, to ensure that each iq + //! gets its own unique id. + virtual std::string NextId(); + +private: + friend class XmppLoginTask; + friend class XmppIqEntry; + + void IncomingStanza(const XmlElement *pelStanza); + void IncomingStart(const XmlElement *pelStanza); + void IncomingEnd(bool isError); + + void InternalSendStart(const std::string & domainName); + void InternalSendStanza(const XmlElement * pelStanza); + std::string ChooseBestSaslMechanism(const std::vector<std::string> & mechanisms, bool encrypted); + SaslMechanism * GetSaslMechanism(const std::string & name); + void SignalBound(const Jid & fullJid); + void SignalStreamError(const XmlElement * pelStreamError); + void SignalError(Error errorCode); + bool HasError(); + void DeleteIqCookies(); + bool HandleIqResponse(const XmlElement * element); + void StartTls(const std::string & domain); + void RaiseReset() { raised_reset_ = true; } + + class StanzaParseHandler : public XmppStanzaParseHandler { + public: + StanzaParseHandler(XmppEngineImpl * outer) : outer_(outer) {} + virtual void StartStream(const XmlElement * pelStream) + { outer_->IncomingStart(pelStream); } + virtual void Stanza(const XmlElement * pelStanza) + { outer_->IncomingStanza(pelStanza); } + virtual void EndStream() + { outer_->IncomingEnd(false); } + virtual void XmlError() + { outer_->IncomingEnd(true); } + private: + XmppEngineImpl * const outer_; + }; + + class EnterExit { + public: + EnterExit(XmppEngineImpl* engine); + ~EnterExit(); + private: + XmppEngineImpl* engine_; + State state_; + Error error_; + + }; + + friend class StanzaParseHandler; + friend class EnterExit; + + StanzaParseHandler stanzaParseHandler_; + XmppStanzaParser stanzaParser_; + + + // state + int engine_entered_; + Jid user_jid_; + std::string password_; + std::string requested_resource_; + bool tls_needed_; + std::string tls_server_domain_; + scoped_ptr<XmppLoginTask> login_task_; + + int next_id_; + Jid bound_jid_; + State state_; + bool encrypted_; + Error error_code_; + scoped_ptr<XmlElement> stream_error_; + bool raised_reset_; + XmppOutputHandler* output_handler_; + XmppSessionHandler* session_handler_; + + typedef STD_VECTOR(XmppStanzaHandler*) StanzaHandlerVector; + scoped_ptr<StanzaHandlerVector> stanza_handlers_[HL_COUNT]; + + typedef STD_VECTOR(XmppIqEntry*) IqEntryVector; + scoped_ptr<IqEntryVector> iq_entries_; + + scoped_ptr<SaslHandler> sasl_handler_; + + scoped_ptr<std::stringstream> output_; +}; + +} + + +#endif diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppengineimpl_iq.cc b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppengineimpl_iq.cc new file mode 100644 index 00000000..eb623ed9 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppengineimpl_iq.cc @@ -0,0 +1,279 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <vector> +#include <algorithm> +#include "talk/base/common.h" +#include "talk/xmpp/xmppengineimpl.h" +#include "talk/xmpp/constants.h" + +#define new TRACK_NEW + +namespace buzz { + +class XmppIqEntry { + XmppIqEntry(const std::string & id, const std::string & to, + XmppEngine * pxce, XmppIqHandler * iq_handler) : + id_(id), + to_(to), + engine_(pxce), + iq_handler_(iq_handler) { + } + +private: + friend class XmppEngineImpl; + + const std::string id_; + const std::string to_; + XmppEngine * const engine_; + XmppIqHandler * const iq_handler_; +}; + + +XmppReturnStatus +XmppEngineImpl::SendIq(const XmlElement * element, XmppIqHandler * iq_handler, + XmppIqCookie* cookie) { + if (state_ == STATE_CLOSED) + return XMPP_RETURN_BADSTATE; + if (NULL == iq_handler) + return XMPP_RETURN_BADARGUMENT; + if (!element || element->Name() != QN_IQ) + return XMPP_RETURN_BADARGUMENT; + + const std::string& type = element->Attr(QN_TYPE); + if (type != "get" && type != "set") + return XMPP_RETURN_BADARGUMENT; + + if (!element->HasAttr(QN_ID)) + return XMPP_RETURN_BADARGUMENT; + const std::string& id = element->Attr(QN_ID); + + XmppIqEntry * iq_entry = new XmppIqEntry(id, + element->Attr(QN_TO), + this, iq_handler); + iq_entries_->push_back(iq_entry); + SendStanza(element); + + if (cookie) + *cookie = iq_entry; + + return XMPP_RETURN_OK; +} + + +XmppReturnStatus +XmppEngineImpl::RemoveIqHandler(XmppIqCookie cookie, + XmppIqHandler ** iq_handler) { + + std::vector<XmppIqEntry*, std::allocator<XmppIqEntry*> >::iterator pos; + + pos = std::find(iq_entries_->begin(), + iq_entries_->end(), + reinterpret_cast<XmppIqEntry*>(cookie)); + + if (pos == iq_entries_->end()) + return XMPP_RETURN_BADARGUMENT; + + XmppIqEntry* entry = *pos; + iq_entries_->erase(pos); + if (iq_handler) + *iq_handler = entry->iq_handler_; + delete entry; + + return XMPP_RETURN_OK; +} + +void +XmppEngineImpl::DeleteIqCookies() { + for (size_t i = 0; i < iq_entries_->size(); i += 1) { + XmppIqEntry * iq_entry_ = (*iq_entries_)[i]; + (*iq_entries_)[i] = NULL; + delete iq_entry_; + } + iq_entries_->clear(); +} + +static void +AecImpl(XmlElement * error_element, const QName & name, + const char * type, const char * code) { + error_element->AddElement(new XmlElement(QN_ERROR)); + error_element->AddAttr(QN_CODE, code, 1); + error_element->AddAttr(QN_TYPE, type, 1); + error_element->AddElement(new XmlElement(name, true), 1); +} + + +static void +AddErrorCode(XmlElement * error_element, XmppStanzaError code) { + switch (code) { + case XSE_BAD_REQUEST: + AecImpl(error_element, QN_STANZA_BAD_REQUEST, "modify", "400"); + break; + case XSE_CONFLICT: + AecImpl(error_element, QN_STANZA_CONFLICT, "cancel", "409"); + break; + case XSE_FEATURE_NOT_IMPLEMENTED: + AecImpl(error_element, QN_STANZA_FEATURE_NOT_IMPLEMENTED, + "cancel", "501"); + break; + case XSE_FORBIDDEN: + AecImpl(error_element, QN_STANZA_FORBIDDEN, "auth", "403"); + break; + case XSE_GONE: + AecImpl(error_element, QN_STANZA_GONE, "modify", "302"); + break; + case XSE_INTERNAL_SERVER_ERROR: + AecImpl(error_element, QN_STANZA_INTERNAL_SERVER_ERROR, "wait", "500"); + break; + case XSE_ITEM_NOT_FOUND: + AecImpl(error_element, QN_STANZA_ITEM_NOT_FOUND, "cancel", "404"); + break; + case XSE_JID_MALFORMED: + AecImpl(error_element, QN_STANZA_JID_MALFORMED, "modify", "400"); + break; + case XSE_NOT_ACCEPTABLE: + AecImpl(error_element, QN_STANZA_NOT_ACCEPTABLE, "cancel", "406"); + break; + case XSE_NOT_ALLOWED: + AecImpl(error_element, QN_STANZA_NOT_ALLOWED, "cancel", "405"); + break; + case XSE_PAYMENT_REQUIRED: + AecImpl(error_element, QN_STANZA_PAYMENT_REQUIRED, "auth", "402"); + break; + case XSE_RECIPIENT_UNAVAILABLE: + AecImpl(error_element, QN_STANZA_RECIPIENT_UNAVAILABLE, "wait", "404"); + break; + case XSE_REDIRECT: + AecImpl(error_element, QN_STANZA_REDIRECT, "modify", "302"); + break; + case XSE_REGISTRATION_REQUIRED: + AecImpl(error_element, QN_STANZA_REGISTRATION_REQUIRED, "auth", "407"); + break; + case XSE_SERVER_NOT_FOUND: + AecImpl(error_element, QN_STANZA_REMOTE_SERVER_NOT_FOUND, + "cancel", "404"); + break; + case XSE_SERVER_TIMEOUT: + AecImpl(error_element, QN_STANZA_REMOTE_SERVER_TIMEOUT, "wait", "502"); + break; + case XSE_RESOURCE_CONSTRAINT: + AecImpl(error_element, QN_STANZA_RESOURCE_CONSTRAINT, "wait", "500"); + break; + case XSE_SERVICE_UNAVAILABLE: + AecImpl(error_element, QN_STANZA_SERVICE_UNAVAILABLE, "cancel", "503"); + break; + case XSE_SUBSCRIPTION_REQUIRED: + AecImpl(error_element, QN_STANZA_SUBSCRIPTION_REQUIRED, "auth", "407"); + break; + case XSE_UNDEFINED_CONDITION: + AecImpl(error_element, QN_STANZA_UNDEFINED_CONDITION, "wait", "500"); + break; + case XSE_UNEXPECTED_REQUEST: + AecImpl(error_element, QN_STANZA_UNEXPECTED_REQUEST, "wait", "400"); + break; + } +} + + +XmppReturnStatus +XmppEngineImpl::SendStanzaError(const XmlElement * element_original, + XmppStanzaError code, + const std::string & text) { + + if (state_ == STATE_CLOSED) + return XMPP_RETURN_BADSTATE; + + XmlElement error_element(element_original->Name()); + error_element.AddAttr(QN_TYPE, "error"); + + // copy attrs, copy 'from' to 'to' and strip 'from' + for (const XmlAttr * attribute = element_original->FirstAttr(); + attribute; attribute = attribute->NextAttr()) { + QName name = attribute->Name(); + if (name == QN_TO) + continue; // no need to put a from attr. Server will stamp stanza + else if (name == QN_FROM) + name = QN_TO; + else if (name == QN_TYPE) + continue; + error_element.AddAttr(name, attribute->Value()); + } + + // copy children + for (const XmlChild * child = element_original->FirstChild(); + child; + child = child->NextChild()) { + if (child->IsText()) { + error_element.AddText(child->AsText()->Text()); + } else { + error_element.AddElement(new XmlElement(*(child->AsElement()))); + } + } + + // add error information + AddErrorCode(&error_element, code); + if (text != STR_EMPTY) { + XmlElement * text_element = new XmlElement(QN_STANZA_TEXT, true); + text_element->AddText(text); + error_element.AddElement(text_element); + } + + SendStanza(&error_element); + + return XMPP_RETURN_OK; +} + + +bool +XmppEngineImpl::HandleIqResponse(const XmlElement * element) { + if (iq_entries_->empty()) + return false; + if (element->Name() != QN_IQ) + return false; + std::string type = element->Attr(QN_TYPE); + if (type != "result" && type != "error") + return false; + if (!element->HasAttr(QN_ID)) + return false; + std::string id = element->Attr(QN_ID); + std::string from = element->Attr(QN_FROM); + + for (std::vector<XmppIqEntry *>::iterator it = iq_entries_->begin(); + it != iq_entries_->end(); it += 1) { + XmppIqEntry * iq_entry = *it; + if (iq_entry->id_ == id && iq_entry->to_ == from) { + iq_entries_->erase(it); + iq_entry->iq_handler_->IqResponse(iq_entry, element); + delete iq_entry; + return true; + } + } + + return false; +} + +} diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpplogintask.cc b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpplogintask.cc new file mode 100644 index 00000000..470c2dc2 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpplogintask.cc @@ -0,0 +1,357 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <string> +#include <vector> +#include <iostream> +#include "talk/xmpp/jid.h" +#include "talk/xmllite/xmlelement.h" +#include "talk/base/common.h" +#include "talk/xmpp/xmppengineimpl.h" +#include "talk/xmpp/constants.h" +#include "talk/base/base64.h" +#include "talk/xmpp/xmpplogintask.h" +#include "talk/xmpp/saslmechanism.h" + +#define new TRACK_NEW + +namespace buzz { + +XmppLoginTask::XmppLoginTask(XmppEngineImpl * pctx) : + pctx_(pctx), + authNeeded_(true), + state_(LOGINSTATE_INIT), + pelStanza_(NULL), + isStart_(false), + iqId_(STR_EMPTY), + pelFeatures_(NULL), + fullJid_(STR_EMPTY), + streamId_(STR_EMPTY), + pvecQueuedStanzas_(new std::vector<XmlElement *>()), + sasl_mech_(NULL) { +} + +XmppLoginTask::~XmppLoginTask() { + for (size_t i = 0; i < pvecQueuedStanzas_->size(); i += 1) + delete (*pvecQueuedStanzas_)[i]; +} + +void +XmppLoginTask::IncomingStanza(const XmlElement *element, bool isStart) { + pelStanza_ = element; + isStart_ = isStart; + Advance(); + pelStanza_ = NULL; + isStart_ = false; +} + +const XmlElement * +XmppLoginTask::NextStanza() { + const XmlElement * result = pelStanza_; + pelStanza_ = NULL; + return result; +} + +bool +XmppLoginTask::Advance() { + + for (;;) { + + const XmlElement * element = NULL; + + switch (state_) { + + case LOGINSTATE_INIT: { + pctx_->RaiseReset(); + pelFeatures_.reset(NULL); + + pctx_->InternalSendStart(pctx_->user_jid_.domain()); + state_ = LOGINSTATE_STREAMSTART_SENT; + break; + } + + case LOGINSTATE_STREAMSTART_SENT: { + if (NULL == (element = NextStanza())) + return true; + + if (!isStart_ || !HandleStartStream(element)) + return Failure(XmppEngine::ERROR_VERSION); + + state_ = LOGINSTATE_STARTED_XMPP; + return true; + } + + case LOGINSTATE_STARTED_XMPP: { + if (NULL == (element = NextStanza())) + return true; + + if (!HandleFeatures(element)) + return Failure(XmppEngine::ERROR_VERSION); + + if (pctx_->tls_needed_) { + state_ = LOGINSTATE_TLS_INIT; + continue; + } + + if (authNeeded_) { + state_ = LOGINSTATE_AUTH_INIT; + continue; + } + + state_ = LOGINSTATE_BIND_INIT; + continue; + } + + case LOGINSTATE_TLS_INIT: { + const XmlElement * pelTls = GetFeature(QN_TLS_STARTTLS); + if (!pelTls) + return Failure(XmppEngine::ERROR_TLS); + + XmlElement el(QN_TLS_STARTTLS, true); + pctx_->InternalSendStanza(&el); + state_ = LOGINSTATE_TLS_REQUESTED; + continue; + } + + case LOGINSTATE_TLS_REQUESTED: { + if (NULL == (element = NextStanza())) + return true; + if (element->Name() != QN_TLS_PROCEED) + return Failure(XmppEngine::ERROR_TLS); + + // The proper domain to verify against is the real underlying + // domain - i.e., the domain that owns the JID. Our XmppEngineImpl + // also allows matching against a proxy domain instead, if it is told + // to do so - see the implementation of XmppEngineImpl::StartTls and + // XmppEngine::SetTlsServerDomain to see how you can use that feature + pctx_->StartTls(pctx_->user_jid_.domain()); + pctx_->tls_needed_ = false; + state_ = LOGINSTATE_INIT; + continue; + } + + case LOGINSTATE_AUTH_INIT: { + const XmlElement * pelSaslAuth = GetFeature(QN_SASL_MECHANISMS); + if (!pelSaslAuth) { + return Failure(XmppEngine::ERROR_AUTH); + } + + // Collect together the SASL auth mechanisms presented by the server + std::vector<std::string> mechanisms; + for (const XmlElement * pelMech = + pelSaslAuth->FirstNamed(QN_SASL_MECHANISM); + pelMech; + pelMech = pelMech->NextNamed(QN_SASL_MECHANISM)) { + + mechanisms.push_back(pelMech->BodyText()); + } + + // Given all the mechanisms, choose the best + std::string choice(pctx_->ChooseBestSaslMechanism(mechanisms, pctx_->IsEncrypted())); + if (choice.empty()) { + return Failure(XmppEngine::ERROR_AUTH); + } + + // No recognized auth mechanism - that's an error + sasl_mech_.reset(pctx_->GetSaslMechanism(choice)); + if (sasl_mech_.get() == NULL) { + return Failure(XmppEngine::ERROR_AUTH); + } + + // OK, let's start it. + XmlElement * auth = sasl_mech_->StartSaslAuth(); + if (auth == NULL) { + return Failure(XmppEngine::ERROR_AUTH); + } + + pctx_->InternalSendStanza(auth); + delete auth; + state_ = LOGINSTATE_SASL_RUNNING; + continue; + } + + case LOGINSTATE_SASL_RUNNING: { + if (NULL == (element = NextStanza())) + return true; + if (element->Name().Namespace() != NS_SASL) + return Failure(XmppEngine::ERROR_AUTH); + if (element->Name() == QN_SASL_CHALLENGE) { + XmlElement * response = sasl_mech_->HandleSaslChallenge(element); + if (response == NULL) { + return Failure(XmppEngine::ERROR_AUTH); + } + pctx_->InternalSendStanza(response); + delete response; + state_ = LOGINSTATE_SASL_RUNNING; + continue; + } + if (element->Name() != QN_SASL_SUCCESS) { + return Failure(XmppEngine::ERROR_UNAUTHORIZED); + } + + // Authenticated! + authNeeded_ = false; + state_ = LOGINSTATE_INIT; + continue; + } + + case LOGINSTATE_BIND_INIT: { + const XmlElement * pelBindFeature = GetFeature(QN_BIND_BIND); + const XmlElement * pelSessionFeature = GetFeature(QN_SESSION_SESSION); + if (!pelBindFeature || !pelSessionFeature) + return Failure(XmppEngine::ERROR_BIND); + + XmlElement iq(QN_IQ); + iq.AddAttr(QN_TYPE, "set"); + + iqId_ = pctx_->NextId(); + iq.AddAttr(QN_ID, iqId_); + iq.AddElement(new XmlElement(QN_BIND_BIND, true)); + + if (pctx_->requested_resource_ != STR_EMPTY) { + iq.AddElement(new XmlElement(QN_BIND_RESOURCE), 1); + iq.AddText(pctx_->requested_resource_, 2); + } + pctx_->InternalSendStanza(&iq); + state_ = LOGINSTATE_BIND_REQUESTED; + continue; + } + + case LOGINSTATE_BIND_REQUESTED: { + if (NULL == (element = NextStanza())) + return true; + + if (element->Name() != QN_IQ || element->Attr(QN_ID) != iqId_ || + element->Attr(QN_TYPE) == "get" || element->Attr(QN_TYPE) == "set") + return true; + + if (element->Attr(QN_TYPE) != "result" || element->FirstElement() == NULL || + element->FirstElement()->Name() != QN_BIND_BIND) + return Failure(XmppEngine::ERROR_BIND); + + fullJid_ = Jid(element->FirstElement()->TextNamed(QN_BIND_JID)); + if (!fullJid_.IsFull()) { + return Failure(XmppEngine::ERROR_BIND); + } + + if (pctx_->user_jid_.domain() != STR_DEFAULT_DOMAIN && + fullJid_.BareJid() != pctx_->user_jid_) { + return Failure(XmppEngine::ERROR_BIND); + } + + // now request session + XmlElement iq(QN_IQ); + iq.AddAttr(QN_TYPE, "set"); + + iqId_ = pctx_->NextId(); + iq.AddAttr(QN_ID, iqId_); + iq.AddElement(new XmlElement(QN_SESSION_SESSION, true)); + pctx_->InternalSendStanza(&iq); + + state_ = LOGINSTATE_SESSION_REQUESTED; + continue; + } + + case LOGINSTATE_SESSION_REQUESTED: { + if (NULL == (element = NextStanza())) + return true; + if (element->Name() != QN_IQ || element->Attr(QN_ID) != iqId_ || + element->Attr(QN_TYPE) == "get" || element->Attr(QN_TYPE) == "set") + return false; + + if (element->Attr(QN_TYPE) != "result") + return Failure(XmppEngine::ERROR_BIND); + + pctx_->SignalBound(fullJid_); + FlushQueuedStanzas(); + state_ = LOGINSTATE_DONE; + return true; + } + + case LOGINSTATE_DONE: + return false; + } + } +} + +bool +XmppLoginTask::HandleStartStream(const XmlElement *element) { + + if (element->Name() != QN_STREAM_STREAM) + return false; + + if (element->Attr(QN_XMLNS) != "jabber:client") + return false; + + if (element->Attr(QN_VERSION) != "1.0") + return false; + + if (!element->HasAttr(QN_ID)) + return false; + + streamId_ = element->Attr(QN_ID); + + return true; +} + +bool +XmppLoginTask::HandleFeatures(const XmlElement *element) { + if (element->Name() != QN_STREAM_FEATURES) + return false; + + pelFeatures_.reset(new XmlElement(*element)); + return true; +} + +const XmlElement * +XmppLoginTask::GetFeature(const QName & name) { + return pelFeatures_->FirstNamed(name); +} + +bool +XmppLoginTask::Failure(XmppEngine::Error reason) { + state_ = LOGINSTATE_DONE; + pctx_->SignalError(reason); + return false; +} + +void +XmppLoginTask::OutgoingStanza(const XmlElement * element) { + XmlElement * pelCopy = new XmlElement(*element); + pvecQueuedStanzas_->push_back(pelCopy); +} + +void +XmppLoginTask::FlushQueuedStanzas() { + for (size_t i = 0; i < pvecQueuedStanzas_->size(); i += 1) { + pctx_->InternalSendStanza((*pvecQueuedStanzas_)[i]); + delete (*pvecQueuedStanzas_)[i]; + } + pvecQueuedStanzas_->clear(); +} + +} diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpplogintask.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpplogintask.h new file mode 100644 index 00000000..7f321a30 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpplogintask.h @@ -0,0 +1,95 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _logintask_h_ +#define _logintask_h_ + +#include <string> +#include "talk/xmpp/jid.h" +#include "talk/base/scoped_ptr.h" +#include "talk/xmpp/xmppengine.h" +#include "talk/base/stl_decl.h" + +namespace buzz { + +class XmlElement; +class XmppEngineImpl; +class SaslMechanism; + + +class XmppLoginTask { + +public: + XmppLoginTask(XmppEngineImpl *pctx); + ~XmppLoginTask(); + + bool IsDone() + { return state_ == LOGINSTATE_DONE; } + void IncomingStanza(const XmlElement * element, bool isStart); + void OutgoingStanza(const XmlElement *element); + +private: + enum LoginTaskState { + LOGINSTATE_INIT = 0, + LOGINSTATE_STREAMSTART_SENT, + LOGINSTATE_STARTED_XMPP, + LOGINSTATE_TLS_INIT, + LOGINSTATE_AUTH_INIT, + LOGINSTATE_BIND_INIT, + LOGINSTATE_TLS_REQUESTED, + LOGINSTATE_SASL_RUNNING, + LOGINSTATE_BIND_REQUESTED, + LOGINSTATE_SESSION_REQUESTED, + LOGINSTATE_DONE, + }; + + const XmlElement * NextStanza(); + bool Advance(); + bool HandleStartStream(const XmlElement * element); + bool HandleFeatures(const XmlElement * element); + const XmlElement * GetFeature(const QName & name); + bool Failure(XmppEngine::Error reason); + void FlushQueuedStanzas(); + + XmppEngineImpl * pctx_; + bool authNeeded_; + LoginTaskState state_; + const XmlElement * pelStanza_; + bool isStart_; + std::string iqId_; + scoped_ptr<XmlElement> pelFeatures_; + Jid fullJid_; + std::string streamId_; + scoped_ptr<std::vector<XmlElement *, + std::allocator<XmlElement *> > > pvecQueuedStanzas_; + + scoped_ptr<SaslMechanism> sasl_mech_; +}; + +} + +#endif diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpppassword.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpppassword.h new file mode 100644 index 00000000..f431b4e5 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpppassword.h @@ -0,0 +1,163 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _XMPPPASSWORD_H_ +#define _XMPPPASSWORD_H_ + +#include "talk/base/linked_ptr.h" +#include "talk/base/scoped_ptr.h" + +namespace buzz { + +class XmppPasswordImpl { +public: + virtual ~XmppPasswordImpl() {} + virtual size_t GetLength() const = 0; + virtual void CopyTo(char * dest, bool nullterminate) const = 0; + virtual std::string UrlEncode() const = 0; + virtual XmppPasswordImpl * Copy() const = 0; +}; + +class EmptyXmppPasswordImpl : public XmppPasswordImpl { +public: + virtual ~EmptyXmppPasswordImpl() {} + virtual size_t GetLength() const { return 0; } + virtual void CopyTo(char * dest, bool nullterminate) const { + if (nullterminate) { + *dest = '\0'; + } + } + virtual std::string UrlEncode() const { return ""; } + virtual XmppPasswordImpl * Copy() const { return new EmptyXmppPasswordImpl(); } +}; + +class XmppPassword { +public: + XmppPassword() : impl_(new EmptyXmppPasswordImpl()) {} + size_t GetLength() const { return impl_->GetLength(); } + void CopyTo(char * dest, bool nullterminate) const { impl_->CopyTo(dest, nullterminate); } + XmppPassword(const XmppPassword & other) : impl_(other.impl_->Copy()) {} + explicit XmppPassword(const XmppPasswordImpl & impl) : impl_(impl.Copy()) {} + XmppPassword & operator=(const XmppPassword & other) { + if (this != &other) { + impl_.reset(other.impl_->Copy()); + } + return *this; + } + void Clear() { impl_.reset(new EmptyXmppPasswordImpl()); } + std::string UrlEncode() const { return impl_->UrlEncode(); } + +private: + scoped_ptr<const XmppPasswordImpl> impl_; +}; + + +// Used for constructing strings where a password is involved and we +// need to ensure that we zero memory afterwards +class FormatXmppPassword { +public: + FormatXmppPassword() { + storage_ = new char[32]; + capacity_ = 32; + length_ = 0; + storage_[0] = 0; + } + + void Append(const std::string & text) { + Append(text.data(), text.length()); + } + + void Append(const char * data, size_t length) { + EnsureStorage(length_ + length + 1); + memcpy(storage_ + length_, data, length); + length_ += length; + storage_[length_] = '\0'; + } + + void Append(const XmppPassword * password) { + size_t len = password->GetLength(); + EnsureStorage(length_ + len + 1); + password->CopyTo(storage_ + length_, true); + length_ += len; + } + + size_t GetLength() { + return length_; + } + + const char * GetData() { + return storage_; + } + + + // Ensures storage of at least n bytes + void EnsureStorage(size_t n) { + if (capacity_ >= n) { + return; + } + + size_t old_capacity = capacity_; + char * old_storage = storage_; + + for (;;) { + capacity_ *= 2; + if (capacity_ >= n) + break; + } + + storage_ = new char[capacity_]; + + if (old_capacity) { + memcpy(storage_, old_storage, length_); + + // zero memory in a way that an optimizer won't optimize it out + old_storage[0] = 0; + for (size_t i = 1; i < old_capacity; i++) { + old_storage[i] = old_storage[i - 1]; + } + delete[] old_storage; + } + } + + ~FormatXmppPassword() { + if (capacity_) { + storage_[0] = 0; + for (size_t i = 1; i < capacity_; i++) { + storage_[i] = storage_[i - 1]; + } + } + delete[] storage_; + } +private: + char * storage_; + size_t capacity_; + size_t length_; +}; + +} + +#endif diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppstanzaparser.cc b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppstanzaparser.cc new file mode 100644 index 00000000..66ed44fb --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppstanzaparser.cc @@ -0,0 +1,104 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <expat.h> +#include "talk/xmllite/xmlelement.h" +#include "talk/base/common.h" +#include "talk/xmpp/xmppstanzaparser.h" +#include "talk/xmpp/constants.h" + +#define new TRACK_NEW + +namespace buzz { + +XmppStanzaParser::XmppStanzaParser(XmppStanzaParseHandler *psph) : + psph_(psph), + innerHandler_(this), + parser_(&innerHandler_), + depth_(0), + builder_() { +} + +void +XmppStanzaParser::Reset() { + parser_.Reset(); + depth_ = 0; + builder_.Reset(); +} + +void +XmppStanzaParser::IncomingStartElement( + XmlParseContext * pctx, const char * name, const char ** atts) { + if (depth_++ == 0) { + XmlElement * pelStream = XmlBuilder::BuildElement(pctx, name, atts); + if (pelStream == NULL) { + pctx->RaiseError(XML_ERROR_SYNTAX); + return; + } + psph_->StartStream(pelStream); + delete pelStream; + return; + } + + builder_.StartElement(pctx, name, atts); +} + +void +XmppStanzaParser::IncomingCharacterData( + XmlParseContext * pctx, const char * text, int len) { + if (depth_ > 1) { + builder_.CharacterData(pctx, text, len); + } +} + +void +XmppStanzaParser::IncomingEndElement( + XmlParseContext * pctx, const char * name) { + if (--depth_ == 0) { + psph_->EndStream(); + return; + } + + builder_.EndElement(pctx, name); + + if (depth_ == 1) { + XmlElement *element = builder_.CreateElement(); + psph_->Stanza(element); + delete element; + } +} + +void +XmppStanzaParser::IncomingError( + XmlParseContext * pctx, XML_Error errCode) { + UNUSED(pctx); + UNUSED(errCode); + psph_->XmlError(); +} + +} + diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppstanzaparser.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppstanzaparser.h new file mode 100644 index 00000000..1e109a3d --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmppstanzaparser.h @@ -0,0 +1,96 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _xmppstanzaparser_h_ +#define _xmppstanzaparser_h_ + +#include "talk/xmllite/xmlparser.h" +#include "talk/xmllite/xmlbuilder.h" + + +namespace buzz { + +class XmlElement; + +class XmppStanzaParseHandler { +public: + virtual void StartStream(const XmlElement * pelStream) = 0; + virtual void Stanza(const XmlElement * pelStanza) = 0; + virtual void EndStream() = 0; + virtual void XmlError() = 0; +}; + +class XmppStanzaParser { +public: + XmppStanzaParser(XmppStanzaParseHandler *psph); + bool Parse(const char * data, size_t len, bool isFinal) + { return parser_.Parse(data, len, isFinal); } + void Reset(); + +private: + class ParseHandler : public XmlParseHandler { + public: + ParseHandler(XmppStanzaParser * outer) : outer_(outer) {} + virtual void StartElement(XmlParseContext * pctx, + const char * name, const char ** atts) + { outer_->IncomingStartElement(pctx, name, atts); } + virtual void EndElement(XmlParseContext * pctx, + const char * name) + { outer_->IncomingEndElement(pctx, name); } + virtual void CharacterData(XmlParseContext * pctx, + const char * text, int len) + { outer_->IncomingCharacterData(pctx, text, len); } + virtual void Error(XmlParseContext * pctx, + XML_Error errCode) + { outer_->IncomingError(pctx, errCode); } + private: + XmppStanzaParser * const outer_; + }; + + friend class ParseHandler; + + void IncomingStartElement(XmlParseContext * pctx, + const char * name, const char ** atts); + void IncomingEndElement(XmlParseContext * pctx, + const char * name); + void IncomingCharacterData(XmlParseContext * pctx, + const char * text, int len); + void IncomingError(XmlParseContext * pctx, + XML_Error errCode); + + XmppStanzaParseHandler * psph_; + ParseHandler innerHandler_; + XmlParser parser_; + int depth_; + XmlBuilder builder_; + + }; + + +} + +#endif diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpptask.cc b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpptask.cc new file mode 100644 index 00000000..82207f3b --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpptask.cc @@ -0,0 +1,168 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "talk/xmpp/xmpptask.h" +#include "talk/xmpp/xmppclient.h" +#include "talk/xmpp/xmppengine.h" +#include "talk/xmpp/constants.h" + +namespace buzz { + +XmppTask::XmppTask(Task * parent, XmppEngine::HandlerLevel level) + : Task(parent), client_(NULL) { + XmppClient * client = (XmppClient*)parent->GetParent(XMPP_CLIENT_TASK_CODE); + client_ = client; + id_ = client->NextId(); + client->AddXmppTask(this, level); + client->SignalDisconnected.connect(this, &XmppTask::OnDisconnect); +} + +XmppTask::~XmppTask() { + StopImpl(); +} + +void +XmppTask::StopImpl() { + while (NextStanza() != NULL) {} + if (client_) { + client_->RemoveXmppTask(this); + client_->SignalDisconnected.disconnect(this); + client_ = NULL; + } +} + +XmppReturnStatus +XmppTask::SendStanza(const XmlElement * stanza) { + if (client_ == NULL) + return XMPP_RETURN_BADSTATE; + return client_->SendStanza(stanza); +} + +XmppReturnStatus +XmppTask::SendStanzaError(const XmlElement * element_original, + XmppStanzaError code, + const std::string & text) { + if (client_ == NULL) + return XMPP_RETURN_BADSTATE; + return client_->SendStanzaError(element_original, code, text); +} + +void +XmppTask::Stop() { + StopImpl(); + Task::Stop(); +} + +void +XmppTask::OnDisconnect() { + Error(); +} + +void +XmppTask::QueueStanza(const XmlElement * stanza) { + stanza_queue_.push_back(new XmlElement(*stanza)); + Wake(); +} + +const XmlElement * +XmppTask::NextStanza() { + XmlElement * result = NULL; + if (!stanza_queue_.empty()) { + result = stanza_queue_.front(); + stanza_queue_.pop_front(); + } + next_stanza_.reset(result); + return result; +} + +XmlElement * +XmppTask::MakeIq(const std::string & type, + const buzz::Jid & to, const std::string id) { + XmlElement * result = new XmlElement(QN_IQ); + if (!type.empty()) + result->AddAttr(QN_TYPE, type); + if (to != JID_EMPTY) + result->AddAttr(QN_TO, to.Str()); + if (!id.empty()) + result->AddAttr(QN_ID, id); + return result; +} + +XmlElement * +XmppTask::MakeIqResult(const XmlElement * query) { + XmlElement * result = new XmlElement(QN_IQ); + result->AddAttr(QN_TYPE, STR_RESULT); + if (query->HasAttr(QN_FROM)) { + result->AddAttr(QN_TO, query->Attr(QN_FROM)); + } + result->AddAttr(QN_ID, query->Attr(QN_ID)); + return result; +} + +bool +XmppTask::MatchResponseIq(const XmlElement * stanza, + const Jid & to, const std::string & id) { + if (stanza->Name() != QN_IQ) + return false; + + if (stanza->Attr(QN_ID) != id) + return false; + + Jid from(stanza->Attr(QN_FROM)); + if (from != to) { + Jid me = client_->jid(); + // we address the server as "", but it is legal for the server + // to identify itself with "domain" or "myself@domain" + if (to != JID_EMPTY) { + return false; + } + + if (from != Jid(me.domain()) && from != me.BareJid()) { + return false; + } + } + + + return true; +} + +bool +XmppTask::MatchRequestIq(const XmlElement * stanza, + const std::string & type, const QName & qn) { + if (stanza->Name() != QN_IQ) + return false; + + if (stanza->Attr(QN_TYPE) != type) + return false; + + if (stanza->FirstNamed(qn) == NULL) + return false; + + return true; +} + +} diff --git a/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpptask.h b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpptask.h new file mode 100644 index 00000000..3b56a1c9 --- /dev/null +++ b/kopete/protocols/jabber/jingle/libjingle/talk/xmpp/xmpptask.h @@ -0,0 +1,113 @@ +/* + * libjingle + * Copyright 2004--2005, Google Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _XMPPTASK_H_ +#define _XMPPTASK_H_ + +#include <string> +#include <deque> +#include "talk/base/sigslot.h" +#include "talk/xmpp/xmppengine.h" +#include "talk/base/task.h" + +namespace buzz { + +///////////////////////////////////////////////////////////////////// +// +// XMPPTASK +// +///////////////////////////////////////////////////////////////////// +// +// See Task and XmppClient first. +// +// XmppTask is a task that is designed to go underneath XmppClient and be +// useful there. It has a way of finding its XmppClient parent so you +// can have it nested arbitrarily deep under an XmppClient and it can +// still find the XMPP services. +// +// Tasks register themselves to listen to particular kinds of stanzas +// that are sent out by the client. Rather than processing stanzas +// right away, they should decide if they own the sent stanza, +// and if so, queue it and Wake() the task, or if a stanza does not belong +// to you, return false right away so the next XmppTask can take a crack. +// This technique (synchronous recognize, but asynchronous processing) +// allows you to have arbitrary logic for recognizing stanzas yet still, +// for example, disconnect a client while processing a stanza - +// without reentrancy problems. +// +///////////////////////////////////////////////////////////////////// + +class XmppClient; + +class XmppTask : + public Task, + public XmppStanzaHandler, + public sigslot::has_slots<> +{ +public: + XmppTask(Task * parent, XmppEngine::HandlerLevel level = XmppEngine::HL_NONE); + virtual ~XmppTask(); + + virtual XmppClient * GetClient() const { return client_; } + std::string task_id() const { return id_; } + +protected: + friend class XmppClient; + + XmppReturnStatus SendStanza(const XmlElement * stanza); + XmppReturnStatus SetResult(const std::string & code); + XmppReturnStatus SendStanzaError(const XmlElement * element_original, + XmppStanzaError code, + const std::string & text); + + virtual void Stop(); + virtual bool HandleStanza(const XmlElement * stanza) { return false; } + virtual void OnDisconnect(); + virtual int ProcessReponse() { return STATE_DONE; } + + void QueueStanza(const XmlElement * stanza); + const XmlElement * NextStanza(); + + bool MatchResponseIq(const XmlElement * stanza, const Jid & to, const std::string & task_id); + bool MatchRequestIq(const XmlElement * stanza, const std::string & type, const QName & qn); + XmlElement *MakeIqResult(const XmlElement * query); + XmlElement *MakeIq(const std::string & type, + const Jid & to, const std::string task_id); + +private: + void StopImpl(); + + XmppClient * client_; + std::deque<XmlElement *> stanza_queue_; + scoped_ptr<XmlElement> next_stanza_; + std::string id_; + +}; + +} + +#endif |