|
|
A Nerd Question
Here's the command line script... its BIG!!
[code:1:ba15ac8f00]#!/usr/bin/perl
=head1 NAME
SRSClient
=head1 SYNOPSIS
$ SRSClient -r <registrar_id> [flags] Transaction: Whois Domain_name: catalyst.net.nz
or read from file
$ SRSClient -r <registrar_id> [flags] -f <filename>
=head1 DESCRIPTION
This is a sample, command-line based client for the SRS. It allows single transactions to be sent to
the server. For more information, see supporting registrar kit documentation.
=head1 USAGE
=head2 Flags
The following flags can be specified on the command line:
=over 4
=item B<-r>
[Required] The 'signing' registrar id number. The registrar id can also be specified by setting
the SRS_REGISTRAR enviroment variable. The -r flag will override this variable, however.
=item B<-a>
[Required] The address (URL) to send the transaction request to. The 'http://' prefix is optional.
The URL can also be specified by setting the SRS_URL enviroment variable. The -a flag will override
this variable, however.
=item B<-aS>
The URL to connect to when using a secure channel. This in only required if the address is
different to the standard address, or the remote secure port is non-standard (that is, anuthing other
than 443). The secure URL can also be specified by setting the SRS_SECURL enviroment variable.
The -aS flag will override this variable, however.
=item B<-e>
Effective registrar id number for the transaction. In most cases, this will be the same as the
signing registrar. The default is the signing registrar.
=item B<-s>
The security setting. Valid options are:
=over 4
=item FORCE_SECURE
Force the transaction to be sent over a secure channel.
=item FORCE_INSECURE
Force the transaction to be sent over an insecure channel.
=item DEFAULT_SECURITY
Default to the security level required by the transaction type.
=back
The default setting is 'DEFAULT_SECURITY'
=item B<-t>
The timeout for connection to the server in seconds. Default is 180.
=item B<-u>
User ID of the PGP (or GPG) public/private key to use for signing requests, and for encrypting and
decrypting UDAIs.
=item B<-kS>
Specifies the path to the secret key ring containing the secret key used for signing requests. (This
will normally be a secring.gpg file, when using GnuPG). There are several default locations checked
for if this path is not specified, including the .gnupg directory in the home directory of the current
user (the default directory that the gpg application creates secret keys in).
=item B<-kP>
Specifies the path to the public key ring containing the public key used for verifying requests. (This
will normally be a pubring.gpg file, when using GnuPG). Defaults are as per the -kS option.
=item B<-d>
Debugging option. Specifying 'ON' (case insensitive) will print out the Request XML and the
Response XML (if any). Defaults to 'OFF'.
=item B<-h>
Display a basic help message.
=back
=head2 Transactions
The following transactions are supported. (All case insensitive).
=over 4
=item * Whois (alias: GetDomainDetails)
=item * DomainDetailsQry
=item * DomainCreate
=item * DomainUpdate
=item * GetMessages
=item * UDAIValidQry
=item * RegistrarCreate
=item * RegistrarUpdate
=item * RegistrarDetailsQry
=back
=head2 Fields
Fields can either be specifed directly on the command line, or read in from file, specifed with the
'-f' flag. The format is fieldname: value. Fieldnames are case insensitive. Supported fields are:
* B<Transaction>: [required] One of the transaction types listed above.
* B<Domain_name>: the domain name
* B<Domain_name_filter>: a list of domain names, separated by commas. If the transaction is DomainDetailsQry then the list of domain names B<CAN> contain names using ? and * wild cards. If the transaction is DomainUpdate then the list of domain names B<CANNOT> contain names using ? and * wild cards (see registrar kit documentation for information on this).
* B<Ns_name_n>: The FQDN (fully qualified domain name) of Name server I<n>. The I<n> should be a
positive integer.
* B<Ns_ip_n>: The IP address of Name server I<n>. The I<n> should be a positive integer.
* B<Locked_date_from>: A date of locked dates to query from. Should be in the format
'dd/mm/yyyy,hh::mm::ss' (Seconds are optional) For example:
Locked_date_from: 28/05/2002,12:30
(indicates a date from 29/05/2002, 12:30pm)
* B<Locked_date_to>: As for Locked_date_from but indicates the locked date to value.
* B<Effective_date_from>: As for Locked_date_from but indicates the effective date range from value.
* B<Effective_date_to>: As for Locked_date_from but indicates the effective date range to value.
* B<Billed_until_date_from>: As for Locked_date_from but indicates the billed until date from value.
* B<Billed_until_date_to>: As for Locked_date_from but indicates the billed until date to value.
* B<Registered_date_from>: As for Locked_date_from but indicates registered date from value.
* B<Registered_date_to>: As for Locked_date_from but indicates registered date to value.
* B<Cancelled_date_from>: As for Locked_date_from but indicates cancelled date from value.
* B<Cancelled_date_to>: As for Locked_date_from but indicates cancelled date to value.
* B<Trans_date_from>: As for Locked_date_from but indicates transaction date from value.
* B<Trans_date_to>: As for Locked_date_from but indicates transaction date to value.
* B<Field_list>: Comma separated list of fields to return. Valid fields are:
=over 4
=item * DomainName
=item * Status
=item * NameServers
=item * RegistrantContact
=item * RegisteredDate
=item * AdminContact
=item * TechnicalContact
=item * Delegate
=item * RegistrarId
=item * RegistrarName
=item * RegistrantRef
=item * Term
=item * LastActionId
=item * BilledUntil
=item * CancelledDate
=item * LastChangeDate
=item * LastChangedBy
=item * AuditText
=back
* B<Billing_term>: Integer indicatining billing term.
* B<Delegate>: Delegate flag. '0' indicates false, '1' indicates true.
* B<Max_results>: Maximum number of results to display.
* B<Skip_results>: Skip Results flag. '0' indicates false, '1' indicates true.
* B<Audit_text>: Audit text supplied by registrar
* B<Action_id>: The action ID. Specifying %d will use a timestamp value.
* B<UDAI>: The Unique Domain Autentication Identifier.
* B<New_UDAI>: The new UDAI flag. '0' indicates false, '1' indicates true.
* B<Renew_now>: Renew now flag. '0' indicates false, '1' indicates true.
* B<Lock_request>: Lock Request flag. '0' indicates false, '1' indicates true.
* B<Cancel>: Cancel domain flag. '0' indicates false, '1' indicates true.
* B<Registrar_id>: Registrar ID.
* B<Status>: Domain Status. Valid Status values are:
=over 4
=item * Available
=item * PendingRelease
=back
* B<URL>: The URL of a registrar's home page.
* B<Name>: The name of the registrar
* B<Accref>: Registrar's Accounting Reference
* B<Registrant_contact>: The contact identifier of the registrant.
* B<Registrant_customer_ref>: Registrar's reference to the registrant.
* B<Registrant_name>: Name of the registrant contact.
* B<Registrant_phone>: Voice phone contact of the Registrant, in the format
+(country_code)-(area_code)-(local_number)
eg. +64-4-4567890
The '+' is optional and an extra '-' can optionally be placed in the local_number.
* B<Registrant_fax>: Fax number of the registrant, in the same format as Registrant_phone.
* B<Registrant_address1>: Address line 1 of the registrant
* B<Registrant_address2>: Address line 2 of the registrant
* B<Registrant_city>: City of the registrant
* B<Registrant_country>: Two letter country code of the registrant.
* B<Registrant_postalcode>: Postal code of the registrant.
* B<Registrant_email>: Email address of the registrant.
* B<Other Contact Fields>: All other contact fields follow the same format as registrant (with the
exception of customer_ref and contact fields), but use one of the following as a prefix:
=over 4
=item * Admin
(Administrative Contact)
=item * Tech
(Technical Contact)
=item * RegistrarSRS
(Registrar SRS Contact)
=item * RegistrarPub
(Registrar Public Contact)
=item * DefaultTech
(Registrar Default Technical Contact)
=back
Eg. The Administrative Contact Name is specified with the 'admin_name' field.
=head1 AUTHOR
Sam Crawley <sam@catalyst.net.nz>
=head1 COPYRIGHT
Copyright 2002-2004 NZ Registry Services
=cut
use warnings;
use strict;
use Carp;
use SRS::NativeData;
use SRS::NativeData::Request;
use SRS::NativeData::DomainCreate;
use SRS::NativeData::DomainDetailsQry;
use SRS::NativeData::DomainUpdate;
use SRS::NativeData::GetMessages;
use SRS::NativeData::Transaction;
use SRS::NativeData::Whois;
use SRS::NativeData::UDAIValidQry;
use SRS::Logger::Stream;
use SRS::OpenPGP;
use SRS::Client::XMLTranslator;
use SRS::NativeData::RunLog;
use SRS::NativeData::SysParam;
#### CONSTANTS ####
my %validTransactions = (
whois => 'WhoisTransaction',
domaindetailsqry => 'DomainDetailsQryTransaction',
domaincreate => 'DomainCreateTransaction',
domainupdate => 'DomainUpdateTransaction',
getmessages => 'GetMessagesTransaction',
getdomaindetails => 'WhoisTransaction',
udaivalidqry => 'UDAIValidQryTransaction',
registrarcreate => 'RegistrarCreateTransaction',
registrardetailsqry => 'RegistrarDetailsQryTransaction',
registrarupdate => 'RegistrarUpdateTransaction',
registraraccountqry => 'RegistrarAccountQryTransaction',
actiondetailsqry => 'ActionDetailsQryTransaction',
scheduleqry => 'ScheduleQryTransaction',
runlogqry => 'RunLogQryTransaction',
runlogcreate => 'RunLogCreateTransaction',
sysparamsqry => 'SysParamsQryTransaction',
sysparamsupdate => 'SysParamsUpdateTransaction',
);
my %validFields = (
# Note, 'transaction' is not checked for here.
domain_name_filter => 'DomainNameFilter',
registrant_name => 'RegistrantContact',
registrant_phone => 'RegistrantContact',
registrant_fax => 'RegistrantContact',
registrant_address1 => 'RegistrantContact',
registrant_address2 => 'RegistrantContact',
registrant_city => 'RegistrantContact',
registrant_country => 'RegistrantContact',
registrant_email => 'RegistrantContact',
registrant_postalcode => 'RegistrantContact',
registrant_province => 'RegistrantContact',
admin_name => 'AdminContact',
admin_phone => 'AdminContact',
admin_fax => 'AdminContact',
admin_address1 => 'AdminContact',
admin_address2 => 'AdminContact',
admin_city => 'AdminContact',
admin_country => 'AdminContact',
admin_email => 'AdminContact',
admin_postalcode => 'AdminContact',
admin_province => 'AdminContact',
tech_name => 'TechnicalContact',
tech_phone => 'TechnicalContact',
tech_fax => 'TechnicalContact',
tech_address1 => 'TechnicalContact',
tech_address2 => 'TechnicalContact',
tech_city => 'TechnicalContact',
tech_country => 'TechnicalContact',
tech_email => 'TechnicalContact',
tech_postalcode => 'TechnicalContact',
tech_province => 'TechnicalContact',
registrarpub_name => 'RegistrarPublicContact',
registrarpub_phone => 'RegistrarPublicContact',
registrarpub_fax => 'RegistrarPublicContact',
registrarpub_address1 => 'RegistrarPublicContact',
registrarpub_address2 => 'RegistrarPublicContact',
registrarpub_city => 'RegistrarPublicContact',
registrarpub_country => 'RegistrarPublicContact',
registrarpub_email => 'RegistrarPublicContact',
registrarpub_postalcode => 'RegistrarPublicContact',
registrarsrs_name => 'RegistrarSRSContact',
registrarsrs_phone => 'RegistrarSRSContact',
registrarsrs_fax => 'RegistrarSRSContact',
registrarsrs_address1 => 'RegistrarSRSContact',
registrarsrs_address2 => 'RegistrarSRSContact',
registrarsrs_city => 'RegistrarSRSContact',
registrarsrs_country => 'RegistrarSRSContact',
registrarsrs_email => 'RegistrarSRSContact',
registrarsrs_postalcode => 'RegistrarSRSContact',
defaulttech_name => 'DefaultTechnicalContact',
defaulttech_phone => 'DefaultTechnicalContact',
defaulttech_fax => 'DefaultTechnicalContact',
defaulttech_address1 => 'DefaultTechnicalContact',
defaulttech_address2 => 'DefaultTechnicalContact',
defaulttech_city => 'DefaultTechnicalContact',
defaulttech_country => 'DefaultTechnicalContact',
defaulttech_email => 'DefaultTechnicalContact',
defaulttech_postalcode => 'DefaultTechnicalContact',
ns_name => 'NameServers',
ns_ip => 'NameServers',
ns_filter_name => 'NameServerFilter',
ns_filter_ip => 'NameServerFilter',
locked_date_from => 'LockedDateRange',
effective_date_from => 'EffectiveDateRange',
billed_until_date_from => 'BilledUntilDateRange',
registered_date_from => 'RegisteredDateRange',
cancelled_date_from => 'CancelledDateRange',
trans_date_from => 'TransDateRange',
search_date_from => 'SearchDateRange',
result_date_from => 'ResultDateRange',
invoice_date_from => 'InvoiceDateRange',
log_date_from => 'LogDateRange',
locked_date_to => 'LockedDateRange',
effective_date_to => 'EffectiveDateRange',
billed_until_date_to => 'BilledUntilDateRange',
registered_date_to => 'RegisteredDateRange',
cancelled_date_to => 'CancelledDateRange',
trans_date_to => 'TransDateRange',
search_date_to => 'SearchDateRange',
result_date_to => 'ResultDateRange',
invoice_date_to => 'InvoiceDateRange',
log_date_to => 'LogDateRange',
active_on => 'ActiveOn',
field_list => 'FieldList',
runlog_processname => 'RunLog',
runlog_details => 'RunLog',
runlog_actionstatus => 'RunLog',
runlog_control => 'RunLog',
runlog_action_id => 'RunLog',
runlog_timestamp => 'RunLog',
billing_term => 'Term',
delegate => 'Delegate',
max_results => 'MaxResults',
skip_results => 'SkipResults',
audit_text => 'AuditText',
action_id => 'ActionId',
udai => 'UDAI',
new_udai => 'NewUDAI',
renew_now => 'Renew',
lock_request => 'Lock',
registrar_id => 'RegistrarId',
domain_name => 'DomainName',
registrant_contact => 'RegistrantName',
registrant_customer_ref => 'RegistrantRef',
originating_registrar_id => 'OriginatingRegistrarId',
effective_registrar_id => 'RecipientRegistrarId',
cancel => 'Cancel',
status => 'Status',
public_key => 'EncryptKey',
url => 'URL',
name => 'Name',
accref => 'AccRef',
allowed_2lds => 'Allowed2LDs',
roles => 'Roles',
name_filter => 'NameFilter',
invoice_id => 'InvoiceId',
processname => 'ProcessName',
parameters => 'Parameters',
release => 'Release',
sysparam_name => 'SysParam',
sysparam_value => 'SysParam',
);
#-------------------------------------------------------------------------------------------------
# Initialise Native Data
if (my $error = SRS::NativeData::initialize('SrsClient')) {
$error->print;
exit;
}
# Print out usage if there's a help command issued, or no arguments are given
usage() if ! @ARGV || $ARGV[0] eq '-h' || $ARGV[0] eq '--help';
# Must have at least 2 arguments
error ("Incorrect Syntax") unless scalar(@ARGV) >= 2;
my %flags;
# Get the list of flags
{
no warnings; # Disable warnings in case we have an uneven number of arguments
%flags = @ARGV;
}
# Get registrar_id and URL environment variables if they exist and weren't specified
$flags{'-r'} = $ENV{SRS_REGISTRAR} unless $flags{'-r'};
$flags{'-a'} = $ENV{SRS_URL} unless defined $flags{'-a'};
$flags{'-aS'} = $ENV{SRS_SECURL} unless defined $flags{'-aS'};
# Require a registrar ID to be specified
error ("You must specify a registrar id") unless $flags{'-r'};
# Require a URL to be specified
error ("You must include an address to connect to") unless $flags{'-a'};
# Get security setting
my $security_level;
if (defined $flags{'-s'}) {
if ($flags{'-s'} eq 'FORCE_SECURE') {
$security_level = SRS::NativeData::Request::FORCE_SECURE;
}
elsif ($flags{'-s'} eq 'FORCE_INSECURE') {
$security_level = SRS::NativeData::Request::FORCE_INSECURE;
}
else {
$security_level = SRS::NativeData::Request::DEFAULT_SECURITY;
}
}
my @tempFields;
# Either read the file, or the parameters
if ($flags{-f}) {
my $data;
error ("You must specify a file name") unless $flags{'-f'};
{
# Temporarily undef the buffer so we can read the entire file in as a scalar
local(*INPUT, $/);
open (INPUT, $flags{'-f'}) || error ("can't open $flags{'-f'}: $!");
$data = <INPUT>;
close(INPUT);
}
# Split the fields up
@tempFields = split /\n+/,$data;
# Remove Comments.
@tempFields = grep {!/^#/} @tempFields;
@tempFields = map {split/\: /,$_} @tempFields;
}
else {
@tempFields = @ARGV;
# Get rid of any arguments that are flags
foreach my $field (@ARGV) {
if ($field =~ /^-.+$/) {
shift @tempFields;
shift @tempFields;
}
}
}
# Must have an even number of parameters
error ("Invalid parameter format (@tempFields)") if scalar(@tempFields) % 2;
my %tempFields = @tempFields;
my %fields;
my @nameServers;
my @nameServerFilter;
my $transaction;
my %postalAddress;
# Iterate over fields and process them
while ( my ($key, $value) = each %tempFields) {
# Couldn't find a value
error ("Value missing ($key)") unless defined $value;
# Reformat key/value
$key =~ s/\:?\s?//g;
$key = lc($key);
$value =~ s/^\s+?//g;
$value = '' if $value eq 'NULL';
# Get the 'Transaction' key
if ($key eq 'transaction') {
$transaction = lc($value);
next;
}
# Remove trailing index number of nameserver.
$key =~ s/\_(\d+)$// if $key =~ /^ns/;
my $index = $1; # Store the index for later.
error ("Field ($key) not recognised") unless defined $validFields{$key};
# Change ActionID macro
if ($key eq 'action_id' && $value eq '%d') {
my ($sec,$min,$hour,$mday,$mon,$year) = localtime(time);
$year += 1900;
$value = "$year-$mon-$mday-$hour-$min-$sec " . rand;
}
# Contacts
if ($validFields{$key} =~ /Contact$/) {
my ($top,$subField) = split /\_/,$key;
if ($subField eq 'phone' || $subField eq 'fax') {
my $temp_value = $value;
$value = new SRS::NativeData::PhoneDetails;
if ($temp_value ne '') {
my ($countryCode,$areaCode,$number) = splitPhone($temp_value);
$value->setFields(
CountryCode => $countryCode,
AreaCode => $areaCode,
LocalNumber => $number
);
}
}
if ($subField eq 'address1' || $subField eq 'address2' ||
$subField eq 'city' || $subField eq 'country' ||
$subField eq 'postalcode' || $subField eq 'province') {
$subField = 'CountryCode' if $subField eq 'country';
$subField = 'PostalCode' if $subField eq 'postalcode';
$postalAddress{$validFields{$key}} = new SRS::NativeData::PostalAddress
unless exists $postalAddress{$validFields{$key}};
$postalAddress{$validFields{$key}}->setFields( ucfirst($subField) => $value );
$value = $postalAddress{$validFields{$key}};
$subField = 'PostalAddress';
}
# Create a contact object for this Contact if it doesn't exist
$fields{$validFields{$key}} = new SRS::NativeData::ContactDetails
unless exists $fields{$validFields{$key}};
$fields{$validFields{$key}}->setFields( ucfirst($subField) => $value );
}
# Public Key
elsif ($validFields{$key} eq "EncryptKey") {
my $pubkey;
if ($value) {
# Temporarily undef the buffer so we can read the entire file in as a scalar
local(*INPUT, $/);
open (INPUT, $value) || error ("can't open $value: $!");
$pubkey = <INPUT>;
close(INPUT);
}
$fields{$validFields{$key}} = $pubkey;
}
# Date Ranges
elsif ($validFields{$key} =~ /DateRange$/) {
$key =~ /\_([a-z]+?)$/;
my $subField = $1;
$value =~ s/\,/ /g;
my $dateTime = SRS::NativeData::DateTime->newFromString($value);
error("Invalid date format ($key)") unless defined($dateTime);
# Create DateRange if it doesn't already exist
$fields{$validFields{$key}} = new SRS::NativeData::DateRange
unless exists $fields{$validFields{$key}};
$fields{$validFields{$key}}->setFields( ucfirst($subField) => $dateTime);
}
# Date
elsif ($validFields{$key} eq 'ActiveOn' || $validFields{$key} eq 'RunLogTimeStamp') {
$value =~ s/\,/ /g;
my $dateTime = SRS::NativeData::DateTime->parseDate($value);
error("Invalid date format ($key)") unless defined($dateTime);
$fields{$validFields{$key}} = $dateTime;
}
# Name Servers
elsif ($validFields{$key} eq 'NameServers') {
my ($top,$subField) = split /\_/,$key;
my $subKey = $subField eq 'name' ? 'FQDN' : 'IP4Addr';
$nameServers[$index-1] = new SRS::NativeData::NameServer
unless defined $nameServers[$index-1];
$nameServers[$index-1]->setFields($subKey => $value);
}
# Name Server Filter
elsif ($validFields{$key} eq 'NameServerFilter') {
my ($top,$middle,$subField) = split /\_/,$key;
my $subKey = $subField eq 'name' ? 'FQDN' : 'IP4Addr';
$nameServerFilter[$index-1] = new SRS::NativeData::NameServerFilter
unless defined $nameServerFilter[$index-1];
$nameServerFilter[$index-1]->setFields($subKey => $value);
}
# Domain Name Filter, Field List, Allowed2lds, Roles
elsif ($validFields{$key} eq 'DomainNameFilter' || $validFields{$key} eq 'FieldList'
|| $validFields{$key} eq 'Allowed2LDs') {
my @filters = split /\,/,$value;
$fields{$validFields{$key}} = \@filters;
}
# RunLog
elsif ($validFields{$key} eq 'RunLog') {
my ($top,$subField) = split /\_/,$key;
$fields{$validFields{$key}} = new SRS::NativeData::RunLog
unless exists $fields{$validFields{$key}};
warn $subField;
$subField = 'ActionStatus' if $subField eq 'actionstatus';
$subField = 'ProcessName' if $subField eq 'processname';
if ($subField eq 'timestamp') {
$subField = 'RunLogTimeStamp';
$value =~ s/\,/ /g;
$value = SRS::NativeData::DateTime->parseDate($value);
}
$fields{$validFields{$key}}->setFields( ucfirst($subField) => $value );
}
elsif ($validFields{$key} eq 'Roles') {
my @roles = split /\,/,$value;
my $roleList = new SRS::NativeData::RoleList(@roles);
$fields{$validFields{$key}} = $roleList;
}
elsif ($validFields{$key} eq 'SysParam') {
my ($junk, $subField) = split /\_/,$key;
$fields{$validFields{$key}} = new SRS::NativeData::SysParam
unless exists $fields{$validFields{$key}};
$subField = 'ParamValue' if $subField eq 'value';
$fields{$validFields{$key}}->setFields(ucfirst($subField) => $value);
}
# Everything else
else {
$fields{$validFields{$key}} = $value;
}
}
unless ($transaction && $validTransactions{$transaction}) {
error ("Missing or invalid transaction type");
}
# Assign the nameserver list.
$fields{NameServers} = \@nameServers if @nameServers;
$fields{NameServerFilter} = \@nameServerFilter if @nameServerFilter;
my $class = 'SRS::NativeData::' . $validTransactions{$transaction};
my $nd = $class->new(%fields);
my $request = new SRS::NativeData::Request (
transactions => [$nd],
registrarId => $flags{'-e'} || $flags{'-r'},
security => $security_level,
);
$ENV{DEBUG} = 'on' if lc($flags{'-d'}) eq 'on';
my $pgp = new SRS::OpenPGP(
secretKeyRing => $flags{'-kS'},
publicKeyRing => $flags{'-kP'},
uid => $flags{'-u'},
);
my $translator = new SRS::Client::XMLTranslator(
registrar => $flags{'-r'},
url => $flags{'-a'},
timeout => $flags{'-t'},
logger => SRS::Logger::Stream->new(\*STDOUT),
secureUrl => $flags{'-aS'},
pgp => $pgp,
);
my $error = $translator->execute($request);
if ($error) {
if ($error->getField('description')) {
print $error->getField('description');
foreach my $detail (@{$error->getField('details')}) {
print ": $detail";
}
}
else {
print 'An error occured. ' . ($error->getField('id'));
}
print "\n";
exit;
}
my @transactions = $request->getTransactions;
foreach my $trans (@transactions) {
if (my %errorResp = $trans->getError) {
print $errorResp{Error}->getField('description');
foreach my $detail (@{$errorResp{Error}->getField('details')}) {
print ": $detail";
}
print "\n";
}
elsif (! $flags{-nR}) {
my $response = $trans->getResponse();
my %respFields = $response->getFields();
print "Results:\n";
printFields(%respFields);
}
}
my $indent;
sub printFields {
my %fields = @_;
$indent .= ' ';
while (my ($key, $value) = each %fields) {
if (ref($value) eq 'HASH') {
print "$indent$key:\n";
printFields(%$value);
}
elsif (ref($value) eq 'ARRAY') {
print "$indent$key List:\n";
foreach my $element (@$value) {
if (ref($element)) {
printFields($key => $element);
}
else {
print "$indent $element\n"
}
}
}
elsif (ref($value) && $value->can("getFields")) {
print $indent . "$key:\n";
printFields ($value->getFields);
}
else {
print "$indent$key => $value\n" if defined $value;
}
}
$indent = substr($indent,0,-3);
}
sub error {
print $_[0] . "\n\n";
usage();
}
sub usage {
print <<USAGE;
USAGE:
SRSClient -r <registrar_id> [flags] Transaction: <transaction-type> [field_list]
- or -
SRSClient -r <registrar_id> [flags] -f <file_name>
See POD documentation for more details (type 'perldoc SRSClient' in the same directory as the SRSClient
executable).
USAGE
exit;
}
sub splitPhone {
my $phone = shift or croak "Phone number not supplied";
$phone =~ m/^\+*(\d+)[ \-]?\(?(\d*)\)?[ \-]?(.+)$/o;
return ($1,$2,$3);
}
[/code:1:ba15ac8f00]
That has to work as a website! Good luck :icon_lol:
|