X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=C4%2FContext.pm;h=4dab9a98c52211587718fcc947ad96fab7f8b709;hb=cd14fd421c6908a73174d2cd0267779b9fd4e08f;hp=fb85ff966996831d00b69dde1feab343f050c399;hpb=cac5265e0b8861821e0e7b4a407cb8f2ac7e81e3;p=koha.git
diff --git a/C4/Context.pm b/C4/Context.pm
index fb85ff9669..4dab9a98c5 100644
--- a/C4/Context.pm
+++ b/C4/Context.pm
@@ -1,3 +1,4 @@
+package C4::Context;
# Copyright 2002 Katipo Communications
#
# This file is part of Koha.
@@ -15,19 +16,77 @@
# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place,
# Suite 330, Boston, MA 02111-1307 USA
-# $Id$
-
-package C4::Context;
use strict;
+use warnings;
+use vars qw($VERSION $AUTOLOAD $context @context_stack);
+
+BEGIN {
+ if ($ENV{'HTTP_USER_AGENT'}) {
+ require CGI::Carp;
+ # FIXME for future reference, CGI::Carp doc says
+ # "Note that fatalsToBrowser does not work with mod_perl version 2.0 and higher."
+ import CGI::Carp qw(fatalsToBrowser);
+ sub handle_errors {
+ my $msg = shift;
+ my $debug_level;
+ eval {C4::Context->dbh();};
+ if ($@){
+ $debug_level = 1;
+ }
+ else {
+ $debug_level = C4::Context->preference("DebugLevel");
+ }
+
+ print q(
+
+
Koha Error
+
+ );
+ if ($debug_level eq "2"){
+ # debug 2 , print extra info too.
+ my %versions = get_versions();
+
+ # a little example table with various version info";
+ print "
+ Koha error
+ The following fatal error has occurred:
+ $msg
+
+ Apache | $versions{apacheVersion} |
+ Koha | $versions{kohaVersion} |
+ Koha DB | $versions{kohaDbVersion} |
+ MySQL | $versions{mysqlVersion} |
+ OS | $versions{osVersion} |
+ Perl | $versions{perlVersion} |
+
";
+
+ } elsif ($debug_level eq "1"){
+ print "
+ Koha error
+ The following fatal error has occurred:
+ $msg
";
+ } else {
+ print "production mode - trapped fatal error
";
+ }
+ print "";
+ }
+ CGI::Carp::set_message(\&handle_errors);
+ ## give a stack backtrace if KOHA_BACKTRACES is set
+ ## can't rely on DebugLevel for this, as we're not yet connected
+ if ($ENV{KOHA_BACKTRACES}) {
+ $main::SIG{__DIE__} = \&CGI::Carp::confess;
+ }
+ } # else there is no browser to send fatals to!
+ $VERSION = '3.00.00.036';
+}
+
use DBI;
+use ZOOM;
+use XML::Simple;
use C4::Boolean;
-
-use vars qw($VERSION $AUTOLOAD),
- qw($context),
- qw(@context_stack);
-
-$VERSION = do { my @v = '$Revision$' =~ /\d+/g;
- shift(@v) . "." . join("_", map {sprintf "%03d", $_ } @v); };
+use C4::Debug;
+use POSIX ();
=head1 NAME
@@ -37,17 +96,23 @@ C4::Context - Maintain and manipulate the context of a Koha script
use C4::Context;
- use C4::Context("/path/to/koha.conf");
+ use C4::Context("/path/to/koha-conf.xml");
$config_value = C4::Context->config("config_variable");
+
+ $koha_preference = C4::Context->preference("preference");
+
$db_handle = C4::Context->dbh;
+
+ $Zconn = C4::Context->Zconn;
+
$stopwordhash = C4::Context->stopwords;
=head1 DESCRIPTION
When a Koha script runs, it makes use of a certain number of things:
-configuration settings in F, a connection to the Koha
-database, and so forth. These things make up the I in which
+configuration settings in F, a connection to the Koha
+databases, and so forth. These things make up the I in which
the script runs.
This module takes care of setting up the context for a script:
@@ -67,7 +132,7 @@ different contexts to search both databases. Such scripts should use
the C<&set_context> and C<&restore_context> functions, below.
By default, C4::Context reads the configuration from
-F. This may be overridden by setting the C<$KOHA_CONF>
+F. This may be overridden by setting the C<$KOHA_CONF>
environment variable to the pathname of a configuration file to use.
=head1 METHODS
@@ -81,121 +146,138 @@ environment variable to the pathname of a configuration file to use.
# reference-to-hash with the following fields:
#
# config
-# A reference-to-hash whose keys and values are the
-# configuration variables and values specified in the config
-# file (/etc/koha.conf).
+# A reference-to-hash whose keys and values are the
+# configuration variables and values specified in the config
+# file (/etc/koha/koha-conf.xml).
# dbh
-# A handle to the appropriate database for this context.
+# A handle to the appropriate database for this context.
# dbh_stack
-# Used by &set_dbh and &restore_dbh to hold other database
-# handles for this context.
+# Used by &set_dbh and &restore_dbh to hold other database
+# handles for this context.
# Zconn
-# A connection object for the Zebra server
+# A connection object for the Zebra server
-use constant CONFIG_FNAME => "/etc/koha.conf";
- # Default config file, if none is specified
+# Koha's main configuration file koha-conf.xml
+# is searched for according to this priority list:
+#
+# 1. Path supplied via use C4::Context '/path/to/koha-conf.xml'
+# 2. Path supplied in KOHA_CONF environment variable.
+# 3. Path supplied in INSTALLED_CONFIG_FNAME, as long
+# as value has changed from its default of
+# '__KOHA_CONF_DIR__/koha-conf.xml', as happens
+# when Koha is installed in 'standard' or 'single'
+# mode.
+# 4. Path supplied in CONFIG_FNAME.
+#
+# The first entry that refers to a readable file is used.
-$context = undef; # Initially, no context is set
-@context_stack = (); # Initially, no saved contexts
+use constant CONFIG_FNAME => "/etc/koha/koha-conf.xml";
+ # Default config file, if none is specified
+
+my $INSTALLED_CONFIG_FNAME = '__KOHA_CONF_DIR__/koha-conf.xml';
+ # path to config file set by installer
+ # __KOHA_CONF_DIR__ is set by rewrite-confg.PL
+ # when Koha is installed in 'standard' or 'single'
+ # mode. If Koha was installed in 'dev' mode,
+ # __KOHA_CONF_DIR__ is *not* rewritten; instead
+ # developers should set the KOHA_CONF environment variable
-# read_config_file
-# Reads the specified Koha config file. Returns a reference-to-hash
-# whose keys are the configuration variables, and whose values are the
-# configuration values (duh).
-# Returns undef in case of error.
-#
-# Revision History:
-# 2004-08-10 A. Tarallo: Added code that checks if a variable is already
-# assigned and prints a message, otherwise create a new entry in the hash to
-# be returned.
-# Also added code that complaints if finds a line that isn't a variable
-# assignmet and skips the line.
-# Added a quick hack that makes the translation between the db_schema
-# and the DBI driver for that schema.
-#
-sub read_config_file
-{
- my $fname = shift; # Config file to read
- my $retval = {}; # Return value: ref-to-hash holding the
- # configuration
-
- open (CONF, $fname) or return undef;
-
- while ()
- {
- my $var; # Variable name
- my $value; # Variable value
-
- chomp;
- s/#.*//; # Strip comments
- next if /^\s*$/; # Ignore blank lines
-
- # Look for a line of the form
- # var = value
- if (!/^\s*(\w+)\s*=\s*(.*?)\s*$/)
- {
- print STDERR
- "$_ isn't a variable assignment, skipping it";
- next;
- }
+$context = undef; # Initially, no context is set
+@context_stack = (); # Initially, no saved contexts
- # Found a variable assignment
- if ( exists $retval->{$1} )
- {
- print STDERR "$var was already defined, ignoring\n";
- }else{
- # Quick hack for allowing databases name in full text
- if ( $1 eq "db_scheme" )
- {
- $value = db_scheme2dbi($2);
- }else {
- $value = $2;
- }
- $retval->{$1} = $value;
- }
- }
- close CONF;
- return $retval;
+=item KOHAVERSION
+ returns the kohaversion stored in kohaversion.pl file
+
+=cut
+
+sub KOHAVERSION {
+ my $cgidir = C4::Context->intranetdir;
+
+ # Apparently the GIT code does not run out of a CGI-BIN subdirectory
+ # but distribution code does? (Stan, 1jan08)
+ if(-d $cgidir . "/cgi-bin"){
+ my $cgidir .= "/cgi-bin";
+ }
+
+ do $cgidir."/kohaversion.pl" || die "NO $cgidir/kohaversion.pl";
+ return kohaversion();
+}
+=item read_config_file
+
+=over 4
+
+Reads the specified Koha config file.
+
+Returns an object containing the configuration variables. The object's
+structure is a bit complex to the uninitiated ... take a look at the
+koha-conf.xml file as well as the XML::Simple documentation for details. Or,
+here are a few examples that may give you what you need:
+
+The simple elements nested within the element:
+
+ my $pass = $koha->{'config'}->{'pass'};
+
+The elements:
+
+ my $listen = $koha->{'listen'}->{'biblioserver'}->{'content'};
+
+The elements nested within the element:
+
+ my $ccl2rpn = $koha->{'server'}->{'biblioserver'}->{'cql2rpn'};
+
+Returns undef in case of error.
+
+=back
+
+=cut
+
+sub read_config_file { # Pass argument naming config file to read
+ my $koha = XMLin(shift, keyattr => ['id'], forcearray => ['listen', 'server', 'serverinfo']);
+ return $koha; # Return value: ref-to-hash holding the configuration
}
# db_scheme2dbi
# Translates the full text name of a database into de appropiate dbi name
#
-sub db_scheme2dbi
-{
- my $name = shift;
+sub db_scheme2dbi {
+ my $name = shift;
- for ($name) {
+ for ($name) {
# FIXME - Should have other databases.
- if (/mysql/i) { return("mysql"); }
- if (/Postgres|Pg|PostgresSQL/) { return("Pg"); }
- if (/oracle/i) { return("Oracle"); }
- }
- return undef; # Just in case
+ if (/mysql/i) { return("mysql"); }
+ if (/Postgres|Pg|PostgresSQL/) { return("Pg"); }
+ if (/oracle/i) { return("Oracle"); }
+ }
+ return undef; # Just in case
}
-sub import
-{
- my $package = shift;
- my $conf_fname = shift; # Config file name
- my $context;
+sub import {
+ # Create the default context ($C4::Context::Context)
+ # the first time the module is called
+ # (a config file can be optionaly passed)
- # Create a new context from the given config file name, if
- # any, then set it as the current context.
- $context = new C4::Context($conf_fname);
- return undef if !defined($context);
- $context->set_context;
+ # default context allready exists?
+ return if $context;
+
+ # no ? so load it!
+ my ($pkg,$config_file) = @_ ;
+ my $new_ctx = __PACKAGE__->new($config_file);
+ return unless $new_ctx;
+
+ # if successfully loaded, use it by default
+ $new_ctx->set_context;
+ 1;
}
=item new
$context = new C4::Context;
- $context = new C4::Context("/path/to/koha.conf");
+ $context = new C4::Context("/path/to/koha-conf.xml");
Allocates a new context. Initializes the context from the specified
file, which defaults to either the file given by the C<$KOHA_CONF>
-environment variable, or F.
+environment variable, or F.
C<&new> does not set this context as the new default context; for
that, use C<&set_context>.
@@ -205,39 +287,49 @@ that, use C<&set_context>.
#'
# Revision History:
# 2004-08-10 A. Tarallo: Added check if the conf file is not empty
-sub new
-{
- my $class = shift;
- my $conf_fname = shift; # Config file to load
- my $self = {};
-
- # check that the specified config file exists and is not empty
- undef $conf_fname unless
- (defined $conf_fname && -e $conf_fname && -s $conf_fname);
- # Figure out a good config file to load if none was specified.
- if (!defined($conf_fname))
- {
- # If the $KOHA_CONF environment variable is set, use
- # that. Otherwise, use the built-in default.
- $conf_fname = $ENV{"KOHA_CONF"} || CONFIG_FNAME;
- }
- $self->{"config_file"} = $conf_fname;
-
- # Load the desired config file.
- $self->{"config"} = &read_config_file($conf_fname);
- warn "read_config_file($conf_fname) returned undef" if !defined($self->{"config"});
- return undef if !defined($self->{"config"});
-
- $self->{"dbh"} = undef; # Database handle
- $self->{"Zconn"} = undef; # Zebra Connection
- $self->{"Zconnauth"} = undef; # Zebra Connection for updating
- $self->{"stopwords"} = undef; # stopwords list
- $self->{"marcfromkohafield"} = undef; # the hash with relations between koha table fields and MARC field/subfield
- $self->{"userenv"} = undef; # User env
- $self->{"activeuser"} = undef; # current active user
-
- bless $self, $class;
- return $self;
+sub new {
+ my $class = shift;
+ my $conf_fname = shift; # Config file to load
+ my $self = {};
+
+ # check that the specified config file exists and is not empty
+ undef $conf_fname unless
+ (defined $conf_fname && -s $conf_fname);
+ # Figure out a good config file to load if none was specified.
+ if (!defined($conf_fname))
+ {
+ # If the $KOHA_CONF environment variable is set, use
+ # that. Otherwise, use the built-in default.
+ if (exists $ENV{"KOHA_CONF"} and $ENV{'KOHA_CONF'} and -s $ENV{"KOHA_CONF"}) {
+ $conf_fname = $ENV{"KOHA_CONF"};
+ } elsif ($INSTALLED_CONFIG_FNAME !~ /__KOHA_CONF_DIR/ and -s $INSTALLED_CONFIG_FNAME) {
+ # NOTE: be careful -- don't change __KOHA_CONF_DIR in the above
+ # regex to anything else -- don't want installer to rewrite it
+ $conf_fname = $INSTALLED_CONFIG_FNAME;
+ } elsif (-s CONFIG_FNAME) {
+ $conf_fname = CONFIG_FNAME;
+ } else {
+ warn "unable to locate Koha configuration file koha-conf.xml";
+ return undef;
+ }
+ }
+ # Load the desired config file.
+ $self = read_config_file($conf_fname);
+ $self->{"config_file"} = $conf_fname;
+
+ warn "read_config_file($conf_fname) returned undef" if !defined($self->{"config"});
+ return undef if !defined($self->{"config"});
+
+ $self->{"dbh"} = undef; # Database handle
+ $self->{"Zconn"} = undef; # Zebra Connections
+ $self->{"stopwords"} = undef; # stopwords list
+ $self->{"marcfromkohafield"} = undef; # the hash with relations between koha table fields and MARC field/subfield
+ $self->{"userenv"} = undef; # User env
+ $self->{"activeuser"} = undef; # current active user
+ $self->{"shelves"} = undef;
+
+ bless $self, $class;
+ return $self;
}
=item set_context
@@ -260,32 +352,32 @@ operations. To restore the previous context, use C<&restore_context>.
#'
sub set_context
{
- my $self = shift;
- my $new_context; # The context to set
-
- # Figure out whether this is a class or instance method call.
- #
- # We're going to make the assumption that control got here
- # through valid means, i.e., that the caller used an instance
- # or class method call, and that control got here through the
- # usual inheritance mechanisms. The caller can, of course,
- # break this assumption by playing silly buggers, but that's
- # harder to do than doing it properly, and harder to check
- # for.
- if (ref($self) eq "")
- {
- # Class method. The new context is the next argument.
- $new_context = shift;
- } else {
- # Instance method. The new context is $self.
- $new_context = $self;
- }
-
- # Save the old context, if any, on the stack
- push @context_stack, $context if defined($context);
-
- # Set the new context
- $context = $new_context;
+ my $self = shift;
+ my $new_context; # The context to set
+
+ # Figure out whether this is a class or instance method call.
+ #
+ # We're going to make the assumption that control got here
+ # through valid means, i.e., that the caller used an instance
+ # or class method call, and that control got here through the
+ # usual inheritance mechanisms. The caller can, of course,
+ # break this assumption by playing silly buggers, but that's
+ # harder to do than doing it properly, and harder to check
+ # for.
+ if (ref($self) eq "")
+ {
+ # Class method. The new context is the next argument.
+ $new_context = shift;
+ } else {
+ # Instance method. The new context is $self.
+ $new_context = $self;
+ }
+
+ # Save the old context, if any, on the stack
+ push @context_stack, $context if defined($context);
+
+ # Set the new context
+ $context = $new_context;
}
=item restore_context
@@ -299,19 +391,19 @@ Restores the context set by C<&set_context>.
#'
sub restore_context
{
- my $self = shift;
+ my $self = shift;
- if ($#context_stack < 0)
- {
- # Stack underflow.
- die "Context stack underflow";
- }
+ if ($#context_stack < 0)
+ {
+ # Stack underflow.
+ die "Context stack underflow";
+ }
- # Pop the old context and set it.
- $context = pop @context_stack;
+ # Pop the old context and set it.
+ $context = pop @context_stack;
- # FIXME - Should this return something, like maybe the context
- # that was current when this was called?
+ # FIXME - Should this return something, like maybe the context
+ # that was current when this was called?
}
=item config
@@ -329,59 +421,90 @@ Cnew> will not return it.
=cut
-#'
-sub config
-{
- my $self = shift;
- my $var = shift; # The config variable to return
-
- return undef if !defined($context->{"config"});
- # Presumably $self->{config} might be
- # undefined if the config file given to &new
- # didn't exist, and the caller didn't bother
- # to check the return value.
+sub _common_config ($$) {
+ my $var = shift;
+ my $term = shift;
+ return undef if !defined($context->{$term});
+ # Presumably $self->{$term} might be
+ # undefined if the config file given to &new
+ # didn't exist, and the caller didn't bother
+ # to check the return value.
+
+ # Return the value of the requested config variable
+ return $context->{$term}->{$var};
+}
- # Return the value of the requested config variable
- return $context->{"config"}{$var};
+sub config {
+ return _common_config($_[1],'config');
+}
+sub zebraconfig {
+ return _common_config($_[1],'server');
+}
+sub ModZebrations {
+ return _common_config($_[1],'serverinfo');
}
=item preference
- $sys_preference = C4::Context->preference("some_variable");
+ $sys_preference = C4::Context->preference('some_variable');
Looks up the value of the given system preference in the
systempreferences table of the Koha database, and returns it. If the
-variable is not set, or in case of error, returns the undefined value.
+variable is not set or does not exist, undef is returned.
+
+In case of an error, this may return 0.
+
+Note: It is impossible to tell the difference between system
+preferences which do not exist, and those whose values are set to NULL
+with this method.
=cut
-#'
-# FIXME - The preferences aren't likely to change over the lifetime of
-# the script (and things might break if they did change), so perhaps
-# this function should cache the results it finds.
-sub preference
-{
- my $self = shift;
- my $var = shift; # The system preference to return
- my $retval; # Return value
- my $dbh = C4::Context->dbh; # Database handle
- my $sth; # Database query handle
-
- # Look up systempreferences.variable==$var
- $retval = $dbh->selectrow_array(<dbh or return 0;
+
+ # Look up systempreferences.variable==$var
+ my $sql = <<'END_SQL';
+ SELECT value
+ FROM systempreferences
+ WHERE variable=?
+ LIMIT 1
+END_SQL
+ $sysprefs{$var} = $dbh->selectrow_array( $sql, {}, $var );
+ return $sysprefs{$var};
}
sub boolean_preference ($) {
- my $self = shift;
- my $var = shift; # The system preference to return
- my $it = preference($self, $var);
- return defined($it)? C4::Boolean::true_p($it): undef;
+ my $self = shift;
+ my $var = shift; # The system preference to return
+ my $it = preference($self, $var);
+ return defined($it)? C4::Boolean::true_p($it): undef;
+}
+
+=item clear_syspref_cache
+
+ C4::Context->clear_syspref_cache();
+
+ cleans the internal cache of sysprefs. Please call this method if
+ you update the systempreferences table. Otherwise, your new changes
+ will not be seen by this process.
+
+=cut
+
+sub clear_syspref_cache {
+ %sysprefs = ();
}
# AUTOLOAD
@@ -395,11 +518,11 @@ sub boolean_preference ($) {
# encourage people to use it.
sub AUTOLOAD
{
- my $self = shift;
+ my $self = shift;
- $AUTOLOAD =~ s/.*:://; # Chop off the package name,
- # leaving only the function name.
- return $self->config($AUTOLOAD);
+ $AUTOLOAD =~ s/.*:://; # Chop off the package name,
+ # leaving only the function name.
+ return $self->config($AUTOLOAD);
}
=item Zconn
@@ -410,109 +533,151 @@ Returns a connection to the Zebra database for the current
context. If no connection has yet been made, this method
creates one and connects.
+C<$self>
+
+C<$server> one of the servers defined in the koha-conf.xml file
+
+C<$async> whether this is a asynchronous connection
+
+C<$auth> whether this connection has rw access (1) or just r access (0 or NULL)
+
+
=cut
sub Zconn {
- my $self = shift;
- my $rs;
- my $Zconn;
- if (defined($context->{"Zconn"})) {
- $Zconn = $context->{"Zconn"};
-# $rs=$Zconn->search_pqf('@attr 1=4 mineral');
-# if ($Zconn->errcode() != 0) {
-# $context->{"Zconn"} = &new_Zconn();
-# return $context->{"Zconn"};
-# }
- return $context->{"Zconn"};
- } else {
- $context->{"Zconn"} = &new_Zconn();
- return $context->{"Zconn"};
- }
+ my $self=shift;
+ my $server=shift;
+ my $async=shift;
+ my $auth=shift;
+ my $piggyback=shift;
+ my $syntax=shift;
+ if ( defined($context->{"Zconn"}->{$server}) && (0 == $context->{"Zconn"}->{$server}->errcode()) ) {
+ return $context->{"Zconn"}->{$server};
+ # No connection object or it died. Create one.
+ }else {
+ # release resources if we're closing a connection and making a new one
+ # FIXME: this needs to be smarter -- an error due to a malformed query or
+ # a missing index does not necessarily require us to close the connection
+ # and make a new one, particularly for a batch job. However, at
+ # first glance it does not look like there's a way to easily check
+ # the basic health of a ZOOM::Connection
+ $context->{"Zconn"}->{$server}->destroy() if defined($context->{"Zconn"}->{$server});
+
+ $context->{"Zconn"}->{$server} = &_new_Zconn($server,$async,$auth,$piggyback,$syntax);
+ return $context->{"Zconn"}->{$server};
+ }
}
-=item Zconnauth
-Returns a connection to the Zebradb with write privileges.Requires setting from etc/koha.conf
-zebradb,zebraport,zebrauser,zebrapass
+=item _new_Zconn
-=cut
+$context->{"Zconn"} = &_new_Zconn($server,$async);
-sub Zconnauth {
- my $self = shift;
- my $Zconnauth;
- if (defined($context->{"Zconnauth"})) {
- $Zconnauth = $context->{"Zconnauth"};
- return $context->{"Zconnauth"};
- } else {
- $context->{"Zconnauth"} = &new_Zconnauth();
- return $context->{"Zconnauth"};
- }
-}
+Internal function. Creates a new database connection from the data given in the current context and returns it.
-=item new_Zconn
+C<$server> one of the servers defined in the koha-conf.xml file
-Internal helper function. creates a new database connection from
-the data given in the current context and returns it.
+C<$async> whether this is a asynchronous connection
-=cut
+C<$auth> whether this connection has rw access (1) or just r access (0 or NULL)
-sub new_Zconn {
- use ZOOM;
- my $Zconn;
- eval {
- $Zconn = new ZOOM::Connection(C4::Context->config("zebradb"));
- };
- if ($@){
- warn "Error ", $@->code(), ": ", $@->message(), "\n";
- die "Fatal error, cant connect to z3950 server";
- }
- $Zconn->option(cqlfile => C4::Context->config("intranetdir")."/zebra/pqf.properties");
- $Zconn->option(preferredRecordSyntax => "xml");
- return $Zconn;
-}
+=cut
+sub _new_Zconn {
+ my ($server,$async,$auth,$piggyback,$syntax) = @_;
+
+ my $tried=0; # first attempt
+ my $Zconn; # connection object
+ $server = "biblioserver" unless $server;
+ $syntax = "usmarc" unless $syntax;
+
+ my $host = $context->{'listen'}->{$server}->{'content'};
+ my $servername = $context->{"config"}->{$server};
+ my $user = $context->{"serverinfo"}->{$server}->{"user"};
+ my $password = $context->{"serverinfo"}->{$server}->{"password"};
+ $auth = 1 if($user && $password);
+ retry:
+ eval {
+ # set options
+ my $o = new ZOOM::Options();
+ $o->option(user=>$user) if $auth;
+ $o->option(password=>$password) if $auth;
+ $o->option(async => 1) if $async;
+ $o->option(count => $piggyback) if $piggyback;
+ $o->option(cqlfile=> $context->{"server"}->{$server}->{"cql2rpn"});
+ $o->option(cclfile=> $context->{"serverinfo"}->{$server}->{"ccl2rpn"});
+ $o->option(preferredRecordSyntax => $syntax);
+ $o->option(elementSetName => "F"); # F for 'full' as opposed to B for 'brief'
+ $o->option(databaseName => ($servername?$servername:"biblios"));
+
+ # create a new connection object
+ $Zconn= create ZOOM::Connection($o);
+
+ # forge to server
+ $Zconn->connect($host, 0);
+
+ # check for errors and warn
+ if ($Zconn->errcode() !=0) {
+ warn "something wrong with the connection: ". $Zconn->errmsg();
+ }
-## Zebra handler with write permission
-sub new_Zconnauth {
-use ZOOM;
-my $Zconnauth;
-my $option1=new ZOOM::Options();
-$option1->option(user=>$context->{"config"}{"zebrauser"});
-my $option2=new ZOOM::Options();
-$option2->option(password=>$context->{"config"}{"zebrapass"});
-my $opts = new ZOOM::Options($option1,$option2);
-
- $Zconnauth=create ZOOM::Connection($opts);
-
- eval {
- $Zconnauth->connect($context->{"config"}{"zebradb"},$context->{"config"}{"zebraport"});
- };
- if ($@){
- warn "Error-auth ", $@->code(), ": ", $@->message(), "\n";
- die "Fatal error, cant connect to z3950 server";
-
- }
- $Zconnauth->option(preferredRecordSyntax => "XML");
- $Zconnauth->option(elementSetName=> "F");
- $Zconnauuth->option(cqlfile => C4::Context->config("intranetdir")."/zebra/pqf.properties");
- return $Zconnauth;
+ };
+# if ($@) {
+# # Koha manages the Zebra server -- this doesn't work currently for me because of permissions issues
+# # Also, I'm skeptical about whether it's the best approach
+# warn "problem with Zebra";
+# if ( C4::Context->preference("ManageZebra") ) {
+# if ($@->code==10000 && $tried==0) { ##No connection try restarting Zebra
+# $tried=1;
+# warn "trying to restart Zebra";
+# my $res=system("zebrasrv -f $ENV{'KOHA_CONF'} >/koha/log/zebra-error.log");
+# goto "retry";
+# } else {
+# warn "Error ", $@->code(), ": ", $@->message(), "\n";
+# $Zconn="error";
+# return $Zconn;
+# }
+# }
+# }
+ return $Zconn;
}
+
# _new_dbh
# Internal helper function (not a method!). This creates a new
# database connection from the data given in the current context, and
# returns it.
sub _new_dbh
{
- my $db_driver = $context->{"config"}{"db_scheme"} || "mysql";
- my $db_name = $context->{"config"}{"database"};
- my $db_host = $context->{"config"}{"hostname"};
- my $db_user = $context->{"config"}{"user"};
- my $db_passwd = $context->{"config"}{"pass"};
- my $dbh= DBI->connect("DBI:$db_driver:$db_name:$db_host",
- $db_user, $db_passwd);
- # Koha 3.0 is utf-8, so force utf8 communication between mySQL and koha, whatever the mysql default config.
- # this is better than modifying my.cnf (and forcing all communications to be in utf8)
- $dbh->do("set NAMES 'utf8'");
- return $dbh;
+
+ ## $context
+ ## correct name for db_schme
+ my $db_driver;
+ if ($context->config("db_scheme")){
+ $db_driver=db_scheme2dbi($context->config("db_scheme"));
+ }else{
+ $db_driver="mysql";
+ }
+
+ my $db_name = $context->config("database");
+ my $db_host = $context->config("hostname");
+ my $db_port = $context->config("port") || '';
+ my $db_user = $context->config("user");
+ my $db_passwd = $context->config("pass");
+ # MJR added or die here, as we can't work without dbh
+ my $dbh= DBI->connect("DBI:$db_driver:dbname=$db_name;host=$db_host;port=$db_port",
+ $db_user, $db_passwd) or die $DBI::errstr;
+ my $tz = $ENV{TZ};
+ if ( $db_driver eq 'mysql' ) {
+ # Koha 3.0 is utf-8, so force utf8 communication between mySQL and koha, whatever the mysql default config.
+ # this is better than modifying my.cnf (and forcing all communications to be in utf8)
+ $dbh->{'mysql_enable_utf8'}=1; #enable
+ $dbh->do("set NAMES 'utf8'");
+ ($tz) and $dbh->do(qq(SET time_zone = "$tz"));
+ }
+ elsif ( $db_driver eq 'Pg' ) {
+ $dbh->do( "set client_encoding = 'UTF8';" );
+ ($tz) and $dbh->do(qq(SET TIME ZONE = "$tz"));
+ }
+ return $dbh;
}
=item dbh
@@ -533,18 +698,17 @@ possibly C<&set_dbh>.
#'
sub dbh
{
- my $self = shift;
- my $sth;
+ my $self = shift;
+ my $sth;
- if (defined($context->{"dbh"})) {
- $sth=$context->{"dbh"}->prepare("select 1");
- return $context->{"dbh"} if (defined($sth->execute));
- }
+ if (defined($context->{"dbh"}) && $context->{"dbh"}->ping()) {
+ return $context->{"dbh"};
+ }
- # No database handle or it died . Create one.
- $context->{"dbh"} = &_new_dbh();
+ # No database handle or it died . Create one.
+ $context->{"dbh"} = &_new_dbh();
- return $context->{"dbh"};
+ return $context->{"dbh"};
}
=item new_dbh
@@ -563,9 +727,9 @@ connect to so that the caller doesn't have to know.
#'
sub new_dbh
{
- my $self = shift;
+ my $self = shift;
- return &_new_dbh();
+ return &_new_dbh();
}
=item set_dbh
@@ -588,15 +752,15 @@ C<$my_dbh> is assumed to be a good database handle.
#'
sub set_dbh
{
- my $self = shift;
- my $new_dbh = shift;
-
- # Save the current database handle on the handle stack.
- # We assume that $new_dbh is all good: if the caller wants to
- # screw himself by passing an invalid handle, that's fine by
- # us.
- push @{$context->{"dbh_stack"}}, $context->{"dbh"};
- $context->{"dbh"} = $new_dbh;
+ my $self = shift;
+ my $new_dbh = shift;
+
+ # Save the current database handle on the handle stack.
+ # We assume that $new_dbh is all good: if the caller wants to
+ # screw himself by passing an invalid handle, that's fine by
+ # us.
+ push @{$context->{"dbh_stack"}}, $context->{"dbh"};
+ $context->{"dbh"} = $new_dbh;
}
=item restore_dbh
@@ -611,19 +775,19 @@ Cset_dbh>.
#'
sub restore_dbh
{
- my $self = shift;
+ my $self = shift;
- if ($#{$context->{"dbh_stack"}} < 0)
- {
- # Stack underflow
- die "DBH stack underflow";
- }
+ if ($#{$context->{"dbh_stack"}} < 0)
+ {
+ # Stack underflow
+ die "DBH stack underflow";
+ }
- # Pop the old database handle and set it.
- $context->{"dbh"} = pop @{$context->{"dbh_stack"}};
+ # Pop the old database handle and set it.
+ $context->{"dbh"} = pop @{$context->{"dbh_stack"}};
- # FIXME - If it is determined that restore_context should
- # return something, then this function should, too.
+ # FIXME - If it is determined that restore_context should
+ # return something, then this function should, too.
}
=item marcfromkohafield
@@ -640,15 +804,15 @@ Cmarcfromkohafield> twice, you will get the same hash without
#'
sub marcfromkohafield
{
- my $retval = {};
+ my $retval = {};
- # If the hash already exists, return it.
- return $context->{"marcfromkohafield"} if defined($context->{"marcfromkohafield"});
+ # If the hash already exists, return it.
+ return $context->{"marcfromkohafield"} if defined($context->{"marcfromkohafield"});
- # No hash. Create one.
- $context->{"marcfromkohafield"} = &_new_marcfromkohafield();
+ # No hash. Create one.
+ $context->{"marcfromkohafield"} = &_new_marcfromkohafield();
- return $context->{"marcfromkohafield"};
+ return $context->{"marcfromkohafield"};
}
# _new_marcfromkohafield
@@ -656,15 +820,15 @@ sub marcfromkohafield
# hash with stopwords
sub _new_marcfromkohafield
{
- my $dbh = C4::Context->dbh;
- my $marcfromkohafield;
- my $sth = $dbh->prepare("select frameworkcode,kohafield,tagfield,tagsubfield from marc_subfield_structure where kohafield > ''");
- $sth->execute;
- while (my ($frameworkcode,$kohafield,$tagfield,$tagsubfield) = $sth->fetchrow) {
- my $retval = {};
- $marcfromkohafield->{$frameworkcode}->{$kohafield} = [$tagfield,$tagsubfield];
- }
- return $marcfromkohafield;
+ my $dbh = C4::Context->dbh;
+ my $marcfromkohafield;
+ my $sth = $dbh->prepare("select frameworkcode,kohafield,tagfield,tagsubfield from marc_subfield_structure where kohafield > ''");
+ $sth->execute;
+ while (my ($frameworkcode,$kohafield,$tagfield,$tagsubfield) = $sth->fetchrow) {
+ my $retval = {};
+ $marcfromkohafield->{$frameworkcode}->{$kohafield} = [$tagfield,$tagsubfield];
+ }
+ return $marcfromkohafield;
}
=item stopwords
@@ -681,15 +845,15 @@ Cstopwords> twice, you will get the same hash without real DB
#'
sub stopwords
{
- my $retval = {};
+ my $retval = {};
- # If the hash already exists, return it.
- return $context->{"stopwords"} if defined($context->{"stopwords"});
+ # If the hash already exists, return it.
+ return $context->{"stopwords"} if defined($context->{"stopwords"});
- # No hash. Create one.
- $context->{"stopwords"} = &_new_stopwords();
+ # No hash. Create one.
+ $context->{"stopwords"} = &_new_stopwords();
- return $context->{"stopwords"};
+ return $context->{"stopwords"};
}
# _new_stopwords
@@ -697,74 +861,102 @@ sub stopwords
# hash with stopwords
sub _new_stopwords
{
- my $dbh = C4::Context->dbh;
- my $stopwordlist;
- my $sth = $dbh->prepare("select word from stopwords");
- $sth->execute;
- while (my $stopword = $sth->fetchrow_array) {
- my $retval = {};
- $stopwordlist->{$stopword} = uc($stopword);
- }
- $stopwordlist->{A} = "A" unless $stopwordlist;
- return $stopwordlist;
+ my $dbh = C4::Context->dbh;
+ my $stopwordlist;
+ my $sth = $dbh->prepare("select word from stopwords");
+ $sth->execute;
+ while (my $stopword = $sth->fetchrow_array) {
+ $stopwordlist->{$stopword} = uc($stopword);
+ }
+ $stopwordlist->{A} = "A" unless $stopwordlist;
+ return $stopwordlist;
}
=item userenv
C4::Context->userenv;
-Builds a hash for user environment variables.
+Retrieves a hash for user environment variables.
This hash shall be cached for future use: if you call
Cuserenv> twice, you will get the same hash without real DB access
-set_userenv is called in Auth.pm
-
=cut
#'
-sub userenv
-{
- my $var = $context->{"activeuser"};
- return $context->{"userenv"}->{$var} if (defined $context->{"userenv"}->{$var});
- return 0;
- warn "NO CONTEXT for $var";
+sub userenv {
+ my $var = $context->{"activeuser"};
+ return $context->{"userenv"}->{$var} if (defined $var and defined $context->{"userenv"}->{$var});
+ # insecure=1 management
+ if ($context->{"dbh"} && $context->preference('insecure')) {
+ my %insecure;
+ $insecure{flags} = '16382';
+ $insecure{branchname} ='Insecure';
+ $insecure{number} ='0';
+ $insecure{cardnumber} ='0';
+ $insecure{id} = 'insecure';
+ $insecure{branch} = 'INS';
+ $insecure{emailaddress} = 'test@mode.insecure.com';
+ return \%insecure;
+ } else {
+ return;
+ }
}
=item set_userenv
C4::Context->set_userenv($usernum, $userid, $usercnum, $userfirstname, $usersurname, $userbranch, $userflags, $emailaddress);
-Informs a hash for user environment variables.
-
-This hash shall be cached for future use: if you call
-Cuserenv> twice, you will get the same hash without real DB access
+Establish a hash of user environment variables.
set_userenv is called in Auth.pm
=cut
+
#'
-sub set_userenv{
- my ($usernum, $userid, $usercnum, $userfirstname, $usersurname, $userbranch, $userflags, $emailaddress)= @_;
- my $var=$context->{"activeuser"};
- my $cell = {
- "number" => $usernum,
- "id" => $userid,
- "cardnumber" => $usercnum,
-# "firstname" => $userfirstname,
-# "surname" => $usersurname,
-#possibly a law problem
- "branch" => $userbranch,
- "flags" => $userflags,
- "emailaddress" => $emailaddress,
- };
- $context->{userenv}->{$var} = $cell;
- return $cell;
+sub set_userenv {
+ my ($usernum, $userid, $usercnum, $userfirstname, $usersurname, $userbranch, $branchname, $userflags, $emailaddress, $branchprinter)= @_;
+ my $var=$context->{"activeuser"};
+ my $cell = {
+ "number" => $usernum,
+ "id" => $userid,
+ "cardnumber" => $usercnum,
+ "firstname" => $userfirstname,
+ "surname" => $usersurname,
+ #possibly a law problem
+ "branch" => $userbranch,
+ "branchname" => $branchname,
+ "flags" => $userflags,
+ "emailaddress" => $emailaddress,
+ "branchprinter" => $branchprinter
+ };
+ $context->{userenv}->{$var} = $cell;
+ return $cell;
+}
+
+sub set_shelves_userenv ($$) {
+ my ($type, $shelves) = @_ or return undef;
+ my $activeuser = $context->{activeuser} or return undef;
+ $context->{userenv}->{$activeuser}->{barshelves} = $shelves if $type eq 'bar';
+ $context->{userenv}->{$activeuser}->{pubshelves} = $shelves if $type eq 'pub';
+ $context->{userenv}->{$activeuser}->{totshelves} = $shelves if $type eq 'tot';
+}
+
+sub get_shelves_userenv () {
+ my $active;
+ unless ($active = $context->{userenv}->{$context->{activeuser}}) {
+ $debug and warn "get_shelves_userenv cannot retrieve context->{userenv}->{context->{activeuser}}";
+ return undef;
+ }
+ my $totshelves = $active->{totshelves} or undef;
+ my $pubshelves = $active->{pubshelves} or undef;
+ my $barshelves = $active->{barshelves} or undef;
+ return ($totshelves, $pubshelves, $barshelves);
}
=item _new_userenv
- C4::Context->_new_userenv($session);
+ C4::Context->_new_userenv($session); # FIXME: This calling style is wrong for what looks like an _internal function
Builds a hash for user environment variables.
@@ -778,9 +970,9 @@ _new_userenv is called in Auth.pm
#'
sub _new_userenv
{
- shift;
- my ($sessionID)= @_;
- $context->{"activeuser"}=$sessionID;
+ shift; # Useless except it compensates for bad calling style
+ my ($sessionID)= @_;
+ $context->{"activeuser"}=$sessionID;
}
=item _unset_userenv
@@ -790,15 +982,44 @@ sub _new_userenv
Destroys the hash for activeuser user environment variables.
=cut
+
#'
sub _unset_userenv
{
- my ($sessionID)= @_;
- undef $context->{"activeuser"} if ($context->{"activeuser"} eq $sessionID);
+ my ($sessionID)= @_;
+ undef $context->{"activeuser"} if ($context->{"activeuser"} eq $sessionID);
}
+=item get_versions
+
+ C4::Context->get_versions
+
+Gets various version info, for core Koha packages, Currently called from carp handle_errors() sub, to send to browser if 'DebugLevel' syspref is set to '2'.
+
+=cut
+
+#'
+
+# A little example sub to show more debugging info for CGI::Carp
+sub get_versions {
+ my %versions;
+ $versions{kohaVersion} = KOHAVERSION();
+ $versions{kohaDbVersion} = C4::Context->preference('version');
+ $versions{osVersion} = join(" ", POSIX::uname());
+ $versions{perlVersion} = $];
+ {
+ no warnings qw(exec); # suppress warnings if unable to find a program in $PATH
+ $versions{mysqlVersion} = `mysql -V`;
+ $versions{apacheVersion} = `httpd -v`;
+ $versions{apacheVersion} = `httpd2 -v` unless $versions{apacheVersion} ;
+ $versions{apacheVersion} = `apache2 -v` unless $versions{apacheVersion} ;
+ $versions{apacheVersion} = `/usr/sbin/apache2 -v` unless $versions{apacheVersion} ;
+ }
+ return %versions;
+}
+
1;
__END__
@@ -817,14 +1038,187 @@ Specifies the configuration file to read.
=head1 SEE ALSO
-DBI(3)
+XML::Simple
-=head1 AUTHOR
+=head1 AUTHORS
Andrew Arensburger
+Joshua Ferraro
+
=cut
-# $Log$
+
+# Revision 1.57 2007/05/22 09:13:55 tipaul
+# Bugfixes & improvements (various and minor) :
+# - updating templates to have tmpl_process3.pl running without any errors
+# - adding a drupal-like css for prog templates (with 3 small images)
+# - fixing some bugs in circulation & other scripts
+# - updating french translation
+# - fixing some typos in templates
+#
+# Revision 1.56 2007/04/23 15:21:17 tipaul
+# renaming currenttransfers to transferstoreceive
+#
+# Revision 1.55 2007/04/17 08:48:00 tipaul
+# circulation cleaning continued: bufixing
+#
+# Revision 1.54 2007/03/29 16:45:53 tipaul
+# Code cleaning of Biblio.pm (continued)
+#
+# All subs have be cleaned :
+# - removed useless
+# - merged some
+# - reordering Biblio.pm completly
+# - using only naming conventions
+#
+# Seems to have broken nothing, but it still has to be heavily tested.
+# Note that Biblio.pm is now much more efficient than previously & probably more reliable as well.
+#
+# Revision 1.53 2007/03/29 13:30:31 tipaul
+# Code cleaning :
+# == Biblio.pm cleaning (useless) ==
+# * some sub declaration dropped
+# * removed modbiblio sub
+# * removed moditem sub
+# * removed newitems. It was used only in finishrecieve. Replaced by a TransformKohaToMarc+AddItem, that is better.
+# * removed MARCkoha2marcItem
+# * removed MARCdelsubfield declaration
+# * removed MARCkoha2marcBiblio
+#
+# == Biblio.pm cleaning (naming conventions) ==
+# * MARCgettagslib renamed to GetMarcStructure
+# * MARCgetitems renamed to GetMarcItem
+# * MARCfind_frameworkcode renamed to GetFrameworkCode
+# * MARCmarc2koha renamed to TransformMarcToKoha
+# * MARChtml2marc renamed to TransformHtmlToMarc
+# * MARChtml2xml renamed to TranformeHtmlToXml
+# * zebraop renamed to ModZebra
+#
+# == MARC=OFF ==
+# * removing MARC=OFF related scripts (in cataloguing directory)
+# * removed checkitems (function related to MARC=off feature, that is completly broken in head. If someone want to reintroduce it, hard work coming...)
+# * removed getitemsbybiblioitem (used only by MARC=OFF scripts, that is removed as well)
+#
+# Revision 1.52 2007/03/16 01:25:08 kados
+# Using my precrash CVS copy I did the following:
+#
+# cvs -z3 -d:ext:kados@cvs.savannah.nongnu.org:/sources/koha co -P koha
+# find koha.precrash -type d -name "CVS" -exec rm -v {} \;
+# cp -r koha.precrash/* koha/
+# cd koha/
+# cvs commit
+#
+# This should in theory put us right back where we were before the crash
+#
+# Revision 1.52 2007/03/12 21:17:05 rych
+# add server, serverinfo as arrays from config
+#
+# Revision 1.51 2007/03/09 14:31:47 tipaul
+# rel_3_0 moved to HEAD
+#
+# Revision 1.43.2.10 2007/02/09 17:17:56 hdl
+# Managing a little better database absence.
+# (preventing from BIG 550)
+#
+# Revision 1.43.2.9 2006/12/20 16:50:48 tipaul
+# improving "insecure" management
+#
+# WARNING KADOS :
+# you told me that you had some libraries with insecure=ON (behind a firewall).
+# In this commit, I created a "fake" user when insecure=ON. It has a fake branch. You may find better to have the 1st branch in branch table instead of a fake one.
+#
+# Revision 1.43.2.8 2006/12/19 16:48:16 alaurin
+# reident programs, and adding branchcode value in reserves
+#
+# Revision 1.43.2.7 2006/12/06 21:55:38 hdl
+# Adding ModZebrations for servers to get serverinfos in Context.pm
+# Using this function in rebuild_zebra.pl
+#
+# Revision 1.43.2.6 2006/11/24 21:18:31 kados
+# very minor changes, no functional ones, just comments, etc.
+#
+# Revision 1.43.2.5 2006/10/30 13:24:16 toins
+# fix some minor POD error.
+#
+# Revision 1.43.2.4 2006/10/12 21:42:49 hdl
+# Managing multiple zebra connections
+#
+# Revision 1.43.2.3 2006/10/11 14:27:26 tipaul
+# removing a warning
+#
+# Revision 1.43.2.2 2006/10/10 15:28:16 hdl
+# BUG FIXING : using database name in Zconn if defined and not hard coded value
+#
+# Revision 1.43.2.1 2006/10/06 13:47:28 toins
+# Synch with dev_week.
+# /!\ WARNING :: Please now use the new version of koha.xml.
+#
+# Revision 1.18.2.5.2.14 2006/09/24 15:24:06 kados
+# remove Zebraauth routine, fold the functionality into Zconn
+# Zconn can now take several arguments ... this will probably
+# change soon as I'm not completely happy with the readability
+# of the current format ... see the POD for details.
+#
+# cleaning up Biblio.pm, removing unnecessary routines.
+#
+# DeleteBiblio - used to delete a biblio from zebra and koha tables
+# -- checks to make sure there are no existing issues
+# -- saves backups of biblio,biblioitems,items in deleted* tables
+# -- does commit operation
+#
+# getRecord - used to retrieve one record from zebra in piggyback mode using biblionumber
+# brought back z3950_extended_services routine
+#
+# Lots of modifications to Context.pm, you can now store user and pass info for
+# multiple servers (for federated searching) using the element.
+# I'll commit my koha.xml to demonstrate this or you can refer to the POD in
+# Context.pm (which I also expanded on).
+#
+# Revision 1.18.2.5.2.13 2006/08/10 02:10:21 kados
+# Turned warnings on, and running a search turned up lots of warnings.
+# Cleaned up those ...
+#
+# removed getitemtypes from Koha.pm (one in Search.pm looks newer)
+# removed itemcount from Biblio.pm
+#
+# made some local subs local with a _ prefix (as they were redefined
+# elsewhere)
+#
+# Add two new search subs to Search.pm the start of a new search API
+# that's a bit more scalable
+#
+# Revision 1.18.2.5.2.10 2006/07/21 17:50:51 kados
+# moving the *.properties files to intranetdir/etc dir
+#
+# Revision 1.18.2.5.2.9 2006/07/17 08:05:20 tipaul
+# there was a hardcoded link to /koha/etc/ I replaced it with intranetdir config value
+#
+# Revision 1.18.2.5.2.8 2006/07/11 12:20:37 kados
+# adding ccl and cql files ... Tumer, if you want to fit these into the
+# config file by all means do.
+#
+# Revision 1.18.2.5.2.7 2006/06/04 22:50:33 tgarip1957
+# We do not hard code cql2rpn conversion file in context.pm our koha.xml configuration file already describes the path for this file.
+# At cql searching we use method CQL not CQL2RPN as the cql2rpn conversion file is defined at server level
+#
+# Revision 1.18.2.5.2.6 2006/06/02 23:11:24 kados
+# Committing my working dev_week. It's been tested only with
+# searching, and there's quite a lot of config stuff to set up
+# beforehand. As things get closer to a release, we'll be making
+# some scripts to do it for us
+#
+# Revision 1.18.2.5.2.5 2006/05/28 18:49:12 tgarip1957
+# This is an unusual commit. The main purpose is a working model of Zebra on a modified rel2_2.
+# Any questions regarding these commits should be asked to Joshua Ferraro unless you are Joshua whom I'll report to
+#
+# Revision 1.36 2006/05/09 13:28:08 tipaul
+# adding the branchname and the librarian name in every page :
+# - modified userenv to add branchname
+# - modifier menus.inc to have the librarian name & userenv displayed on every page. they are in a librarian_information div.
+#
+# Revision 1.35 2006/04/13 08:40:11 plg
+# bug fixed: typo on Zconnauth name
+#
# Revision 1.34 2006/04/10 21:40:23 tgarip1957
# A new handler defined for zebra Zconnauth with read/write permission. Zconnauth should only be called in biblio.pm where write operations are. Use of this handler will break things unless koha.conf contains new variables:
# zebradb=localhost