1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
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/tqname.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_RETQUIRED,
XSE_RECIPIENT_UNAVAILABLE,
XSE_REDIRECT,
XSE_REGISTRATION_RETQUIRED,
XSE_SERVER_NOT_FOUND,
XSE_SERVER_TIMEOUT,
XSE_RESOURCE_CONSTRAINT,
XSE_SERVICE_UNAVAILABLE,
XSE_SUBSCRIPTION_RETQUIRED,
XSE_UNDEFINED_CONDITION,
XSE_UNEXPECTED_REQUEST,
};
// XmppReturntqStatus
// This is used by API functions to synchronously return status.
enum XmppReturntqStatus {
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 XmppReturntqStatus SetOutputHandler(XmppOutputHandler *pxoh) = 0;
//! Provides socket input to the engine
virtual XmppReturntqStatus HandleInput(const char * bytes, size_t len) = 0;
//! Advises the engine that the socket has closed
virtual XmppReturntqStatus ConnectionClosed() = 0;
// SESSION SETUP ---------------------------------------------------------
//! Indicates the (bare) JID for the user to use.
virtual XmppReturntqStatus 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 XmppReturntqStatus SetSaslHandler(SaslHandler * h) = 0;
//! Sets whether TLS will be used within the connection (default true).
virtual XmppReturntqStatus 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 XmppReturntqStatus 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 XmppReturntqStatus 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 XmppReturntqStatus 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 XmppReturntqStatus 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 XmppReturntqStatus 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 XmppReturntqStatus AddStanzaHandler(XmppStanzaHandler* handler, HandlerLevel level = HL_PEEK) = 0;
//! Removes a listener for session events.
virtual XmppReturntqStatus RemoveStanzaHandler(XmppStanzaHandler* handler) = 0;
//! Sends a stanza to the server.
virtual XmppReturntqStatus SendStanza(const XmlElement * pelStanza) = 0;
//! Sends raw text to the server
virtual XmppReturntqStatus 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 XmppReturntqStatus 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 XmppReturntqStatus 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 XmppReturntqStatus 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
|