diff --git a/textfilter/vibe/textfilter/markdown.d b/textfilter/vibe/textfilter/markdown.d
index 697b07e98a..fab1929b29 100644
--- a/textfilter/vibe/textfilter/markdown.d
+++ b/textfilter/vibe/textfilter/markdown.d
@@ -1090,20 +1090,56 @@ pure @safe {
private bool parseAutoLink(ref string str, ref string url)
pure @safe {
+ import std.algorithm.searching : all;
+ import std.ascii : isAlphaNum;
+
string pstr = str;
- if( pstr.length < 3 ) return false;
- if( pstr[0] != '<' ) return false;
+ if (pstr.length < 3) return false;
+ if (pstr[0] != '<') return false;
pstr = pstr[1 .. $];
auto cidx = pstr.indexOf('>');
- if( cidx < 0 ) return false;
+ if (cidx < 0) return false;
+
url = pstr[0 .. cidx];
- if( anyOf(url, " \t") ) return false;
- if( !anyOf(url, ":@") ) return false;
+ if (url.anyOf(" \t")) return false;
+ auto atidx = url.indexOf('@');
+ auto colonidx = url.indexOf(':');
+ if (atidx < 0 && colonidx < 0) return false;
+
str = pstr[cidx+1 .. $];
- if( url.indexOf('@') > 0 ) url = "mailto:"~url;
+ if (atidx < 0) return true;
+ if (colonidx < 0 || colonidx > atidx ||
+ !url[0 .. colonidx].all!(ch => ch.isAlphaNum))
+ url = "mailto:" ~ url;
return true;
}
+unittest {
+ void test(bool expected, string str, string url)
+ {
+ string strcpy = str;
+ string outurl;
+ if (!expected) {
+ assert(!parseAutoLink(strcpy, outurl));
+ assert(outurl.length == 0);
+ assert(strcpy == str);
+ } else {
+ assert(parseAutoLink(strcpy, outurl));
+ assert(outurl == url);
+ assert(strcpy.length == 0);
+ }
+ }
+
+ test(true, "", "http://foo/");
+ test(false, "", "mailto:foo@bar");
+ test(true, "", "mailto:foo@bar");
+ test(true, "", "proto:foo@bar");
+ test(true, "", "proto:foo@bar:123");
+ test(true, "<\"foo:bar\"@baz>", "mailto:\"foo:bar\"@baz");
+}
+
+
private LinkRef[string] scanForReferences(ref string[] lines)
pure @safe {
LinkRef[string] ret;