bridge.hpp 9.77 KB
Newer Older
1 2 3
#ifndef BRIDGE_INCLUDED
# define BRIDGE_INCLUDED

4
#include <irc/irc_message.hpp>
5
#include <irc/irc_client.hpp>
6
#include <bridge/colors.hpp>
7
#include <irc/irc_user.hpp>
8 9 10
#include <irc/iid.hpp>

#include <unordered_map>
11
#include <functional>
12
#include <exception>
13 14 15
#include <string>
#include <memory>

16
class BiboumiComponent;
17 18
class Poller;

19 20
/**
 * A callback called for each IrcMessage we receive. If the message triggers
21 22
 * a response, it must send ore or more iq and return true (in that case it
 * is removed from the list), otherwise it must do nothing and just return
23 24
 * false.
 */
25
using irc_responder_callback_t = std::function<bool(const std::string& irc_hostname, const IrcMessage& message)>;
26

27 28 29 30 31 32 33 34 35
/**
 * One bridge is spawned for each XMPP user that uses the component.  The
 * bridge spawns IrcClients when needed (when the user wants to join a
 * channel on a new server) and does the translation between the two
 * protocols.
 */
class Bridge
{
public:
36
  explicit Bridge(const std::string& user_jid, BiboumiComponent* xmpp, std::shared_ptr<Poller> poller);
37
  ~Bridge();
louiz’'s avatar
louiz’ committed
38 39 40
  /**
   * QUIT all connected IRC servers.
   */
41
  void shutdown(const std::string& exit_message);
louiz’'s avatar
louiz’ committed
42 43 44 45
  /**
   * Remove all inactive IrcClients
   */
  void clean();
46 47 48 49
  /**
   * Return the jid of the XMPP user using this bridge
   */
  const std::string& get_jid() const;
louiz’'s avatar
louiz’ committed
50
  std::string get_bare_jid() const;
51

52
  static Xmpp::body make_xmpp_body(const std::string& str);
53 54 55 56 57 58
  /***
   **
   ** From XMPP to IRC.
   **
   **/

louiz’'s avatar
louiz’ committed
59 60 61 62
  /**
   * Try to join an irc_channel, does nothing and return true if the channel
   * was already joined.
   */
63 64
  bool join_irc_channel(const Iid& iid, const std::string& nickname, const std::string& password);

louiz’'s avatar
louiz’ committed
65
  void send_channel_message(const Iid& iid, const std::string& body);
louiz’'s avatar
louiz’ committed
66
  void send_private_message(const Iid& iid, const std::string& body, const std::string& type="PRIVMSG");
louiz’'s avatar
louiz’ committed
67
  void send_raw_message(const std::string& hostname, const std::string& body);
68
  void leave_irc_channel(Iid&& iid, std::string&& status_message);
louiz’'s avatar
louiz’ committed
69
  void send_irc_nick_change(const Iid& iid, const std::string& new_nick);
70 71
  void send_irc_kick(const Iid& iid, const std::string& target, const std::string& reason,
                     const std::string& iq_id, const std::string& to_jid);
72
  void set_channel_topic(const Iid& iid, const std::string& subject);
73 74
  void send_xmpp_version_to_irc(const Iid& iid, const std::string& name, const std::string& version,
                                const std::string& os);
75
  void send_irc_ping_result(const Iid& iid, const std::string& id);
76 77 78
  void send_irc_version_request(const std::string& irc_hostname, const std::string& target,
                                const std::string& iq_id, const std::string& to_jid,
                                const std::string& from_jid);
79 80
  void send_irc_channel_list_request(const Iid& iid, const std::string& iq_id,
                                     const std::string& to_jid);
81 82
  void forward_affiliation_role_change(const Iid& iid, const std::string& nick,
                                       const std::string& affiliation, const std::string& role);
83 84 85 86 87 88
  /**
   * Directly send a CTCP PING request to the IRC user
   */
  void send_irc_user_ping_request(const std::string& irc_hostname, const std::string& nick,
                                  const std::string& iq_id, const std::string& to_jid,
                                  const std::string& from_jid);
89 90 91 92 93 94 95
  /**
   * First check if the participant is in the room, before sending a direct
   * CTCP PING request to the IRC user
   */
  void send_irc_participant_ping_request(const Iid& iid, const std::string& nick,
                                         const std::string& iq_id, const std::string& to_jid,
                                         const std::string& from_jid);
96 97 98 99 100 101
  /**
   * Directly send back a result if it's a gateway ping or if we are
   * connected to the given IRC server, an error otherwise.
   */
  void on_gateway_ping(const std::string& irc_hostname, const std::string& iq_id, const std::string& to_jid,
                       const std::string& from_jid);
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116

  /***
   **
   ** From IRC to XMPP.
   **
   **/

  /**
   * Send a message corresponding to a server NOTICE, the from attribute
   * should be juste the server hostname@irc.component.
   */
  void send_xmpp_message(const std::string& from, const std::string& author, const std::string& msg);
  /**
   * Send the presence of a new user in the MUC.
   */
117 118
  void send_user_join(const std::string& hostname,
                      const std::string& chan_name,
119
                      const IrcUser* user,
120
                      const char user_mode,
121
                      const bool self);
122 123 124
  /**
   * Send the topic of the MUC to the user
   */
125
  void send_topic(const std::string& hostname, const std::string& chan_name, const std::string& topic);
louiz’'s avatar
louiz’ committed
126 127 128
  /**
   * Send a MUC message from some participant
   */
129
  void send_message(const Iid& iid, const std::string& nick, const std::string& body, const bool muc);
130
  /**
131
   * Send a presence of type error, from a room.
132
   */
133
  void send_presence_error(const Iid& iid, const std::string& nick, const std::string& type, const std::string& condition, const std::string& error_code, const std::string& text);
134 135 136
  /**
   * Send an unavailable presence from this participant
   */
louiz’'s avatar
louiz’ committed
137 138 139
  void send_muc_leave(Iid&& iid, std::string&& nick, const std::string& message, const bool self);
  /**
   * Send presences to indicate that an user old_nick (ourself if self ==
140 141 142
   * true) changed his nick to new_nick.  The user_mode is needed because
   * the xmpp presence needs ton contain the role and affiliation of the
   * user.
louiz’'s avatar
louiz’ committed
143
   */
144 145 146 147 148
  void send_nick_change(Iid&& iid,
                        const std::string& old_nick,
                        const std::string& new_nick,
                        const char user_mode,
                        const bool self);
149
  void kick_muc_user(Iid&& iid, const std::string& target, const std::string& reason, const std::string& author);
150
  void send_nickname_conflict_error(const Iid& iid, const std::string& nickname);
151 152 153 154
  /**
   * Send a role/affiliation change, matching the change of mode for that user
   */
  void send_affiliation_role_change(const Iid& iid, const std::string& target, const char mode);
155
  /**
louiz’'s avatar
louiz’ committed
156
   * Send an iq version request coming from nick!hostname@
157 158
   */
  void send_iq_version_request(const std::string& nick, const std::string& hostname);
159 160 161 162 163
  /**
   * Send an iq ping request coming from nick!hostname@
   */
  void send_xmpp_ping_request(const std::string& nick, const std::string& hostname,
                              const std::string& id);
louiz’'s avatar
louiz’ committed
164 165 166 167
  /**
   * Misc
   */
  std::string get_own_nick(const Iid& iid);
louiz’'s avatar
louiz’ committed
168
  /**
169
   * Get the number of server to which this bridge is connected or connecting.
louiz’'s avatar
louiz’ committed
170
   */
171
  size_t active_clients() const;
172 173 174 175 176 177 178 179
  /**
   * Add (or replace the existing) <nick, jid> into the preferred_user_from map
   */
  void set_preferred_from_jid(const std::string& nick, const std::string& full_jid);
  /**
   * Remove the preferred jid for the given IRC nick
   */
  void remove_preferred_from_jid(const std::string& nick);
180
  /**
181
   * Add a callback to the waiting list of irc callbacks.
182
   */
183
  void add_waiting_irc(irc_responder_callback_t&& callback);
184 185 186 187 188
  /**
   * Iter over all the waiting_iq, call the iq_responder_filter_t for each,
   * whenever one of them returns true: call the corresponding
   * iq_responder_callback_t and remove the callback from the list.
   */
189
  void trigger_on_irc_message(const std::string& irc_hostname, const IrcMessage& message);
190
  std::unordered_map<std::string, std::shared_ptr<IrcClient>>& get_irc_clients();
191

192 193 194 195 196 197
private:
  /**
   * Returns the client for the given hostname, create one (and use the
   * username in this case) if none is found, and connect that newly-created
   * client immediately.
   */
198
  IrcClient* make_irc_client(const std::string& hostname, const std::string& nickname);
louiz’'s avatar
louiz’ committed
199
  /**
200 201
   * This version does not create the IrcClient if it does not exist, throws
   * a IRCServerNotConnected error in that case.
louiz’'s avatar
louiz’ committed
202 203
   */
  IrcClient* get_irc_client(const std::string& hostname);
204 205 206 207
  /**
   * Idem, but returns nullptr if the server does not exist.
   */
  IrcClient* find_irc_client(const std::string& hostname);
208 209 210 211
  /**
   * The JID of the user associated with this bridge. Messages from/to this
   * JID are only managed by this bridge.
   */
212
  const std::string user_jid;
213 214 215 216 217 218 219 220 221 222
  /**
   * One IrcClient for each IRC server we need to be connected to.
   * The pointer is shared by the bridge and the poller.
   */
  std::unordered_map<std::string, std::shared_ptr<IrcClient>> irc_clients;
  /**
   * A raw pointer, because we do not own it, the XMPP component owns us,
   * but we still need to communicate with it, when sending messages from
   * IRC to XMPP.
   */
223
  BiboumiComponent* xmpp;
224 225 226 227
  /**
   * Poller, to give it the IrcClients that we spawn, to make it manage
   * their sockets.
   */
228
  std::shared_ptr<Poller> poller;
229 230 231 232 233 234 235 236
  /**
   * A map of <nick, full_jid>. For example if this map contains <"toto",
   * "#somechan%server@biboumi/ToTo">, whenever a private message is
   * received from the user "toto", instead of forwarding it to XMPP with
   * from='toto!server@biboumi', we use instead
   * from='#somechan%server@biboumi/ToTo'
   */
  std::unordered_map<std::string, std::string> preferred_user_from;
237 238 239 240 241 242
  /**
   * A list of callbacks that are waiting for some IrcMessage to trigger a
   * response.  We add callbacks in this list whenever we received an IQ
   * request and we need a response from IRC to be able to provide the
   * response iq.
   */
243
  std::list<irc_responder_callback_t> waiting_irc;
244 245 246 247 248 249 250

  Bridge(const Bridge&) = delete;
  Bridge(Bridge&& other) = delete;
  Bridge& operator=(const Bridge&) = delete;
  Bridge& operator=(Bridge&&) = delete;
};

251 252 253 254 255 256 257
struct IRCNotConnected: public std::exception
{
  IRCNotConnected(const std::string& hostname):
    hostname(hostname) {}
  const std::string hostname;
};

258
#endif // BRIDGE_INCLUDED