6 use Net::Z3950::SimpleServer;
19 # databases names (left) must be in uppercase!
21 # 'COBISS' => 'COBISS',
25 'GOOGLEBOOKS' => 'GoogleBooks',
26 'HATHITRUST' => 'vuFind',
28 'MKUTUP' => 'AlephTR',
30 'CROSBI-CASOPIS' => 'CROSBI',
31 'CROSBI-PREPRINT' => 'CROSBI',
32 'CROSBI-RKNJIGA' => 'CROSBI',
33 'CROSBI-ZBORNIK' => 'CROSBI',
34 'CROSBI-OSTALO' => 'CROSBI',
37 my $max_records = 10; # XXX configure this
38 my $max_result_sets = 10;
48 $self->{HANDLE} = $session;
49 $self->{IMP_NAME} = "Biblio Z39.50";
50 $self->{IMP_VER} = "0.2";
51 $session->{SETS} = {};
57 diag "SearchHandle ",Dumper($self);
59 my $session = $self->{HANDLE};
60 my $rpn = $self->{RPN};
63 my $database = uc $self->{DATABASES}->[0];
64 my $module = $databases->{$database};
65 if ( ! defined $module ) {
66 $self->{ERR_CODE} = 108;
67 warn $self->{ERR_STR} = "$database NOT FOUND in available databases: " . join(" ", keys %$databases);
71 my $from = $module->new( $database );
73 diag "using $module for $database ", Dumper( $from );
75 eval { $query = $rpn->{query}->render( $from->usemap ); };
76 warn "ERROR: ", Dumper($@) if $@;
77 if ( $@ && ref($@) ) { ## Did someone/something report any errors?
78 $self->{ERR_CODE} = $@->{errcode};
79 $self->{ERR_STR} = $@->{errstr};
83 $query = decode('utf-8', $query); # FIXME Zoom encoding
85 diag "search for $query";
87 my $setname = $self->{SETNAME};
88 my $repl_set = $self->{REPL_SET};
89 diag "SETNAME $setname REPL_SET $repl_set";
91 unless ( $hits = $from->search( $query ) ) {
92 warn $self->{ERR_STR} = "no results for $query";
93 $self->{ERR_CODE} = 108;
96 diag "got $hits hits";
99 upper => $hits < $max_records ? $max_records : $hits,
102 results => [ undef ], # we don't use 0 element
103 database => $database,
105 my $sets = $session->{SETS};
107 if ( defined( $sets->{$setname} ) && !$repl_set ) {
108 $self->{ERR_CODE} = 21;
111 if ( scalar keys %$sets >= $max_result_sets ) {
112 $self->{ERR_CODE} = 112;
113 $self->{ERR_STR} = "Max number is $max_result_sets";
116 $sets->{$setname} = $rs;
117 $self->{HITS} = $session->{HITS} = $hits;
118 $session->{QUERY} = $query;
123 my $session = $self->{HANDLE};
124 my $setname = $self->{SETNAME};
125 my $req_form = $self->{REQ_FORM};
126 my $offset = $self->{OFFSET};
127 my $sets = $session->{SETS};
128 my $hits = $session->{HITS};
132 if ( !defined( $rs = $sets->{$setname} ) ) {
133 $self->{ERR_CODE} = 30;
136 if ( $offset > $hits ) {
137 $self->{ERR_CODE} = 13;
141 $self->{BASENAME} = $rs->{database};
144 $req_form eq Net::Z3950::OID::xml() ? 'xml' :
145 $req_form eq Net::Z3950::OID::unimarc() ? 'unimarc' :
146 $req_form eq Net::Z3950::OID::usmarc() ? 'marc' : # XXX usmarc -> marc
147 die "unknown format $req_form";
150 warn "ERROR: $req_form format not supported";
151 $self->{ERR_CODE} = 239; ## Unsupported record format
152 $self->{ERR_STR} = $req_form;
156 $self->{REP_FORM} = $req_form;
158 my $from = $rs->{from} || die "no from?";
159 # fetch records up to offset
160 while( $#{ $rs->{results} } < $offset ) {
161 my $marc = $from->next_marc;
162 last if ! $marc; # abort results
163 push @{ $rs->{results} }, $marc;
164 warn "# rs result ", $#{ $rs->{results} },"\n";
167 my $id = $rs->{results}->[$offset] || die "no id for record $offset in ",Dumper( $rs->{results} );
169 my $path = 'marc/' . $rs->{database} . "/$id.$format";
171 warn "ERROR: $path not found";
172 ## Unsupported record format
173 $self->{ERR_CODE} = 239;
174 $self->{ERR_STR} = $req_form;
179 open(my $in, '<', $path) || die "$path: $!";
183 $self->{RECORD} = $marc;
187 if ( $offset == $hits ) {
199 my $z = new Net::Z3950::SimpleServer(
200 INIT => \&InitHandle,
201 SEARCH => \&SearchHandle,
202 FETCH => \&FetchHandle,
203 CLOSE => \&CloseHandle
205 $z->launch_server( $0, @ARGV );
207 package Net::Z3950::RPN::And;
210 my ($self,$usemap) = @_;
211 return $self->[0]->render($usemap)
212 . ( $usemap->{RPN}->{And} || ' AND ' )
213 . $self->[1]->render($usemap);
216 package Net::Z3950::RPN::Or;
219 my ($self,$usemap) = @_;
220 return $self->[0]->render($usemap)
221 . ( $usemap->{RPN}->{Or} || ' OR ' )
222 . $self->[1]->render($usemap);
225 package Net::Z3950::RPN::AndNot;
228 my ($self,$usemap) = @_;
229 return $self->[0]->render($usemap)
230 . ( $usemap->{RPN}->{Or} || ' AND NOT ' )
231 . $self->[1]->render($usemap);
234 package Net::Z3950::RPN::Term;
236 use Data::Dump qw(dump);
239 my ($self,$usemap) = @_;
241 die "no usemap" unless $usemap;
243 warn "# render ", dump($self);
244 warn "# usemap ", dump($usemap);
248 foreach my $attr ( @{ $self->{attributes} } ) {
249 my $type = $attr->{attributeType};
250 my $value = $attr->{attributeValue};
251 $attributes->{$type} = $value;
253 if ( defined( my $use = $attributes->{1} ) ) {
254 if ( defined( my $field = $usemap->{$use} ) ) {
258 warn "FIXME add $use in usemap ",dump( $usemap );
259 die { errcode => 114, errstr => $use }; ## Unsupported use attribute
262 if ( defined( my $rel = $attributes->{2} ) )
263 { ## No relation attributes supported
265 die { errcode => 117, errstr => $rel };
268 if ( defined( my $pos = $attributes->{3} ) )
269 { ## No position attributes either
271 die { errcode => 119, errstr => $pos };
274 if ( defined( my $struc = $attributes->{4} ) ) { ## No structure
275 if ( ( $struc != 1 ) && ( $struc != 2 ) ) {
276 die { errcode => 118, errstr => $struc };
279 if ( defined( $attributes->{5} ) ) { ## No truncation
280 # die { errcode => 113, errstr => 5 };
281 warn "# truncation is ignored";
283 my $comp = $attributes->{6};
285 if ( defined($comp) && ( $comp >= 2 ) ) {
286 $prefix = "all$prefix"; # FIXME?
292 if ( $usemap->{prefix_term} ) {
293 warn "# using custom prefix_term query";
294 $q = $usemap->{prefix_term}->( $prefix, $self->{term} );
296 $q = $prefix . $self->{term} . '*';