
package SRS::EPP::Response::Error::Map;
{
  $SRS::EPP::Response::Error::Map::VERSION = '0.22';
}

use YAML;
use strict;

use Sub::Exporter -setup => {
	exports => [
		qw(map_srs_error_code map_srs_error
			ERROR_MAP HINT_CODE_FALLBACK SEVERITY_FALLBACK)
		]
};

# map SRS codes to EPP codes.  Remember that this list squashes a lot
# of errors to 2400 which, if the requests weren't generated by us,
# would be a different code.

use constant ERROR_MAP => {

	# 20x errors are technically supposed to indicate EPP protocol
	# violations; 2002 means 'command use error' and indicates
	# that what the registrar is trying to do doesn't make sense
	# semantically.  These might be better as 2400.
	CONFLICTING_RESULTS_PARAMETERS => 2002,
	DELETE_FLAG_WITH_OTHER_FIELDS => 2002,
	DOMAIN_CANCEL_AND_RENEW => 2002,
	INVALID_FIELDSET => 2002,
	MESSAGE_DOES_NOT_EXIST => 2002,

	# 22xx are for security; 2200 means 'login failed', so any
	# kind of PGP error will map to that.
	PUBLIC_KEY_INVALID => 2200,
	SIG_INVALID => 2200,
	SIG_VERIFY_FAILED => 2200,
	UNKNOWN_REGISTRAR => 2200,

	# 2201 means "Authorization error", eg, no permissions to do
	# that *type* of operation.
	DOMAIN_ASSIGNED_TO_NON_REGISTRAR => 2201,
	LOCK_ATTEMPT => 2201,
	MODERATED_DOMAIN_VIOLATION => 2201,
	NOT_PERMITTED_TO_FILTER_REGISTRAR_BY_NAME => 2201,
	PERMISSION_DENIED => 2201,

	# 2202 means credentials error
	UDAI_DOMAIN_MISMATCH => 2202,

	# 2302 : An error because something already exists
	ALREADY_ACKED_MESSAGE => 2302,
	DOMAIN_ALREADY_EXISTS => 2302,
	HANDLE_ALREADY_EXISTS => 2302,
	JOB_ALREADY_EXISTS => 2302,
	LIST_ENTRY_ALREADY_EXISTS => 2302,

	# 2303: An error because something does not exist
	EFFECTIVE_REGISTRAR_DOES_NOT_EXIST => 2303,
	HANDLE_DOES_NOT_EXIST => 2303,
	JOB_UNKNOWN => 2303,

	# 2304: error due to object status
	ALLOWED_2LD_FOR_REGISTRAR => 2304,
	CANCELLED_TRANSFER_WITH_UPDATE => 2304,
	DOMAIN_INACTIVE => 2304,
	DOMAIN_IS_NOT_CANCELLED => 2304,
	DOMAIN_LOCKED => 2304,
	DOMAIN_WITH_BILL_DAY => 2304,
	OWNERSHIP_RESTRICTION => 2304,
	RENEW_NOT_REQUIRED => 2304,
	TRANSFER_WITHIN_GRACE_PERIOD => 2304,

	# 2305: association prevents operation
	HANDLE_IN_USE => 2305,
	REMOVING_REGISTRAR_ROLE => 2305,

	# 2306: value error, invalid input
	ACTION_ID_ALREADY_USED => 2306,
	BILLED_UNTIL_IN_PAST => 2306,
	BILLED_UNTIL_TOO_FAR_IN_FUTURE => 2306,
	FINAL_RUNTIME_BEFORE_FIRST_RUNTIME => 2306,
	FIRST_RUNTIME_PAST => 2306,
	FREQUENCY_TOO_SMALL => 2306,
	HANDLE_ID_WITH_CONTACT_FIELDS => 2306,
	IDN_DOMAINNAME_MISMATCH => 2306,
	IDN_INVALID_CHARACTER => 2306,
	IDN_INVALID_DOMAINNAME => 2306,
	IDN_INVALID_UNICODE => 2306,
	IDN_MALFORMED_DOMAINNAME => 2306,
	IDN_UNDEFINED_UNICODE => 2306,
	IDN_UNICODE_MISMATCH => 2306,
	INSUFFICIENT_TERM_FOR_RENEW => 2306,
	INVALID_ADDRESS => 2306,
	INVALID_ADDRESS_FILTER => 2306,
	INVALID_CCTLD => 2306,
	INVALID_DATE_RANGE => 2306,
	INVALID_EFFECTIVE_REGISTRAR_ID_IN_CreateRegistrar => 2306,
	INVALID_EXPLICIT_REGISTRAR_ID => 2306,
	INVALID_PASSWORD => 2306,
	INVALID_REGISTRAR_ID_FILTER => 2306,
	INVALID_WILDCARD_IN_DOMAINNAMEFILTER => 2306,
	IP4ADDR_NOT_ALLOWED => 2306,
	IP6ADDR_NOT_ALLOWED => 2306,
	MISSING_MANDATORY_FIELD => 2306,
	MULTIPLE_VALUE_IN_FIELD => 2306,
	NAME_SERVER_DUPLICATION => 2306,
	NAMESERVERS_EXCEEDED_MAX => 2306,
	NUMBER_OF_FILTERS_EXCEEDS_MAX => 2306,
	PAST_EFFECTIVE_DATE => 2306,
	RENEWAL_EXCEEDS_MAX => 2306,
	RENEW_REQUIRES_TERM => 2306,
	RUNLOG_QRY_PARAM_WITHOUT_PROCESS => 2306,
	SELF_SERVING_DNS_VIOLATION => 2306,
	TERM_EXCEEDS_MAX => 2306,
	UNDEFINED_VALUE => 2306,
	ZERO_TERM_RENEW => 2306,
	INVALID_FIELD => 2306,

	# 2308: policy violation.
	DOMAIN_BLOCKED => 2308,
	DOUBLE_CANCEL_ATTEMPT => 2308,
	HANDLE_ID_ON_REGISTRAR_CREATE => 2308,
	IDN_NOT_ALLOWED => 2308,
	MULTIPLE_DOMAIN_TRANSFER => 2308,
	REGISTRY_MUST_BE_EFFECTIVE_REGISTRAR => 2308,
	REGISTRY_MUST_NOT_BE_EFFECTIVE_REGISTRAR => 2308,
	DNSSEC_2LD_NOT_ALLOWED => 2308,

	# 2400: errors that do not stop the connection
	CONSENT_ERROR => 2400,
	INCORRECT_EFFECTIVE_REGISTRAR => 2400,
	INSECURE_UPDATE => 2400,
	INVALID_EFFECTIVE_REGISTRAR => 2400,
	LOCK_ERROR => 2400,
	MESSAGE_TOO_LARGE => 2400,
	NO_ACTION => 2400,
	NO_MESSAGE_FILTER_VALUES => 2400,
	REQUEST_TOO_LONG => 2400,
	UNEXPECTED_FIELD => 2400,
	UNKNOWN_TRANSACTION_TYPE => 2400,

	# 2500: these errors are more serious, something is badly
	# wrong and hanging up is a good thing to do.
	CONCURRENT_ACK => 2500,
	EXTRA_POST_PARAMETERS => 2500,
	INTERNAL_ERROR => 2500,
	MISSING_POST_PARAMETERS => 2500,
	SYSTEM_ERROR => 2500,
	SYSTEM_MAINTENANCE => 2500,
	SYSTEM_MIGRATION => 2500,
	SYSTEM_OFFLINE => 2500,
	SYSTEM_READONLY => 2500,
	UNDETERMINED_RESULT => 2500,
	VERMAJOR_TOO_HIGH => 2500,
	WRONG_MIME_TYPE => 2500,
	XML_PARSE_ERROR => 2500,
	SYSTEM_ERROR => 2500,

};

# if the specific error is not found in the above table, we can use
# the hint field.

use constant HINT_CODE_FALLBACK => {
	MALFORMED_REQUEST_ERROR => 2306,
	INVALID_REQUEST_ERROR => 2308,
	TEMPORARY_SERVER_ERROR => 2500,

	#UNKNOWN_RESULT => 2400,
	#APPLICATION_ERROR => 2400,
	#UNKNOWN_ERROR_HINT => 2400,
};

# a bit weaker still, very urgent errors may as well hang up.
use constant SEVERITY_FALLBACK => {
	alert => 2500,
	crit => 2500,
	err => 2400,
};

sub map_srs_error_code {
	my $srs_error = shift;
	ERROR_MAP->{$srs_error->error_id} ||
		HINT_CODE_FALLBACK->{$srs_error->hint} ||
		SEVERITY_FALLBACK->{$srs_error->severity} ||
		2400;
}

sub map_srs_error {
	my $srs_error = shift;

	my @details = $srs_error->named_details;
	my @errors;
	while ( my ($name, $value) = splice @details, 0, 2 ) {
		push @errors, XML::EPP::Error->new(
			value => $value,
			reason => $name,
		);
	}

	@errors;
}

1;
