// Copyright 2014 The Closure Library Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS-IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /** * @fileoverview Provides functions to parse and manipulate internationalized * email addresses. This is useful in the context of Email Address * Internationalization (EAI) as defined by RFC6530. * */ goog.provide('goog.format.InternationalizedEmailAddress'); goog.require('goog.format.EmailAddress'); goog.require('goog.string'); /** * Formats an email address string for display, and allows for extraction of * the individual components of the address. * @param {string=} opt_address The email address. * @param {string=} opt_name The name associated with the email address. * @constructor * @extends {goog.format.EmailAddress} */ goog.format.InternationalizedEmailAddress = function(opt_address, opt_name) { goog.format.InternationalizedEmailAddress.base( this, 'constructor', opt_address, opt_name); }; goog.inherits( goog.format.InternationalizedEmailAddress, goog.format.EmailAddress); /** * A string representing the RegExp for the local part of an EAI email address. * @private */ goog.format.InternationalizedEmailAddress.EAI_LOCAL_PART_REGEXP_STR_ = '((?!\\s)[+a-zA-Z0-9_.!#$%&\'*\\/=?^`{|}~\u0080-\uFFFFFF-])+'; /** * A string representing the RegExp for a label in the domain part of an EAI * email address. * @private */ goog.format.InternationalizedEmailAddress.EAI_LABEL_CHAR_REGEXP_STR_ = '(?!\\s)[a-zA-Z0-9\u0080-\u3001\u3003-\uFF0D\uFF0F-\uFF60\uFF62-\uFFFFFF-]'; /** * A string representing the RegExp for the domain part of an EAI email address. * @private */ goog.format.InternationalizedEmailAddress.EAI_DOMAIN_PART_REGEXP_STR_ = // A unicode character (ASCII or Unicode excluding periods) '(' + goog.format.InternationalizedEmailAddress.EAI_LABEL_CHAR_REGEXP_STR_ + // Such character 1+ times, followed by a Unicode period. All 1+ times. '+[\\.\\uFF0E\\u3002\\uFF61])+' + // And same thing but without a period in the end goog.format.InternationalizedEmailAddress.EAI_LABEL_CHAR_REGEXP_STR_ + '{2,63}'; /** * Match string for address separators. This list is the result of the * discussion in b/16241003. * @type {string} * @private */ goog.format.InternationalizedEmailAddress.ADDRESS_SEPARATORS_ = ',' + // U+002C ( , ) COMMA ';' + // U+003B ( ; ) SEMICOLON '\u055D' + // ( ՝ ) ARMENIAN COMMA '\u060C' + // ( ، ) ARABIC COMMA '\u1363' + // ( ፣ ) ETHIOPIC COMMA '\u1802' + // ( ᠂ ) MONGOLIAN COMMA '\u1808' + // ( ᠈ ) MONGOLIAN MANCHU COMMA '\u2E41' + // ( ⹁ ) REVERSED COMMA '\u3001' + // ( 、 ) IDEOGRAPHIC COMMA '\uFF0C' + // ( , ) FULLWIDTH COMMA '\u061B' + // ( ‎؛‎ ) ARABIC SEMICOLON '\u1364' + // ( ፤ ) ETHIOPIC SEMICOLON '\uFF1B' + // ( ; ) FULLWIDTH SEMICOLON '\uFF64' + // ( 、 ) HALFWIDTH IDEOGRAPHIC COMMA '\u104A'; // ( ၊ ) MYANMAR SIGN LITTLE SECTION /** * Match string for characters that, when in a display name, require it to be * quoted. * @type {string} * @private */ goog.format.InternationalizedEmailAddress.CHARS_REQUIRE_QUOTES_ = goog.format.EmailAddress.SPECIAL_CHARS + goog.format.InternationalizedEmailAddress.ADDRESS_SEPARATORS_; /** * A RegExp to match the local part of an EAI email address. * @private {!RegExp} */ goog.format.InternationalizedEmailAddress.EAI_LOCAL_PART_ = new RegExp( '^' + goog.format.InternationalizedEmailAddress.EAI_LOCAL_PART_REGEXP_STR_ + '$'); /** * A RegExp to match the domain part of an EAI email address. * @private {!RegExp} */ goog.format.InternationalizedEmailAddress.EAI_DOMAIN_PART_ = new RegExp( '^' + goog.format.InternationalizedEmailAddress.EAI_DOMAIN_PART_REGEXP_STR_ + '$'); /** * A RegExp to match an EAI email address. * @private {!RegExp} */ goog.format.InternationalizedEmailAddress.EAI_EMAIL_ADDRESS_ = new RegExp( '^' + goog.format.InternationalizedEmailAddress.EAI_LOCAL_PART_REGEXP_STR_ + '@' + goog.format.InternationalizedEmailAddress.EAI_DOMAIN_PART_REGEXP_STR_ + '$'); /** * Checks if the provided string is a valid local part (part before the '@') of * an EAI email address. * @param {string} str The local part to check. * @return {boolean} Whether the provided string is a valid local part. */ goog.format.InternationalizedEmailAddress.isValidLocalPartSpec = function(str) { if (!goog.isDefAndNotNull(str)) { return false; } return goog.format.InternationalizedEmailAddress.EAI_LOCAL_PART_.test(str); }; /** * Checks if the provided string is a valid domain part (part after the '@') of * an EAI email address. * @param {string} str The domain part to check. * @return {boolean} Whether the provided string is a valid domain part. */ goog.format.InternationalizedEmailAddress.isValidDomainPartSpec = function( str) { if (!goog.isDefAndNotNull(str)) { return false; } return goog.format.InternationalizedEmailAddress.EAI_DOMAIN_PART_.test(str); }; /** @override */ goog.format.InternationalizedEmailAddress.prototype.isValid = function() { return goog.format.InternationalizedEmailAddress.isValidAddrSpec( this.address); }; /** * Checks if the provided string is a valid email address. Supports both * simple email addresses (address specs) and addresses that contain display * names. * @param {string} str The email address to check. * @return {boolean} Whether the provided string is a valid address. */ goog.format.InternationalizedEmailAddress.isValidAddress = function(str) { if (!goog.isDefAndNotNull(str)) { return false; } return goog.format.InternationalizedEmailAddress.parse(str).isValid(); }; /** * Checks if the provided string is a valid address spec (local@domain.com). * @param {string} str The email address to check. * @return {boolean} Whether the provided string is a valid address spec. */ goog.format.InternationalizedEmailAddress.isValidAddrSpec = function(str) { if (!goog.isDefAndNotNull(str)) { return false; } // This is a fairly naive implementation, but it covers 99% of use cases. // For more details, see http://en.wikipedia.org/wiki/Email_address#Syntax return goog.format.InternationalizedEmailAddress.EAI_EMAIL_ADDRESS_.test(str); }; /** * Parses a string containing email addresses of the form * "name" <address> into an array of email addresses. * @param {string} str The address list. * @return {!Array} The parsed emails. */ goog.format.InternationalizedEmailAddress.parseList = function(str) { return goog.format.EmailAddress.parseListInternal( str, goog.format.InternationalizedEmailAddress.parse, goog.format.InternationalizedEmailAddress.isAddressSeparator); }; /** * Parses an email address of the form "name" <address> into * an email address. * @param {string} addr The address string. * @return {!goog.format.EmailAddress} The parsed address. */ goog.format.InternationalizedEmailAddress.parse = function(addr) { return goog.format.EmailAddress.parseInternal( addr, goog.format.InternationalizedEmailAddress); }; /** * @param {string} ch The character to test. * @return {boolean} Whether the provided character is an address separator. */ goog.format.InternationalizedEmailAddress.isAddressSeparator = function(ch) { return goog.string.contains( goog.format.InternationalizedEmailAddress.ADDRESS_SEPARATORS_, ch); }; /** * Return the address in a standard format: * - remove extra spaces. * - Surround name with quotes if it contains special characters. * @return {string} The cleaned address. * @override */ goog.format.InternationalizedEmailAddress.prototype.toString = function() { return this.toStringInternal( goog.format.InternationalizedEmailAddress.CHARS_REQUIRE_QUOTES_); };