blob: 9776db360c7be68ca46ecb8fda89fe89a052a437 [file] [log] [blame]
////////////////////////////////////////////////////////////////////////////////
//
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You 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.
//
////////////////////////////////////////////////////////////////////////////////
package mx.validators
{
[ResourceBundle("validators")]
/**
* The EmailValidator class validates that a String has a single @ sign,
* a period in the domain name and that the top-level domain suffix has
* two, three, four, or six characters.
* IP domain names are valid if they are enclosed in square brackets.
* The validator does not check whether the domain and user name
* actually exist.
*
* <p>You can use IP domain names if they are enclosed in square brackets;
* for example, myname&#64;[206.132.22.1].
* You can use individual IP numbers from 0 to 255.</p>
*
* @mxml
*
* <p>The <code>&lt;mx:EmailValidator&gt;</code> tag
* inherits all of the tag attributes of its superclass,
* and adds the following tag attributes:</p>
*
* <pre>
* &lt;mx:EmailValidator
* invalidCharError="Your e-mail address contains invalid characters."
* invalidDomainError= "The domain in your e-mail address is incorrectly formatted."
* invalidIPDomainError="The IP domain in your e-mail address is incorrectly formatted."
* invalidPeriodsInDomainError="The domain in your e-mail address has consecutive periods."
* missingAtSignError="An at sign (&64;) is missing in your e-mail address."
* missingPeriodInDomainError="The domain in your e-mail address is missing a period."
* missingUsernameError="The username in your e-mail address is missing."
* tooManyAtSignsError="Your e-mail address contains too many &64; characters."
* /&gt;
* </pre>
*
* @includeExample examples/EmailValidatorExample.mxml
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public class EmailValidator extends Validator
{
include "../core/Version.as";
//--------------------------------------------------------------------------
//
// Class constants
//
//--------------------------------------------------------------------------
/**
* @private
*/
private static const DISALLOWED_LOCALNAME_CHARS:String =
"()<>,;:\\\"[] `~!#$%^&*={}|/?'\t\n\r";
/**
* @private
*/
private static const DISALLOWED_DOMAIN_CHARS:String =
"()<>,;:\\\"[] `~!#$%^&*+={}|/?'\t\n\r";
//--------------------------------------------------------------------------
//
// Class methods
//
//--------------------------------------------------------------------------
/**
* Convenience method for calling a validator
* from within a custom validation function.
* Each of the standard Flex validators has a similar convenience method.
*
* @param validator The EmailValidator instance.
*
* @param value A field to validate.
*
* @param baseField Text representation of the subfield
* specified in the value parameter.
* For example, if the <code>value</code> parameter specifies value.email,
* the <code>baseField</code> value is "email".
*
* @return An Array of ValidationResult objects, with one
* ValidationResult object for each field examined by the validator.
*
* @see mx.validators.ValidationResult
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public static function validateEmail(validator:EmailValidator,
value:Object,
baseField:String):Array
{
var results:Array = [];
// Validate the domain name
// If IP domain, then must follow [x.x.x.x] format
// Can not have continous periods.
// Must have at least one period.
// Must end in a top level domain name that has 2, 3, 4, or 6 characters.
var emailStr:String = String(value);
var username:String = "";
var domain:String = "";
var n:int;
var i:int;
// Find the @
var ampPos:int = emailStr.indexOf("@");
if (ampPos == -1)
{
results.push(new ValidationResult(
true, baseField, "missingAtSign",
validator.missingAtSignError));
return results;
}
// Make sure there are no extra @s.
else if (emailStr.indexOf("@", ampPos + 1) != -1)
{
results.push(new ValidationResult(
true, baseField, "tooManyAtSigns",
validator.tooManyAtSignsError));
return results;
}
// Separate the address into username and domain.
username = emailStr.substring(0, ampPos);
domain = emailStr.substring(ampPos + 1);
// Validate username has no illegal characters
// and has at least one character.
var usernameLen:int = username.length;
if (usernameLen == 0)
{
results.push(new ValidationResult(
true, baseField, "missingUsername",
validator.missingUsernameError));
return results;
}
for (i = 0; i < usernameLen; i++)
{
if (DISALLOWED_LOCALNAME_CHARS.indexOf(username.charAt(i)) != -1)
{
results.push(new ValidationResult(
true, baseField, "invalidChar",
validator.invalidCharError));
return results;
}
}
// name can't start with a dot
if (username.charAt(0) == '.')
{
results.push(new ValidationResult(
true, baseField, "invalidChar",
validator.invalidCharError));
return results;
}
var domainLen:int = domain.length;
// check for IP address
if ((domain.charAt(0) == "[") && (domain.charAt(domainLen - 1) == "]"))
{
// Validate IP address
if (!isValidIPAddress(domain.substring(1, domainLen - 1)))
{
results.push(new ValidationResult(
true, baseField, "invalidIPDomain",
validator.invalidIPDomainError));
return results;
}
}
else
{
// Must have at least one period
var periodPos:int = domain.indexOf(".");
var nextPeriodPos:int = 0;
var lastDomain:String = "";
if (periodPos == -1)
{
results.push(new ValidationResult(
true, baseField, "missingPeriodInDomain",
validator.missingPeriodInDomainError));
return results;
}
while (true)
{
nextPeriodPos = domain.indexOf(".", periodPos + 1);
if (nextPeriodPos == -1)
{
lastDomain = domain.substring(periodPos + 1);
break;
}
else if (nextPeriodPos == periodPos + 1)
{
results.push(new ValidationResult(
true, baseField, "invalidPeriodsInDomain",
validator.invalidPeriodsInDomainError));
return results;
}
periodPos = nextPeriodPos;
}
// Check that there are no illegal characters in the domain.
for (i = 0; i < domainLen; i++)
{
if (DISALLOWED_DOMAIN_CHARS.indexOf(domain.charAt(i)) != -1)
{
results.push(new ValidationResult(
true, baseField, "invalidChar",
validator.invalidCharError));
return results;
}
}
// Check that the character immediately after the @ is not a period or an hyphen.
// And check that the character before the period is not an hyphen.
if (domain.charAt(0) == "." || domain.charAt(0) == "-" || domain.charAt(periodPos - 1) == "-")
{
results.push(new ValidationResult(
true, baseField, "invalidDomain",
validator.invalidDomainError));
return results;
}
}
return results;
}
/**
* Validate a given IP address
*
* If IP domain, then must follow [x.x.x.x] format
* or for IPv6, then follow [x:x:x:x:x:x:x:x] or [x::x:x:x] or some
* IPv4 hybrid, like [::x.x.x.x] or [0:00::192.168.0.1]
*
* @private
*/
private static function isValidIPAddress(ipAddr:String):Boolean
{
var ipArray:Array = [];
var pos:int = 0;
var newpos:int = 0;
var item:Number;
var n:int;
var i:int;
// if you have :, you're in IPv6 mode
// if you have ., you're in IPv4 mode
if (ipAddr.indexOf(":") != -1)
{
// IPv6
// validate by splitting on the colons
// to make it easier, since :: means zeros,
// lets rid ourselves of these wildcards in the beginning
// and then validate normally
// get rid of unlimited zeros notation so we can parse better
var hasUnlimitedZeros:Boolean = ipAddr.indexOf("::") != -1;
if (hasUnlimitedZeros)
{
ipAddr = ipAddr.replace(/^::/, "");
ipAddr = ipAddr.replace(/::/g, ":");
}
while (true)
{
newpos = ipAddr.indexOf(":", pos);
if (newpos != -1)
{
ipArray.push(ipAddr.substring(pos,newpos));
}
else
{
ipArray.push(ipAddr.substring(pos));
break;
}
pos = newpos + 1;
}
n = ipArray.length;
const lastIsV4:Boolean = ipArray[n-1].indexOf(".") != -1;
if (lastIsV4)
{
// if no wildcards, length must be 7
// always, never more than 7
if ((ipArray.length != 7 && !hasUnlimitedZeros) || (ipArray.length > 7))
return false;
for (i = 0; i < n; i++)
{
if (i == n-1)
{
// IPv4 part...
return isValidIPAddress(ipArray[i]);
}
item = parseInt(ipArray[i], 16);
if (item != 0)
return false;
}
}
else
{
// if no wildcards, length must be 8
// always, never more than 8
if ((ipArray.length != 8 && !hasUnlimitedZeros) || (ipArray.length > 8))
return false;
for (i = 0; i < n; i++)
{
item = parseInt(ipArray[i], 16);
if (isNaN(item) || item < 0 || item > 0xFFFF || ipArray[i] == "")
return false;
}
}
return true;
}
if (ipAddr.indexOf(".") != -1)
{
// IPv4
// validate by splling on the periods
while (true)
{
newpos = ipAddr.indexOf(".", pos);
if (newpos != -1)
{
ipArray.push(ipAddr.substring(pos,newpos));
}
else
{
ipArray.push(ipAddr.substring(pos));
break;
}
pos = newpos + 1;
}
if (ipArray.length != 4)
return false;
n = ipArray.length;
for (i = 0; i < n; i++)
{
item = Number(ipArray[i]);
if (isNaN(item) || item < 0 || item > 255 || ipArray[i] == "")
return false;
}
return true;
}
return false;
}
//--------------------------------------------------------------------------
//
// Constructor
//
//--------------------------------------------------------------------------
/**
* Constructor.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function EmailValidator()
{
super();
}
//--------------------------------------------------------------------------
//
// Properties: Errors
//
//--------------------------------------------------------------------------
//----------------------------------
// invalidCharError
//----------------------------------
/**
* @private
* Storage for the invalidCharError property.
*/
private var _invalidCharError:String;
/**
* @private
*/
private var invalidCharErrorOverride:String;
[Inspectable(category="Errors", defaultValue="null")]
/**
* Error message when there are invalid characters in the e-mail address.
*
* @default "Your e-mail address contains invalid characters."
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get invalidCharError():String
{
return _invalidCharError;
}
/**
* @private
*/
public function set invalidCharError(value:String):void
{
invalidCharErrorOverride = value;
_invalidCharError = value != null ?
value :
resourceManager.getString(
"validators", "invalidCharErrorEV");
}
//----------------------------------
// invalidDomainError
//----------------------------------
/**
* @private
* Storage for the invalidDomainError property.
*/
private var _invalidDomainError:String;
/**
* @private
*/
private var invalidDomainErrorOverride:String;
[Inspectable(category="Errors", defaultValue="null")]
/**
* Error message when the suffix (the top level domain)
* is not 2, 3, 4 or 6 characters long.
*
* @default "The domain in your e-mail address is incorrectly formatted."
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get invalidDomainError():String
{
return _invalidDomainError;
}
/**
* @private
*/
public function set invalidDomainError(value:String):void
{
invalidDomainErrorOverride = value;
_invalidDomainError = value != null ?
value :
resourceManager.getString(
"validators", "invalidDomainErrorEV");
}
//----------------------------------
// invalidIPDomainError
//----------------------------------
/**
* @private
* Storage for the invalidIPDomainError property.
*/
private var _invalidIPDomainError:String;
/**
* @private
*/
private var invalidIPDomainErrorOverride:String;
[Inspectable(category="Errors", defaultValue="null")]
/**
* Error message when the IP domain is invalid. The IP domain must be enclosed by square brackets.
*
* @default "The IP domain in your e-mail address is incorrectly formatted."
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get invalidIPDomainError():String
{
return _invalidIPDomainError;
}
/**
* @private
*/
public function set invalidIPDomainError(value:String):void
{
invalidIPDomainErrorOverride = value;
_invalidIPDomainError = value != null ?
value :
resourceManager.getString(
"validators", "invalidIPDomainError");
}
//----------------------------------
// invalidPeriodsInDomainError
//----------------------------------
/**
* @private
* Storage for the invalidPeriodsInDomainError property.
*/
private var _invalidPeriodsInDomainError:String;
/**
* @private
*/
private var invalidPeriodsInDomainErrorOverride:String;
[Inspectable(category="Errors", defaultValue="null")]
/**
* Error message when there are continuous periods in the domain.
*
* @default "The domain in your e-mail address has continous periods."
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get invalidPeriodsInDomainError():String
{
return _invalidPeriodsInDomainError;
}
/**
* @private
*/
public function set invalidPeriodsInDomainError(value:String):void
{
invalidPeriodsInDomainErrorOverride = value;
_invalidPeriodsInDomainError = value != null ?
value :
resourceManager.getString(
"validators", "invalidPeriodsInDomainError");
}
//----------------------------------
// missingAtSignError
//----------------------------------
/**
* @private
* Storage for the missingAtSignError property.
*/
private var _missingAtSignError:String;
/**
* @private
*/
private var missingAtSignErrorOverride:String;
[Inspectable(category="Errors", defaultValue="null")]
/**
* Error message when there is no at sign in the email address.
*
* @default "An at sign (&64;) is missing in your e-mail address."
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get missingAtSignError():String
{
return _missingAtSignError;
}
/**
* @private
*/
public function set missingAtSignError(value:String):void
{
missingAtSignErrorOverride = value;
_missingAtSignError = value != null ?
value :
resourceManager.getString(
"validators", "missingAtSignError");
}
//----------------------------------
// missingPeriodInDomainError
//----------------------------------
/**
* @private
* Storage for the missingPeriodInDomainError property.
*/
private var _missingPeriodInDomainError:String;
/**
* @private
*/
private var missingPeriodInDomainErrorOverride:String;
[Inspectable(category="Errors", defaultValue="null")]
/**
* Error message when there is no period in the domain.
*
* @default "The domain in your e-mail address is missing a period."
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get missingPeriodInDomainError():String
{
return _missingPeriodInDomainError;
}
/**
* @private
*/
public function set missingPeriodInDomainError(value:String):void
{
missingPeriodInDomainErrorOverride = value;
_missingPeriodInDomainError = value != null ?
value :
resourceManager.getString(
"validators", "missingPeriodInDomainError");
}
//----------------------------------
// missingUsernameError
//----------------------------------
/**
* @private
* Storage for the missingUsernameError property.
*/
private var _missingUsernameError:String;
/**
* @private
*/
private var missingUsernameErrorOverride:String;
[Inspectable(category="Errors", defaultValue="null")]
/**
* Error message when there is no username.
*
* @default "The username in your e-mail address is missing."
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get missingUsernameError():String
{
return _missingUsernameError;
}
/**
* @private
*/
public function set missingUsernameError(value:String):void
{
missingUsernameErrorOverride = value;
_missingUsernameError = value != null ?
value :
resourceManager.getString(
"validators", "missingUsernameError");
}
//----------------------------------
// tooManyAtSignsError
//----------------------------------
/**
* @private
* Storage for the tooManyAtSignsError property.
*/
private var _tooManyAtSignsError:String;
/**
* @private
*/
private var tooManyAtSignsErrorOverride:String;
[Inspectable(category="Errors", defaultValue="null")]
/**
* Error message when there is more than one at sign in the e-mail address.
* This property is optional.
*
* @default "Your e-mail address contains too many &64; characters."
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get tooManyAtSignsError():String
{
return _tooManyAtSignsError;
}
/**
* @private
*/
public function set tooManyAtSignsError(value:String):void
{
tooManyAtSignsErrorOverride = value;
_tooManyAtSignsError = value != null ?
value :
resourceManager.getString(
"validators", "tooManyAtSignsError");
}
//--------------------------------------------------------------------------
//
// Overridden methods
//
//--------------------------------------------------------------------------
/**
* @private
*/
override protected function resourcesChanged():void
{
super.resourcesChanged();
invalidCharError = invalidCharErrorOverride;
invalidDomainError = invalidDomainErrorOverride;
invalidIPDomainError = invalidIPDomainErrorOverride;
invalidPeriodsInDomainError = invalidPeriodsInDomainErrorOverride;
missingAtSignError = missingAtSignErrorOverride;
missingPeriodInDomainError = missingPeriodInDomainErrorOverride;
missingUsernameError = missingUsernameErrorOverride;
tooManyAtSignsError = tooManyAtSignsErrorOverride;
}
/**
* Override of the base class <code>doValidation()</code> method
* to validate an e-mail address.
*
* <p>You do not call this method directly;
* Flex calls it as part of performing a validation.
* If you create a custom Validator class, you must implement this method. </p>
*
* @param value Either a String or an Object to validate.
*
* @return An Array of ValidationResult objects, with one ValidationResult
* object for each field examined by the validator.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
override protected function doValidation(value:Object):Array
{
var results:Array = super.doValidation(value);
// Return if there are errors
// or if the required property is set to false and length is 0.
var val:String = value ? String(value) : "";
if (results.length > 0 || ((val.length == 0) && !required))
return results;
else
return EmailValidator.validateEmail(this, value, null);
}
}
}