summaryrefslogtreecommitdiff
path: root/src/xmpp/biboumi_component.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/xmpp/biboumi_component.cpp')
-rw-r--r--src/xmpp/biboumi_component.cpp141
1 files changed, 123 insertions, 18 deletions
diff --git a/src/xmpp/biboumi_component.cpp b/src/xmpp/biboumi_component.cpp
index 32f3968..0e1d270 100644
--- a/src/xmpp/biboumi_component.cpp
+++ b/src/xmpp/biboumi_component.cpp
@@ -83,6 +83,14 @@ void BiboumiComponent::shutdown()
{
for (auto& pair: this->bridges)
pair.second->shutdown("Gateway shutdown");
+#ifdef USE_DATABASE
+ for (const Database::RosterItem& roster_item: Database::get_full_roster())
+ {
+ this->send_presence_to_contact(roster_item.col<Database::LocalJid>(),
+ roster_item.col<Database::RemoteJid>(),
+ "unavailable");
+ }
+#endif
}
void BiboumiComponent::clean()
@@ -160,16 +168,50 @@ void BiboumiComponent::handle_presence(const Stanza& stanza)
{
if (type == "subscribe")
{ // Auto-accept any subscription request for an IRC server
- this->accept_subscription(to_str, from.bare());
- this->ask_subscription(to_str, from.bare());
+ this->send_presence_to_contact(to_str, from.bare(), "subscribed", id);
+ if (iid.type == Iid::Type::None || bridge->find_irc_client(iid.get_server()))
+ this->send_presence_to_contact(to_str, from.bare(), "");
+ this->send_presence_to_contact(to_str, from.bare(), "subscribe");
+#ifdef USE_DATABASE
+ if (!Database::has_roster_item(to_str, from.bare()))
+ Database::add_roster_item(to_str, from.bare());
+#endif
+ }
+ else if (type == "unsubscribe")
+ {
+ this->send_presence_to_contact(to_str, from.bare(), "unavailable", id);
+ this->send_presence_to_contact(to_str, from.bare(), "unsubscribed");
+ this->send_presence_to_contact(to_str, from.bare(), "unsubscribe");
+#ifdef USE_DATABASE
+ const bool res = Database::has_roster_item(to_str, from.bare());
+ if (res)
+ Database::delete_roster_item(to_str, from.bare());
+#endif
+ }
+ else if (type == "probe")
+ {
+ if ((iid.type == Iid::Type::Server && bridge->find_irc_client(iid.get_server()))
+ || iid.type == Iid::Type::None)
+ {
+#ifdef USE_DATABASE
+ if (Database::has_roster_item(to_str, from.bare()))
+#endif
+ this->send_presence_to_contact(to_str, from.bare(), "");
+#ifdef USE_DATABASE
+ else // rfc 6121 4.3.2.1
+ this->send_presence_to_contact(to_str, from.bare(), "unsubscribed");
+#endif
+ }
+ }
+ else if (type.empty())
+ { // We just receive a presence from someone (as the result of a probe,
+ // or a directed presence, or a normal presence change)
+ if (iid.type == Iid::Type::None)
+ this->send_presence_to_contact(to_str, from.bare(), "");
}
-
}
- else
- {
- // A user wants to join an invalid IRC channel, return a presence error to him/her
- if (type.empty())
- this->send_invalid_room_error(to.local, to.resource, from_str);
+ else if (iid.type == Iid::Type::User)
+ { // Do nothing yet
}
}
catch (const IRCNotConnected& ex)
@@ -177,7 +219,7 @@ void BiboumiComponent::handle_presence(const Stanza& stanza)
if (type != "unavailable")
this->send_stanza_error("presence", from_str, to_str, id,
"cancel", "remote-server-not-found",
- "Not connected to IRC server "s + ex.hostname,
+ "Not connected to IRC server " + ex.hostname,
true);
}
stanza_error.disable();
@@ -268,7 +310,11 @@ void BiboumiComponent::handle_message(const Stanza& stanza)
const auto invite_to = invite->get_tag("to");
if (!invite_to.empty())
{
- bridge->send_irc_invitation(iid, invite_to);
+ Jid invited_jid{invite_to};
+ if (invited_jid.domain == this->get_served_hostname() || invited_jid.local.empty())
+ bridge->send_irc_invitation(iid, invite_to);
+ else
+ this->send_invitation_from_fulljid(std::to_string(iid), invite_to, from_str);
}
}
@@ -277,7 +323,7 @@ void BiboumiComponent::handle_message(const Stanza& stanza)
{
this->send_stanza_error("message", from_str, to_str, id,
"cancel", "remote-server-not-found",
- "Not connected to IRC server "s + ex.hostname,
+ "Not connected to IRC server " + ex.hostname,
true);
}
stanza_error.disable();
@@ -586,7 +632,7 @@ void BiboumiComponent::handle_iq(const Stanza& stanza)
{
this->send_stanza_error("iq", from, to_str, id,
"cancel", "remote-server-not-found",
- "Not connected to IRC server "s + ex.hostname,
+ "Not connected to IRC server " + ex.hostname,
true);
stanza_error.disable();
return;
@@ -806,7 +852,7 @@ void BiboumiComponent::send_irc_server_disco_info(const std::string& id, const s
XmlSubNode identity(query, "identity");
identity["category"] = "conference";
identity["type"] = "irc";
- identity["name"] = "IRC server "s + from.local + " over Biboumi";
+ identity["name"] = "IRC server " + from.local + " over Biboumi";
for (const char *ns: {DISCO_INFO_NS, MUC_NS, ADHOC_NS, PING_NS, MAM_NS, VERSION_NS})
{
XmlSubNode feature(query, "feature");
@@ -849,7 +895,7 @@ void BiboumiComponent::send_irc_channel_disco_info(const std::string& id, const
XmlSubNode identity(query, "identity");
identity["category"] = "conference";
identity["type"] = "irc";
- identity["name"] = "IRC channel "s + iid.get_local() + " from server " + iid.get_server() + " over biboumi";
+ identity["name"] = "IRC channel " + iid.get_local() + " from server " + iid.get_server() + " over biboumi";
for (const char *ns: {DISCO_INFO_NS, MUC_NS, ADHOC_NS, PING_NS, MAM_NS, VERSION_NS})
{
XmlSubNode feature(query, "feature");
@@ -945,6 +991,16 @@ void BiboumiComponent::send_invitation(const std::string& room_target,
const std::string& jid_to,
const std::string& author_nick)
{
+ if (author_nick.empty())
+ this->send_invitation_from_fulljid(room_target, jid_to, room_target + "@" + this->served_hostname);
+ else
+ this->send_invitation_from_fulljid(room_target, jid_to, room_target + "@" + this->served_hostname + "/" + author_nick);
+}
+
+void BiboumiComponent::send_invitation_from_fulljid(const std::string& room_target,
+ const std::string& jid_to,
+ const std::string& from)
+{
Stanza message("message");
{
message["from"] = room_target + "@" + this->served_hostname;
@@ -952,10 +1008,7 @@ void BiboumiComponent::send_invitation(const std::string& room_target,
XmlSubNode x(message, "x");
x["xmlns"] = MUC_USER_NS;
XmlSubNode invite(x, "invite");
- if (author_nick.empty())
- invite["from"] = room_target + "@" + this->served_hostname;
- else
- invite["from"] = room_target + "@" + this->served_hostname + "/" + author_nick;
+ invite["from"] = from;
}
this->send_stanza(message);
}
@@ -979,3 +1032,55 @@ void BiboumiComponent::ask_subscription(const std::string& from, const std::stri
presence["type"] = "subscribe";
this->send_stanza(presence);
}
+
+void BiboumiComponent::send_presence_to_contact(const std::string& from, const std::string& to,
+ const std::string& type, const std::string& id)
+{
+ Stanza presence("presence");
+ presence["from"] = from;
+ presence["to"] = to;
+ if (!type.empty())
+ presence["type"] = type;
+ if (!id.empty())
+ presence["id"] = id;
+ this->send_stanza(presence);
+}
+
+void BiboumiComponent::on_irc_client_connected(const std::string& irc_hostname, const std::string& jid)
+{
+#ifdef USE_DATABASE
+ const auto local_jid = irc_hostname + "@" + this->served_hostname;
+ if (Database::has_roster_item(local_jid, jid))
+ this->send_presence_to_contact(local_jid, jid, "");
+#endif
+}
+
+void BiboumiComponent::on_irc_client_disconnected(const std::string& irc_hostname, const std::string& jid)
+{
+#ifdef USE_DATABASE
+ const auto local_jid = irc_hostname + "@" + this->served_hostname;
+ if (Database::has_roster_item(local_jid, jid))
+ this->send_presence_to_contact(irc_hostname + "@" + this->served_hostname, jid, "unavailable");
+#endif
+}
+
+void BiboumiComponent::after_handshake()
+{
+ XmppComponent::after_handshake();
+
+#ifdef USE_DATABASE
+ const auto contacts = Database::get_contact_list(this->get_served_hostname());
+
+ for (const Database::RosterItem& roster_item: contacts)
+ {
+ const auto remote_jid = roster_item.col<Database::RemoteJid>();
+ // In response, we will receive a presence indicating the
+ // contact is online, to which we will respond with our own
+ // presence.
+ // If the contact removed us from their roster while we were
+ // offline, we will receive an unsubscribed presence, letting us
+ // stay in sync.
+ this->send_presence_to_contact(this->get_served_hostname(), remote_jid, "probe");
+ }
+#endif
+}