From 19ac4f72aa375e9c189b48e899cdbe20b0760b4c Mon Sep 17 00:00:00 2001 From: Pavel Djundik Date: Tue, 19 Jun 2018 18:00:07 +0300 Subject: [PATCH] Implement irc:// protocol handler --- client/js/options.js | 16 ++++ client/js/socket-events/configuration.js | 114 +++++++++++++++++------ client/views/windows/settings.tpl | 4 + 3 files changed, 107 insertions(+), 27 deletions(-) diff --git a/client/js/options.js b/client/js/options.js index ad37bdbb..2f1b0d5b 100644 --- a/client/js/options.js +++ b/client/js/options.js @@ -320,4 +320,20 @@ function initialize() { // We always ask for synced settings even if it is disabled. // Settings can be mandatory to sync and it is used to determine sync base state. socket.emit("setting:get"); + + // Protocol handler + const defaultClientButton = $("#make-default-client"); + + if (window.navigator.registerProtocolHandler) { + defaultClientButton.on("click", function() { + const uri = document.location.origin + document.location.pathname + "?uri=%s"; + + window.navigator.registerProtocolHandler("irc", uri, "The Lounge"); + window.navigator.registerProtocolHandler("ircs", uri, "The Lounge"); + + return false; + }); + } else { + defaultClientButton.hide(); + } } diff --git a/client/js/socket-events/configuration.js b/client/js/socket-events/configuration.js index a83c0284..f354d789 100644 --- a/client/js/socket-events/configuration.js +++ b/client/js/socket-events/configuration.js @@ -90,35 +90,95 @@ socket.on("configuration", function(data) { utils.togglePasswordField("#connect .reveal-password"); }); - if ($(document.body).hasClass("public") && "URLSearchParams" in window) { + if ("URLSearchParams" in window) { const params = new URLSearchParams(document.location.search); - for (let [key, value] of params) { - // Support `channels` as a compatibility alias with other clients - if (key === "channels") { - key = "join"; - } - - if (!data.defaults.hasOwnProperty(key)) { - continue; - } - - if (key === "join") { - value = value.split(",").map((chan) => { - if (!chan.match(/^[#&!+]/)) { - return `#${chan}`; - } - - return chan; - }).join(", "); - } - - // Override server provided defaults with parameters passed in the URL if they match the data type - switch (typeof data.defaults[key]) { - case "boolean": data.defaults[key] = value === "1" || value === "true"; break; - case "number": data.defaults[key] = Number(value); break; - case "string": data.defaults[key] = String(value); break; - } + if (params.has("uri")) { + parseIrcUri(params.get("uri") + location.hash, data); + } else if ($(document.body).hasClass("public")) { + parseOverrideParams(params, data); } } }); + +function parseIrcUri(stringUri, defaults) { + const data = Object.assign({}, defaults.defaults); + + try { + // https://tools.ietf.org/html/draft-butcher-irc-url-04 + const uri = new URL(stringUri); + + // Replace protocol with a "special protocol" (that's what it's called in WHATWG spec) + // So that the uri can be properly parsed + if (uri.protocol === "irc:") { + uri.protocol = "http:"; + + if (!uri.port) { + uri.port = 6667; + } + + data.tls = false; + } else if (uri.protocol === "ircs:") { + uri.protocol = "https:"; + + if (!uri.port) { + uri.port = 6697; + } + + data.tls = true; + } else { + return; + } + + data.host = data.name = uri.hostname; + data.port = uri.port; + data.username = window.decodeURIComponent(uri.username) || data.username; + data.password = window.decodeURIComponent(uri.password) || data.password; + + let channel = (uri.pathname + uri.hash).substr(1); + const index = channel.indexOf(","); + + if (index > -1) { + channel = channel.substring(0, index); + } + + data.join = channel; + + // TODO: Need to show connect window with uri params without overriding defaults + defaults.defaults = data; + + $('button[data-target="#connect"]').trigger("click"); + } catch (e) { + // do nothing on invalid uri + } +} + +function parseOverrideParams(params, data) { + for (let [key, value] of params) { + // Support `channels` as a compatibility alias with other clients + if (key === "channels") { + key = "join"; + } + + if (!data.defaults.hasOwnProperty(key)) { + continue; + } + + if (key === "join") { + value = value.split(",").map((chan) => { + if (!chan.match(/^[#&!+]/)) { + return `#${chan}`; + } + + return chan; + }).join(", "); + } + + // Override server provided defaults with parameters passed in the URL if they match the data type + switch (typeof data.defaults[key]) { + case "boolean": data.defaults[key] = value === "1" || value === "true"; break; + case "number": data.defaults[key] = Number(value); break; + case "string": data.defaults[key] = String(value); break; + } + } +} diff --git a/client/views/windows/settings.tpl b/client/views/windows/settings.tpl index 04d71bb3..0443d1cf 100644 --- a/client/views/windows/settings.tpl +++ b/client/views/windows/settings.tpl @@ -14,6 +14,10 @@
+
+ +
+ {{#unless public}}