history.txt removing a useless tab
[koha.git] / C4 / Context.pm
1 package C4::Context;
2 # Copyright 2002 Katipo Communications
3 #
4 # This file is part of Koha.
5 #
6 # Koha is free software; you can redistribute it and/or modify it under the
7 # terms of the GNU General Public License as published by the Free Software
8 # Foundation; either version 2 of the License, or (at your option) any later
9 # version.
10 #
11 # Koha is distributed in the hope that it will be useful, but WITHOUT ANY
12 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License along
16 # with Koha; if not, write to the Free Software Foundation, Inc.,
17 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18
19 use strict;
20 use warnings;
21 use vars qw($VERSION $AUTOLOAD $context @context_stack $servers $memcached $ismemcached);
22
23 BEGIN {
24         if ($ENV{'HTTP_USER_AGENT'})    {
25                 require CGI::Carp;
26         # FIXME for future reference, CGI::Carp doc says
27         #  "Note that fatalsToBrowser does not work with mod_perl version 2.0 and higher."
28                 import CGI::Carp qw(fatalsToBrowser);
29                         sub handle_errors {
30                             my $msg = shift;
31                             my $debug_level;
32                             eval {C4::Context->dbh();};
33                             if ($@){
34                                 $debug_level = 1;
35                             } 
36                             else {
37                                 $debug_level =  C4::Context->preference("DebugLevel");
38                             }
39
40                 print q(<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
41                             "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
42                        <html lang="en" xml:lang="en"  xmlns="http://www.w3.org/1999/xhtml">
43                        <head><title>Koha Error</title></head>
44                        <body>
45                 );
46                                 if ($debug_level eq "2"){
47                                         # debug 2 , print extra info too.
48                                         my %versions = get_versions();
49
50                 # a little example table with various version info";
51                                         print "
52                                                 <h1>Koha error</h1>
53                                                 <p>The following fatal error has occurred:</p> 
54                         <pre><code>$msg</code></pre>
55                                                 <table>
56                                                 <tr><th>Apache</th><td>  $versions{apacheVersion}</td></tr>
57                                                 <tr><th>Koha</th><td>    $versions{kohaVersion}</td></tr>
58                                                 <tr><th>Koha DB</th><td> $versions{kohaDbVersion}</td></tr>
59                                                 <tr><th>MySQL</th><td>   $versions{mysqlVersion}</td></tr>
60                                                 <tr><th>OS</th><td>      $versions{osVersion}</td></tr>
61                                                 <tr><th>Perl</th><td>    $versions{perlVersion}</td></tr>
62                                                 </table>";
63
64                                 } elsif ($debug_level eq "1"){
65                                         print "
66                                                 <h1>Koha error</h1>
67                                                 <p>The following fatal error has occurred:</p> 
68                         <pre><code>$msg</code></pre>";
69                                 } else {
70                                         print "<p>production mode - trapped fatal error</p>";
71                                 }       
72                 print "</body></html>";
73                         }
74                 #CGI::Carp::set_message(\&handle_errors);
75                 ## give a stack backtrace if KOHA_BACKTRACES is set
76                 ## can't rely on DebugLevel for this, as we're not yet connected
77                 if ($ENV{KOHA_BACKTRACES}) {
78                         $main::SIG{__DIE__} = \&CGI::Carp::confess;
79                 }
80     }   # else there is no browser to send fatals to!
81
82     # Check if there are memcached servers set
83     $servers = $ENV{'MEMCACHED_SERVERS'};
84     if ($servers) {
85         # Load required libraries and create the memcached object
86         require Cache::Memcached;
87         $memcached = Cache::Memcached->new({
88                       servers => [ $servers ],
89                       debug   => 0,
90                       compress_threshold => 10_000,
91                       namespace => $ENV{'MEMCACHED_NAMESPACE'} || 'koha'
92                   });
93         # Verify memcached available (set a variable and test the output)
94         $ismemcached = $memcached->set('ismemcached','1');
95     }
96
97         $VERSION = '3.00.00.036';
98 }
99
100 use DBI;
101 use ZOOM;
102 use XML::Simple;
103 use C4::Boolean;
104 use C4::Debug;
105 use POSIX ();
106
107 =head1 NAME
108
109 C4::Context - Maintain and manipulate the context of a Koha script
110
111 =head1 SYNOPSIS
112
113   use C4::Context;
114
115   use C4::Context("/path/to/koha-conf.xml");
116
117   $config_value = C4::Context->config("config_variable");
118
119   $koha_preference = C4::Context->preference("preference");
120
121   $db_handle = C4::Context->dbh;
122
123   $Zconn = C4::Context->Zconn;
124
125   $stopwordhash = C4::Context->stopwords;
126
127 =head1 DESCRIPTION
128
129 When a Koha script runs, it makes use of a certain number of things:
130 configuration settings in F</etc/koha/koha-conf.xml>, a connection to the Koha
131 databases, and so forth. These things make up the I<context> in which
132 the script runs.
133
134 This module takes care of setting up the context for a script:
135 figuring out which configuration file to load, and loading it, opening
136 a connection to the right database, and so forth.
137
138 Most scripts will only use one context. They can simply have
139
140   use C4::Context;
141
142 at the top.
143
144 Other scripts may need to use several contexts. For instance, if a
145 library has two databases, one for a certain collection, and the other
146 for everything else, it might be necessary for a script to use two
147 different contexts to search both databases. Such scripts should use
148 the C<&set_context> and C<&restore_context> functions, below.
149
150 By default, C4::Context reads the configuration from
151 F</etc/koha/koha-conf.xml>. This may be overridden by setting the C<$KOHA_CONF>
152 environment variable to the pathname of a configuration file to use.
153
154 =head1 METHODS
155
156 =cut
157
158 #'
159 # In addition to what is said in the POD above, a Context object is a
160 # reference-to-hash with the following fields:
161 #
162 # config
163 #    A reference-to-hash whose keys and values are the
164 #    configuration variables and values specified in the config
165 #    file (/etc/koha/koha-conf.xml).
166 # dbh
167 #    A handle to the appropriate database for this context.
168 # dbh_stack
169 #    Used by &set_dbh and &restore_dbh to hold other database
170 #    handles for this context.
171 # Zconn
172 #     A connection object for the Zebra server
173
174 # Koha's main configuration file koha-conf.xml
175 # is searched for according to this priority list:
176 #
177 # 1. Path supplied via use C4::Context '/path/to/koha-conf.xml'
178 # 2. Path supplied in KOHA_CONF environment variable.
179 # 3. Path supplied in INSTALLED_CONFIG_FNAME, as long
180 #    as value has changed from its default of 
181 #    '__KOHA_CONF_DIR__/koha-conf.xml', as happens
182 #    when Koha is installed in 'standard' or 'single'
183 #    mode.
184 # 4. Path supplied in CONFIG_FNAME.
185 #
186 # The first entry that refers to a readable file is used.
187
188 use constant CONFIG_FNAME => "/etc/koha/koha-conf.xml";
189                 # Default config file, if none is specified
190                 
191 my $INSTALLED_CONFIG_FNAME = '__KOHA_CONF_DIR__/koha-conf.xml';
192                 # path to config file set by installer
193                 # __KOHA_CONF_DIR__ is set by rewrite-confg.PL
194                 # when Koha is installed in 'standard' or 'single'
195                 # mode.  If Koha was installed in 'dev' mode, 
196                 # __KOHA_CONF_DIR__ is *not* rewritten; instead
197                 # developers should set the KOHA_CONF environment variable 
198
199 $context = undef;        # Initially, no context is set
200 @context_stack = ();        # Initially, no saved contexts
201
202
203 =head2 KOHAVERSION
204
205 returns the kohaversion stored in kohaversion.pl file
206
207 =cut
208
209 sub KOHAVERSION {
210     my $cgidir = C4::Context->intranetdir;
211
212     # Apparently the GIT code does not run out of a CGI-BIN subdirectory
213     # but distribution code does?  (Stan, 1jan08)
214     if(-d $cgidir . "/cgi-bin"){
215         my $cgidir .= "/cgi-bin";
216     }
217     
218     do $cgidir."/kohaversion.pl" || die "NO $cgidir/kohaversion.pl";
219     return kohaversion();
220 }
221 =head2 read_config_file
222
223 Reads the specified Koha config file. 
224
225 Returns an object containing the configuration variables. The object's
226 structure is a bit complex to the uninitiated ... take a look at the
227 koha-conf.xml file as well as the XML::Simple documentation for details. Or,
228 here are a few examples that may give you what you need:
229
230 The simple elements nested within the <config> element:
231
232     my $pass = $koha->{'config'}->{'pass'};
233
234 The <listen> elements:
235
236     my $listen = $koha->{'listen'}->{'biblioserver'}->{'content'};
237
238 The elements nested within the <server> element:
239
240     my $ccl2rpn = $koha->{'server'}->{'biblioserver'}->{'cql2rpn'};
241
242 Returns undef in case of error.
243
244 =cut
245
246 sub read_config_file {          # Pass argument naming config file to read
247     my $koha = XMLin(shift, keyattr => ['id'], forcearray => ['listen', 'server', 'serverinfo'], suppressempty => '');
248
249     if ($ismemcached) {
250       $memcached->set('kohaconf',$koha);
251     }
252
253     return $koha;                       # Return value: ref-to-hash holding the configuration
254 }
255
256 # db_scheme2dbi
257 # Translates the full text name of a database into de appropiate dbi name
258
259 sub db_scheme2dbi {
260     my $name = shift;
261     # for instance, we support only mysql, so don't care checking
262     return "mysql";
263     for ($name) {
264 # FIXME - Should have other databases. 
265         if (/mysql/) { return("mysql"); }
266         if (/Postgres|Pg|PostgresSQL/) { return("Pg"); }
267         if (/oracle/) { return("Oracle"); }
268     }
269     return undef;         # Just in case
270 }
271
272 sub import {
273     # Create the default context ($C4::Context::Context)
274     # the first time the module is called
275     # (a config file can be optionaly passed)
276
277     # default context allready exists? 
278     return if $context;
279
280     # no ? so load it!
281     my ($pkg,$config_file) = @_ ;
282     my $new_ctx = __PACKAGE__->new($config_file);
283     return unless $new_ctx;
284
285     # if successfully loaded, use it by default
286     $new_ctx->set_context;
287     1;
288 }
289
290 =head2 new
291
292   $context = new C4::Context;
293   $context = new C4::Context("/path/to/koha-conf.xml");
294
295 Allocates a new context. Initializes the context from the specified
296 file, which defaults to either the file given by the C<$KOHA_CONF>
297 environment variable, or F</etc/koha/koha-conf.xml>.
298
299 It saves the koha-conf.xml values in the declared memcached server(s)
300 if currently available and uses those values until them expire and
301 re-reads them.
302
303 C<&new> does not set this context as the new default context; for
304 that, use C<&set_context>.
305
306 =cut
307
308 #'
309 # Revision History:
310 # 2004-08-10 A. Tarallo: Added check if the conf file is not empty
311 sub new {
312     my $class = shift;
313     my $conf_fname = shift;        # Config file to load
314     my $self = {};
315
316     # check that the specified config file exists and is not empty
317     undef $conf_fname unless 
318         (defined $conf_fname && -s $conf_fname);
319     # Figure out a good config file to load if none was specified.
320     if (!defined($conf_fname))
321     {
322         # If the $KOHA_CONF environment variable is set, use
323         # that. Otherwise, use the built-in default.
324         if (exists $ENV{"KOHA_CONF"} and $ENV{'KOHA_CONF'} and -s  $ENV{"KOHA_CONF"}) {
325             $conf_fname = $ENV{"KOHA_CONF"};
326         } elsif ($INSTALLED_CONFIG_FNAME !~ /__KOHA_CONF_DIR/ and -s $INSTALLED_CONFIG_FNAME) {
327             # NOTE: be careful -- don't change __KOHA_CONF_DIR in the above
328             # regex to anything else -- don't want installer to rewrite it
329             $conf_fname = $INSTALLED_CONFIG_FNAME;
330         } elsif (-s CONFIG_FNAME) {
331             $conf_fname = CONFIG_FNAME;
332         } else {
333             warn "unable to locate Koha configuration file koha-conf.xml";
334             return undef;
335         }
336     }
337     
338     if ($ismemcached) {
339       # retreive from memcached
340       $self = $memcached->get('kohaconf');
341       if (not defined $self) {
342         # not in memcached yet
343         $self = read_config_file($conf_fname);
344       }
345     } else {
346       # non-memcached env, read from file
347       $self = read_config_file($conf_fname);
348     }
349
350     $self->{"config_file"} = $conf_fname;
351     warn "read_config_file($conf_fname) returned undef" if !defined($self->{"config"});
352     return undef if !defined($self->{"config"});
353
354     $self->{"dbh"} = undef;        # Database handle
355     $self->{"Zconn"} = undef;    # Zebra Connections
356     $self->{"stopwords"} = undef; # stopwords list
357     $self->{"marcfromkohafield"} = undef; # the hash with relations between koha table fields and MARC field/subfield
358     $self->{"userenv"} = undef;        # User env
359     $self->{"activeuser"} = undef;        # current active user
360     $self->{"shelves"} = undef;
361
362     bless $self, $class;
363     return $self;
364 }
365
366 =head2 set_context
367
368   $context = new C4::Context;
369   $context->set_context();
370 or
371   set_context C4::Context $context;
372
373   ...
374   restore_context C4::Context;
375
376 In some cases, it might be necessary for a script to use multiple
377 contexts. C<&set_context> saves the current context on a stack, then
378 sets the context to C<$context>, which will be used in future
379 operations. To restore the previous context, use C<&restore_context>.
380
381 =cut
382
383 #'
384 sub set_context
385 {
386     my $self = shift;
387     my $new_context;    # The context to set
388
389     # Figure out whether this is a class or instance method call.
390     #
391     # We're going to make the assumption that control got here
392     # through valid means, i.e., that the caller used an instance
393     # or class method call, and that control got here through the
394     # usual inheritance mechanisms. The caller can, of course,
395     # break this assumption by playing silly buggers, but that's
396     # harder to do than doing it properly, and harder to check
397     # for.
398     if (ref($self) eq "")
399     {
400         # Class method. The new context is the next argument.
401         $new_context = shift;
402     } else {
403         # Instance method. The new context is $self.
404         $new_context = $self;
405     }
406
407     # Save the old context, if any, on the stack
408     push @context_stack, $context if defined($context);
409
410     # Set the new context
411     $context = $new_context;
412 }
413
414 =head2 restore_context
415
416   &restore_context;
417
418 Restores the context set by C<&set_context>.
419
420 =cut
421
422 #'
423 sub restore_context
424 {
425     my $self = shift;
426
427     if ($#context_stack < 0)
428     {
429         # Stack underflow.
430         die "Context stack underflow";
431     }
432
433     # Pop the old context and set it.
434     $context = pop @context_stack;
435
436     # FIXME - Should this return something, like maybe the context
437     # that was current when this was called?
438 }
439
440 =head2 config
441
442   $value = C4::Context->config("config_variable");
443
444   $value = C4::Context->config_variable;
445
446 Returns the value of a variable specified in the configuration file
447 from which the current context was created.
448
449 The second form is more compact, but of course may conflict with
450 method names. If there is a configuration variable called "new", then
451 C<C4::Config-E<gt>new> will not return it.
452
453 =cut
454
455 sub _common_config ($$) {
456         my $var = shift;
457         my $term = shift;
458     return undef if !defined($context->{$term});
459        # Presumably $self->{$term} might be
460        # undefined if the config file given to &new
461        # didn't exist, and the caller didn't bother
462        # to check the return value.
463
464     # Return the value of the requested config variable
465     return $context->{$term}->{$var};
466 }
467
468 sub config {
469         return _common_config($_[1],'config');
470 }
471 sub zebraconfig {
472         return _common_config($_[1],'server');
473 }
474 sub ModZebrations {
475         return _common_config($_[1],'serverinfo');
476 }
477
478 =head2 preference
479
480   $sys_preference = C4::Context->preference('some_variable');
481
482 Looks up the value of the given system preference in the
483 systempreferences table of the Koha database, and returns it. If the
484 variable is not set or does not exist, undef is returned.
485
486 In case of an error, this may return 0.
487
488 Note: It is impossible to tell the difference between system
489 preferences which do not exist, and those whose values are set to NULL
490 with this method.
491
492 =cut
493
494 # FIXME: running this under mod_perl will require a means of
495 # flushing the caching mechanism.
496
497 my %sysprefs;
498
499 sub preference {
500     my $self = shift;
501     my $var  = lc(shift);                          # The system preference to return
502
503     if (exists $sysprefs{$var}) {
504         return $sysprefs{$var};
505     }
506
507     my $dbh  = C4::Context->dbh or return 0;
508
509     # Look up systempreferences.variable==$var
510     my $sql = <<'END_SQL';
511         SELECT    value
512         FROM    systempreferences
513         WHERE    variable=?
514         LIMIT    1
515 END_SQL
516     $sysprefs{$var} = $dbh->selectrow_array( $sql, {}, $var );
517     return $sysprefs{$var};
518 }
519
520 sub boolean_preference ($) {
521     my $self = shift;
522     my $var = shift;        # The system preference to return
523     my $it = preference($self, $var);
524     return defined($it)? C4::Boolean::true_p($it): undef;
525 }
526
527 =head2 clear_syspref_cache
528
529   C4::Context->clear_syspref_cache();
530
531 cleans the internal cache of sysprefs. Please call this method if
532 you update the systempreferences table. Otherwise, your new changes
533 will not be seen by this process.
534
535 =cut
536
537 sub clear_syspref_cache {
538     %sysprefs = ();
539 }
540
541 =head2 set_preference
542
543   C4::Context->set_preference( $variable, $value );
544
545 This updates a preference's value both in the systempreferences table and in
546 the sysprefs cache.
547
548 =cut
549
550 sub set_preference {
551     my $self = shift;
552     my $var = lc(shift);
553     my $value = shift;
554
555     my $dbh = C4::Context->dbh or return 0;
556
557     my $type = $dbh->selectrow_array( "SELECT type FROM systempreferences WHERE variable = ?", {}, $var );
558
559     $value = 0 if ( $type && $type eq 'YesNo' && $value eq '' );
560
561     my $sth = $dbh->prepare( "
562       INSERT INTO systempreferences
563         ( variable, value )
564         VALUES( ?, ? )
565         ON DUPLICATE KEY UPDATE value = VALUES(value)
566     " );
567
568     if($sth->execute( $var, $value )) {
569         $sysprefs{$var} = $value;
570     }
571     $sth->finish;
572 }
573
574 # AUTOLOAD
575 # This implements C4::Config->foo, and simply returns
576 # C4::Context->config("foo"), as described in the documentation for
577 # &config, above.
578
579 # FIXME - Perhaps this should be extended to check &config first, and
580 # then &preference if that fails. OTOH, AUTOLOAD could lead to crappy
581 # code, so it'd probably be best to delete it altogether so as not to
582 # encourage people to use it.
583 sub AUTOLOAD
584 {
585     my $self = shift;
586
587     $AUTOLOAD =~ s/.*:://;        # Chop off the package name,
588                     # leaving only the function name.
589     return $self->config($AUTOLOAD);
590 }
591
592 =head2 Zconn
593
594   $Zconn = C4::Context->Zconn
595
596 Returns a connection to the Zebra database for the current
597 context. If no connection has yet been made, this method 
598 creates one and connects.
599
600 C<$self> 
601
602 C<$server> one of the servers defined in the koha-conf.xml file
603
604 C<$async> whether this is a asynchronous connection
605
606 C<$auth> whether this connection has rw access (1) or just r access (0 or NULL)
607
608
609 =cut
610
611 sub Zconn {
612     my $self=shift;
613     my $server=shift;
614     my $async=shift;
615     my $auth=shift;
616     my $piggyback=shift;
617     my $syntax=shift;
618     if ( defined($context->{"Zconn"}->{$server}) && (0 == $context->{"Zconn"}->{$server}->errcode()) ) {
619         return $context->{"Zconn"}->{$server};
620     # No connection object or it died. Create one.
621     }else {
622         # release resources if we're closing a connection and making a new one
623         # FIXME: this needs to be smarter -- an error due to a malformed query or
624         # a missing index does not necessarily require us to close the connection
625         # and make a new one, particularly for a batch job.  However, at
626         # first glance it does not look like there's a way to easily check
627         # the basic health of a ZOOM::Connection
628         $context->{"Zconn"}->{$server}->destroy() if defined($context->{"Zconn"}->{$server});
629
630         $context->{"Zconn"}->{$server} = &_new_Zconn($server,$async,$auth,$piggyback,$syntax);
631         return $context->{"Zconn"}->{$server};
632     }
633 }
634
635 =head2 _new_Zconn
636
637 $context->{"Zconn"} = &_new_Zconn($server,$async);
638
639 Internal function. Creates a new database connection from the data given in the current context and returns it.
640
641 C<$server> one of the servers defined in the koha-conf.xml file
642
643 C<$async> whether this is a asynchronous connection
644
645 C<$auth> whether this connection has rw access (1) or just r access (0 or NULL)
646
647 =cut
648
649 sub _new_Zconn {
650     my ($server,$async,$auth,$piggyback,$syntax) = @_;
651
652     my $tried=0; # first attempt
653     my $Zconn; # connection object
654     $server = "biblioserver" unless $server;
655     $syntax = "usmarc" unless $syntax;
656
657     my $host = $context->{'listen'}->{$server}->{'content'};
658     my $servername = $context->{"config"}->{$server};
659     my $user = $context->{"serverinfo"}->{$server}->{"user"};
660     my $password = $context->{"serverinfo"}->{$server}->{"password"};
661  $auth = 1 if($user && $password);   
662     retry:
663     eval {
664         # set options
665         my $o = new ZOOM::Options();
666         $o->option(user=>$user) if $auth;
667         $o->option(password=>$password) if $auth;
668         $o->option(async => 1) if $async;
669         $o->option(count => $piggyback) if $piggyback;
670         $o->option(cqlfile=> $context->{"server"}->{$server}->{"cql2rpn"});
671         $o->option(cclfile=> $context->{"serverinfo"}->{$server}->{"ccl2rpn"});
672         $o->option(preferredRecordSyntax => $syntax);
673         $o->option(elementSetName => "F"); # F for 'full' as opposed to B for 'brief'
674         $o->option(databaseName => ($servername?$servername:"biblios"));
675
676         # create a new connection object
677         $Zconn= create ZOOM::Connection($o);
678
679         # forge to server
680         $Zconn->connect($host, 0);
681
682         # check for errors and warn
683         if ($Zconn->errcode() !=0) {
684             warn "something wrong with the connection: ". $Zconn->errmsg();
685         }
686
687     };
688 #     if ($@) {
689 #         # Koha manages the Zebra server -- this doesn't work currently for me because of permissions issues
690 #         # Also, I'm skeptical about whether it's the best approach
691 #         warn "problem with Zebra";
692 #         if ( C4::Context->preference("ManageZebra") ) {
693 #             if ($@->code==10000 && $tried==0) { ##No connection try restarting Zebra
694 #                 $tried=1;
695 #                 warn "trying to restart Zebra";
696 #                 my $res=system("zebrasrv -f $ENV{'KOHA_CONF'} >/koha/log/zebra-error.log");
697 #                 goto "retry";
698 #             } else {
699 #                 warn "Error ", $@->code(), ": ", $@->message(), "\n";
700 #                 $Zconn="error";
701 #                 return $Zconn;
702 #             }
703 #         }
704 #     }
705     return $Zconn;
706 }
707
708 # _new_dbh
709 # Internal helper function (not a method!). This creates a new
710 # database connection from the data given in the current context, and
711 # returns it.
712 sub _new_dbh
713 {
714
715     ## $context
716     ## correct name for db_schme        
717     my $db_driver;
718     if ($context->config("db_scheme")){
719         $db_driver=db_scheme2dbi($context->config("db_scheme"));
720     }else{
721         $db_driver="mysql";
722     }
723
724     my $db_name   = $context->config("database");
725     my $db_host   = $context->config("hostname");
726     my $db_port   = $context->config("port") || '';
727     my $db_user   = $context->config("user");
728     my $db_passwd = $context->config("pass");
729     # MJR added or die here, as we can't work without dbh
730     my $dbh= DBI->connect("DBI:$db_driver:dbname=$db_name;host=$db_host;port=$db_port",
731     $db_user, $db_passwd, {'RaiseError' => $ENV{DEBUG}?1:0 }) or die $DBI::errstr;
732         my $tz = $ENV{TZ};
733     if ( $db_driver eq 'mysql' ) { 
734         # Koha 3.0 is utf-8, so force utf8 communication between mySQL and koha, whatever the mysql default config.
735         # this is better than modifying my.cnf (and forcing all communications to be in utf8)
736         $dbh->{'mysql_enable_utf8'}=1; #enable
737         $dbh->do("set NAMES 'utf8'");
738         ($tz) and $dbh->do(qq(SET time_zone = "$tz"));
739     }
740     elsif ( $db_driver eq 'Pg' ) {
741             $dbh->do( "set client_encoding = 'UTF8';" );
742         ($tz) and $dbh->do(qq(SET TIME ZONE = "$tz"));
743     }
744     return $dbh;
745 }
746
747 =head2 dbh
748
749   $dbh = C4::Context->dbh;
750
751 Returns a database handle connected to the Koha database for the
752 current context. If no connection has yet been made, this method
753 creates one, and connects to the database.
754
755 This database handle is cached for future use: if you call
756 C<C4::Context-E<gt>dbh> twice, you will get the same handle both
757 times. If you need a second database handle, use C<&new_dbh> and
758 possibly C<&set_dbh>.
759
760 =cut
761
762 #'
763 sub dbh
764 {
765     my $self = shift;
766     my $sth;
767
768     if (defined($context->{"dbh"}) && $context->{"dbh"}->ping()) {
769         return $context->{"dbh"};
770     }
771
772     # No database handle or it died . Create one.
773     $context->{"dbh"} = &_new_dbh();
774
775     return $context->{"dbh"};
776 }
777
778 =head2 new_dbh
779
780   $dbh = C4::Context->new_dbh;
781
782 Creates a new connection to the Koha database for the current context,
783 and returns the database handle (a C<DBI::db> object).
784
785 The handle is not saved anywhere: this method is strictly a
786 convenience function; the point is that it knows which database to
787 connect to so that the caller doesn't have to know.
788
789 =cut
790
791 #'
792 sub new_dbh
793 {
794     my $self = shift;
795
796     return &_new_dbh();
797 }
798
799 =head2 set_dbh
800
801   $my_dbh = C4::Connect->new_dbh;
802   C4::Connect->set_dbh($my_dbh);
803   ...
804   C4::Connect->restore_dbh;
805
806 C<&set_dbh> and C<&restore_dbh> work in a manner analogous to
807 C<&set_context> and C<&restore_context>.
808
809 C<&set_dbh> saves the current database handle on a stack, then sets
810 the current database handle to C<$my_dbh>.
811
812 C<$my_dbh> is assumed to be a good database handle.
813
814 =cut
815
816 #'
817 sub set_dbh
818 {
819     my $self = shift;
820     my $new_dbh = shift;
821
822     # Save the current database handle on the handle stack.
823     # We assume that $new_dbh is all good: if the caller wants to
824     # screw himself by passing an invalid handle, that's fine by
825     # us.
826     push @{$context->{"dbh_stack"}}, $context->{"dbh"};
827     $context->{"dbh"} = $new_dbh;
828 }
829
830 =head2 restore_dbh
831
832   C4::Context->restore_dbh;
833
834 Restores the database handle saved by an earlier call to
835 C<C4::Context-E<gt>set_dbh>.
836
837 =cut
838
839 #'
840 sub restore_dbh
841 {
842     my $self = shift;
843
844     if ($#{$context->{"dbh_stack"}} < 0)
845     {
846         # Stack underflow
847         die "DBH stack underflow";
848     }
849
850     # Pop the old database handle and set it.
851     $context->{"dbh"} = pop @{$context->{"dbh_stack"}};
852
853     # FIXME - If it is determined that restore_context should
854     # return something, then this function should, too.
855 }
856
857 =head2 marcfromkohafield
858
859   $dbh = C4::Context->marcfromkohafield;
860
861 Returns a hash with marcfromkohafield.
862
863 This hash is cached for future use: if you call
864 C<C4::Context-E<gt>marcfromkohafield> twice, you will get the same hash without real DB access
865
866 =cut
867
868 #'
869 sub marcfromkohafield
870 {
871     my $retval = {};
872
873     # If the hash already exists, return it.
874     return $context->{"marcfromkohafield"} if defined($context->{"marcfromkohafield"});
875
876     # No hash. Create one.
877     $context->{"marcfromkohafield"} = &_new_marcfromkohafield();
878
879     return $context->{"marcfromkohafield"};
880 }
881
882 # _new_marcfromkohafield
883 # Internal helper function (not a method!). This creates a new
884 # hash with stopwords
885 sub _new_marcfromkohafield
886 {
887     my $dbh = C4::Context->dbh;
888     my $marcfromkohafield;
889     my $sth = $dbh->prepare("select frameworkcode,kohafield,tagfield,tagsubfield from marc_subfield_structure where kohafield > ''");
890     $sth->execute;
891     while (my ($frameworkcode,$kohafield,$tagfield,$tagsubfield) = $sth->fetchrow) {
892         my $retval = {};
893         $marcfromkohafield->{$frameworkcode}->{$kohafield} = [$tagfield,$tagsubfield];
894     }
895     return $marcfromkohafield;
896 }
897
898 =head2 stopwords
899
900   $dbh = C4::Context->stopwords;
901
902 Returns a hash with stopwords.
903
904 This hash is cached for future use: if you call
905 C<C4::Context-E<gt>stopwords> twice, you will get the same hash without real DB access
906
907 =cut
908
909 #'
910 sub stopwords
911 {
912     my $retval = {};
913
914     # If the hash already exists, return it.
915     return $context->{"stopwords"} if defined($context->{"stopwords"});
916
917     # No hash. Create one.
918     $context->{"stopwords"} = &_new_stopwords();
919
920     return $context->{"stopwords"};
921 }
922
923 # _new_stopwords
924 # Internal helper function (not a method!). This creates a new
925 # hash with stopwords
926 sub _new_stopwords
927 {
928     my $dbh = C4::Context->dbh;
929     my $stopwordlist;
930     my $sth = $dbh->prepare("select word from stopwords");
931     $sth->execute;
932     while (my $stopword = $sth->fetchrow_array) {
933         $stopwordlist->{$stopword} = uc($stopword);
934     }
935     $stopwordlist->{A} = "A" unless $stopwordlist;
936     return $stopwordlist;
937 }
938
939 =head2 userenv
940
941   C4::Context->userenv;
942
943 Retrieves a hash for user environment variables.
944
945 This hash shall be cached for future use: if you call
946 C<C4::Context-E<gt>userenv> twice, you will get the same hash without real DB access
947
948 =cut
949
950 #'
951 sub userenv {
952     my $var = $context->{"activeuser"};
953     return $context->{"userenv"}->{$var} if (defined $var and defined $context->{"userenv"}->{$var});
954     # insecure=1 management
955     if ($context->{"dbh"} && $context->preference('insecure') eq 'yes') {
956         my %insecure;
957         $insecure{flags} = '16382';
958         $insecure{branchname} ='Insecure';
959         $insecure{number} ='0';
960         $insecure{cardnumber} ='0';
961         $insecure{id} = 'insecure';
962         $insecure{branch} = 'INS';
963         $insecure{emailaddress} = 'test@mode.insecure.com';
964         return \%insecure;
965     } else {
966         return;
967     }
968 }
969
970 =head2 set_userenv
971
972   C4::Context->set_userenv($usernum, $userid, $usercnum, $userfirstname, 
973                   $usersurname, $userbranch, $userflags, $emailaddress);
974
975 Establish a hash of user environment variables.
976
977 set_userenv is called in Auth.pm
978
979 =cut
980
981 #'
982 sub set_userenv {
983     my ($usernum, $userid, $usercnum, $userfirstname, $usersurname, $userbranch, $branchname, $userflags, $emailaddress, $branchprinter)= @_;
984     my $var=$context->{"activeuser"};
985     my $cell = {
986         "number"     => $usernum,
987         "id"         => $userid,
988         "cardnumber" => $usercnum,
989         "firstname"  => $userfirstname,
990         "surname"    => $usersurname,
991         #possibly a law problem
992         "branch"     => $userbranch,
993         "branchname" => $branchname,
994         "flags"      => $userflags,
995         "emailaddress"     => $emailaddress,
996         "branchprinter"    => $branchprinter
997     };
998     $context->{userenv}->{$var} = $cell;
999     return $cell;
1000 }
1001
1002 sub set_shelves_userenv ($$) {
1003         my ($type, $shelves) = @_ or return undef;
1004         my $activeuser = $context->{activeuser} or return undef;
1005         $context->{userenv}->{$activeuser}->{barshelves} = $shelves if $type eq 'bar';
1006         $context->{userenv}->{$activeuser}->{pubshelves} = $shelves if $type eq 'pub';
1007         $context->{userenv}->{$activeuser}->{totshelves} = $shelves if $type eq 'tot';
1008 }
1009
1010 sub get_shelves_userenv () {
1011         my $active;
1012         unless ($active = $context->{userenv}->{$context->{activeuser}}) {
1013                 $debug and warn "get_shelves_userenv cannot retrieve context->{userenv}->{context->{activeuser}}";
1014                 return undef;
1015         }
1016         my $totshelves = $active->{totshelves} or undef;
1017         my $pubshelves = $active->{pubshelves} or undef;
1018         my $barshelves = $active->{barshelves} or undef;
1019         return ($totshelves, $pubshelves, $barshelves);
1020 }
1021
1022 =head2 _new_userenv
1023
1024   C4::Context->_new_userenv($session);  # FIXME: This calling style is wrong for what looks like an _internal function
1025
1026 Builds a hash for user environment variables.
1027
1028 This hash shall be cached for future use: if you call
1029 C<C4::Context-E<gt>userenv> twice, you will get the same hash without real DB access
1030
1031 _new_userenv is called in Auth.pm
1032
1033 =cut
1034
1035 #'
1036 sub _new_userenv
1037 {
1038     shift;  # Useless except it compensates for bad calling style
1039     my ($sessionID)= @_;
1040      $context->{"activeuser"}=$sessionID;
1041 }
1042
1043 =head2 _unset_userenv
1044
1045   C4::Context->_unset_userenv;
1046
1047 Destroys the hash for activeuser user environment variables.
1048
1049 =cut
1050
1051 #'
1052
1053 sub _unset_userenv
1054 {
1055     my ($sessionID)= @_;
1056     undef $context->{"activeuser"} if ($context->{"activeuser"} eq $sessionID);
1057 }
1058
1059
1060 =head2 get_versions
1061
1062   C4::Context->get_versions
1063
1064 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'.
1065
1066 =cut
1067
1068 #'
1069
1070 # A little example sub to show more debugging info for CGI::Carp
1071 sub get_versions {
1072     my %versions;
1073     $versions{kohaVersion}  = KOHAVERSION();
1074     $versions{kohaDbVersion} = C4::Context->preference('version');
1075     $versions{osVersion} = join(" ", POSIX::uname());
1076     $versions{perlVersion} = $];
1077     {
1078         no warnings qw(exec); # suppress warnings if unable to find a program in $PATH
1079         $versions{mysqlVersion}  = `mysql -V`;
1080         $versions{apacheVersion} = `httpd -v`;
1081         $versions{apacheVersion} = `httpd2 -v`            unless  $versions{apacheVersion} ;
1082         $versions{apacheVersion} = `apache2 -v`           unless  $versions{apacheVersion} ;
1083         $versions{apacheVersion} = `/usr/sbin/apache2 -v` unless  $versions{apacheVersion} ;
1084     }
1085     return %versions;
1086 }
1087
1088
1089 1;
1090 __END__
1091
1092 =head1 ENVIRONMENT
1093
1094 =head2 C<KOHA_CONF>
1095
1096 Specifies the configuration file to read.
1097
1098 =head1 SEE ALSO
1099
1100 XML::Simple
1101
1102 =head1 AUTHORS
1103
1104 Andrew Arensburger <arensb at ooblick dot com>
1105
1106 Joshua Ferraro <jmf at liblime dot com>
1107
1108 =cut