# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
-# You should have received a copy of the GNU General Public License along with
-# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
-# Suite 330, Boston, MA 02111-1307 USA
+# You should have received a copy of the GNU General Public License along
+# with Koha; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
use strict;
use warnings;
+use List::MoreUtils qw(any);
+
use C4::ILSDI::Services;
use C4::Auth;
use C4::Output;
This script is a basic implementation of ILS-DI protocol for Koha.
It acts like a dispatcher, that get the CGI request, check required and
-optionals arguments, call a function from C4::ILS-DI::Services, and finaly
+optionals arguments, call a function from C4::ILS-DI, and finaly
outputs the returned hashref as XML.
=cut
# List of available services, sorted by level
my @services = (
- 'Describe', # Not part of ILS-DI, online API doc
-# Level 1: Basic Discovery Interfaces
-# 'HarvestBibliographicRecords', # OAI-PMH
-# 'HarvestExpandedRecords', # OAI-PMH
- 'GetAvailability', # FIXME Add bibbliographic level
-# 'GoToBibliographicRequestPage' # I don't understant this one
-# Level 2: Elementary OPAC supplement
-# 'HarvestAuthorityRecords', # OAI-PMH
-# 'HarvestHoldingsRecords', # OAI-PMH
- 'GetRecords', # Note that we can use OAI-PMH for this too
-# 'Search', # TODO
-# 'Scan', # TODO
- 'GetAuthorityRecords',
-# 'OutputRewritablePage', # I don't understant this one
-# 'OutputIntermediateFormat', # I don't understant this one
-# Level 3: Elementary OPAC alternative
- 'LookupPatron',
- 'AuthenticatePatron',
- 'GetPatronInfo',
- 'GetPatronStatus',
- 'GetServices', # FIXME Loans
- 'RenewLoan',
- 'HoldTitle', # FIXME Add dates support
- 'HoldItem', # FIXME Add dates support
- 'CancelHold',
-# 'RecallItem', # Not supported by Koha
-# 'CancelRecall', # Not supported by Koha
-# Level 4: Robust/domain specific discovery platforms
-# 'SearchCourseReserves', # TODO
-# 'Explain' # TODO
+ 'Describe', # Not part of ILS-DI, online API doc
+
+ # Level 1: Basic Discovery Interfaces
+ # 'HarvestBibliographicRecords', # OAI-PMH
+ # 'HarvestExpandedRecords', # OAI-PMH
+ 'GetAvailability', # FIXME Add bibbliographic level
+
+ # 'GoToBibliographicRequestPage' # I don't understant this one
+ # Level 2: Elementary OPAC supplement
+ # 'HarvestAuthorityRecords', # OAI-PMH
+ # 'HarvestHoldingsRecords', # OAI-PMH
+ 'GetRecords', # Note that we can use OAI-PMH for this too
+
+ # 'Search', # TODO
+ # 'Scan', # TODO
+ 'GetAuthorityRecords',
+
+ # 'OutputRewritablePage', # I don't understant this one
+ # 'OutputIntermediateFormat', # I don't understant this one
+ # Level 3: Elementary OPAC alternative
+ 'LookupPatron',
+ 'AuthenticatePatron',
+ 'GetPatronInfo',
+ 'GetPatronStatus',
+ 'GetServices', # FIXME Loans
+ 'RenewLoan',
+ 'HoldTitle', # FIXME Add dates support
+ 'HoldItem', # FIXME Add dates support
+ 'CancelHold',
+
+ # 'RecallItem', # Not supported by Koha
+ # 'CancelRecall', # Not supported by Koha
+ # Level 4: Robust/domain specific discovery platforms
+ # 'SearchCourseReserves', # TODO
+ # 'Explain' # TODO
);
# List of required arguments
my %required = (
- 'Describe' => ['verb'],
- 'GetAvailability' => ['id', 'id_type'],
- 'GetRecords' => ['id'],
- 'GetAuthorityRecords' => ['id'],
- 'LookupPatron' => ['id'],
- 'AuthenticatePatron' => ['username', 'password'],
- 'GetPatronInfo' => ['patron_id'],
- 'GetPatronStatus' => ['patron_id'],
- 'GetServices' => ['patron_id', 'item_id'],
- 'RenewLoan' => ['patron_id', 'item_id'],
- 'HoldTitle' => ['patron_id', 'bib_id', 'request_location'],
- 'HoldItem' => ['patron_id', 'bib_id', 'item_id'],
- 'CancelHold' => ['patron_id', 'item_id'],
+ 'Describe' => ['verb'],
+ 'GetAvailability' => [ 'id', 'id_type' ],
+ 'GetRecords' => ['id'],
+ 'GetAuthorityRecords' => ['id'],
+ 'LookupPatron' => ['id'],
+ 'AuthenticatePatron' => [ 'username', 'password' ],
+ 'GetPatronInfo' => ['patron_id'],
+ 'GetPatronStatus' => ['patron_id'],
+ 'GetServices' => [ 'patron_id', 'item_id' ],
+ 'RenewLoan' => [ 'patron_id', 'item_id' ],
+ 'HoldTitle' => [ 'patron_id', 'bib_id', 'request_location' ],
+ 'HoldItem' => [ 'patron_id', 'bib_id', 'item_id' ],
+ 'CancelHold' => [ 'patron_id', 'item_id' ],
);
# List of optional arguments
my %optional = (
- 'Describe' => [],
- 'GetAvailability' => ['return_type', 'return_fmt'],
- 'GetRecords' => ['schema'],
- 'GetAuthorityRecords' => ['schema'],
- 'LookupPatron' => ['id_type'],
- 'AuthenticatePatron' => [],
- 'GetPatronInfo' => ['show_contact', 'show_fines', 'show_holds', 'show_loans'],
- 'GetPatronStatus' => [],
- 'GetServices' => [],
- 'RenewLoan' => ['desired_due_date'],
- 'HoldTitle' => ['pickup_location', 'needed_before_date', 'pickup_expiry_date'],
- 'HoldItem' => ['pickup_location', 'needed_before_date', 'pickup_expiry_date'],
- 'CancelHold' => [],
+ 'Describe' => [],
+ 'GetAvailability' => [ 'return_type', 'return_fmt' ],
+ 'GetRecords' => ['schema'],
+ 'GetAuthorityRecords' => ['schema'],
+ 'LookupPatron' => ['id_type'],
+ 'AuthenticatePatron' => [],
+ 'GetPatronInfo' => [ 'show_contact', 'show_fines', 'show_holds', 'show_loans' ],
+ 'GetPatronStatus' => [],
+ 'GetServices' => [],
+ 'RenewLoan' => ['desired_due_date'],
+ 'HoldTitle' => [ 'pickup_location', 'needed_before_date', 'pickup_expiry_date' ],
+ 'HoldItem' => [ 'pickup_location', 'needed_before_date', 'pickup_expiry_date' ],
+ 'CancelHold' => [],
);
-# If ILS-DI module is disabled in System->Preferences, redirect to 404
-if (not C4::Context->preference('ILS-DI')) {
- print $cgi->redirect("/cgi-bin/koha/errors/404.pl");
-}
-
# If no service is requested, display the online documentation
-if (not $cgi->param('service')) {
- my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
- {
- template_name => "ilsdi.tmpl",
- query => $cgi,
- type => "opac",
- authnotrequired => 1,
- debug => 1,
- }
- );
- output_html_with_http_headers $cgi, $cookie, $template->output;
- exit 0;
+unless ( $cgi->param('service') ) {
+ my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
+ { template_name => "ilsdi.tmpl",
+ query => $cgi,
+ type => "opac",
+ authnotrequired => 1,
+ debug => 1,
+ }
+ );
+ output_html_with_http_headers $cgi, $cookie, $template->output;
+ exit 0;
}
# If user requested a service description, then display it
-if ($cgi->param('service') eq "Describe" and grep {$cgi->param('verb') eq $_} @services) {
- my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
- {
- template_name => "ilsdi.tmpl",
- query => $cgi,
- type => "opac",
- authnotrequired => 1,
- debug => 1,
- }
- );
- $template->param( $cgi->param('verb') => 1 );
- output_html_with_http_headers $cgi, $cookie, $template->output;
- exit 0;
+if ( $cgi->param('service') eq "Describe" and any { $cgi->param('verb') eq $_ } @services ) {
+ my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
+ { template_name => "ilsdi.tmpl",
+ query => $cgi,
+ type => "opac",
+ authnotrequired => 1,
+ debug => 1,
+ }
+ );
+ $template->param( $cgi->param('verb') => 1 );
+ output_html_with_http_headers $cgi, $cookie, $template->output;
+ exit 0;
}
-my $service = $cgi->param('service') || "ilsdi";
-
my $out;
+# If ILS-DI module is disabled in System->Preferences, redirect to 404
+unless ( C4::Context->preference('ILS-DI') ) {
+ $out->{'code'} = "NotAllowed";
+ $out->{'message'} = "ILS-DI is disabled.";
+}
+
+# If the remote address is not allowed, redirect to 403
+my @AuthorizedIPs = split(/,/, C4::Context->preference('ILS-DI:AuthorizedIPs'));
+if ( @AuthorizedIPs # If no filter set, allow access to everybody
+ and not any { $ENV{'REMOTE_ADDR'} eq $_ } @AuthorizedIPs # IP Check
+ ) {
+ $out->{'code'} = "NotAllowed";
+ $out->{'message'} = "Unauthorized IP address: ".$ENV{'REMOTE_ADDR'}.".";
+}
+
+my $service = $cgi->param('service') || "ilsdi";
+
# Check if the requested service is in the list
-if ($service and grep {$service eq $_} @services) {
-
- my @parmsrequired = @{$required{$service}};
- my @parmsoptional = @{$optional{$service}};
- my @parmsall = (@parmsrequired, @parmsoptional);
- my @names = $cgi->param;
- my %paramhash = ();
- foreach my $name (@names) {
- $paramhash{$name} = 1;
- }
-
- # check for missing parameters
- foreach my $name (@parmsrequired) {
- if ((! exists $paramhash{$name})) {
- $out->{'message'} = "missing $name parameter";
- }
- }
-
- # check for illegal parameters
- foreach my $name (@names) {
- my $found = 0;
- foreach my $name2 (@parmsall) {
- if ($name eq $name2) {
- $found = 1;
- }
- }
- if (($found == 0) && ($name ne 'service')) {
- $out->{'message'} = "$name is an illegal parameter";
- }
- }
-
- # check for multiple parameters
- foreach my $name (@names) {
- my @values = $cgi->param($name);
- if ($#values != 0) {
- $out->{'message'} = "multiple values are not allowed for the $name parameter";
- }
- }
-
- if (! $out->{'message'}) {
- # GetAvailability is a special case, as it cannot use XML::Simple
- if ($service eq "GetAvailability") {
- print CGI::header('text/xml');
- print C4::ILSDI::Services::GetAvailability($cgi);
- exit 0;
- }
- else {
- # Variable functions
- my $sub = do{
- no strict 'refs';
- my $symbol = 'C4::ILSDI::Services::'.$service;
- \&{"$symbol"};
- };
- # Call the requested service, and get its return value
- $out = &$sub($cgi);
- }
- }
-}
-else {
- $out->{'message'} = "NotSupported";
+if ( $service and any { $service eq $_ } @services ) {
+
+ my @parmsrequired = @{ $required{$service} };
+ my @parmsoptional = @{ $optional{$service} };
+ my @parmsall = ( @parmsrequired, @parmsoptional );
+ my @names = $cgi->param;
+ my %paramhash;
+ $paramhash{$_} = 1 for @names;
+
+ # check for missing parameters
+ for ( @parmsrequired ) {
+ unless ( exists $paramhash{$_} ) {
+ $out->{'code'} = "MissingParameter";
+ $out->{'message'} = "The required parameter ".$_." is missing.";
+ }
+ }
+
+ # check for illegal parameters
+ for my $name ( @names ) {
+ my $found = 0;
+ for my $name2 (@parmsall) {
+ if ( $name eq $name2 ) {
+ $found = 1;
+ }
+ }
+ if ( $found == 0 && $name ne 'service' ) {
+ $out->{'code'} = "IllegalParameter";
+ $out->{'message'} = "The parameter ".$name." is illegal.";
+ }
+ }
+
+ # check for multiple parameters
+ for ( @names ) {
+ my @values = $cgi->param($_);
+ if ( $#values != 0 ) {
+ $out->{'code'} = "MultipleValuesNotAllowed";
+ $out->{'message'} = "Multiple values not allowed for the parameter ".$_.".";
+ }
+ }
+
+ if ( !$out->{'message'} ) {
+
+ # GetAvailability is a special case, as it cannot use XML::Simple
+ if ( $service eq "GetAvailability" ) {
+ print CGI::header('text/xml');
+ print C4::ILSDI::Services::GetAvailability($cgi);
+ exit 0;
+ } else {
+
+ # Variable functions
+ my $sub = do {
+ no strict 'refs';
+ my $symbol = 'C4::ILSDI::Services::' . $service;
+ \&{"$symbol"};
+ };
+
+ # Call the requested service, and get its return value
+ $out = &$sub($cgi);
+ }
+ }
+} else {
+ $out->{'message'} = "NotSupported";
}
# Output XML by passing the hashref to XMLOut
-print CGI::header('text/xml');
-print XMLout($out,
- noattr => 1,
- noescape => 1,
- nosort => 1,
- xmldecl => '<?xml version="1.0" encoding="ISO-8859-1" ?>',
- RootName => $service,
- SuppressEmpty => 1);
+binmode STDOUT, ':encoding(UTF-8)';
+print CGI::header('-type'=>'text/xml', '-charset'=>'utf-8');
+print XMLout(
+ $out,
+ noattr => 1,
+ nosort => 1,
+ xmldecl => '<?xml version="1.0" encoding="UTF-8" ?>',
+ RootName => $service,
+ SuppressEmpty => 1
+);
+exit 0;