xmpp_component.hpp 10.1 KB
Newer Older
1
2
3
#ifndef XMPP_COMPONENT_INCLUDED
# define XMPP_COMPONENT_INCLUDED

4
#include <xmpp/adhoc_commands_handler.hpp>
5
#include <network/tcp_socket_handler.hpp>
6
#include <xmpp/xmpp_parser.hpp>
7
#include <bridge/bridge.hpp>
8
9

#include <unordered_map>
10
11
#include <memory>
#include <string>
12
#include <map>
13

14
15
16
17
18
19
20
21
22
23
24
25
26
#define STREAM_NS        "http://etherx.jabber.org/streams"
#define COMPONENT_NS     "jabber:component:accept"
#define MUC_NS           "http://jabber.org/protocol/muc"
#define MUC_USER_NS      MUC_NS"#user"
#define MUC_ADMIN_NS     MUC_NS"#admin"
#define DISCO_NS         "http://jabber.org/protocol/disco"
#define DISCO_ITEMS_NS   DISCO_NS"#items"
#define DISCO_INFO_NS    DISCO_NS"#info"
#define XHTMLIM_NS       "http://jabber.org/protocol/xhtml-im"
#define STANZA_NS        "urn:ietf:params:xml:ns:xmpp-stanzas"
#define STREAMS_NS       "urn:ietf:params:xml:ns:xmpp-streams"
#define VERSION_NS       "jabber:iq:version"
#define ADHOC_NS         "http://jabber.org/protocol/commands"
27
28
29
30
31
/**
 * A callback called when the waited iq result is received (it is matched
 * against the iq id)
 */
using iq_responder_callback_t = std::function<void(Bridge* bridge, const Stanza& stanza)>;
32

33
34
35
36
37
38
/**
 * An XMPP component, communicating with an XMPP server using the protocole
 * described in XEP-0114: Jabber Component Protocol
 *
 * TODO: implement XEP-0225: Component Connections
 */
39
class XmppComponent: public TCPSocketHandler
40
41
{
public:
42
  explicit XmppComponent(std::shared_ptr<Poller> poller, const std::string& hostname, const std::string& secret);
43
  ~XmppComponent();
louiz’'s avatar
louiz’ committed
44

45
  void on_connection_failed(const std::string& reason) override final;
louiz’'s avatar
louiz’ committed
46
  void on_connected() override final;
47
  void on_connection_close(const std::string& error) override final;
48
  void parse_in_buffer(const size_t size) override final;
louiz’'s avatar
louiz’ committed
49

50
51
52
53
54
55
56
57
58
59
  /**
   * Returns the bridge for the given user. If it does not exist, return
   * nullptr.
   */
  Bridge* find_user_bridge(const std::string& user_jid);
  /**
   * Return a list of all the managed bridges.
   */
  std::list<Bridge*> get_bridges() const;

louiz’'s avatar
louiz’ committed
60
61
62
63
  /**
   * Returns a unique id, to be used in the 'id' element of our iq stanzas.
   */
  static std::string next_id();
louiz’'s avatar
louiz’ committed
64
65
66
67
68
69
70
71
  /**
   * Send a "close" message to all our connected peers.  That message
   * depends on the protocol used (this may be a QUIT irc message, or a
   * <stream/>, etc).  We may also directly close the connection, or we may
   * wait for the remote peer to acknowledge it before closing.
   */
  void shutdown();
  bool is_document_open() const;
louiz’'s avatar
louiz’ committed
72
73
74
75
76
  /**
   * Run a check on all bridges, to remove all disconnected (socket is
   * closed, or no channel is joined) IrcClients. Some kind of garbage collector.
   */
  void clean();
77
  /**
louiz’'s avatar
louiz’ committed
78
   * Connect to the XMPP server.
79
   */
80
  void start();
81
82
83
84
  /**
   * Reset the component so we can use the component on a new XMPP stream
   */
  void reset();
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
  /**
   * Serialize the stanza and add it to the out_buf to be sent to the
   * server.
   */
  void send_stanza(const Stanza& stanza);
  /**
   * Handle the opening of the remote stream
   */
  void on_remote_stream_open(const XmlNode& node);
  /**
   * Handle the closing of the remote stream
   */
  void on_remote_stream_close(const XmlNode& node);
  /**
   * Handle received stanzas
   */
  void on_stanza(const Stanza& stanza);
  /**
   * Send an error stanza. Message being the name of the element inside the
   * stanza, and explanation being a short human-readable sentence
   * describing the error.
   */
  void send_stream_error(const std::string& message, const std::string& explanation);
108
109
110
111
112
  /**
   * Send error stanza, described in http://xmpp.org/rfcs/rfc6120.html#stanzas-error
   */
  void send_stanza_error(const std::string& kind, const std::string& to, const std::string& from,
                         const std::string& id, const std::string& error_type,
113
114
                         const std::string& defined_condition, const std::string& text,
                         const bool fulljid=true);
115
116
117
118
  /**
   * Send the closing signal for our document (not closing the connection though).
   */
  void close_document();
119
120
  /**
   * Send a message from from@served_hostname, with the given body
121
122
123
   *
   * If fulljid is false, the provided 'from' doesn't contain the
   * server-part of the JID and must be added.
124
   */
125
  void send_message(const std::string& from, Xmpp::body&& body,
126
127
                    const std::string& to, const std::string& type,
                    const bool fulljid=false);
128
129
130
  /**
   * Send a join from a new participant
   */
131
132
133
  void send_user_join(const std::string& from,
                      const std::string& nick,
                      const std::string& realjid,
134
135
136
137
                      const std::string& affiliation,
                      const std::string& role,
                      const std::string& to,
                      const bool self);
138
139
140
141
142
143
  /**
   * Send an error to indicate that the user tried to join an invalid room
   */
  void send_invalid_room_error(const std::string& muc_jid,
                               const std::string& nick,
                               const std::string& to);
louiz’'s avatar
louiz’ committed
144
145
146
147
148
149
  /**
   * Send an error to indicate that the user tried to send a message to an
   * invalid user.
   */
  void send_invalid_user_error(const std::string& user_name,
                               const std::string& to);
150
151
152
  /**
   * Send the MUC topic to the user
   */
153
  void send_topic(const std::string& from, Xmpp::body&& xmpp_topic, const std::string& to);
louiz’'s avatar
louiz’ committed
154
155
156
  /**
   * Send a (non-private) message to the MUC
   */
157
  void send_muc_message(const std::string& muc_name, const std::string& nick, Xmpp::body&& body, const std::string& jid_to);
louiz’'s avatar
louiz’ committed
158
159
160
  /**
   * Send an unavailable presence for this nick
   */
louiz’'s avatar
louiz’ committed
161
  void send_muc_leave(const std::string& muc_name, std::string&& nick, Xmpp::body&& message, const std::string& jid_to, const bool self);
louiz’'s avatar
louiz’ committed
162
163
164
  /**
   * Indicate that a participant changed his nick
   */
165
166
167
168
169
170
171
  void send_nick_change(const std::string& muc_name,
                        const std::string& old_nick,
                        const std::string& new_nick,
                        const std::string& affiliation,
                        const std::string& role,
                        const std::string& jid_to,
                        const bool self);
172
173
174
175
176
177
178
179
  /**
   * An user is kicked from a room
   */
  void kick_user(const std::string& muc_name,
                     const std::string& target,
                     const std::string& reason,
                     const std::string& author,
                     const std::string& jid_to);
180
181
182
183
  /**
   * Send a generic presence error
   */
  void send_presence_error(const std::string& muc_name,
184
185
186
187
188
189
                           const std::string& nickname,
                           const std::string& jid_to,
                           const std::string& type,
                           const std::string& condition,
                           const std::string& error_code,
                           const std::string& text);
190
191
192
193
194
195
196
197
198
  /**
   * Send a presence from the MUC indicating a change in the role and/or
   * affiliation of a participant
   */
  void send_affiliation_role_change(const std::string& muc_name,
                                    const std::string& target,
                                    const std::string& affiliation,
                                    const std::string& role,
                                    const std::string& jid_to);
199
200
201
202
  /**
   * Send a result IQ with the gateway disco informations.
   */
  void send_self_disco_info(const std::string& id, const std::string& jid_to);
203
  /**
204
205
   * Send a result IQ with the given version, or the gateway version if the
   * passed string is empty.
206
   */
207
208
  void send_version(const std::string& id, const std::string& jid_to, const std::string& jid_from,
                    const std::string& version="");
209
210
211
212
213
  /**
   * Send the list of all available ad-hoc commands to that JID. The list is
   * different depending on what JID made the request.
   */
  void send_adhoc_commands_list(const std::string& id, const std::string& requester_jid);
214
215
216
217
218
  /**
   * Send an iq version request
   */
  void send_iq_version_request(const std::string& from,
                               const std::string& jid_to);
219
220
221
222
  /**
   * Send an empty iq of type result
   */
  void send_iq_result(const std::string& id, const std::string& to_jid, const std::string& from);
223
224
225
226
  /**
   * Handle the various stanza types
   */
  void handle_handshake(const Stanza& stanza);
227
  void handle_presence(const Stanza& stanza);
louiz’'s avatar
louiz’ committed
228
  void handle_message(const Stanza& stanza);
229
  void handle_iq(const Stanza& stanza);
louiz’'s avatar
louiz’ committed
230
  void handle_error(const Stanza& stanza);
231

232
233
234
235
236
237
238
239
240
  /**
   * Whether or not we ever succeeded our authentication to the XMPP server
   */
  bool ever_auth;
  /**
   * Whether or not the last connection+auth attempt was successful
   */
  bool last_auth;

241
private:
242
243
244
245
246
  /**
   * Return the bridge associated with the given full JID. Create a new one
   * if none already exist.
   */
  Bridge* get_user_bridge(const std::string& user_jid);
247
248
249
250
251
  /**
   * Return a buffer provided by the XML parser, to read data directly into
   * it, and avoiding some unnecessary copy.
   */
  void* get_receive_buffer(const size_t size) const override final;
252
253
254
255
256
  XmppParser parser;
  std::string stream_id;
  std::string served_hostname;
  std::string secret;
  bool authenticated;
louiz’'s avatar
louiz’ committed
257
258
259
260
  /**
   * Whether or not OUR XMPP document is open
   */
  bool doc_open;
261
262

  std::unordered_map<std::string, std::function<void(const Stanza&)>> stanza_handlers;
263
  AdhocCommandsHandler adhoc_commands_handler;
264

265
266
267
268
269
270
271
272
  /**
   * A map of id -> callback.  When we want to wait for an iq result, we add
   * the callback to this map, with the iq id as the key. When an iq result
   * is received, we look for a corresponding callback in this map. If
   * found, we call it and remove it.
   */
  std::map<std::string, iq_responder_callback_t> waiting_iq;

273
274
275
276
277
278
  /**
   * One bridge for each user of the component. Indexed by the user's full
   * jid
   */
  std::unordered_map<std::string, std::unique_ptr<Bridge>> bridges;

279
280
281
282
283
284
285
  XmppComponent(const XmppComponent&) = delete;
  XmppComponent(XmppComponent&&) = delete;
  XmppComponent& operator=(const XmppComponent&) = delete;
  XmppComponent& operator=(XmppComponent&&) = delete;
};

#endif // XMPP_COMPONENT_INCLUDED