123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148 |
- import { pctEncChar, pctDecChars, unescapeComponent } from "../uri";
- import punycode from "punycode";
- import { merge, subexp, toUpperCase, toArray } from "../util";
- const O = {};
- const isIRI = true;
- const UNRESERVED$$ = "[A-Za-z0-9\\-\\.\\_\\~" + (isIRI ? "\\xA0-\\u200D\\u2010-\\u2029\\u202F-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFEF" : "") + "]";
- const HEXDIG$$ = "[0-9A-Fa-f]";
- const PCT_ENCODED$ = subexp(subexp("%[EFef]" + HEXDIG$$ + "%" + HEXDIG$$ + HEXDIG$$ + "%" + HEXDIG$$ + HEXDIG$$) + "|" + subexp("%[89A-Fa-f]" + HEXDIG$$ + "%" + HEXDIG$$ + HEXDIG$$) + "|" + subexp("%" + HEXDIG$$ + HEXDIG$$));
- const ATEXT$$ = "[A-Za-z0-9\\!\\$\\%\\'\\*\\+\\-\\^\\_\\`\\{\\|\\}\\~]";
- const QTEXT$$ = "[\\!\\$\\%\\'\\(\\)\\*\\+\\,\\-\\.0-9\\<\\>A-Z\\x5E-\\x7E]";
- const VCHAR$$ = merge(QTEXT$$, "[\\\"\\\\]");
- const DOT_ATOM_TEXT$ = subexp(ATEXT$$ + "+" + subexp("\\." + ATEXT$$ + "+") + "*");
- const QUOTED_PAIR$ = subexp("\\\\" + VCHAR$$);
- const QCONTENT$ = subexp(QTEXT$$ + "|" + QUOTED_PAIR$);
- const QUOTED_STRING$ = subexp('\\"' + QCONTENT$ + "*" + '\\"');
- const DTEXT_NO_OBS$$ = "[\\x21-\\x5A\\x5E-\\x7E]";
- const SOME_DELIMS$$ = "[\\!\\$\\'\\(\\)\\*\\+\\,\\;\\:\\@]";
- const QCHAR$ = subexp(UNRESERVED$$ + "|" + PCT_ENCODED$ + "|" + SOME_DELIMS$$);
- const DOMAIN$ = subexp(DOT_ATOM_TEXT$ + "|" + "\\[" + DTEXT_NO_OBS$$ + "*" + "\\]");
- const LOCAL_PART$ = subexp(DOT_ATOM_TEXT$ + "|" + QUOTED_STRING$);
- const ADDR_SPEC$ = subexp(LOCAL_PART$ + "\\@" + DOMAIN$);
- const TO$ = subexp(ADDR_SPEC$ + subexp("\\," + ADDR_SPEC$) + "*");
- const HFNAME$ = subexp(QCHAR$ + "*");
- const HFVALUE$ = HFNAME$;
- const HFIELD$ = subexp(HFNAME$ + "\\=" + HFVALUE$);
- const HFIELDS2$ = subexp(HFIELD$ + subexp("\\&" + HFIELD$) + "*");
- const HFIELDS$ = subexp("\\?" + HFIELDS2$);
- const MAILTO_URI = new RegExp("^mailto\\:" + TO$ + "?" + HFIELDS$ + "?$");
- const UNRESERVED = new RegExp(UNRESERVED$$, "g");
- const PCT_ENCODED = new RegExp(PCT_ENCODED$, "g");
- const NOT_LOCAL_PART = new RegExp(merge("[^]", ATEXT$$, "[\\.]", '[\\"]', VCHAR$$), "g");
- const NOT_DOMAIN = new RegExp(merge("[^]", ATEXT$$, "[\\.]", "[\\[]", DTEXT_NO_OBS$$, "[\\]]"), "g");
- const NOT_HFNAME = new RegExp(merge("[^]", UNRESERVED$$, SOME_DELIMS$$), "g");
- const NOT_HFVALUE = NOT_HFNAME;
- const TO = new RegExp("^" + TO$ + "$");
- const HFIELDS = new RegExp("^" + HFIELDS2$ + "$");
- function decodeUnreserved(str) {
- const decStr = pctDecChars(str);
- return (!decStr.match(UNRESERVED) ? str : decStr);
- }
- const handler = {
- scheme: "mailto",
- parse: function (components, options) {
- const mailtoComponents = components;
- const to = mailtoComponents.to = (mailtoComponents.path ? mailtoComponents.path.split(",") : []);
- mailtoComponents.path = undefined;
- if (mailtoComponents.query) {
- let unknownHeaders = false;
- const headers = {};
- const hfields = mailtoComponents.query.split("&");
- for (let x = 0, xl = hfields.length; x < xl; ++x) {
- const hfield = hfields[x].split("=");
- switch (hfield[0]) {
- case "to":
- const toAddrs = hfield[1].split(",");
- for (let x = 0, xl = toAddrs.length; x < xl; ++x) {
- to.push(toAddrs[x]);
- }
- break;
- case "subject":
- mailtoComponents.subject = unescapeComponent(hfield[1], options);
- break;
- case "body":
- mailtoComponents.body = unescapeComponent(hfield[1], options);
- break;
- default:
- unknownHeaders = true;
- headers[unescapeComponent(hfield[0], options)] = unescapeComponent(hfield[1], options);
- break;
- }
- }
- if (unknownHeaders)
- mailtoComponents.headers = headers;
- }
- mailtoComponents.query = undefined;
- for (let x = 0, xl = to.length; x < xl; ++x) {
- const addr = to[x].split("@");
- addr[0] = unescapeComponent(addr[0]);
- if (!options.unicodeSupport) {
-
- try {
- addr[1] = punycode.toASCII(unescapeComponent(addr[1], options).toLowerCase());
- }
- catch (e) {
- mailtoComponents.error = mailtoComponents.error || "Email address's domain name can not be converted to ASCII via punycode: " + e;
- }
- }
- else {
- addr[1] = unescapeComponent(addr[1], options).toLowerCase();
- }
- to[x] = addr.join("@");
- }
- return mailtoComponents;
- },
- serialize: function (mailtoComponents, options) {
- const components = mailtoComponents;
- const to = toArray(mailtoComponents.to);
- if (to) {
- for (let x = 0, xl = to.length; x < xl; ++x) {
- const toAddr = String(to[x]);
- const atIdx = toAddr.lastIndexOf("@");
- const localPart = (toAddr.slice(0, atIdx)).replace(PCT_ENCODED, decodeUnreserved).replace(PCT_ENCODED, toUpperCase).replace(NOT_LOCAL_PART, pctEncChar);
- let domain = toAddr.slice(atIdx + 1);
-
- try {
- domain = (!options.iri ? punycode.toASCII(unescapeComponent(domain, options).toLowerCase()) : punycode.toUnicode(domain));
- }
- catch (e) {
- components.error = components.error || "Email address's domain name can not be converted to " + (!options.iri ? "ASCII" : "Unicode") + " via punycode: " + e;
- }
- to[x] = localPart + "@" + domain;
- }
- components.path = to.join(",");
- }
- const headers = mailtoComponents.headers = mailtoComponents.headers || {};
- if (mailtoComponents.subject)
- headers["subject"] = mailtoComponents.subject;
- if (mailtoComponents.body)
- headers["body"] = mailtoComponents.body;
- const fields = [];
- for (const name in headers) {
- if (headers[name] !== O[name]) {
- fields.push(name.replace(PCT_ENCODED, decodeUnreserved).replace(PCT_ENCODED, toUpperCase).replace(NOT_HFNAME, pctEncChar) +
- "=" +
- headers[name].replace(PCT_ENCODED, decodeUnreserved).replace(PCT_ENCODED, toUpperCase).replace(NOT_HFVALUE, pctEncChar));
- }
- }
- if (fields.length) {
- components.query = fields.join("&");
- }
- return components;
- }
- };
- export default handler;
|