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