From 49a59077b7458994e5a9c0d36299b36fa9846f06 Mon Sep 17 00:00:00 2001
From: Simon Ser <contact@emersion.fr>
Date: Wed, 20 Oct 2021 14:33:16 +0200
Subject: [PATCH] lib/irc: extend parseURL to support flags and skip auth +
 options

---
 components/app.js |  4 ++--
 lib/irc.js        | 56 ++++++++++++++++++++++++++++++++++++++---------
 2 files changed, 48 insertions(+), 12 deletions(-)

diff --git a/components/app.js b/components/app.js
index 468157c..a85aa5e 100644
--- a/components/app.js
+++ b/components/app.js
@@ -909,11 +909,11 @@ export default class App extends Component {
 
 		event.preventDefault();
 
-		let buf = State.getBuffer(this.state, { server: serverID, name: url.channel || SERVER_BUFFER });
+		let buf = State.getBuffer(this.state, { server: serverID, name: url.entity || SERVER_BUFFER });
 		if (buf) {
 			this.switchBuffer(buf.id);
 		} else {
-			this.open(url.channel, serverID);
+			this.open(url.entity, serverID);
 		}
 	}
 
diff --git a/lib/irc.js b/lib/irc.js
index 2286fcb..601e67e 100644
--- a/lib/irc.js
+++ b/lib/irc.js
@@ -648,6 +648,8 @@ export function forEachChannelModeUpdate(msg, isupport, callback) {
 }
 
 /**
+ * Check if a realname is worth displaying.
+ *
  * Since the realname is mandatory, many clients set a meaningless realname.
  */
 export function isMeaningfulRealname(realname, nick) {
@@ -664,26 +666,60 @@ export function isMeaningfulRealname(realname, nick) {
 	return true;
 }
 
+/* Parse an irc:// URL.
+ *
+ * See: https://datatracker.ietf.org/doc/html/draft-butcher-irc-url-04
+ */
 export function parseURL(str) {
 	if (!str.startsWith("irc://") && !str.startsWith("ircs://")) {
 		return null;
 	}
 
-	str = str.slice(str.indexOf(":") + 3);
+	str = str.slice(str.indexOf(":") + "://".length);
 
+	let loc;
 	let i = str.indexOf("/");
 	if (i < 0) {
-		return { host: str };
+		loc = str;
+		str = "";
+	} else {
+		loc = str.slice(0, i);
+		str = str.slice(i + 1);
 	}
 
-	let host = str.slice(0, i);
-	str = str.slice(i + 1);
-
-	// TODO: handle URLs with query params
-	let channel = null;
-	if (str.startsWith("#")) {
-		channel = str;
+	let host = loc;
+	i = loc.indexOf("@");
+	if (i >= 0) {
+		host = loc.slice(i + 1);
+		// TODO: parse authinfo
 	}
 
-	return { host, channel };
+	i = str.indexOf("?");
+	if (i >= 0) {
+		str = str.slice(0, i);
+		// TODO: parse options
+	}
+
+	let enttype;
+	i = str.indexOf(",");
+	if (i >= 0) {
+		let flags = str.slice(i + 1).split(",");
+		str = str.slice(0, i);
+
+		if (flags.indexOf("isuser") >= 0) {
+			enttype = "user";
+		} else if (flags.indexOf("ischannel") >= 0) {
+			enttype = "channel";
+		}
+
+		// TODO: parse hosttype
+	}
+
+	let entity = decodeURIComponent(str);
+	if (!enttype) {
+		// TODO: technically we should use the PREFIX ISUPPORT here
+		enttype = entity.startsWith("#") ? "channel" : "user";
+	}
+
+	return { host, enttype, entity };
 }