#!/usr/bin/perl # # fdsnws-station "bridge" handler: # # A test and template handler for the NCEDC Web Service Shell (WSS) # implementing fdsnws-station version 1.0. # # This handler validates and processes a request and responds as # expected by the WSS using a NCEDC web service to fulfill the request. # # Data requests are submitted as command line arguments. All returned # data is written to STDOUT and all diagnostics and errors are written # to STDERR. # ## Use as a template # # To modify this handler to access local data center repositories the # HandleRequest() routine should be modified, replacing the call to a # NCEDC web service with data extraction from local repositories or # whatever else might be appropriate. # # Name parameter lists: each of network, station, location and channel # may contain a list of comma separated values, which may further # contain wildcards. For example, the channel value may contain # "LHE,LHN,LHZ" or "LH?,BH?". # # The exit statuses employed and expected by the WSS: # # Exit Status = Description # 0 = Successfully processed request, data returned via stdout # 1 = General error. An error description may be provided on stderr # 2 = No data. Request was successful but results in no data # 3 = Invalid or unsupported argument/parameter # 4 = Too much data requested # # All start times and end times are assumed to be in UTC and expected # in be one of these forms (with optional trailing Z): # YYYY-MM-DD[T]HH:MM:SS.ssssss # YYYY-MM-DD[T]HH:MM:SS # # ChangeLog: # # 2013.163: # - Initial version use Env qw( CLASSPATH ); use strict; use Getopt::Long; use File::Basename; use Config; use LWP::UserAgent; use HTTP::Status qw(status_message); use HTTP::Date; my $version = "2013.163"; my $scriptname = basename($0); my $cmd = undef; my $verbose = undef; my $usage = undef; my $pretend = undef; my $starttime = undef; my $endtime = undef; my $startbefore = undef; my $startafter = undef; my $endbefore = undef; my $endafter = undef; my $network = undef; my $station = undef; my $location = undef; my $channel = undef; my $minlatitude = undef; my $maxlatitude = undef; my $minlongitude = undef; my $maxlongitude = undef; my $latitude = undef; my $longitude = undef; my $minradius = undef; my $maxradius = undef; my $level = "station"; my $format = "xml"; my $includerestricted = undef; my $includeavailability = undef; my $updatedafter = undef; my $selectstdin = undef; my $selectfile = undef; my @requests = (); $ENV{CLASSPATH} = "/home/tomcat/local/fdsn-station/jar/saxon9he.jar:/home/tomcat/local/fdsn-station/jar/sml.jar:/home/tomcat/local/fdsn-station/jar/org.springframework.beans-3.0.3.RELEASE.jar:/home/tomcat/local/fdsn-station/jar/joda-time-2.2.jar:/home/tomcat/local/fdsn-station/jar/commons-lang-2.6.jar:/home/tomcat/local/fdsn-station/jar/commons-codec-1.8.jar:/home/tomcat/local/fdsn-station/jar/spring-jdbc-2.0.6.jar:/home/tomcat/local/fdsn-station/jar/spring-dao-2.0.8.jar:/home/tomcat/local/fdsn-station/jar/org.springframework.core.jar:/home/tomcat/local/fdsn-station/jar/commons-collections-3.2.1.jar:/home/tomcat/local/fdsn-station/jar/commons-logging-1.1.3.jar:/share/apps/lib/Oracle/current32/ojdbc6.jar"; # The WSS will always translate URI parameters to command line options # prefixed with a double-dash (--), e.g. 'station=ANMO' becomes '--station ANMO' # # This characteristic is leveraged to allow this handler script to # support options specified with a single dash (for diagnostics and # testing) that can never be specified by a remote call via the WSS. # # This is enforced by limiting the arguments that can be called # using double-dashes to a subset needed to match the web service # request paramters and the special case '--STDIN' option. # All such options should be in the @doubledash list. my @doubledash = ('STDIN', 'starttime', 'start', 'endtime', 'end', 'startbefore', 'startafter', 'endbefore', 'endafter', 'network', 'net', 'station', 'sta', 'location', 'loc', 'channel', 'cha', 'minlatitude', 'minlat', 'maxlatitude', 'maxlat', 'minlongitude', 'minlon', 'maxlongitude', 'maxlon', 'latitude', 'lat', 'longitude', 'lon', 'minradius', 'maxradius', 'level', 'format', 'includerestricted', 'includeavailability', 'updatedafter'); foreach my $idx ( 0..$#ARGV ) { if ( $ARGV[$idx] =~ /^--.+/ ) { my $arg = substr $ARGV[$idx], 2; if ( ! grep (/^${arg}$/, @doubledash) ) { print STDERR "Unrecognized option: $ARGV[$idx]\n"; exit (3); } } } # Parse command line arguments Getopt::Long::Configure (qw{ bundling_override no_auto_abbrev no_ignore_case_always }); my $getoptsret = GetOptions ( 'v+' => \$verbose, 'h' => \$usage, 'p' => \$pretend, 's=s' => \$selectfile, 'STDIN' => \$selectstdin, 'starttime|start|ts=s' => \$starttime, 'endtime|end|te=s' => \$endtime, 'startbefore=s' => \$startbefore, 'startafter=s' => \$startafter, 'endbefore=s' => \$endbefore, 'endafter=s' => \$endafter, 'network|net|N=s' => \$network, 'station|sta|S=s' => \$station, 'location|loc|L=s' => \$location, 'channel|cha|C=s' => \$channel, 'minlatitude|minlat=s' => \$minlatitude, 'maxlatitude|maxlat=s' => \$maxlatitude, 'minlongitude|minlon=s' => \$minlongitude, 'maxlongitude|maxlon=s' => \$maxlongitude, 'latitude|lat=s' => \$latitude, 'longitude|lon=s' => \$longitude, 'minradius=s' => \$minradius, 'maxradius=s' => \$maxradius, 'level=s' => \$level, 'format=s' => \$format, 'includerestricted=s' => \$includerestricted, 'includeavailability=s' => \$includeavailability, 'updatedafter=s' => \$updatedafter, ); exit (3) if ( ! $getoptsret ); if ( defined $usage ) { my $name = basename ($0); print STDERR "WSS Handler to fetch metadata from the NCEDC ($version)\n\n"; print STDERR "Usage: $name [-v] \n\n"; print STDERR " -h Print this help message\n"; print STDERR " -v Be more verbose, multiple flags can be used\n"; print STDERR " -p Pretend, do everything except request data from backend\n"; print STDERR "\n"; print STDERR " -s selectfile Determine extraction from a selection file\n"; print STDERR " --STDIN Selection will be supplied via stdin\n"; print STDERR "\n"; print STDERR " --starttime Specify start time (YYYY-MM-DDTHH:MM:SS.ssssss)\n"; print STDERR " --endtime Specify end time (YYYY-MM-DDTHH:MM:SS.ssssss)\n"; print STDERR " --startbefore Specify start before time (YYYY-MM-DDTHH:MM:SS.ssssss)\n"; print STDERR " --startafter Specify start after time (YYYY-MM-DDTHH:MM:SS.ssssss)\n"; print STDERR " --endbefore Specify end before time (YYYY-MM-DDTHH:MM:SS.ssssss)\n"; print STDERR " --endafter Specify end after time (YYYY-MM-DDTHH:MM:SS.ssssss)\n"; print STDERR "\n"; print STDERR " --network Network code, list and wildcards (* and ?) accepted\n"; print STDERR " --station Station code, list and wildcards (* and ?) accepted\n"; print STDERR " --location Location ID, list and wildcards (* and ?) accepted\n"; print STDERR " --channel Channel codes, list and wildcards (* and ?) accepted\n"; print STDERR "\n"; print STDERR " --minlatitude Specify minimum latitude in degrees\n"; print STDERR " --maxlatitude Specify maximum latitude in degrees\n"; print STDERR " --minlongitude Specify minimum longitude in degrees\n"; print STDERR " --maxlongitude Specify maximum longitude in degrees\n"; print STDERR "\n"; print STDERR " --latitude Specify latitude for radius search\n"; print STDERR " --longitude Specify longitude for radius search\n"; print STDERR " --minradius Specify minimum radius from latitude:longitude\n"; print STDERR " --maxradius Specify maximum radius from latitude:longitude\n"; print STDERR "\n"; print STDERR " --level Specify level of StationXML results [network,station,channel,response]\n"; print STDERR " --format Specify output format [xml|text]. Default: xml\n"; print STDERR " --includerestricted Toggle including restricted data in results [TRUE|FALSE]\n"; print STDERR " --includeavailability Toggle including availability in results [TRUE|FALSE]\n"; print STDERR " --updatedafter Limit results to metadata updated after time\n"; print STDERR "\n"; exit (1); } # Track run duration for diagnostics my $startrequest = time; # Validate global request parameters, exit if needed my $retval = &ValidateRequest(); if ( $retval ) { exit ($retval); } # Handle/fullfill data request my $retval = &HandleRequest(); if ( $retval ) { exit ($retval); } if ( $verbose ) { my $runtime = time - $startrequest; print STDERR "Finished ($runtime seconds)\n"; } # Return with success code exit (0); ## End of main ###################################################################### # HandleRequest: # # Process validated request and return selected data on STDOUT. On # errors this routine should return either an appropriate error code # or exit within the routine with the appropriate message and error # code. The request parameters are available from global variables. # # Name parameter lists: each of $network, $station, $location and # $channel may contain a list of comma separated values, which may # futher contain wildcards. For example, the channel value may # contain "LHE,LHN,LHZ" or "LH?,BH?". # # When a fatal error is reached in this routine be sure to use the # appropriate exit code: # # Exit Status = Description # 1 = General error. An error description may be provided on stderr # 2 = No data. Request was successful but results in no data # 3 = Invalid or unsupported argument/parameter # 4 = Too much data requested # # Returns 0 on success, otherwise an appropriate exit code. ###################################################################### sub HandleRequest () { my $uri = undef; my $ltime = time(); my $workdir = "/scr/slip/ws/ws.fdsn.sx.$$.$ltime"; # If --STDIN is specified expect selections from stdin $selectfile = "-" if ( $selectstdin ); # Read selection file/stdin if supplied if ( $selectfile ) { print STDERR "Opening $selectfile\n" if ( $verbose ); if ( ! open (SF, $selectfile) ) { print STDERR "Cannot open $selectfile: $?\n"; return 1; } # Read selection file and determine input files foreach my $sline ( ) { # Trim trailing newlines and white spaces chomp $sline; $sline =~ s/^\s+//; $sline =~ s/\s*$//; $sline =~ s/selection=//; my ($qual) = $sline =~ /^quality\=(.+)/i; my ($msl) = $sline =~ /^minimumlength\=(.+)/i; my ($lso) = $sline =~ /^longestonly\=(.+)/i; my ($tmplevel) = $sline =~ /^level\=(.+)/i; my ($tmpformat) = $sline =~ /^format\=(.+)/i; my ($tmpupdatedafter) = $sline =~ /^updatedafter\=(.+)/i; my ($tmpminlatitude) = $sline =~ /^minlatitude\=(.+)/i; my ($tmpmaxlatitude) = $sline =~ /^maxlatitude\=(.+)/i; my ($tmpminlongitude) = $sline =~ /^minlongitude\=(.+)/i; my ($tmpmaxlongitude) = $sline =~ /^maxlongitude\=(.+)/i; my ($tmplatitude) = $sline =~ /^latitude\=(.+)/i; my ($tmplongitude) = $sline =~ /^longitude\=(.+)/i; my ($tmpminradius) = $sline =~ /^minradius\=(.+)/i; my ($tmpmaxradius) = $sline =~ /^maxradius\=(.+)/i; my ($net,$sta,$loc,$chan,$start,$end) = split (' ', $sline); if ( $tmplevel ) { $level = $tmplevel; } elsif ( $tmpformat ) { $format = $tmpformat; } elsif ( $tmpupdatedafter ) { $updatedafter = $tmpupdatedafter; } elsif ( $tmpminlatitude ) { $minlatitude = $tmpminlatitude; } elsif ( $tmpmaxlatitude ) { $maxlatitude = $tmpmaxlatitude; } elsif ( $tmpminlongitude ) { $minlongitude = $tmpminlongitude; } elsif ( $tmpmaxlongitude ) { $maxlongitude = $tmpmaxlongitude; } elsif ( $tmplatitude ) { $latitude = $tmplatitude; } elsif ( $tmplongitude ) { $longitude = $tmplongitude; } elsif ( $tmpminradius ) { $minradius = $tmpminradius; } elsif ( $tmpmaxradius ) { $maxradius = $tmpmaxradius; } elsif ( $end ) { if ( $verbose ) { print STDERR "Adding request: $net $sta $loc $chan $start $end\n"; } push (@requests, "$net $sta $loc $chan $start $end"); } else { print STDERR "Unrecognized data selection: '$sline'\n"; $retval = 3; } close SF; } } if ( defined $starttime && !defined $endtime ) { $endtime = '2030-01-01T00:00:00'; } if ( !defined $starttime && defined $endtime ) { $starttime = '1900-01-01T00:00:00'; } # Text output if ($format eq 'text') { $uri = "/home/tomcat/local/fdsn-station/stxt "; $uri .= "--level $level " if ( defined $level ); $uri .= "--starttime $starttime --endtime $endtime " if ( defined $starttime && defined $endtime ); $uri .= "--startbefore $startbefore " if ( defined $startbefore ); $uri .= "--startafter $startafter " if ( defined $startafter ); $uri .= "--endbefore $endbefore " if ( defined $endbefore ); $uri .= "--endafter $endafter " if ( defined $endafter ); $uri .= "--network \"$network\" " if ( defined $network ); $uri .= "--station \"$station\" " if ( defined $station ); $uri .= "--location \"$location\" " if ( defined $location ); $uri .= "--channel \"$channel\" " if ( defined $channel ); $uri .= "--minlat $minlatitude " if ( defined $minlatitude ); $uri .= "--maxlat $maxlatitude " if ( defined $maxlatitude ); $uri .= "--minlon $minlongitude " if ( defined $minlongitude ); $uri .= "--maxlon $maxlongitude " if ( defined $maxlongitude ); $uri .= "--latitude $latitude " if ( defined $latitude ); $uri .= "--longitude $longitude " if ( defined $longitude ); $uri .= "--minradius $minradius " if ( defined $minradius ); $uri .= "--maxradius $maxradius " if ( defined $maxradius ); $uri .= "--updatedafter $updatedafter " if ( defined $updatedafter ); } else { # XML output my $backendservice = "/usr/bin/java sml "; my $ilevel = 1; $ilevel = 0 if ( $level eq "network" ); $ilevel = 1 if ( $level eq "station" ); $ilevel = 2 if (( $level eq "channel" ) || ( $level eq "chan" )); $ilevel = 3 if ( $level eq "response" ); # Create the request URI $uri = "$backendservice -e $ilevel "; my $tmp1 = substr $starttime,0,19; my $tmp2 = substr $endtime,0,19; $uri .= "-w $tmp1,$tmp2 " if ( defined $starttime && defined $endtime ); $tmp1 = substr $startbefore,0,19; $uri .= "-f $tmp1 " if ( defined $startbefore ); $tmp1 = substr $startafter,0,19; $uri .= "-F $tmp1 " if ( defined $startafter ); $tmp1 = substr $endbefore,0,19; $uri .= "-t $tmp1 " if ( defined $endbefore ); $tmp1 = substr $endafter,0,19; $uri .= "-T $tmp1 " if ( defined $endafter ); $uri .= "-N \"$network\" " if ( defined $network ); $uri .= "-S \"$station\" " if ( defined $station ); $uri .= "-L \"$location\" " if ( defined $location ); $uri .= "-C \"$channel\" " if ( defined $channel ); $uri .= "-a $minlatitude " if ( defined $minlatitude ); $uri .= "-A $maxlatitude " if ( defined $maxlatitude ); $uri .= "-o $minlongitude " if ( defined $minlongitude ); $uri .= "-O $maxlongitude " if ( defined $maxlongitude ); $uri .= "-x $latitude " if ( defined $latitude ); $uri .= "-y $longitude " if ( defined $longitude ); $uri .= "-r $minradius " if ( defined $minradius ); $uri .= "-R $maxradius " if ( defined $maxradius ); # $uri .= "&includerestricted=$includerestricted" if ( $includerestricted ); $uri .= "-v $includeavailability " if ( defined $includeavailability ); $tmp1 = substr $updatedafter,0,19; $uri .= "-u $tmp1 " if ( defined $updatedafter ); } if ( $selectfile ) { # Create working directory system ("mkdir $workdir"); # Text output if ($format eq 'text') { foreach my $req ( @requests ) { my ($network,$station,$location,$channel,$starttime,$endtime) = split (' ', $req); my $nuri = $uri; $nuri .= "-N \"$network\" " if ( defined $network ); $nuri .= "-S \"$station\" " if ( defined $station ); $nuri .= "-L \"$location\" " if ( defined $location ); $nuri .= "-C \"$channel\" " if ( defined $channel ); $nuri .= "--starttime $starttime --endtime $endtime "; if ( $verbose ) { print STDERR "Backend Data\n"; print STDERR "-----------\n"; print STDERR "${nuri}\n"; print STDERR "-----------\n"; } # Call back end service $cmd = "$nuri >> $workdir/output.$$"; system ($cmd); } # Test if file has been created if (-e "$workdir/output.$$") { # File exists } else { # Remove working directory $cmd = "rm -rf $workdir"; system ($cmd); print STDERR "No Data Found\n"; return 2; } # Return file $ENV{LANG}=""; $cmd = "sort -u $workdir/output.$$"; system ($cmd); # Remove working directory $cmd = "rm -rf $workdir"; system ($cmd); return 0; } else { # XML output my $reqnb = 0; foreach my $req ( @requests ) { my ($network,$station,$location,$channel,$starttime,$endtime) = split (' ', $req); my $nuri = $uri; my $tmp1 = substr $starttime,0,19; my $tmp2 = substr $endtime,0,19; $nuri .= "-w $tmp1,$tmp2 " if ( defined $starttime && defined $endtime ); $nuri .= "-N \"$network\" " if ( defined $network ); $nuri .= "-S \"$station\" " if ( defined $station ); $nuri .= "-L \"$location\" " if ( defined $location ); $nuri .= "-C \"$channel\" " if ( defined $channel ); $nuri .= "--starttime $starttime --endtime $endtime "; if ( $verbose ) { print STDERR "Backend Data\n"; print STDERR "-----------\n"; print STDERR "${nuri}\n"; print STDERR "-----------\n"; } # Call back end service $cmd = "$nuri >> $workdir/output.$$.$reqnb"; system ($cmd); $reqnb++; } # Merge XML files $cmd = "cp $workdir/output.$$.0 $workdir/output.$$"; system ($cmd); for( $a = 1; $a < $reqnb; $a = $a + 1 ) { my $cmd = "/usr/bin/java net.sf.saxon.Transform $workdir/output.$$ /home/tomcat/local/fdsn-station/merge.xslt with=$workdir/output.$$.$a > $workdir/output.$$.tmp"; if ( $verbose ) { print STDERR "-----------\n"; print STDERR "${cmd}\n"; print STDERR "-----------\n"; } system ($cmd); my $cmd = "mv $workdir/output.$$.tmp $workdir/output.$$"; system ($cmd); } # Test if file has been created if (-e "$workdir/output.$$") { # File exists } else { # Remove working directory $cmd = "rm -rf $workdir"; system ($cmd); print STDERR "No Data Found\n"; return 2; } # Return file $cmd = "cat $workdir/output.$$"; system ($cmd); # Remove working directory $cmd = "rm -rf $workdir"; system ($cmd); return 0; } } else { if ( $verbose ) { print STDERR "Backend Data\n"; print STDERR "-----------\n"; print STDERR "${uri}\n"; print STDERR "-----------\n"; } # Stop here if pretending return 0 if $pretend; # Create working directory system ("mkdir $workdir"); # Call back end service my $cmd = "$uri > $workdir/output.$$"; system ($cmd); # Test if file has been created if (-e "$workdir/output.$$") { # File exists } else { # Remove working directory $cmd = "rm -rf $workdir"; system ($cmd); print STDERR "No Data Found\n"; return 2; } # Return file $cmd = "cat $workdir/output.$$"; system ($cmd); # Remove working directory $cmd = "rm -rf $workdir"; system ($cmd); return 0; } } # End of HandleRequest() ###################################################################### # ValidateRequest: # # Validate the data selection parameter values and print specific # errors to STDERR. # # Expected date-time formats are one of: # # YYYY-MM-DD[T]HH:MM:SS.ssssss # YYYY-MM-DD[T]HH:MM:SS # # Month, day, hour, min and second values may be single digits. # # If specified, network, station, location and channel are # validated for length and characters allowed in the SEED 2.4 # specification or wildcards. # # Name parameter lists: each of network, station, location and channel # may contain a list of comma separated values, which may futher # contain wildcards. For example, the channel value may contain # "LHE,LHN,LHZ" or "LH?,BH?". # # Returns 0 on success, otherwise an appropriate exit code. ###################################################################### sub ValidateRequest () { my $retval = 0; if ( defined $starttime && ! ValidDateTime ($starttime) ) { print STDERR "Unrecognized start time [YYYY-MM-DDTHH:MM:SS.ssssss]: '$starttime'\n"; $retval = 3; } if ( defined $endtime && ! ValidDateTime ($endtime) ) { print STDERR "Unrecognized end time [YYYY-MM-DDTHH:MM:SS.ssssss]: '$endtime'\n"; $retval = 3; } if ( defined $starttime && defined $endtime ) { # Check for impossible time windows my $startepoch = str2time ($starttime, "UTC"); my $endepoch = str2time ($endtime, "UTC"); if ( $startepoch > $endepoch ) { print STDERR "Start time must be before end time, start: '$starttime', end: '$endtime'\n"; $retval = 3; } } if ( defined $startbefore && ! ValidDateTime ($startbefore) ) { print STDERR "Unrecognized start before time [YYYY-MM-DDTHH:MM:SS.ssssss]: '$startbefore'\n"; $retval = 3; } if ( defined $startafter && ! ValidDateTime ($startafter) ) { print STDERR "Unrecognized start after time [YYYY-MM-DDTHH:MM:SS.ssssss]: '$startafter'\n"; $retval = 3; } if ( defined $endbefore && ! ValidDateTime ($endbefore) ) { print STDERR "Unrecognized end before time [YYYY-MM-DDTHH:MM:SS.ssssss]: '$endbefore'\n"; $retval = 3; } if ( defined $endafter && ! ValidDateTime ($endafter) ) { print STDERR "Unrecognized end after time [YYYY-MM-DDTHH:MM:SS.ssssss]: '$endafter'\n"; $retval = 3; } if ( defined $updatedafter && ! ValidDateTime ($updatedafter) ) { print STDERR "Unrecognized updated after time [YYYY-MM-DDTHH:MM:SS.ssssss]: '$updatedafter'\n"; $retval = 3; } if ( defined $network ) { foreach my $net ( split (/,/, $network) ) { if ( $net !~ /^[A-Za-z0-9\*\?]{1,2}$/ ) { print STDERR "Unrecognized network code [1-2 characters]: '$net'\n"; $retval = 3; } } } if ( defined $station ) { foreach my $sta ( split (/,/, $station) ) { if ( $sta !~ /^[A-Za-z0-9\*\?]{1,5}$/ ) { print STDERR "Unrecognized station code [1-5 characters]: '$sta'\n"; $retval = 3; } } } if ( defined $location ) { foreach my $loc ( split (/,/, $location) ) { if ( $loc !~ /^[A-Za-z0-9\-\*\?]{1,2}$/ ) { print STDERR "Unrecognized location ID [1-2 characters]: '$loc'\n"; $retval = 3; } } } if ( defined $channel ) { foreach my $chan ( split (/,/, $channel) ) { if ( $chan !~ /^[A-Za-z0-9\*\?]{1,3}$/ ) { print STDERR "Unrecognized channel codes [1-3 characters]: '$chan'\n"; $retval = 3; } } } # Validate minlatitude option, must be a decimal value between -90 and 90 if ( defined $minlatitude ) { if ( $minlatitude !~ /^[+-]?\d+(\.\d+)?$/ ) { print STDERR "Unrecognized value for minlatitude [decimal degrees]: '$minlatitude'\n"; $retval = 3; } elsif ( $minlatitude < -90.0 || $minlatitude > 90.0 ) { print STDERR "Value for minlatitude out of range [-90 to 90]: '$minlatitude'\n"; $retval = 3; } } # Validate maxlatitude option, must be a decimal value between -90 and 90 if ( defined $maxlatitude ) { if ( $maxlatitude !~ /^[+-]?\d+(\.\d+)?$/ ) { print STDERR "Unrecognized value for maxlatitude [decimal degrees]: '$maxlatitude'\n"; $retval = 3; } elsif ( $maxlatitude < -90.0 || $maxlatitude > 90.0 ) { print STDERR "Value for maxlatitude out of range [-90 to 90]: '$maxlatitude'\n"; $retval = 3; } } # Test latitude interval if ( defined $minlatitude && defined $maxlatitude ) { if ( $minlatitude > $maxlatitude ) { print STDERR "Minimum latitude is greater than maximum latitude: '$minlatitude','$maxlatitude'\n"; $retval = 3; } } # Validate minlongitude option, must be a decimal value between -180 and 180 if ( defined $minlongitude ) { if ( $minlongitude !~ /^[+-]?\d+(\.\d+)?$/ ) { print STDERR "Unrecognized value for minlongitude [decimal degrees]: '$minlongitude'\n"; $retval = 3; } elsif ( $minlongitude < -180.0 || $minlongitude > 180.0 ) { print STDERR "Value for minlongitude out of range [-180 to 180]: '$minlongitude'\n"; $retval = 3; } } # Validate maxlongitude option, must be a decimal value between -180 and 180 if ( defined $maxlongitude ) { if ( $maxlongitude !~ /^[+-]?\d+(\.\d+)?$/ ) { print STDERR "Unrecognized value for maxlongitude [decimal degrees]: '$maxlongitude'\n"; $retval = 3; } elsif ( $maxlongitude < -180.0 || $maxlongitude > 180.0 ) { print STDERR "Value for maxlongitude out of range [-180 to 180]: '$maxlongitude'\n"; $retval = 3; } } # Test longitude interval if ( defined $minlongitude && defined $maxlongitude ) { if ( $minlongitude > $maxlongitude ) { print STDERR "Minimum longitude is greater than maximum longitude: '$minlongitude','$maxlongitude'\n"; $retval = 3; } } # Validate latitude option, must be a decimal value between -90 and 90 if ( defined $latitude ) { if ( $latitude !~ /^[+-]?\d+(\.\d+)?$/ ) { print STDERR "Unrecognized value for latitude [decimal degrees]: '$latitude'\n"; $retval = 3; } elsif ( $latitude < -90.0 || $latitude > 90.0 ) { print STDERR "Value for latitude out of range [-90 to 90]: '$latitude'\n"; $retval = 3; } } # Validate longitude option, must be a decimal value between -180 and 180 if ( defined $longitude ) { if ( $longitude !~ /^[+-]?\d+(\.\d+)?$/ ) { print STDERR "Unrecognized value for longitude [decimal degrees]: '$longitude'\n"; $retval = 3; } elsif ( $longitude < -180.0 || $longitude > 180.0 ) { print STDERR "Value for longitude out of range [-180 to 180]: '$longitude'\n"; $retval = 3; } } # Validate minradius option, must be a decimal value between 0 and 180 if ( defined $minradius ) { if ( $minradius !~ /^[+-]?\d+(\.\d+)?$/ ) { print STDERR "Unrecognized value for minradius [decimal degrees]: '$minradius'\n"; $retval = 3; } elsif ( $minradius < 0.0 || $minradius > 180.0 ) { print STDERR "Value for minradius out of range [0 to 180]: '$minradius'\n"; $retval = 3; } } # Validate maxradius option, must be a decimal value between 0 and 180 if ( defined $maxradius ) { if ( $maxradius !~ /^[+-]?\d+(\.\d+)?$/ ) { print STDERR "Unrecognized value for maxradius [decimal degrees]: '$maxradius'\n"; $retval = 3; } elsif ( $maxradius < 0.0 || $maxradius > 180.0 ) { print STDERR "Value for maxradius out of range [0 to 180]: '$maxradius'\n"; $retval = 3; } } # Check that latitude & longitude are specified if minradius or maxradius is specified if ( (defined $minradius || defined $maxradius) && ! (defined $latitude && defined $longitude) ) { print STDERR "latitude and longitude must be specified if minradius and/or maxradius is used\n"; $retval = 3; } # Check that min/max lat/lon is not combined with lat/lon/radius if ( (defined $minlatitude || defined $maxlatitude || defined $minlongitude || defined $maxlongitude) && (defined $minradius || defined $maxradius) ) { print STDERR "[min|max]latitude and [min|max]longitude cannot be combined with latitude, longitude [min|max]radius\n"; $retval = 3; } # Test radius interval if ( defined $minradius && defined $maxradius ) { if ( $minradius > $maxradius ) { print STDERR "Minimum radius is greater than maximum radius: '$minradius','$maxradius'\n"; $retval = 3; } } # Validate level option, must be "network", "station", "channel" or "response" if ( defined $level && $level !~ /^(network|station|channel|chan|response)$/i ) { print STDERR "Unrecognized level selection [network, station, channel, response]: '$level'\n"; $retval = 3; } # Validate format option, must be "xml" or "text" if ( defined $format && $format !~ /^(xml|text)$/i ) { print STDERR "Unrecognized format selection [xml, text]: '$format'\n"; $retval = 3; } # Validate includerestricted option, must be TRUE or FALSE case insensitive if ( defined $includerestricted && ($includerestricted !~ /^TRUE$/i && $includerestricted !~ /^FALSE$/i) ) { print STDERR "Unrecognized value for includerestricted [TRUE or FALSE]: '$includerestricted'\n"; $retval = 3; } # Validate includeavailability option, must be TRUE or FALSE case insensitive if ( defined $includeavailability && ($includeavailability !~ /^TRUE$/i && $includeavailability !~ /^FALSE$/i) ) { print STDERR "Unrecognized value for includeavailability [TRUE or FALSE]: '$includeavailability'\n"; $retval = 3; } return $retval; } # End of ValidateRequest() ###################################################################### # ValidateDateTime: # # Validate a string to match one of these date-time formats: # # YYYY-MM-DD[T]HH:MM:SS.ssssss # YYYY-MM-DD[T]HH:MM:SS # # Returns 1 on match and 0 on non-match. ###################################################################### sub ValidDateTime () { my $string = shift; return 0 if ( ! $string ); return 1 if ( $string =~ /^\d{4}-[01]\d-[0-3]\d[T][0-2]\d:[0-5]\d:[0-5]\d\.\d+(Z)?$/ || $string =~ /^\d{4}-[01]\d-[0-3]\d[T][0-2]\d:[0-5]\d:[0-5]\d(Z)?$/ #|| $string =~ /^\d{4}-[01]\d-[0-3]\d(Z)?$/ ); return 0; } # End of ValidDateTime