1/*
2 * libjingle
3 * Copyright 2004--2005, Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 *  1. Redistributions of source code must retain the above copyright notice,
9 *     this list of conditions and the following disclaimer.
10 *  2. Redistributions in binary form must reproduce the above copyright notice,
11 *     this list of conditions and the following disclaimer in the documentation
12 *     and/or other materials provided with the distribution.
13 *  3. The name of the author may not be used to endorse or promote products
14 *     derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#ifndef _xmppengine_h_
29#define _xmppengine_h_
30
31// also part of the API
32#include "talk/xmpp/jid.h"
33#include "talk/xmllite/qname.h"
34#include "talk/xmllite/xmlelement.h"
35
36
37namespace buzz {
38
39class XmppEngine;
40class SaslHandler;
41typedef void * XmppIqCookie;
42
43//! XMPP stanza error codes.
44//! Used in XmppEngine.SendStanzaError().
45enum XmppStanzaError {
46  XSE_BAD_REQUEST,
47  XSE_CONFLICT,
48  XSE_FEATURE_NOT_IMPLEMENTED,
49  XSE_FORBIDDEN,
50  XSE_GONE,
51  XSE_INTERNAL_SERVER_ERROR,
52  XSE_ITEM_NOT_FOUND,
53  XSE_JID_MALFORMED,
54  XSE_NOT_ACCEPTABLE,
55  XSE_NOT_ALLOWED,
56  XSE_PAYMENT_REQUIRED,
57  XSE_RECIPIENT_UNAVAILABLE,
58  XSE_REDIRECT,
59  XSE_REGISTRATION_REQUIRED,
60  XSE_SERVER_NOT_FOUND,
61  XSE_SERVER_TIMEOUT,
62  XSE_RESOURCE_CONSTRAINT,
63  XSE_SERVICE_UNAVAILABLE,
64  XSE_SUBSCRIPTION_REQUIRED,
65  XSE_UNDEFINED_CONDITION,
66  XSE_UNEXPECTED_REQUEST,
67};
68
69// XmppReturnStatus
70//    This is used by API functions to synchronously return status.
71enum XmppReturnStatus {
72  XMPP_RETURN_OK,
73  XMPP_RETURN_BADARGUMENT,
74  XMPP_RETURN_BADSTATE,
75  XMPP_RETURN_PENDING,
76  XMPP_RETURN_UNEXPECTED,
77  XMPP_RETURN_NOTYETIMPLEMENTED,
78};
79
80//! Callback for socket output for an XmppEngine connection.
81//! Register via XmppEngine.SetOutputHandler.  An XmppEngine
82//! can call back to this handler while it is processing
83//! Connect, SendStanza, SendIq, Disconnect, or HandleInput.
84class XmppOutputHandler {
85public:
86  virtual ~XmppOutputHandler() {}
87
88  //! Deliver the specified bytes to the XMPP socket.
89  virtual void WriteOutput(const char * bytes, size_t len) = 0;
90
91  //! Initiate TLS encryption on the socket.
92  //! The implementation must verify that the SSL
93  //! certificate matches the given domainname.
94  virtual void StartTls(const std::string & domainname) = 0;
95
96  //! Called when engine wants the connecton closed.
97  virtual void CloseConnection() = 0;
98};
99
100//! Callback to deliver engine state change notifications
101//! to the object managing the engine.
102class XmppSessionHandler {
103public:
104  virtual ~XmppSessionHandler() {}
105  //! Called when engine changes state. Argument is new state.
106  virtual void OnStateChange(int state) = 0;
107};
108
109//! Callback to deliver stanzas to an Xmpp application module.
110//! Register via XmppEngine.SetDefaultSessionHandler or via
111//! XmppEngine.AddSessionHAndler.
112class XmppStanzaHandler {
113public:
114  virtual ~XmppStanzaHandler() {}
115  //! Process the given stanza.
116  //! The handler must return true if it has handled the stanza.
117  //! A false return value causes the stanza to be passed on to
118  //! the next registered handler.
119  virtual bool HandleStanza(const XmlElement * stanza) = 0;
120};
121
122//! Callback to deliver iq responses (results and errors).
123//! Register while sending an iq via XmppEngine.SendIq.
124//! Iq responses are routed to matching XmppIqHandlers in preference
125//! to sending to any registered SessionHandlers.
126class XmppIqHandler {
127public:
128  virtual ~XmppIqHandler() {}
129  //! Called to handle the iq response.
130  //! The response may be either a result or an error, and will have
131  //! an 'id' that matches the request and a 'from' that matches the
132  //! 'to' of the request.  Called no more than once; once this is
133  //! called, the handler is automatically unregistered.
134  virtual void IqResponse(XmppIqCookie cookie, const XmlElement * pelStanza) = 0;
135};
136
137//! The XMPP connection engine.
138//! This engine implements the client side of the 'core' XMPP protocol.
139//! To use it, register an XmppOutputHandler to handle socket output
140//! and pass socket input to HandleInput.  Then application code can
141//! set up the connection with a user, password, and other settings,
142//! and then call Connect() to initiate the connection.
143//! An application can listen for events and receive stanzas by
144//! registering an XmppStanzaHandler via AddStanzaHandler().
145class XmppEngine {
146public:
147  static XmppEngine * Create();
148  virtual ~XmppEngine() {}
149
150  //! Error codes. See GetError().
151  enum Error {
152    ERROR_NONE = 0,         //!< No error
153    ERROR_XML,              //!< Malformed XML or encoding error
154    ERROR_STREAM,           //!< XMPP stream error - see GetStreamError()
155    ERROR_VERSION,          //!< XMPP version error
156    ERROR_UNAUTHORIZED,     //!< User is not authorized (rejected credentials)
157    ERROR_TLS,              //!< TLS could not be negotiated
158    ERROR_AUTH,             //!< Authentication could not be negotiated
159    ERROR_BIND,             //!< Resource or session binding could not be negotiated
160    ERROR_CONNECTION_CLOSED,//!< Connection closed by output handler.
161    ERROR_DOCUMENT_CLOSED,  //!< Closed by </stream:stream>
162    ERROR_SOCKET,           //!< Socket error
163    ERROR_NETWORK_TIMEOUT,  //!< Some sort of timeout (eg., we never got the roster)
164    ERROR_MISSING_USERNAME  //!< User has a Google Account but no nickname
165  };
166
167  //! States.  See GetState().
168  enum State {
169    STATE_NONE = 0,        //!< Nonexistent state
170    STATE_START,           //!< Initial state.
171    STATE_OPENING,         //!< Exchanging stream headers, authenticating and so on.
172    STATE_OPEN,            //!< Authenticated and bound.
173    STATE_CLOSED,          //!< Session closed, possibly due to error.
174  };
175
176  // SOCKET INPUT AND OUTPUT ------------------------------------------------
177
178  //! Registers the handler for socket output
179  virtual XmppReturnStatus SetOutputHandler(XmppOutputHandler *pxoh) = 0;
180
181  //! Provides socket input to the engine
182  virtual XmppReturnStatus HandleInput(const char * bytes, size_t len) = 0;
183
184  //! Advises the engine that the socket has closed
185  virtual XmppReturnStatus ConnectionClosed(int subcode) = 0;
186
187  // SESSION SETUP ---------------------------------------------------------
188
189  //! Indicates the (bare) JID for the user to use.
190  virtual XmppReturnStatus SetUser(const Jid & jid)= 0;
191
192  //! Get the login (bare) JID.
193  virtual const Jid & GetUser() = 0;
194
195  //! Provides different methods for credentials for login.
196  //! Takes ownership of this object; deletes when login is done
197  virtual XmppReturnStatus SetSaslHandler(SaslHandler * h) = 0;
198
199  //! Sets whether TLS will be used within the connection (default true).
200  virtual XmppReturnStatus SetUseTls(bool useTls) = 0;
201
202  //! Sets an alternate domain from which we allows TLS certificates.
203  //! This is for use in the case where a we want to allow a proxy to
204  //! serve up its own certificate rather than one owned by the underlying
205  //! domain.
206  virtual XmppReturnStatus SetTlsServer(const std::string & proxy_hostname,
207                                        const std::string & proxy_domain) = 0;
208
209  //! Gets whether TLS will be used within the connection.
210  virtual bool GetUseTls() = 0;
211
212  //! Sets the request resource name, if any (optional).
213  //! Note that the resource name may be overridden by the server; after
214  //! binding, the actual resource name is available as part of FullJid().
215  virtual XmppReturnStatus SetRequestedResource(const std::string& resource) = 0;
216
217  //! Gets the request resource name.
218  virtual const std::string & GetRequestedResource() = 0;
219
220  //! Sets language
221  virtual void SetLanguage(const std::string & lang) = 0;
222
223  // SESSION MANAGEMENT ---------------------------------------------------
224
225  //! Set callback for state changes.
226  virtual XmppReturnStatus SetSessionHandler(XmppSessionHandler* handler) = 0;
227
228  //! Initiates the XMPP connection.
229  //! After supplying connection settings, call this once to initiate,
230  //! (optionally) encrypt, authenticate, and bind the connection.
231  virtual XmppReturnStatus Connect() = 0;
232
233  //! The current engine state.
234  virtual State GetState() = 0;
235
236  //! Returns true if the connection is encrypted (under TLS)
237  virtual bool IsEncrypted() = 0;
238
239  //! The error code.
240  //! Consult this after XmppOutputHandler.OnClose().
241  virtual Error GetError(int *subcode) = 0;
242
243  //! The stream:error stanza, when the error is XmppEngine::ERROR_STREAM.
244  //! Notice the stanza returned is owned by the XmppEngine and
245  //! is deleted when the engine is destroyed.
246  virtual const XmlElement * GetStreamError() = 0;
247
248  //! Closes down the connection.
249  //! Sends CloseConnection to output, and disconnects and registered
250  //! session handlers.  After Disconnect completes, it is guaranteed
251  //! that no further callbacks will be made.
252  virtual XmppReturnStatus Disconnect() = 0;
253
254  // APPLICATION USE -------------------------------------------------------
255
256  enum HandlerLevel {
257    HL_NONE = 0,
258    HL_PEEK,   //!< Sees messages before all other processing; cannot abort
259    HL_SINGLE, //!< Watches for a single message, e.g., by id and sender
260    HL_SENDER, //!< Watches for a type of message from a specific sender
261    HL_TYPE,   //!< Watches a type of message, e.g., all groupchat msgs
262    HL_ALL,    //!< Watches all messages - gets last shot
263    HL_COUNT,  //!< Count of handler levels
264  };
265
266  //! Adds a listener for session events.
267  //! Stanza delivery is chained to session handlers; the first to
268  //! return 'true' is the last to get each stanza.
269  virtual XmppReturnStatus AddStanzaHandler(XmppStanzaHandler* handler, HandlerLevel level = HL_PEEK) = 0;
270
271  //! Removes a listener for session events.
272  virtual XmppReturnStatus RemoveStanzaHandler(XmppStanzaHandler* handler) = 0;
273
274  //! Sends a stanza to the server.
275  virtual XmppReturnStatus SendStanza(const XmlElement * pelStanza) = 0;
276
277  //! Sends raw text to the server
278  virtual XmppReturnStatus SendRaw(const std::string & text) = 0;
279
280  //! Sends an iq to the server, and registers a callback for the result.
281  //! Returns the cookie passed to the result handler.
282  virtual XmppReturnStatus SendIq(const XmlElement* pelStanza,
283                                  XmppIqHandler* iq_handler,
284                                  XmppIqCookie* cookie) = 0;
285
286  //! Unregisters an iq callback handler given its cookie.
287  //! No callback will come to this handler after it's unregistered.
288  virtual XmppReturnStatus RemoveIqHandler(XmppIqCookie cookie,
289                                      XmppIqHandler** iq_handler) = 0;
290
291
292  //! Forms and sends an error in response to the given stanza.
293  //! Swaps to and from, sets type to "error", and adds error information
294  //! based on the passed code.  Text is optional and may be STR_EMPTY.
295  virtual XmppReturnStatus SendStanzaError(const XmlElement * pelOriginal,
296                                           XmppStanzaError code,
297                                           const std::string & text) = 0;
298
299  //! The fullly bound JID.
300  //! This JID is only valid after binding has succeeded.  If the value
301  //! is JID_NULL, the binding has not succeeded.
302  virtual const Jid & FullJid() = 0;
303
304  //! The next unused iq id for this connection.
305  //! Call this when building iq stanzas, to ensure that each iq
306  //! gets its own unique id.
307  virtual std::string NextId() = 0;
308
309};
310
311}
312
313
314// Move these to a better location
315
316#define XMPP_FAILED(x)                      \
317  ( (x) == buzz::XMPP_RETURN_OK ? false : true)   \
318
319
320#define XMPP_SUCCEEDED(x)                   \
321  ( (x) == buzz::XMPP_RETURN_OK ? true : false)   \
322
323#define IFR(x)                        \
324  do {                                \
325    xmpp_status = (x);                \
326    if (XMPP_FAILED(xmpp_status)) {   \
327      return xmpp_status;             \
328    }                                 \
329  } while (false)                     \
330
331
332#define IFC(x)                        \
333  do {                                \
334    xmpp_status = (x);                \
335    if (XMPP_FAILED(xmpp_status)) {   \
336      goto Cleanup;                   \
337    }                                 \
338  } while (false)                     \
339
340
341#endif
342