xmpp_component.hpp 9.4 KB
Newer Older
1 2
#pragma once

3 4 5 6 7 8 9 10 11

#include <xmpp/adhoc_commands_handler.hpp>
#include <network/tcp_socket_handler.hpp>
#include <xmpp/xmpp_parser.hpp>
#include <xmpp/body.hpp>

#include <unordered_map>
#include <memory>
#include <string>
louiz’'s avatar
louiz’ committed
12
#include <ctime>
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
#include <map>

#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"
#define PING_NS          "urn:xmpp:ping"
29 30 31 32
#define DELAY_NS         "urn:xmpp:delay"
#define MAM_NS           "urn:xmpp:mam:1"
#define FORWARD_NS       "urn:xmpp:forward:0"
#define CLIENT_NS        "jabber:client"
33
#define DATAFORM_NS      "jabber:x:data"
34
#define RSM_NS           "http://jabber.org/protocol/rsm"
35 36 37 38 39 40 41 42 43 44 45 46 47

/**
 * An XMPP component, communicating with an XMPP server using the protocole
 * described in XEP-0114: Jabber Component Protocol
 *
 * TODO: implement XEP-0225: Component Connections
 */
class XmppComponent: public TCPSocketHandler
{
public:
  explicit XmppComponent(std::shared_ptr<Poller> poller, const std::string& hostname, const std::string& secret);
  virtual ~XmppComponent() = default;

louiz’'s avatar
louiz’ committed
48 49 50 51 52
  XmppComponent(const XmppComponent&) = delete;
  XmppComponent(XmppComponent&&) = delete;
  XmppComponent& operator=(const XmppComponent&) = delete;
  XmppComponent& operator=(XmppComponent&&) = delete;

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
  void on_connection_failed(const std::string& reason) override final;
  void on_connected() override final;
  void on_connection_close(const std::string& error) override final;
  void parse_in_buffer(const size_t size) override final;

  /**
   * Returns a unique id, to be used in the 'id' element of our iq stanzas.
   */
  static std::string next_id();
  bool is_document_open() const;
  /**
   * Connect to the XMPP server.
   */
  void start();
  /**
   * Reset the component so we can use the component on a new XMPP stream
   */
  void reset();
  /**
   * 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);
  /**
   * 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,
                         const std::string& defined_condition, const std::string& text,
                         const bool fulljid=true);
  /**
   * Send the closing signal for our document (not closing the connection though).
   */
  void close_document();
  /**
   * Send a message from from@served_hostname, with the given body
   *
   * If fulljid is false, the provided 'from' doesn't contain the
   * server-part of the JID and must be added.
   */
  void send_message(const std::string& from, Xmpp::body&& body,
                    const std::string& to, const std::string& type,
                    const bool fulljid=false);
  /**
   * Send a join from a new participant
   */
  void send_user_join(const std::string& from,
                      const std::string& nick,
                      const std::string& realjid,
                      const std::string& affiliation,
                      const std::string& role,
                      const std::string& to,
                      const bool self);
  /**
   * 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);
  /**
   * 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);
  /**
   * Send the MUC topic to the user
   */
139
  void send_topic(const std::string& from, Xmpp::body&& xmpp_topic, const std::string& to, const std::string& who);
140 141 142 143
  /**
   * Send a (non-private) message to the MUC
   */
  void send_muc_message(const std::string& muc_name, const std::string& nick, Xmpp::body&& body, const std::string& jid_to);
144 145 146 147 148
  /**
   * Send a message, with a <delay/> element, part of a MUC history
   */
  void send_history_message(const std::string& muc_name, const std::string& nick, const std::string& body,
                            const std::string& jid_to, const std::time_t timestamp);
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
  /**
   * Send an unavailable presence for this nick
   */
  void send_muc_leave(const std::string& muc_name, std::string&& nick, Xmpp::body&& message, const std::string& jid_to, const bool self);
  /**
   * Indicate that a participant changed his nick
   */
  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);
  /**
   * 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);
  /**
   * Send a generic presence error
   */
  void send_presence_error(const std::string& muc_name,
                           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);
  /**
   * 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);
  /**
   * Send a result IQ with the gateway disco informations.
   */
  void send_self_disco_info(const std::string& id, const std::string& jid_to);
  /**
   * Send a result IQ with the given version, or the gateway version if the
   * passed string is empty.
   */
  void send_version(const std::string& id, const std::string& jid_to, const std::string& jid_from,
                    const std::string& version="");
  /**
   * Send the list of all available ad-hoc commands to that JID. The list is
   * different depending on what JID made the request.
   */
204 205
  void send_adhoc_commands_list(const std::string& id, const std::string& requester_jid, const std::string& from_jid,
                                const bool with_admin_only, const AdhocCommandsHandler& adhoc_handler);
206 207 208 209 210 211 212 213 214
  /**
   * Send an iq version request
   */
  void send_iq_version_request(const std::string& from,
                               const std::string& jid_to);
  /**
   * Send an empty iq of type result
   */
  void send_iq_result(const std::string& id, const std::string& to_jid, const std::string& from);
215 216
  void send_iq_result_full_jid(const std::string& id, const std::string& to_jid,
                               const std::string& from_full_jid);
217 218 219 220 221 222

  void handle_handshake(const Stanza& stanza);
  void handle_error(const Stanza& stanza);

  virtual void after_handshake() {}

223 224 225
  const std::string& get_served_hostname() const
  { return this->served_hostname; }

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
  /**
   * Whether or not we ever succeeded our authentication to the XMPP server
   */
  bool ever_auth;
  /**
   * Whether or not this is the first consecutive try on connecting to the
   * XMPP server.  We use this to delay the connection attempt for a few
   * seconds, if it is not the first try.
   */
  bool first_connection_try;

private:
  /**
   * 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;
  XmppParser parser;
  std::string stream_id;
  std::string secret;
  bool authenticated;
  /**
   * Whether or not OUR XMPP document is open
   */
  bool doc_open;
protected:
  std::string served_hostname;

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

258