diff --git a/ext/commonmarker/autolink.c b/ext/commonmarker/autolink.c index 41564ee4..838374c2 100644 --- a/ext/commonmarker/autolink.c +++ b/ext/commonmarker/autolink.c @@ -269,6 +269,22 @@ static cmark_node *match(cmark_syntax_extension *ext, cmark_parser *parser, // inline was finished in inlines.c. } +static bool validate_protocol(char protocol[], uint8_t *data, int rewind) { + size_t len = strlen(protocol); + + // Check that the protocol matches + for (int i = 1; i <= len; i++) { + if (data[-rewind - i] != protocol[len - i]) { + return false; + } + } + + char prev_char = data[-rewind - len - 1]; + + // Make sure the character before the protocol is non-alphanumeric + return !cmark_isalnum(prev_char); +} + static void postprocess_text(cmark_parser *parser, cmark_node *text, int offset, int depth) { // postprocess_text can recurse very deeply if there is a very long line of // '@' only. Stop at a reasonable depth to ensure it cannot crash. @@ -278,6 +294,8 @@ static void postprocess_text(cmark_parser *parser, cmark_node *text, int offset, uint8_t *data = text->as.literal.data, *at; size_t size = text->as.literal.len; + bool auto_mailto = true; + bool is_xmpp = false; int rewind, max_rewind, nb = 0, np = 0, ns = 0; @@ -304,8 +322,18 @@ static void postprocess_text(cmark_parser *parser, cmark_node *text, int offset, if (strchr(".+-_", c) != NULL) continue; - if (c == '/') - ns++; + if (strchr(":", c) != NULL) { + if (validate_protocol("mailto:", data, rewind)) { + auto_mailto = false; + continue; + } + + if (validate_protocol("xmpp:", data, rewind)) { + auto_mailto = false; + is_xmpp = true; + continue; + } + } break; } @@ -325,6 +353,8 @@ static void postprocess_text(cmark_parser *parser, cmark_node *text, int offset, nb++; else if (c == '.' && link_end < size - 1 && cmark_isalnum(data[link_end + 1])) np++; + else if (c == '/' && is_xmpp) + continue; else if (c != '-' && c != '_') break; } @@ -347,7 +377,8 @@ static void postprocess_text(cmark_parser *parser, cmark_node *text, int offset, cmark_node *link_node = cmark_node_new_with_mem(CMARK_NODE_LINK, parser->mem); cmark_strbuf buf; cmark_strbuf_init(parser->mem, &buf, 10); - cmark_strbuf_puts(&buf, "mailto:"); + if (auto_mailto) + cmark_strbuf_puts(&buf, "mailto:"); cmark_strbuf_put(&buf, data - rewind, (bufsize_t)(link_end + rewind)); link_node->as.link.url = cmark_chunk_buf_detach(&buf); diff --git a/ext/commonmarker/cmark-gfm_version.h b/ext/commonmarker/cmark-gfm_version.h index ac403d4d..f487687d 100644 --- a/ext/commonmarker/cmark-gfm_version.h +++ b/ext/commonmarker/cmark-gfm_version.h @@ -1,7 +1,7 @@ #ifndef CMARK_GFM_VERSION_H #define CMARK_GFM_VERSION_H -#define CMARK_GFM_VERSION ((0 << 24) | (29 << 16) | (0 << 8) | 4) -#define CMARK_GFM_VERSION_STRING "0.29.0.gfm.4" +#define CMARK_GFM_VERSION ((0 << 24) | (29 << 16) | (0 << 8) | 5) +#define CMARK_GFM_VERSION_STRING "0.29.0.gfm.5" #endif diff --git a/ext/commonmarker/cmark-upstream b/ext/commonmarker/cmark-upstream index ef1cfcb8..0578e1e4 160000 --- a/ext/commonmarker/cmark-upstream +++ b/ext/commonmarker/cmark-upstream @@ -1 +1 @@ -Subproject commit ef1cfcb8a31de72bb951d9259bc4ac89e266975b +Subproject commit 0578e1e4fedde487a3c763139e80d445b40ebd6d