Commit 096a4e3b authored by louiz’'s avatar louiz’

Handle nick changes, both ways

parent f0d9273d
...@@ -59,10 +59,15 @@ IrcClient* Bridge::get_irc_client(const std::string& hostname) ...@@ -59,10 +59,15 @@ IrcClient* Bridge::get_irc_client(const std::string& hostname)
} }
} }
void Bridge::join_irc_channel(const Iid& iid, const std::string& username) bool Bridge::join_irc_channel(const Iid& iid, const std::string& username)
{ {
IrcClient* irc = this->get_irc_client(iid.server, username); IrcClient* irc = this->get_irc_client(iid.server, username);
irc->send_join_command(iid.chan); if (irc->is_channel_joined(iid.chan) == false)
{
irc->send_join_command(iid.chan);
return true;
}
return false;
} }
void Bridge::send_channel_message(const Iid& iid, const std::string& body) void Bridge::send_channel_message(const Iid& iid, const std::string& body)
...@@ -103,6 +108,13 @@ void Bridge::leave_irc_channel(Iid&& iid, std::string&& status_message) ...@@ -103,6 +108,13 @@ void Bridge::leave_irc_channel(Iid&& iid, std::string&& status_message)
irc->send_part_command(iid.chan, status_message); irc->send_part_command(iid.chan, status_message);
} }
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);
}
void Bridge::send_message(const Iid& iid, const std::string& nick, const std::string& body, const bool muc) void Bridge::send_message(const Iid& iid, const std::string& nick, const std::string& body, const bool muc)
{ {
std::string utf8_body = this->sanitize_for_xmpp(body); std::string utf8_body = this->sanitize_for_xmpp(body);
...@@ -118,11 +130,17 @@ void Bridge::send_message(const Iid& iid, const std::string& nick, const std::st ...@@ -118,11 +130,17 @@ void Bridge::send_message(const Iid& iid, const std::string& nick, const std::st
this->xmpp->send_message(iid.chan + "%" + iid.server, utf8_body, this->user_jid); this->xmpp->send_message(iid.chan + "%" + iid.server, utf8_body, this->user_jid);
} }
void Bridge::send_muc_leave(Iid&& iid, std::string&& nick, std::string&& message, const bool self) void Bridge::send_muc_leave(Iid&& iid, std::string&& nick, const std::string& message, const bool self)
{ {
this->xmpp->send_muc_leave(std::move(iid.chan) + "%" + std::move(iid.server), std::move(nick), this->sanitize_for_xmpp(message), this->user_jid, self); this->xmpp->send_muc_leave(std::move(iid.chan) + "%" + std::move(iid.server), std::move(nick), this->sanitize_for_xmpp(message), this->user_jid, self);
} }
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);
}
void Bridge::send_xmpp_message(const std::string& from, const std::string& author, const std::string& msg) void Bridge::send_xmpp_message(const std::string& from, const std::string& author, const std::string& msg)
{ {
std::string body; std::string body;
...@@ -147,3 +165,11 @@ void Bridge::send_topic(const std::string& hostname, const std::string& chan_nam ...@@ -147,3 +165,11 @@ void Bridge::send_topic(const std::string& hostname, const std::string& chan_nam
{ {
this->xmpp->send_topic(chan_name + "%" + hostname, this->sanitize_for_xmpp(topic), this->user_jid); this->xmpp->send_topic(chan_name + "%" + hostname, this->sanitize_for_xmpp(topic), this->user_jid);
} }
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 "";
}
...@@ -30,10 +30,15 @@ public: ...@@ -30,10 +30,15 @@ public:
** **
**/ **/
void join_irc_channel(const Iid& iid, const std::string& username); /**
* Try to join an irc_channel, does nothing and return true if the channel
* was already joined.
*/
bool join_irc_channel(const Iid& iid, const std::string& username);
void send_channel_message(const Iid& iid, const std::string& body); void send_channel_message(const Iid& iid, const std::string& body);
void send_private_message(const Iid& iid, const std::string& body); void send_private_message(const Iid& iid, const std::string& body);
void leave_irc_channel(Iid&& iid, std::string&& status_message); void leave_irc_channel(Iid&& iid, std::string&& status_message);
void send_irc_nick_change(const Iid& iid, const std::string& new_nick);
/*** /***
** **
...@@ -65,7 +70,17 @@ public: ...@@ -65,7 +70,17 @@ public:
/** /**
* Send an unavailable presence from this participant * Send an unavailable presence from this participant
*/ */
void send_muc_leave(Iid&& iid, std::string&& nick, std::string&& message, const bool self); 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 ==
* true) changed his nick to new_nick
*/
void send_nick_change(Iid&& iid, const std::string& old_nick, const std::string& new_nick, const bool self);
/**
* Misc
*/
std::string get_own_nick(const Iid& iid);
private: private:
/** /**
......
...@@ -53,6 +53,12 @@ IrcChannel* IrcClient::get_channel(const std::string& name) ...@@ -53,6 +53,12 @@ IrcChannel* IrcClient::get_channel(const std::string& name)
} }
} }
bool IrcClient::is_channel_joined(const std::string& name)
{
IrcChannel* client = this->get_channel(name);
return client->joined;
}
std::string IrcClient::get_own_nick() const std::string IrcClient::get_own_nick() const
{ {
return this->current_nick; return this->current_nick;
...@@ -91,6 +97,8 @@ void IrcClient::parse_in_buffer() ...@@ -91,6 +97,8 @@ void IrcClient::parse_in_buffer()
this->on_part(message); this->on_part(message);
else if (message.command == "QUIT") else if (message.command == "QUIT")
this->on_quit(message); this->on_quit(message);
else if (message.command == "NICK")
this->on_nick(message);
} }
} }
...@@ -128,11 +136,9 @@ void IrcClient::send_nick_command(const std::string& nick) ...@@ -128,11 +136,9 @@ void IrcClient::send_nick_command(const std::string& nick)
void IrcClient::send_join_command(const std::string& chan_name) void IrcClient::send_join_command(const std::string& chan_name)
{ {
if (this->welcomed == false) if (this->welcomed == false)
{ this->channels_to_join.push_back(chan_name);
this->channels_to_join.push_back(chan_name); else
return ; this->send_message(IrcMessage("JOIN", {chan_name}));
}
this->send_message(IrcMessage("JOIN", {chan_name}));
} }
bool IrcClient::send_channel_message(const std::string& chan_name, const std::string& body) bool IrcClient::send_channel_message(const std::string& chan_name, const std::string& body)
...@@ -288,7 +294,34 @@ void IrcClient::on_quit(const IrcMessage& message) ...@@ -288,7 +294,34 @@ void IrcClient::on_quit(const IrcMessage& message)
Iid iid; Iid iid;
iid.chan = chan_name; iid.chan = chan_name;
iid.server = this->hostname; iid.server = this->hostname;
this->bridge->send_muc_leave(std::move(iid), std::move(nick), std::move(txt), false); this->bridge->send_muc_leave(std::move(iid), std::move(nick), txt, false);
} }
} }
} }
void IrcClient::on_nick(const IrcMessage& message)
{
const std::string new_nick = message.arguments[0];
for (auto it = this->channels.begin(); it != this->channels.end(); ++it)
{
const std::string chan_name = it->first;
IrcChannel* channel = it->second.get();
IrcUser* user = channel->find_user(message.prefix);
if (user)
{
std::string old_nick = user->nick;
Iid iid;
iid.chan = chan_name;
iid.server = this->hostname;
bool self = channel->get_self()->nick == old_nick;
this->bridge->send_nick_change(std::move(iid), old_nick, new_nick, self);
user->nick = new_nick;
if (self)
{
channel->get_self()->nick = new_nick;
this->current_nick = new_nick;
}
}
}
}
...@@ -44,6 +44,10 @@ public: ...@@ -44,6 +44,10 @@ public:
* Return the channel with this name, create it if it does not yet exist * Return the channel with this name, create it if it does not yet exist
*/ */
IrcChannel* get_channel(const std::string& name); IrcChannel* get_channel(const std::string& name);
/**
* Returns true if the channel is joined
*/
bool is_channel_joined(const std::string& name);
/** /**
* Return our own nick * Return our own nick
*/ */
...@@ -67,7 +71,7 @@ public: ...@@ -67,7 +71,7 @@ public:
*/ */
void send_nick_command(const std::string& username); void send_nick_command(const std::string& username);
/** /**
* Send the JOIN irc command * Send the JOIN irc command.
*/ */
void send_join_command(const std::string& chan_name); void send_join_command(const std::string& chan_name);
/** /**
...@@ -118,6 +122,10 @@ public: ...@@ -118,6 +122,10 @@ public:
* When a PART message is received * When a PART message is received
*/ */
void on_part(const IrcMessage& message); void on_part(const IrcMessage& message);
/**
* When a NICK message is received
*/
void on_nick(const IrcMessage& message);
/** /**
* When a QUIT message is received * When a QUIT message is received
*/ */
......
...@@ -167,7 +167,13 @@ void XmppComponent::handle_presence(const Stanza& stanza) ...@@ -167,7 +167,13 @@ void XmppComponent::handle_presence(const Stanza& stanza)
if (!iid.chan.empty() && !iid.chan.empty()) if (!iid.chan.empty() && !iid.chan.empty())
{ // presence toward a MUC that corresponds to an irc channel { // presence toward a MUC that corresponds to an irc channel
if (type.empty()) if (type.empty())
bridge->join_irc_channel(iid, to.resource); {
const std::string own_nick = bridge->get_own_nick(iid);
if (!own_nick.empty() && own_nick != to.resource)
bridge->send_irc_nick_change(iid, to.resource);
else
bridge->join_irc_channel(iid, to.resource);
}
else if (type == "unavailable") else if (type == "unavailable")
{ {
XmlNode* status = stanza.get_child(MUC_USER_NS":status"); XmlNode* status = stanza.get_child(MUC_USER_NS":status");
...@@ -317,3 +323,37 @@ void XmppComponent::send_muc_leave(std::string&& muc_name, std::string&& nick, s ...@@ -317,3 +323,37 @@ void XmppComponent::send_muc_leave(std::string&& muc_name, std::string&& nick, s
presence.close(); presence.close();
this->send_stanza(presence); this->send_stanza(presence);
} }
void XmppComponent::send_nick_change(const std::string& muc_name, const std::string& old_nick, const std::string& new_nick, const std::string& jid_to, const bool self)
{
Stanza presence("presence");
presence["to"] = jid_to;
presence["from"] = muc_name + "@" + this->served_hostname + "/" + old_nick;
presence["type"] = "unavailable";
XmlNode x("x");
x["xmlns"] = MUC_USER_NS;
XmlNode item("item");
item["nick"] = new_nick;
item.close();
x.add_child(std::move(item));
XmlNode status("status");
status["code"] = "303";
status.close();
x.add_child(std::move(status));
if (self)
{
XmlNode status2("status");
status2["code"] = "110";
status2.close();
x.add_child(std::move(status2));
}
x.close();
presence.add_child(std::move(x));
presence.close();
this->send_stanza(presence);
if (self)
this->send_self_join(muc_name, new_nick, jid_to);
else
this->send_user_join(muc_name, new_nick, jid_to);
}
...@@ -79,6 +79,10 @@ public: ...@@ -79,6 +79,10 @@ public:
* Send an unavailable presence for this nick * Send an unavailable presence for this nick
*/ */
void send_muc_leave(std::string&& muc_name, std::string&& nick, std::string&& message, const std::string& jid_to, const bool self); void send_muc_leave(std::string&& muc_name, std::string&& nick, std::string&& 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& jid_to, const bool self);
/** /**
* Handle the various stanza types * Handle the various stanza types
*/ */
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment