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