Lots of changes. They aren't visible though.
[egate.git] / www / z39util.tcl
1 #
2 # $Id: z39util.tcl,v 1.36 1996/03/07 12:46:09 adam Exp $
3 #
4 proc saveState {} {
5     uplevel #0 {
6     set f [open "tcl.state.${sessionId}" w]
7     foreach var [info globals] {
8         if {$var == "f"} continue
9         if {$var == "sessionId"} continue
10         if {$var == "errorInfo"} continue
11         if {[catch {set names [array names $var]}]} {
12             eval "set v \$${var}"
13             puts $f "set ${var} \{$v\}"
14         } else {
15             foreach n $names {
16                 eval "set v \$${var}(\$n)"
17                 puts $f "set ${var}($n) \{$v\}"
18             }
19             catch {
20                 eval "set v \$${var}"
21                 puts $f "set ${var} \{$v\}"
22             }
23         }
24     }
25     close $f
26     }
27 }
28
29 proc search-response {zz} {
30     global sessionWait
31
32     set status [$zz responseStatus]
33     if {[lindex $status 0] == "NSD"} {
34         $zz nextResultSetPosition 0
35         set code [lindex $status 1]
36         set msg [lindex $status 2]
37         set addinfo [lindex $status 3]
38         displayError "Diagnostic message" \
39                 "$msg: $addinfo<br>\n(error code $code)"
40         set sessionWait -2
41     } else {
42         set sessionWait 1
43     }
44 }
45
46 proc scan-response {zz} {
47     global sessionWait
48
49     set status [$zz scanStatus]
50     if {$status == 6} {
51         displayError "Scan fail" ""
52         set sessionWait -2
53     } else {
54         set sessionWait 1
55     }
56 }
57
58 proc ok-response {} {
59     global sessionWait
60     set sessionWait 1
61 }
62
63 proc fail-response {} {
64     global sessionWait
65     set sessionWait -1
66 }
67
68 proc display-brief {zset no setNo targetNo} {
69     global env
70     global sessionId
71
72     html {<li>}
73     set type [$zset type $no]
74     if {$type == "SD"} {
75         set err [lindex [$zset diag $no] 1]
76         set add [lindex [$zset diag $no] 2]
77         if {$add != {}} {
78             set add " :${add}"
79         }
80         html "${no} Error ${err}${add} <br>\n"
81         return
82     }
83     if {$type != "DB"} {
84         return
85     }
86     set rtype [$zset recordType $no]
87     if {$rtype == "SUTRS"} {
88         html [join [$zset getSutrs $no]]
89         html "<br>\n"
90         return
91     }
92     if {$rtype == "WAIS"} {
93         html { <a href="http:} $env(SCRIPT_NAME) /
94         html $sessionId {/showfull.egw/} $setNo + $targetNo + $no + full {">}
95         html [join [$zset getWAIS $no headline]]
96         html {</a>}
97         html "<br>\n"
98         return
99     }
100     if {![catch {
101         set author [$zset getMarc $no field 100 * a]
102         set corp [$zset getMarc $no field 110 * a]
103         set meet [$zset getMarc $no field 111 * a]
104         set title [$zset getMarc $no field 245 * a]
105         if {[llength $author] == 0} {
106             set cover [$zset getMarc $no field 245 * {[bc]}]
107         } else {
108             set cover [$zset getMarc $no field 245 * b]
109         }
110         set location [$zset getMarc $no field 260 * a] 
111         set publisher [$zset getMarc $no field 260 * b]
112         set year [$zset getMarc $no field 260 * c]
113     } dispError ] } {
114         html { <a href="http:} $env(SCRIPT_NAME) /
115         html $sessionId {/showfull.egw/} $setNo + $targetNo + $no + full {">}
116         set p 0
117         foreach a $author {
118             if {$p} {
119                 html ", "
120             }
121             html $a
122             set p 1
123         }
124         foreach a $corp {
125             if {$p} {
126                 html ", "
127             }
128             html $a
129             set p 1
130         }
131         foreach a $meet {
132             if {$p} {
133                 html ", "
134             }
135             html $a
136             set p 1
137         }
138         if {$p} {
139             html ": "
140         }
141         set nope 1
142         foreach v $title {
143             html $v
144             set nope 0
145         }
146         if {$nope} {
147             set v [join $cover ""]
148             if {[string length $v] > 40} {
149                 set nope 0
150                 html [string range $v 0 38] "..."
151             } elseif {[string length $v] > 0} {
152                 set nope 0
153                 html $v
154             } else {
155                 html "No Title"
156             }
157         }
158         html {</a> }
159     } else {
160         html { <a href="http:} $env(SCRIPT_NAME) /
161         html $sessionId {/showfull.egw/} $setNo + $targetNo + $no + full {">}
162         html {No Title}
163         html {</a> }
164         html "Error: " $dispError "\n"
165     }
166     html "<br>\n"
167 }
168
169 proc display-raw {zset no tno} {
170     set type [$zset type $no]
171     if {$type == "SD"} {
172         set err [lindex [$zset diag $no] 1]
173         set add [lindex [$zset diag $no] 2]
174         if {$add != {}} {
175             set add " :${add}"
176         }
177         html "<h3>${no}</h3>\n"
178         html "Error ${err}${add} <br>\n"
179         return
180     }
181     if {$type != "DB"} {
182         return
183     }
184     set rtype [$zset recordType $no]
185     if {$rtype == "SUTRS"} {
186         html [join [$zset getSutrs $no]] "<br>\n"
187         return
188     } 
189     if {[catch {set r [$zset getMarc $no line * * *]}]} {
190         html "Unknown record type: $rtype <br>\n"
191         return
192     }
193     foreach line $r {
194         set tag [lindex $line 0]
195         set indicator [lindex $line 1]
196         set fields [lindex $line 2]
197         set l [string length $indicator]
198         html "<tt>$tag "
199         if {$l > 0} {
200             for {set i 0} {$i < $l} {incr i} {
201                 if {[string index $indicator $i] == " "} {
202                     html "-"
203                 } else {
204                     html [string index $tag $i]
205                 }
206             }
207         }
208         html "</tt>"
209         foreach field $fields {
210             set id [lindex $field 0]
211             set data [lindex $field 1]
212             if {$id != ""} {
213                 html " <b>\$$id</b> "
214             }
215             html $data
216         }
217         html "<br>\n"
218     }
219 }
220
221 proc put-marc-contents {cc} {
222     set ref ""
223     if {[string first :// $cc] > 0} {
224         foreach urltype {gopher http ftp mailto} {
225             if {[string first ${urltype}:// $cc] == 0} {
226                 set ref $urltype
227                 break
228             }
229         }
230     } 
231     if {$ref != ""} {
232         html {<a href="}
233     }
234     html $cc
235     if {$ref != ""} {
236         html {">} $cc {</a>}
237     }
238 }
239
240 proc dl-marc-field {zset no tag id la lb sep} {
241     set n 0
242     set c [$zset getMarc $no field $tag * $id]
243     set len [llength $c]
244     if {$len == 0} {
245         return 0
246     }
247     if {$len > 1 && "x$lb" != "x"} {
248         html "<dt><b>$lb</b>\n<dd>"
249     } else {
250         html "<dt><b>$la</b>\n<dd>"
251     }
252     foreach cc $c {
253         if {$n > 0} {
254             html $sep
255         }
256         put-marc-contents $cc
257         incr n
258     }
259     return $n
260 }
261
262 proc dd-marc-field {zset no tag id start stop} {
263     set n 0
264     set c [$zset getMarc $no field $tag * $id]
265     set len [llength $c]
266     if {$len == 0} {
267         return 0
268     }
269     foreach cc $c {
270         html $start
271         put-marc-contents $cc
272         html $stop
273         incr n
274     }
275     return $n
276 }
277
278 proc dl-marc-field-rec {zset no tag lead start stop startid sep} {
279     set n 0
280     set lines [$zset getMarc $no line $tag * *]
281     foreach line $lines {
282         foreach field [lindex $line 2] {
283             if {$n == 0} {
284                 html "<dt><b>$lead</b>"
285                 html "\n<dd>"
286             }
287             set id [lindex $field 0]
288             if {$id == $startid} {
289                 if {$n > 0} {
290                     html $stop
291                 }
292                 html $start
293                 incr n
294                 html [lindex $field 1]
295             } else {
296                 html $sep
297                 html [lindex $field 1]
298             }
299         }
300     }
301     if {$n > 0} {
302         html $stop
303     }
304 }
305
306 proc display-full-wais {zset no setNo targetNo} {
307     global env
308     global hist
309     global sessionId
310
311     set i 0    
312     set element junk
313     htmlToken l [join [$zset getWAIS $no text]] {
314         if {[string compare [string index $l 0] {<}]} {
315             set data($element) $l
316             continue
317         }
318         switch -exact $l {
319             <ti> {
320                 set element title 
321             }
322             <dm> {
323                 set element dateOfLastModification
324             }
325             <ci> {
326                 set element controlIdentifier
327             }
328             <lc> {
329                 set element lastChecked
330             }
331             <by> {
332                 set element bytes
333             }
334             <avli> {
335                 set element linkage
336             }
337             <cr> {
338                 incr i
339             }
340             <li> {
341                 set element "$i,linkage"
342             }
343             <cp> {
344                 set element "$i,title"
345             }
346             default {
347                 set element junk
348             }
349         }
350     }
351     if {![info exists data(title)] || ![info exists data(linkage)]} {
352         html "<tt>" [join [$zset getWAIS $no text]] "</tt>\n"
353         return
354     }
355     html {Title: } {<a href="} $data(linkage) {">} $data(title) "</a><br>\n"
356     html {URL: } $data(linkage) "<br>\n"
357     html {Score: } [$zset getWAIS $no score] "<br>\n"
358     html {Lines: } [$zset getWAIS $no lines] "<br>\n"
359     if {[info exists data(bytes)]} {
360         html {Bytes: } $data(bytes) "<br>\n"
361     }
362     if {[info exists data(dateOfLastModification)]} {
363         html {Last modified: } $data(dateOfLastModification) "<br>\n"
364     }
365     if {[info exists data(lastChecked)]} {
366         html {Last checked: } $data(lastChecked) "<br>\n"
367     }
368     html {<a href="} $env(SCRIPT_NAME) / $sessionId {/sameas.egw/}
369     html $setNo + $targetNo + 1 + $hist($setNo,maxPresent) +
370     html [egw_enc [$zset getWAIS $no documentID]] {">}
371     html {Similar WAIS record</a><br>}
372     html "<ul>\n"
373     for {set i 1} {[info exists data($i,linkage)]} {incr i} {
374         html {<li><a href="} $data($i,linkage) {">}
375         html $data($i,title) "</a><br>\n"
376         html "URL: " $data($i,linkage)
377     }
378     html "</ul>\n"
379 }
380
381 proc display-full {zset no setNo targetNo} {
382     set type [$zset type $no]
383     if {$type == "SD"} {
384         set err [lindex [$zset diag $no] 1]
385         set add [lindex [$zset diag $no] 2]
386         if {$add != {}} {
387             set add " :${add}"
388         }
389         html "Error ${err}${add} <br>\n"
390         return
391     }
392     if {$type != "DB"} {
393         return
394     }
395     set rtype [$zset recordType $no]
396     if {$rtype == "SUTRS"} {
397         html [join [$zset getSutrs $no]] "<br>\n"
398         return
399     }
400     if {$rtype == "WAIS"} {
401         display-full-wais $zset $no $setNo $targetNo
402         return
403     }
404     if {[catch {set r [$zset getMarc $no line * * *]}]} {
405         html "Unknown record type: $rtype <br>\n"
406         return
407     }
408     html "<dl>\n"
409     set n [dl-marc-field $zset $no 700 a "Author" "Authors" "<br>\n"]
410     if {$n == 0} {
411         set n [dl-marc-field $zset $no 100 a "Author" "Authors" "<br>\n"]
412     }
413     set n [dl-marc-field $zset $no 710 a "Corporate Name" {} ", "]
414     if {$n == 0} {
415         set n [dl-marc-field $zset $no 110 a "Corporate Name" {} ", "]
416     }
417     set n [dl-marc-field $zset $no 711 a "Meeting Name" {} ", "]
418     if {$n > 0} {
419         dd-marc-field $zset $no 711 {[bndc]} " " ""
420     } else {
421         set n [dl-marc-field $zset $no 111 a "Meeting Name" {} ", "]
422         if {$n > 0} {
423             dd-marc-field $zset $no 111 {[bndc]} " " " "
424         }
425     } 
426     set n [dl-marc-field $zset $no 245 {a} "Title" {} " "]
427     if {$n > 0} {
428         dd-marc-field $zset $no 245 b "<em>" "</em>"
429         dd-marc-field $zset $no 245 c " " ""
430     } else {
431         dl-marc-field $zset $no 245 {[ab]} "Title" {} " "
432     }
433     dl-marc-field $zset $no 520 a "Abstract" {} ", "
434     dl-marc-field $zset $no 072 * "Subject code" "Subject codes" ", "
435     dl-marc-field $zset $no 650 * "Subject" {} ", "
436     dl-marc-field $zset $no 260 * "Publisher" {} " "
437     dl-marc-field $zset $no 300 * "Physical Description" {} " "
438
439     dl-marc-field-rec $zset $no 500 "Notes" "" "<br>\n" "a" ", "
440
441     dl-marc-field-rec $zset $no 510 "References" "" "<br>\n" "a" ", "
442
443     dl-marc-field-rec $zset $no 511 "Participant note" "" "<br>\n" "a" ", "
444
445     dl-marc-field $zset $no 513 a "Report type" {} ", "
446     dl-marc-field $zset $no 513 b "Period covered" {} ", "
447     dl-marc-field-rec $zset $no 515 "Numbering notes" "" "<br>\n" "a" ", "
448     dl-marc-field-rec $zset $no 516 "Data notes" "" "<br>\n" "a" ", "
449     dl-marc-field-rec $zset $no 518 "Date/time notes" "" "<br>\n" "a" ", "
450
451     dl-marc-field $zset $no 350 a "Price" {} ", "
452     dl-marc-field $zset $no 362 a "Dates of publication" {} ", "
453     dl-marc-field $zset $no 850 a "Holdings" {} ", "
454
455     dl-marc-field-rec $zset $no 270 "Contact name" "" "<br>\n" p ", "
456     if {0} {
457         set n [dl-marc-field $zset $no 270 p "Contact name" {} ", "]
458         if {$n > 0} {
459             html "\n<dl>\n"
460             
461             if {0} {
462                 dl-marc-field $zset $no 270 a "Street" {} ", "
463                 dl-marc-field $zset $no 270 b "City" {} ", "
464                 dl-marc-field $zset $no 270 c "State" {} ", "
465                 dl-marc-field $zset $no 270 e "Zip code" {} ", "
466                 dl-marc-field $zset $no 270 d "Country" {} ", "
467                 dl-marc-field $zset $no 270 m "Network address" {} ", "
468                 dl-marc-field $zset $no 301 a "Service hours" {} ", "
469                 dl-marc-field $zset $no 270 k "Phone" {} ", "
470                 dl-marc-field $zset $no 270 l "Fax" {} ", "
471             } else {
472                 dl-marc-field $zset $no 270 {[abcedmakl]} "Address" {} "<br>\n"
473             }
474             
475             html "\n</dl>\n"
476         }
477     }
478     dl-marc-field $zset $no 010 a "LC control number" {} ", "
479     dl-marc-field $zset $no 010 b "NUCMC control number" {} ", "
480     dl-marc-field $zset $no 020 a "ISBN" {} ", "
481     dl-marc-field $zset $no 022 a "ISSN" {} ", "
482     set url [$zset getMarc $no field 856 * u]
483     set sp [$zset getMarc $no field 856 * 3]
484     if {"x$url" != "x"} {
485         html "<dt><b>URL</b>\n"
486         if {"x$sp" == "x"} {
487             set sp $url
488         }
489         html {<dd><a href="} [join $url] {">} [join $sp] "</a>\n"
490     }
491     dl-marc-field $zset $no 037 {[abc]} "Acquisition" {} "<br>\n"
492     dl-marc-field $zset $no 037 {[f6]} "Form of issue" {} "<br>\n"
493     dl-marc-field $zset $no 537 * "Source of data" {} "<br>\n"
494     dl-marc-field $zset $no 538 * "System details" {} "<br>\n"
495     dl-marc-field $zset $no 787 {[rstw6]} "Related information" {} "<br>\n"
496     dl-marc-field $zset $no 001 * "Local control number" {} ", "
497     html "</dl>\n"
498 }
499
500
501 proc display-rec {from to dfunc setNo targetNo} {
502     while {$from <= $to} { 
503         eval "$dfunc z39${targetNo}.${setNo} $from $setNo $targetNo"
504         incr from
505     }
506 }
507
508 proc build-scan {t i} {
509     global targets
510
511     set term [egw_form entry$i]
512     if {$term != ""} {
513         set field [join [egw_form menu$i]]
514         set attr {Title}
515         foreach x [lindex $targets($t) 2] {
516             if {[lindex $x 0] == $field} {
517                 set attr [lindex $x 1]
518             }
519         }
520         return [list $term $attr]
521     }
522     return ""
523 }
524
525 proc build-query {t ilines} {
526     global targets
527
528     set op {}
529     set q {}
530     for {set i 1} {$i <= $ilines} {incr i} {
531         set term [join [egw_form entry$i]]
532         if {[lindex $targets($t) 6] == "1"} {
533             if {[string length $op] == 0} {
534                 set q $term
535             } else {
536                 set q "$term $q"
537             }
538             set op [egw_form logic$i]
539             continue
540         }                
541         if {[string length $term] > 0} {
542             set field [join [egw_form menu$i]]
543             foreach x [lindex $targets($t) 2] {
544                 if {[lindex $x 0] == $field} {
545                     set attr [lindex $x 1]
546                 }
547             }
548             switch $op {
549             And
550                 { set q "@and $q ${attr} \"${term}\"" }
551             Or
552                 { set q "@or $q ${attr} \"${term}\"" }
553             {And not}
554                 { set q "@not $q ${attr} \"${term}\"" }
555             {}
556                 { set q "${attr} \"${term}\"" }
557             }
558             set op [egw_form logic$i]
559         }
560     }
561     return $q
562 }
563
564 proc z39scan {setNo scanNo tno scanLines scanPos cache} {
565     global hist
566     global sessionWait
567     global targets
568
569     set zz z39$tno
570     set host $hist($setNo,$tno,host)
571     set idAuth $hist($setNo,$tno,idAuthentication)
572     set database $hist($setNo,$tno,database)
573     set scanAttr $hist($setNo,scanAttr)
574     set scanTerm $hist($setNo,$scanNo,scanTerm)
575
576     mkAssoc $zz $host
577     if {[catch [list set oldHost [$zz connect]]]} {
578         set oldHost ""
579     }
580     set zs $zz.s$scanNo.$setNo
581     $zz callback ok-response
582     $zz failback fail-response
583     set thisHost [splitHostSpec $host]
584     if {[string compare $oldHost $thisHost]} {
585         catch [list $zz disconnect]
586
587         set sessionWait 0
588         if {[catch [list $zz connect $thisHost]]} {
589             displayError "Cannot connect to target" $thisHost
590             return 0
591         } elseif {$sessionWait == 0} {
592             if {[catch {egw_wait sessionWait 300}]} {
593                 $zz disconnect
594                 displayError "Cannot connect to target" $thisHost
595                 return 0
596             }
597             if {$sessionWait != 1} {
598                 displayError "Cannot connect to target" $thisHost
599                 return 0
600             }
601         }
602         $zz idAuthentication $idAuth
603         set sessionWait 0
604         if {[catch {$zz init}]} {
605             displayError "Cannot initialize target" $thisHost
606             $zz disconnect
607             return 0
608         }
609         if {[catch {egw_wait sessionWait 60}]} {
610             displayError "Cannot initialize target" $thisHost
611             $zz disconnect
612             return 0
613         }
614         if {$sessionWait != "1"} {
615             displayError "Cannot initialize target" $thisHost
616             $zz disconnect
617             return 0
618         }
619         if {![$zz initResult]} {
620             set u [$zz userInformationField]
621             $zz disconnect
622             displayError "Cannot initialize target $thisHost" $u
623             return 0
624         }
625     } else {
626         if {$cache && ![catch [list $zs numberOfTermsRequested 5]]} {
627             return 1
628         }
629     }
630     eval $zz databaseNames $database
631
632     ir-scan $zs $zz
633
634     $zs numberOfTermsRequested $scanLines
635     $zs preferredPositionInResponse $scanPos
636
637     $zz callback [list scan-response $zs]
638
639     egw_log debug "scan: ${scanAttr} ${scanTerm}"
640     set sessionWait 0
641     $zs scan "${scanAttr} ${scanTerm}"
642
643     if {[catch {egw_wait sessionWait 60}]} {
644         egw_log debug "timeout/cancel in scan"
645         displayError "Timeout in scan" {}
646         html "</body></html>\n"
647         $zz disconnect
648         return 0
649     }
650     if {$sessionWait == -1} {
651         displayError "Scan fail" "Connection closed"
652         html "</body></html>\n"
653         $zz disconnect
654     }
655     if {$sessionWait != 1} {
656         return 0
657     }
658     return 1
659 }
660
661 proc display-scan {setNo scanNo tno} {
662     global hist
663     global targets
664     global env
665     global sessionId
666
667     set zz z39$tno
668     set zs $zz.s$scanNo.$setNo
669     set m [$zs numberOfEntriesReturned]
670         
671     if {$m > 0} {
672         set t [lindex [$zs scanLine 0] 1]
673         if {$tno > 0} {
674             set hist($setNo,$tno,[expr $scanNo - 1],scanTerm) $t
675         } else {
676             set hist($setNo,[expr $scanNo - 1],scanTerm) $t
677         }
678         set t [lindex [$zs scanLine [expr $m - 1]] 1]
679         if {$tno > 0} {
680             set hist($setNo,$tno,[expr $scanNo + 1],scanTerm) $t
681         } else {
682             set hist($setNo,[expr $scanNo + 1],scanTerm) $t
683         }
684     }
685     html {<table width=500 border=0><tr>}
686     html {<td align=left><b>Scan term</b>}
687     html {<td align=right><b>Hits</b>}
688     html {<tr>} \n
689
690     for {set i 0} {$i < $m} {incr i} {
691         html {<td align=left>}
692         if {0} {
693             regsub -all {\ } [lindex [$zs scanLine $i] 1] + tterm
694             html {<a href="http:} $env(SCRIPT_NAME)
695             html / $sessionId {/query.egw/} $hist($setNo,host) + $setNo +
696             html $hist($setNo,scan) +  $tterm {">}
697         } else {
698             regsub -all {\ } [lindex [$zs scanLine $i] 1] + tterm
699             html {<a href="http:} $env(SCRIPT_NAME)
700             html / $sessionId {/search.egw/} $setNo + $tno +
701             html hyper + $tterm {">}
702         }
703         html [lindex [$zs scanLine $i] 1]
704         html {</a>} 
705         html {<td align=right>}
706         html [lindex [$zs scanLine $i] 2]
707         html {<tr>} \n
708     }
709     html {</table} \n
710 }
711
712 proc z39search {setNo piggy tno elements} {
713     global hist
714     global sessionWait
715     global targets
716
717     set zz z39$tno
718     set host $hist($setNo,$tno,host)
719     set idAuth $hist($setNo,$tno,idAuthentication)
720     set database $hist($setNo,$tno,database)
721     set query $hist($setNo,$tno,query)
722     catch {set docId $hist($setNo,$tno,queryId)}
723
724     mkAssoc $zz $host
725     if {[catch [list set oldHost [$zz connect]]]} {
726         set oldHost ""
727     }
728     $zz callback ok-response
729     $zz failback fail-response
730     set thisHost [splitHostSpec $host]
731     if {[string compare $oldHost $thisHost]} {
732         catch [list $zz disconnect]
733
734         set sessionWait 0
735         if {[catch [list $zz connect $thisHost]]} {
736             displayError "Cannot connect to target" $thisHost
737             return 0
738         } elseif {$sessionWait == 0} {
739             if {[catch {egw_wait sessionWait 300}]} {
740                 $zz disconnect
741                 displayError "Cannot connect to target" $thisHost
742                 return 0
743             }
744             if {$sessionWait != 1} {
745                 displayError "Cannot connect to target" $thisHost
746                 return 0
747             }
748         }
749         $zz idAuthentication $idAuth
750         set sessionWait 0
751         if {[catch {$zz init}]} {
752             displayError "Cannot initialize target" $thisHost
753             $zz disconnect
754             return 0
755         }
756         if {$sessionWait == 0 && [catch {egw_wait sessionWait 60}]} {
757             displayError "Cannot initialize target" $thisHost
758             $zz disconnect
759             return 0
760         }
761         if {$sessionWait != "1"} {
762             displayError "Cannot initialize target" $thisHost
763             $zz disconnect
764             return 0
765         }
766         if {![$zz initResult]} {
767             set u [$zz userInformationField]
768             $zz disconnect
769             displayError "Cannot initialize target $thisHost" $u
770             return 0
771         }
772     } elseif {![catch  [list $zz.$setNo smallSetUpperBound 0]]} {
773         if {$tno > 0} {
774             if {[info exists hist($setNo,$tno,hits)]} {
775                 return 1
776             }
777         } else {
778             if {[info exists hist($setNo,hits)]} {
779                 return 1
780             }
781         }
782     }
783     
784     if {[lindex $targets($host) 6] == "1"} {
785         wais-set $zz.$setNo $zz
786     } else {
787         ir-set $zz.$setNo $zz
788     }
789     if {![lindex $targets($host) 5]} {
790         set elements {}
791     }
792     $zz.$setNo smallSetElementSetNames $elements
793     $zz.$setNo mediumSetElementSetNames $elements
794     $zz.$setNo recordElements $elements
795
796     egw_log debug "database=$database"
797     eval $zz.$setNo databaseNames $database
798
799     $zz.$setNo preferredRecordSyntax USMARC
800
801     $zz callback [list search-response $zz.$setNo]
802     if {$piggy} {
803         $zz.$setNo largeSetLowerBound 999999
804         $zz.$setNo smallSetUpperBound 0
805         $zz.$setNo mediumSetPresentNumber $hist($setNo,maxPresent)
806     } else {
807         $zz.$setNo largeSetLowerBound 2
808         $zz.$setNo smallSetUpperBound 0
809         $zz.$setNo mediumSetPresentNumber 0
810     }
811     set sessionWait 0
812     egw_log debug "search: $query"
813
814     if {[info exists docId]} {
815         $zz.$setNo search $query $docId
816     } else {
817         $zz.$setNo search $query
818     }
819
820     if {!$sessionWait && [catch {egw_wait sessionWait 60}]} {
821         egw_log debug "timeout/cancel in search"
822         displayError "Timeout in search" {}
823         html "</body></html>\n"
824         $zz disconnect
825         return 0
826     }
827         
828     if {$sessionWait == -1} {
829         displayError "Search fail" "Connection closed"
830         html "</body></html>\n"
831         $zz disconnect
832     }
833     if {$sessionWait != 1} {
834         return 0
835     }
836     set hist($setNo,hits) [$zz.$setNo resultCount]
837     return 1
838 }
839
840 proc init-m-response {i} {
841     global zstatus
842     global zleft
843
844     egw_log debug "init-m-response"
845
846     incr zleft -1
847     if {![z39$i initResult]} {
848         set zstatus($i) -1
849         z39$i disconnect
850         return
851     }
852     set zstatus($i) 1
853 }
854
855 proc connect-m-response {i} {
856     global zstatus
857     global zleft
858
859     egw_log debug "connect-m-response"
860     z39$i callback [list init-m-response $i]
861     if {[catch {z39$i init}]} {
862         set zstatus($i) -1
863         incr zleft -1
864     }
865 }
866
867 proc fail-m-response {i} {
868     global zstatus
869     global zleft
870     
871     egw_log debug "fail-m-response"
872     set zstatus($i) -1
873     incr zleft -1
874 }
875
876 proc search-m-response {setNo i start number} {
877     global zleft
878     global zstatus
879     global hist
880
881     egw_log debug "search-m-response"
882     set status [z39$i.$setNo responseStatus]
883     egw_log debug "search-m-response1"
884     if {[lindex $status 0] == "OK"} {
885         set nor 0
886     } elseif {[lindex $status 0] == "DBOSD"} {
887         set nor [z39$i.$setNo numberOfRecordsReturned]
888     } else {
889         egw_log debug "search-m-response2"
890         incr zleft -1
891         set zstatus($i) 2
892         return
893     }
894     set hist($setNo,$i,hits) [z39$i.$setNo resultCount]
895     egw_log debug "search-m-response3"
896     set hist($setNo,$i,offset) [expr $start + $nor -1]
897     if {[expr $nor + $start] > [z39$i.$setNo resultCount]} {
898         egw_log debug "search-m-response4"
899         incr zleft -1
900         set zstatus($i) 2
901         return
902     }
903     egw_log debug "search-m-response5"
904     if {$nor >= $number} {
905         egw_log debug "search-m-response6 nor=$nor number=$number"
906         incr zleft -1
907         set zstatus($i) 2
908         return
909     }
910     egw_log debug "search-m-response7"
911     set start [expr $start + $nor]
912     set number [expr $number - $nor]
913     if {[expr $start + $number - 1] > [z39$i.$setNo resultCount]} {
914         set number [expr [z39$i.$setNo resultCount] - $start + 1]
915     }
916     z39$i callback [list search-m-response $setNo $i $start $number]
917     egw_log debug "mpresent start=$number number=$number"
918     z39$i.$setNo present $start $number
919 }
920
921 proc z39msearch {setNo elements start number cache} {
922     global zleft
923     global zstatus
924     global hist
925     global targets
926     global debug
927
928     set not $hist($setNo,0,host)
929
930     egw_log debug "z39msearch start=$start number=$number elements=$elements"
931     for {set i 1} {$i <= $not} {incr i} {
932         set host $hist($setNo,$i,host)
933         mkAssoc z39$i $host
934         set oldHost [z39$i connect]
935         set thisHost [splitHostSpec $host]
936         if {[string compare $oldHost $thisHost]} {
937             catch {z39$i disconnect}
938         }
939         z39$i callback [list connect-m-response $i]
940         z39$i failback [list fail-m-response $i]
941     }
942     set zleft 0
943     for {set i 1} {$i <= $not} {incr i} {
944         set oldHost [z39$i connect]
945         set host $hist($setNo,$i,host)
946         set thisHost [splitHostSpec $host]
947         if {![string compare $oldHost $thisHost]} {
948             continue
949         }
950         egw_log debug "old=$oldHost this=$thisHost"
951         z39$i idAuthentication $hist($setNo,$i,idAuthentication)
952         html "Connecting to target " $thisHost " <br>\n"
953         set zstatus($i) -1
954         if {![catch {z39$i connect $thisHost}]} {
955             incr zleft
956         } 
957     }
958     while {$zleft > 0} {
959         egw_log debug "Waiting for init response"
960         if {[catch {egw_wait zleft 20}]} {
961             break
962         }
963     }
964     set zleft 0
965     for {set i 1} {$i <= $not} {incr i} {
966         set host $hist($setNo,$i,host)
967         if {$debug} {
968             html "host " [splitHostSpec $host] ": "
969         }
970         egw_log debug "i=$i zstatus=$zstatus($i)"
971         if {$zstatus($i) < 1} {
972             if {$debug} {
973                 html "fail<br>\n"
974             }
975             continue
976         }
977         if {[catch [list z39$i.$setNo preferredRecordSyntax USMARC]]} {
978             if {$debug} {
979                 html "ok<br>\n"
980             }
981
982             if {[lindex $targets($host) 6] == "1"} {
983                 wais-set z39$i.$setNo z39$i
984             } else {
985                 ir-set z39$i.$setNo z39$i
986             }
987             set hist($setNo,$i,offset) 0
988             eval z39$i.$setNo databaseNames $hist($setNo,$i,database)
989
990             if {![lindex $targets($hist($setNo,$i,host)) 5]} {
991                 set thisElements {}
992             } else {
993                 set thisElements $elements
994             }
995             z39$i.$setNo smallSetElementSetNames $thisElements
996             z39$i.$setNo mediumSetElementSetNames $thisElements
997             z39$i.$setNo elementSetNames $thisElements
998             z39$i.$setNo recordElements $thisElements
999
1000             z39$i.$setNo preferredRecordSyntax USMARC
1001             z39$i callback [list search-m-response $setNo $i $start $number]
1002
1003             if {$start == 1} {
1004                 z39$i.$setNo largeSetLowerBound 999999
1005                 z39$i.$setNo smallSetUpperBound 0
1006                 z39$i.$setNo mediumSetPresentNumber $number
1007             } else {
1008                 z39$i.$setNo largeSetLowerBound 2
1009                 z39$i.$setNo smallSetUpperBound 0
1010                 z39$i.$setNo mediumSetPresentNumber 0
1011             }
1012             set zstatus($i) 1
1013             incr zleft
1014             egw_log debug "setNo=$setNo msearch " $hist($setNo,$i,query)
1015             z39$i.$setNo search $hist($setNo,$i,query)
1016         } elseif {[z39$i.$setNo resultCount] >= $start} {
1017             if {[expr $start + $number - 1] > [z39$i.$setNo resultCount]} {
1018                 set tnumber [expr [z39$i.$setNo resultCount] - $start + 1]
1019             } else {
1020                 set tnumber $number
1021             }
1022             if {![lindex $targets($hist($setNo,$i,host)) 5]} {
1023                 set thisElements {}
1024             } else {
1025                 set thisElements $elements
1026             }
1027             z39$i.$setNo smallSetElementSetNames $thisElements
1028             z39$i.$setNo mediumSetElementSetNames $thisElements
1029             z39$i.$setNo elementSetNames $thisElements
1030             z39$i.$setNo recordElements $thisElements
1031
1032             for {set n 0} {$n < $tnumber} {incr n} {
1033                 if {[z39$i.$setNo recordType [expr $start + $n]] == ""} {
1034                     if {$n > 0} {
1035                         egw_log debug "failed on $n"
1036                     }
1037                     if {$debug} {
1038                         html "no record at #" [expr $start + $n]
1039                         html " el=-" $thisElements "-"
1040                     }
1041                     break
1042                 }
1043             }
1044             if {$n == $tnumber} {
1045                 if {$debug} {
1046                     html "cached<br>\n"
1047                 }
1048                 continue
1049             }
1050             
1051             html "present<br>\n"
1052             z39$i.$setNo preferredRecordSyntax USMARC
1053             z39$i callback [list search-m-response $setNo $i $start $tnumber]
1054             incr zleft
1055             egw_log debug "mpresent start=$start number=$tnumber"
1056             z39$i.$setNo present $start $tnumber
1057         } else {
1058             if {$debug} {
1059                 html "ok<br>\n"
1060             }
1061         }
1062     }
1063     while {$zleft > 0} {
1064         egw_log debug "Waiting for search/present response"
1065         if {[catch {egw_wait zleft 60}]} {
1066             break
1067         }
1068     }
1069     for {set i 1} {$i <= $not} {incr i} {
1070         if {$zstatus($i) != 2} continue
1071         set status [z39$i.$setNo responseStatus]
1072         if {0 && [lindex $status 0] != "NSD"} {
1073             set hist($setNo,$i,offset) [z39$i.$setNo numberOfRecordsReturned]
1074         }
1075     }
1076 }
1077
1078 proc z39present {setNo tno setOffset setMax dfunc elements} {
1079     global hist
1080     global sessionWait
1081     global targets
1082
1083     set zz z39$tno
1084     set host $hist($setNo,$tno,host)
1085
1086     if {![lindex $targets($host) 5]} {
1087         set elements {}
1088     }
1089
1090     $zz.$setNo elementSetNames $elements
1091     $zz.$setNo recordElements $elements
1092     set toGet [expr 1 + $setMax - $setOffset]
1093
1094     $zz callback [list search-response $zz.$setNo]
1095
1096     while {$setMax > 0 && $toGet > 0} {
1097         for {set got 0} {$got < $toGet} {incr got} {
1098             if {[$zz.$setNo recordType [expr $setOffset + $got]] == ""} {
1099                 break
1100             }
1101         }
1102         if {$got < $toGet} {
1103             set sessionWait 0
1104             $zz.$setNo present $setOffset $toGet
1105             if {[catch {egw_wait sessionWait 300}]} {
1106                 egw_log debug "timeout/cancel in present"
1107                 $zz disconnect
1108                 break
1109             }
1110             if {$sessionWait == "0"} {
1111                 $zz disconnect
1112             }
1113             if {$sessionWait != "1"} {
1114                 break
1115             }
1116             set got [$zz.$setNo numberOfRecordsReturned]
1117             if {$got <= 0} {
1118                 break
1119             }
1120         }
1121         display-rec $setOffset [expr $got + $setOffset - 1] $dfunc $setNo $tno
1122         set setOffset [expr $got + $setOffset]
1123         set toGet [expr 1 + $setMax - $setOffset]
1124         egw_flush
1125     }
1126 }
1127
1128 proc buttons-result-set-s {setNo targetNo setMax startPos after} {
1129     global sessionId
1130     global useIcons
1131     global env
1132     global hist
1133
1134     set zz z39$targetNo
1135     html "<p>\n"
1136     button-europagate
1137     if {$setMax > 0 && $setMax < [$zz.$setNo resultCount]} {
1138         html {<a href="http:} $env(SCRIPT_NAME)
1139         html / $sessionId {/search.egw/} $setNo + $targetNo + 
1140         html [expr $setMax + 1] + [expr $setMax + $hist($setNo,maxPresent)]
1141         if {$useIcons} {
1142             html {"><img src="/egwgif/button-next-records.gif" alt="Next Records"}
1143             html { border=0></a>}
1144         } else {
1145             html {">Next Records</a>} " | \n"
1146         }
1147     }
1148     if {$setMax > 0 && $startPos != "" && $startPos != "1"} {
1149         html {<a href="http:} $env(SCRIPT_NAME)
1150         html / $sessionId {/search.egw/} $setNo + $targetNo
1151         html + [expr $startPos - $hist($setNo,maxPresent)]
1152         html + [expr $startPos - 1]
1153         if {$useIcons} {
1154             html {"><img src="/egwgif/button-previous-records.gif" }
1155             html {alt="Previous Records" border=0></a>}
1156         } else {
1157             html {">Previous Records</a>} " | \n"
1158         }
1159     }
1160     button-new-query 1 $setNo
1161     button-new-target 1
1162     button-view-history 0
1163
1164     html "<p>\n"
1165 }
1166
1167 proc display-result-set-s {setNo targetNo startPos endPos} {
1168     global hist
1169     global useIcons
1170
1171     set zz z39$targetNo
1172     set host $hist($setNo,$targetNo,host)
1173     set idAuth $hist($setNo,$targetNo,idAuthentication)
1174     set database $hist($setNo,$targetNo,database)
1175     set query $hist($setNo,$targetNo,query)
1176
1177     set useIcons 1
1178
1179     if {$startPos == ""} {
1180         if {[z39search $setNo 1 $targetNo B] != "1"} {
1181             return
1182         }
1183         set r [$zz.$setNo resultCount]
1184
1185         set setMax [$zz.$setNo resultCount]
1186         if {$setMax > $hist($setNo,maxPresent)} {
1187             set setMax $hist($setNo,maxPresent)
1188         }
1189         buttons-result-set-s $setNo $targetNo $setMax $startPos 0
1190
1191         set setOffset [$zz.$setNo numberOfRecordsReturned]
1192         if {$setMax > 0} {
1193             html {<h3> Records 1-} $setMax " out of $r</h3>\n"
1194         } else {
1195             html "<h3> No hits</h3>\n"
1196         }
1197         egw_flush
1198         html "<ul>\n"
1199         display-rec 1 $setMax display-brief $setNo $targetNo
1200         incr setOffset
1201
1202     } else {
1203         if {[z39search $setNo 0 $targetNo B] != "1"} {
1204             return 
1205         }
1206         set r [$zz.$setNo resultCount]
1207         set setOffset $startPos
1208         set setMax [$zz.$setNo resultCount]
1209         if {$setMax > $endPos} {
1210             set setMax $endPos
1211         }
1212         buttons-result-set-s $setNo $targetNo $setMax $startPos 0
1213         if {$setMax > 0} {
1214             html {<h3> Records } $startPos {-} $setMax " out of $r</h3>\n"
1215         } else {
1216             html "<h3> No hits</h3>\n"
1217         }
1218         egw_flush
1219         html "<ul>\n"
1220     }
1221     if {$setMax > 0} {
1222         z39present $setNo $targetNo $setOffset $setMax display-brief B
1223     }
1224     html "</ul>\n"
1225     set useIcons 0
1226     buttons-result-set-s $setNo $targetNo $setMax $startPos 1
1227 }
1228
1229 proc z39history {} {
1230     global nextSetNo
1231     global hist
1232     global env
1233     global sessionId
1234     global targets
1235     global html3
1236
1237     set targetNo 0
1238     if {![info exists nextSetNo]} {
1239         return
1240     }
1241     html "<h2>History</h2><br>\n"
1242     if {$html3} {
1243         html {<table width=500 border=1><tr>}
1244         html {<td align=center><b>Target</b>}
1245         html {<td align=center><b>Database</b>}
1246         html {<td align=center><b>Hits</b>}
1247         html {<td align=center><b>Query</b>}
1248         html {<tr>} "\n"
1249     } else {
1250         html {<dl>} "\n"
1251     }
1252     for {set setNo 1} {$setNo < $nextSetNo} {incr setNo} {
1253         if {$hist($setNo,scan) > 0} continue
1254         set host $hist($setNo,0,host)
1255         if {$html3} {
1256             html {<td align=left>}
1257         } else {
1258             html {<dt> }
1259         }
1260         html [lindex $targets($host) 0]
1261         if {$html3} {
1262             html {<td align=left>} [join $hist($setNo,0,database)]
1263         } else {
1264             if {[llength [lindex $targets($host) 1]] > 1} {
1265                 html ": "
1266                 foreach b $hist($setNo,0,database) {
1267                     html " $b"
1268                 }
1269             }
1270             html {. }
1271         }
1272         if {$html3} {
1273             html {<td align=right>}
1274         }
1275         if {[info exists hist($setNo,hits)]} {
1276             html { <a href="http:} $env(SCRIPT_NAME)
1277             html / $sessionId {/search.egw/} $setNo + $targetNo + 1
1278             html + $hist($setNo,maxPresent)
1279             if {1} {
1280                 html {">} $hist($setNo,hits) {</a>}
1281             } else {
1282                 html {">Result</a>: } $hist($setNo,hits) { hits.}
1283             }
1284         } else {
1285             if {$html3} {
1286                 html {Failed}
1287             } else {
1288                 html {Search failed.}
1289             }
1290         }
1291         if {$html3} {
1292             html {<td align=left>}
1293         } else {
1294             html "<dd>\n"
1295         }
1296         html { <a href="http:} $env(SCRIPT_NAME)
1297         html / $sessionId {/query.egw/} $host + $setNo
1298         if {$html3} {
1299             html {">}
1300         } else {
1301             html {">Query</a>: }
1302         }
1303         set op {}
1304         for {set i 1} {$i <= 3} {incr i} {
1305             if {[string length $hist($setNo,form,entry$i)] > 0} {
1306                 html " <b>" [join $op " "] "</b> "
1307                 html [join $hist($setNo,form,menu$i)] "=" 
1308                 html $hist($setNo,form,entry$i)
1309                 set op $hist($setNo,form,logic$i)
1310             }
1311         }
1312         if {$html3} {
1313             html {</a><tr>} "\n"
1314         }
1315     }
1316     if {$html3} {
1317         html {</table><p>}
1318     } else {
1319         html {</dl>}
1320     }
1321     html "\n"
1322 }
1323
1324 proc displayError {msga msgb} {
1325     html "<p><center>\n"
1326     html {<img src="/egwgif/noway.gif" alt="Error">}
1327     html "<h2>" $msga "</h2>\n"
1328     if {$msgb != ""} {
1329         html "<h3>" $msgb "</h3>\n"
1330     }
1331     html "</center><p>\n"
1332 }
1333
1334 proc button-europagate {} {
1335     global useIcons
1336     html {<a href="http://europagate.dtv.dk/">}
1337     if {$useIcons} {
1338         html {<img src="/egwgif/button-egw.gif" alt="Europagate" border=0></a>}
1339     } else {
1340         html {Europagate</a> | }
1341     }
1342 }
1343
1344 proc button-define-target {more} {
1345     global useIcons
1346     global env
1347     global sessionId
1348
1349     html {<a href="http:} $env(SCRIPT_NAME)
1350     html / $sessionId {/tform.egw}
1351     if {$useIcons} {
1352         html {"><img src="/egwgif/button-define-target.gif" }
1353         html {alt="Define Target" border=0></a>}
1354     } else {
1355         html {">Define Target</a>}
1356         if {$more} {
1357             html " | \n"
1358         } else {
1359             html "\n"
1360         }
1361     }
1362 }
1363
1364 proc button-new-target {more} {
1365     global useIcons
1366     global env
1367     global sessionId
1368     global mMode
1369
1370     html {<a href="http:} $env(SCRIPT_NAME)
1371     html / $sessionId 
1372     if {$mMode} {
1373         html {/mtargets.egw}
1374     } else {
1375         html {/targets.egw}
1376     }
1377     if {$useIcons} {
1378         html {"><img src="/egwgif/button-new-target.gif" }
1379         html {alt="New Target" border=0></a>}
1380     } else {
1381         html {">New Target</a>}
1382         if {$more} {
1383             html " | \n"
1384         } else {
1385             html "\n"
1386         }
1387     }
1388 }
1389
1390 proc button-view-history {more} {
1391     global useIcons
1392     global env
1393     global sessionId
1394     global nextSetNo
1395
1396     html {<a href="http:} $env(SCRIPT_NAME)
1397     html / $sessionId {/history.egw;}
1398     catch { html "/" $nextSetNo}
1399     if {$useIcons} {
1400         html {"><img src="/egwgif/button-view-history.gif" alt="View History" }
1401         html {border=0></a>}
1402     } else {
1403         html {">View History</a>}
1404         if {$more} {
1405             html " | \n"
1406         } else {
1407             html "\n"
1408         }
1409     }
1410 }
1411
1412 proc button-new-query {more setNo} {
1413     global useIcons
1414     global env
1415     global sessionId
1416     global hist
1417     global mMode
1418
1419     html {<a href="http:} $env(SCRIPT_NAME)
1420     html / $sessionId 
1421     if {$mMode} {
1422         html {/mquery.egw/} $setNo
1423     } else {
1424         html {/query.egw/} $hist($setNo,0,host) + $setNo
1425     }
1426     html {">}
1427     if {$useIcons} {
1428         html {<img src="/egwgif/button-new-query.gif" }
1429         html {alt="New Query" border=0></a>}
1430     } else {
1431         html {New Query</a>}
1432         if {$more} {
1433             html " | \n"
1434         } else {
1435             html "\n"
1436         }
1437     }
1438 }
1439
1440 proc button-scan-window {more setNo} {
1441     global useIcons
1442     global env
1443     global sessionId
1444     global hist
1445
1446     set targetNo 0
1447     html {<a href="http:} $env(SCRIPT_NAME)
1448     html / $sessionId {/search.egw/} $setNo + $targetNo + {scan} {">}
1449     if {$useIcons} {
1450         html {<img src="/egwgif/button-scan-window.gif" }
1451         html {alt="Scan" border=0></a>}
1452     } else {
1453         html {Scan</a>}
1454         if {$more} {
1455             html " | \n"
1456         } else {
1457             html "\n"
1458         }
1459     }
1460 }
1461
1462 proc maintenance {} {
1463     html {<hr>This page is maintained by }
1464     html {<a href="mailto:pwh@dtv.dk"> Peter Wad Hansen </a>.}
1465     html {Last modified 29. january 1996. <br>}
1466     html {<em> This and the following pages are under construction and }
1467     html {will continue to be so until the end of January 1996.</em>}
1468 }
1469
1470 proc splitHostSpec {host} {
1471     set i [string last . $host]
1472     if {$i > 1} {
1473         incr i -1
1474         return [string range $host 0 $i]
1475     }
1476     return $host
1477 }
1478
1479 proc mergeHostSpec {host databases} {
1480     return ${host}.[join $databases -]
1481 }
1482
1483 proc mkAssoc {assoc host} {
1484     global targets
1485
1486     if {[catch {$assoc failback fail-response}]} {
1487         if {[lindex $targets($host) 6] == "1"} {
1488             wais $assoc
1489         } else {
1490             ir $assoc
1491         }
1492     } else {
1493         if {[lindex $targets($host) 6] == "1"} {
1494             if {[$assoc comstack] == "wais"} return
1495             wais $assoc
1496         } else {
1497             if {[$assoc comstack] == "tcpip"} return
1498             ir $assoc
1499         }
1500     }
1501 }