bridge.cpp 7.53 KB
Newer Older
1
#include <bridge/bridge.hpp>
2
#include <bridge/colors.hpp>
3 4
#include <xmpp/xmpp_component.hpp>
#include <network/poller.hpp>
5
#include <utils/encoding.hpp>
louiz’'s avatar
louiz’ committed
6
#include <logger/logger.hpp>
louiz’'s avatar
louiz’ committed
7
#include <utils/split.hpp>
louiz’'s avatar
louiz’ committed
8 9
#include <iostream>

10 11 12
static const char* action_prefix = "\01ACTION ";
static const size_t action_prefix_len = 8;

13 14 15 16 17 18 19 20 21 22 23
Bridge::Bridge(const std::string& user_jid, XmppComponent* xmpp, Poller* poller):
  user_jid(user_jid),
  xmpp(xmpp),
  poller(poller)
{
}

Bridge::~Bridge()
{
}

louiz’'s avatar
louiz’ committed
24 25 26 27 28 29 30 31
void Bridge::shutdown()
{
  for (auto it = this->irc_clients.begin(); it != this->irc_clients.end(); ++it)
  {
    it->second->send_quit_command();
  }
}

louiz’'s avatar
louiz’ committed
32 33 34 35 36 37 38 39 40 41 42 43 44
void Bridge::clean()
{
  auto it = this->irc_clients.begin();
  while (it != this->irc_clients.end())
  {
    IrcClient* client = it->second.get();
    if (!client->is_connected())
      it = this->irc_clients.erase(it);
    else
      ++it;
  }
}

45
Xmpp::body Bridge::make_xmpp_body(const std::string& str)
46 47 48 49 50 51
{
  std::string res;
  if (utils::is_valid_utf8(str.c_str()))
    res = str;
  else
    res = utils::convert_to_utf8(str, "ISO-8859-1");
52
  return irc_format_to_xhtmlim(res);
53 54
}

55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
IrcClient* Bridge::get_irc_client(const std::string& hostname, const std::string& username)
{
  try
    {
      return this->irc_clients.at(hostname).get();
    }
  catch (const std::out_of_range& exception)
    {
      this->irc_clients.emplace(hostname, std::make_shared<IrcClient>(hostname, username, this));
      std::shared_ptr<IrcClient> irc = this->irc_clients.at(hostname);
      this->poller->add_socket_handler(irc);
      return irc.get();
    }
}

louiz’'s avatar
louiz’ committed
70 71 72 73 74 75 76 77 78 79 80 81
IrcClient* Bridge::get_irc_client(const std::string& hostname)
{
  try
    {
      return this->irc_clients.at(hostname).get();
    }
  catch (const std::out_of_range& exception)
    {
      return nullptr;
    }
}

louiz’'s avatar
louiz’ committed
82
bool Bridge::join_irc_channel(const Iid& iid, const std::string& username)
83 84
{
  IrcClient* irc = this->get_irc_client(iid.server, username);
louiz’'s avatar
louiz’ committed
85 86 87 88 89 90
  if (irc->is_channel_joined(iid.chan) == false)
    {
      irc->send_join_command(iid.chan);
      return true;
    }
  return false;
91 92
}

louiz’'s avatar
louiz’ committed
93 94
void Bridge::send_channel_message(const Iid& iid, const std::string& body)
{
95 96 97 98
  std::vector<std::string> lines = utils::split(body, '\n', true);
  if (lines.empty())
    return ;
  const std::string first_line = lines[0];
louiz’'s avatar
louiz’ committed
99 100
  if (iid.chan.empty() || iid.server.empty())
    {
louiz’'s avatar
louiz’ committed
101
      log_warning("Cannot send message to channel: [" << iid.chan << "] on server [" << iid.server << "]");
louiz’'s avatar
louiz’ committed
102 103 104 105 106
      return;
    }
  IrcClient* irc = this->get_irc_client(iid.server);
  if (!irc)
    {
louiz’'s avatar
louiz’ committed
107
      log_warning("Cannot send message: no client exist for server " << iid.server);
louiz’'s avatar
louiz’ committed
108 109
      return;
    }
110
  if (first_line.substr(0, 6) == "/mode ")
louiz’'s avatar
louiz’ committed
111
    {
112
      std::vector<std::string> args = utils::split(first_line.substr(6), ' ', false);
louiz’'s avatar
louiz’ committed
113 114 115
      irc->send_mode_command(iid.chan, args);
      return;
    }
116 117
  if (first_line.substr(0, 4) == "/me ")
    irc->send_channel_message(iid.chan, action_prefix + first_line.substr(4) + "\01");
118
  else
119 120 121 122
    irc->send_channel_message(iid.chan, first_line);
  // Send each of the other lines of the message as a separate IRC message
  for (std::vector<std::string>::const_iterator it = lines.begin() + 1; it != lines.end(); ++it)
    irc->send_channel_message(iid.chan, *it);
123 124
  // We do not need to convert body to utf-8: it comes from our XMPP server,
  // so it's ok to send it back
125 126
  this->xmpp->send_muc_message(iid.chan + "%" + iid.server, irc->get_own_nick(),
                               this->make_xmpp_body(body), this->user_jid);
louiz’'s avatar
louiz’ committed
127 128
}

louiz’'s avatar
louiz’ committed
129 130 131 132 133 134 135 136 137
void Bridge::send_private_message(const Iid& iid, const std::string& body)
{
  if (iid.chan.empty() || iid.server.empty())
    return ;
  IrcClient* irc = this->get_irc_client(iid.server);
  if (irc)
    irc->send_private_message(iid.chan, body);
}

louiz’'s avatar
louiz’ committed
138 139 140 141 142 143 144
void Bridge::leave_irc_channel(Iid&& iid, std::string&& status_message)
{
  IrcClient* irc = this->get_irc_client(iid.server);
  if (irc)
    irc->send_part_command(iid.chan, status_message);
}

louiz’'s avatar
louiz’ committed
145 146 147 148 149 150 151
void Bridge::send_irc_nick_change(const Iid& iid, const std::string& new_nick)
{
  IrcClient* irc = this->get_irc_client(iid.server);
  if (irc)
    irc->send_nick_command(new_nick);
}

152 153 154 155 156 157 158
void Bridge::send_irc_kick(const Iid& iid, const std::string& target, const std::string& reason)
{
  IrcClient* irc = this->get_irc_client(iid.server);
  if (irc)
    irc->send_kick_command(iid.chan, target, reason);
}

louiz’'s avatar
louiz’ committed
159
void Bridge::send_message(const Iid& iid, const std::string& nick, const std::string& body, const bool muc)
louiz’'s avatar
louiz’ committed
160
{
louiz’'s avatar
louiz’ committed
161
  if (muc)
162 163
    this->xmpp->send_muc_message(iid.chan + "%" + iid.server, nick,
                                 this->make_xmpp_body(body), this->user_jid);
louiz’'s avatar
louiz’ committed
164
  else
165 166
    this->xmpp->send_message(iid.chan + "%" + iid.server,
                             this->make_xmpp_body(body), this->user_jid);
louiz’'s avatar
louiz’ committed
167 168
}

louiz’'s avatar
louiz’ committed
169
void Bridge::send_muc_leave(Iid&& iid, std::string&& nick, const std::string& message, const bool self)
louiz’'s avatar
louiz’ committed
170
{
171
  this->xmpp->send_muc_leave(std::move(iid.chan) + "%" + std::move(iid.server), std::move(nick), this->make_xmpp_body(message), this->user_jid, self);
louiz’'s avatar
louiz’ committed
172 173
}

louiz’'s avatar
louiz’ committed
174 175 176 177 178 179
void Bridge::send_nick_change(Iid&& iid, const std::string& old_nick, const std::string& new_nick, const bool self)
{
  this->xmpp->send_nick_change(std::move(iid.chan) + "%" + std::move(iid.server),
                               old_nick, new_nick, this->user_jid, self);
}

180 181
void Bridge::send_xmpp_message(const std::string& from, const std::string& author, const std::string& msg)
{
louiz’'s avatar
louiz’ committed
182 183 184 185 186
  std::string body;
  if (!author.empty())
    body = std::string("[") + author + std::string("] ") + msg;
  else
    body = msg;
187
  this->xmpp->send_message(from, this->make_xmpp_body(body), this->user_jid);
188 189
}

190 191
void Bridge::send_user_join(const std::string& hostname,
                            const std::string& chan_name,
192 193
                            const IrcUser* user,
                            const bool self)
194
{
195 196 197 198 199 200 201 202 203
  std::string affiliation = "participant";
  std::string role = "none";
  if (user->modes.find('o') != user->modes.end())
    {
      affiliation = "admin";
      role = "moderator";
    }
  this->xmpp->send_user_join(chan_name + "%" + hostname, user->nick, user->host,
                             affiliation, role, this->user_jid, self);
204 205 206 207
}

void Bridge::send_topic(const std::string& hostname, const std::string& chan_name, const std::string topic)
{
208
  this->xmpp->send_topic(chan_name + "%" + hostname, this->make_xmpp_body(topic), this->user_jid);
209
}
louiz’'s avatar
louiz’ committed
210 211 212 213 214 215 216 217

std::string Bridge::get_own_nick(const Iid& iid)
{
  IrcClient* irc = this->get_irc_client(iid.server);
  if (irc)
    return irc->get_own_nick();
  return "";
}
218 219 220 221 222

void Bridge::kick_muc_user(Iid&& iid, const std::string& target, const std::string& reason, const std::string& author)
{
  this->xmpp->kick_user(iid.chan + "%" + iid.server, target, reason, author, this->user_jid);
}
223 224 225 226 227

void Bridge::send_nickname_conflict_error(const Iid& iid, const std::string& nickname)
{
  this->xmpp->send_nickname_conflict_error(iid.chan + "%" + iid.server, nickname, this->user_jid);
}
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

void Bridge::send_affiliation_role_change(const Iid& iid, const std::string& target, const char mode)
{
  std::string role;
  std::string affiliation;
  if (mode == 0)
    {
      role = "participant";
      affiliation = "none";
    }
  else if (mode == 'a')
    {
      role = "moderator";
      affiliation = "owner";
    }
  else if (mode == 'o')
    {
      role = "moderator";
      affiliation = "admin";
    }
  else if (mode == 'h')
    {
      role = "moderator";
      affiliation = "member";
    }
  else if (mode == 'v')
    {
      role = "participant";
      affiliation = "member";
    }
  this->xmpp->send_affiliation_role_change(iid.chan + "%" + iid.server, target, affiliation, role, this->user_jid);
}