Yet another fix regarding relative links.
[tclrobot.git] / robot.tcl
1 #!/usr/bin/tclsh 
2 # $Id: robot.tcl,v 1.20 2001/06/29 22:25:55 adam Exp $
3 #
4 proc RobotFileNext1 {area lead} {
5     # puts "RobotFileNext1 area=$area lead=$lead"
6     if {[catch {set ns [glob ${area}/*]}]} {
7         return {}
8     }
9     foreach n $ns {
10         if {[file isfile $n]} {
11             set off [string last / $n]
12             incr off 2
13             return $lead/[string range $n $off end]
14         }
15     }
16     foreach n $ns {
17         if {[file isdirectory $n]} {
18             set off [string last / $n]
19             incr off 2
20             set sb [RobotFileNext1 $n $lead/[string range $n $off end]]
21             if {[string length $sb]} {
22                 return $sb
23             }
24         }
25     }
26     return {}
27 }
28
29 proc RobotWriteRecord {outf fromurl distance} {
30     puts $outf "<zmbot>"
31     puts $outf "<distance>"
32     puts $outf $distance
33     puts $outf "</distance>"
34     puts $outf "<fromurl>"
35     puts $outf $fromurl
36     puts $outf "</fromurl>"
37     puts $outf "</zmbot>"
38 }
39
40 proc RobotReadRecord {inf fromurlx distancex} {
41     upvar $fromurlx fromurl
42     upvar $distancex distance
43     gets $inf
44     gets $inf
45     set distance [string trim [gets $inf]]
46     # puts "got distance = $distance"
47     gets $inf
48     gets $inf
49     set fromurl [string trim [gets $inf]]
50 }
51
52 proc RobotFileNext {area} {
53     global robotSeq global idleTime ns
54
55     # puts "RobotFileNext robotSeq=$robotSeq"
56     if {$robotSeq < 0} {
57         return {}
58     }
59     if {$robotSeq == 0} {
60         if {[catch {set ns [glob ${area}/*]}]} {
61             return {}
62         }
63     }
64     set off [string length $area]
65     incr off
66     set n [lindex $ns $robotSeq]
67     if {![string length $n]} {
68         set robotSeq -1
69         flush stdout
70         puts "------------ N E X T  R O U N D --------"
71         return wait
72     }
73     incr robotSeq
74     if {[file isfile $n/frobots.txt]} {
75         puts "ok returning http://[string range $n $off end]/robots.txt"
76         return http://[string range $n $off end]/robots.txt
77     } elseif {[file isdirectory $n]} {
78         set sb [RobotFileNext1 $n http://[string range $n $off end]]
79         if {[string length $sb]} {
80             return $sb
81         }
82     }
83     puts "no more work at end of RobotFileNext n=$n"
84     puts "ns=$ns"
85     return {}
86 }
87
88
89 proc RobotFileExist {area host path} {
90     # puts "RobotFileExist begin area=$area host=$host path=$path"
91     set lpath [split $path /]
92     set l [llength $lpath]
93     incr l -1
94     set t [lindex $lpath $l]
95     incr l -1
96     set npath $area/$host[join [lrange $lpath 0 $l] /d]/f$t
97     # puts "RobotFileExist end npath=$npath"
98     return [file exists $npath]
99 }
100
101 proc RobotFileUnlink {area host path} {
102     # puts "RobotFileUnlink begin"
103     # puts "area=$area host=$host path=$path"
104     set lpath [split $path /]
105     set l [llength $lpath]
106     incr l -1
107     set t [lindex $lpath $l]
108     incr l -1
109     set npath $area/$host[join [lrange $lpath 0 $l] /d]/f$t
110     # puts "npath=$npath"
111     set comp [split $npath /]
112     set l [llength $comp]
113     incr l -1
114     if {[catch {exec rm [join $comp /]}]} return
115     incr l -1
116     for {set i $l} {$i > 0} {incr i -1} {
117         set path [join [lrange $comp 0 $i] /]
118         if {![catch {glob $path/*}]} return
119         exec rmdir ./$path
120     }
121     # puts "RobotFileUnlink end"
122 }
123
124 proc RobotFileClose {out} {
125     if [string compare $out stdout] {
126         close $out
127     }
128 }
129
130 proc RobotFileOpen {area host path {mode w}} {
131     set orgPwd [pwd]
132     global workdir
133
134     if {![info exists workdir]} {
135         return stdout
136     }
137     #puts "RobotFileOpen orgPwd=$orgPwd area=$area host=$host path=$path mode=$mode"
138     if {[string compare $orgPwd $workdir]} {
139         puts "ooops. RobotFileOpen failed"
140         puts "workdir = $workdir"
141         puts "pwd = $orgPwd"
142         exit 1
143     }
144     set comp [split $area/$host$path /]
145     set len [llength $comp]
146     incr len -1
147     for {set i 0} {$i < $len} {incr i} {
148         if {$i > 1} {
149             set d "d[lindex $comp $i]" 
150         } else {
151             set d [lindex $comp $i]
152         }
153         if {[catch {cd ./$d}]} {
154             exec mkdir $d
155             cd ./$d
156             if {![string compare $area unvisited] && $i == 1 && $mode == "w"} {
157                 set out [open frobots.txt w]
158                 puts "creating robots.txt in $d"
159                 close $out
160             }
161         }
162     }
163     set d [lindex $comp $len]
164     if {[string length $d]} {
165         if {[file isdirectory $d]} {
166             set out [open $d/f $mode]
167         } else {
168             set out [open f$d $mode]
169         }
170     } else {
171         set out [open f $mode]
172     }
173     cd $orgPwd
174     return $out
175 }
176
177 proc RobotRR {} {
178     global robotSeq robotsRunning
179
180     incr robotsRunning -1
181     while {$robotsRunning} {
182         vwait robotsRunning
183     }
184     set robotSeq 0
185     RobotStart
186 }
187
188 proc RobotRestart {url sock} {
189     global URL robotsRunning
190
191     close $sock
192     after cancel $URL($sock,cancel) 
193
194     foreach v [array names URL $url,*] {
195         unset URL($v)
196     }
197
198     incr robotsRunning -1
199     RobotStart
200 }
201
202 proc RobotStart {} {
203     global URL
204     global robotsRunning robotsMax idleTime
205   
206     # puts "RobotStart"
207     while {1} {
208         set url [RobotFileNext unvisited]
209         if {![string length $url]} {
210             return
211         }
212         incr robotsRunning
213         if {[string compare $url wait] == 0} {
214             after $idleTime RobotRR
215             return
216         }
217         set r [RobotGetUrl $url {}]
218         if {!$r} {
219             if {$robotsRunning >= $robotsMax} return
220         } else {
221             incr robotsRunning -1
222             if {![RobotFileExist bad $URL($url,hostport) $URL($url,path)]} {
223                 set outf [RobotFileOpen bad $URL($url,hostport) $URL($url,path)]
224                 RobotFileClose $outf
225             }
226             RobotFileUnlink unvisited $URL($url,hostport) $URL($url,path)
227         }
228     }
229 }
230
231 proc headSave {url out} {
232     global URL
233     
234     if {[info exists URL($url,head,last-modified)]} {
235         puts $out "<lastmodified>$URL($url,head,last-modified)</lastmodified>"
236     }
237     puts $out {<si>}
238     if {[info exists URL($url,head,date)]} {
239         puts $out " <date>$URL($url,head,date)</date>"
240     }
241     if {[info exists URL($url,head,content-length)]} {
242         puts $out " <by>$URL($url,head,content-length)</by>"
243     }
244     if {[info exists URL($url,head,server)]} {
245         puts $out " <format>$URL($url,head,server)</format>"
246     }
247     puts $out {</si>}
248     puts $out {<publisher>}
249     puts $out " <identifier>$url</identifier>"
250     if {[info exists URL($url,head,content-type)]} {
251         puts $out " <type>$URL($url,head,content-type)</type>"
252     }
253     puts $out {</publisher>}
254 }
255
256 proc RobotHref {url hrefx hostx pathx} {
257     global URL domains
258     upvar $hrefx href
259     upvar $hostx host
260     upvar $pathx path
261
262     puts "Ref url = $url href=$href"
263
264     if {[string first { } $href] >= 0} {
265         return 0
266     }
267     if {[string length $href] > 256} {
268         return 0
269     }
270     if {[string first {?} $href] >= 0} {
271         return 0
272     }
273     if {[string first {?} $url] >= 0 && [string first {?} $href] >= 0} {
274         return 0
275     }
276     # get method (if any)
277     if {![regexp {^([^/:]+):(.*)} $href x method hpath]} {
278         set hpath $href
279         set method http
280     } else {
281         if {[string compare $method http]} {
282             return 0
283         }
284     }
285     # get host (if any)
286     if {[regexp {^//([^/]+)([^\#]*)} $hpath x host surl]} {
287         if {![string length $surl]} {
288             set surl /
289         }
290         if {[info exist domains]} {
291             set ok 0
292             foreach domain $domains {
293                 if {[string match $domain $host]} {
294                     set ok 1
295                     break
296                  }
297             }
298             if {!$ok} {
299                 return 0
300             }
301         }
302     } else {
303         regexp {^([^\#]*)} $hpath x surl
304         set host $URL($url,hostport)
305     }
306     if {![string length $surl]} {
307         return 0
308     }
309     if {[string first / $surl]} {
310         # relative path
311         regexp {^([^\#?]*)} $URL($url,path) x dpart
312         set l [string last / $dpart]
313         if {[expr $l >= 0]} {
314             set surl [string range $dpart 0 $l]$surl
315         } else {
316             set surl $dpart/$surl
317         }
318     }
319     set surllist [split $surl /]
320     catch {unset path}
321     set pathl 0
322     foreach c $surllist {
323         switch -- $c {
324             .. {
325                 if {$pathl > 0} {
326                     incr pathl -2
327                     set path [lrange $path 0 $pathl]
328                     incr pathl
329                 }
330             }
331             . {
332
333             }
334             default {
335                 incr pathl
336                 lappend path $c
337             }
338         }
339     }
340     if {$pathl} {
341         set path [join $path /]
342     } else {
343         set path ""
344     }
345     regsub -all {~} $path {%7E} path
346     set href "$method://$host$path"
347     puts "Ref href = $href"
348     return 1
349 }
350
351 proc RobotError {url code} {
352     global URL
353
354     puts "Bad URL $url, $code"
355     set fromurl {}
356     set distance -1
357     if {[RobotFileExist unvisited $URL($url,hostport) $URL($url,path)]} {
358         set inf [RobotFileOpen unvisited $URL($url,hostport) $URL($url,path) r]
359         RobotReadRecord $inf fromurl distance
360         RobotFileClose $inf
361     }
362     RobotFileUnlink unvisited $URL($url,hostport) $URL($url,path)
363     if {![RobotFileExist bad $URL($url,hostport) $URL($url,path)]} {
364         set outf [RobotFileOpen bad $URL($url,hostport) $URL($url,path)]
365         RobotWriteRecord $outf $fromurl $distance
366         RobotFileClose $outf
367     }
368 }
369
370 proc RobotRedirect {url tourl code} {
371     global URL
372
373     puts "Redirecting from $url to $tourl"
374
375     set distance {}
376     set fromurl {}
377     if {[RobotFileExist unvisited $URL($url,hostport) $URL($url,path)]} {
378         set inf [RobotFileOpen unvisited $URL($url,hostport) $URL($url,path) r]
379         RobotReadRecord $inf fromurl distance
380         RobotFileClose $inf
381     }
382     if {![RobotFileExist bad $URL($url,hostport) $URL($url,path)]} {
383         set outf [RobotFileOpen bad $URL($url,hostport) $URL($url,path)]
384         RobotWriteRecord $outf $fromurl $distance
385         RobotFileClose $outf
386     }
387     if {[RobotHref $url tourl host path]} {
388         if {![RobotFileExist visited $host $path]} {
389             if {![RobotFileExist unvisited $host $path]} {
390                 set outf [RobotFileOpen unvisited $host $path]
391                 RobotWriteRecord $outf $fromurl $distance
392                 RobotFileClose $outf
393             }
394         } else {
395             set olddistance {}
396             set inf [RobotFileOpen visited $host $path r]
397             RobotReadRecord $inf oldurl olddistance
398             RobotFileClose $inf
399             if {[string length $olddistance] == 0} {
400                 set olddistance 1000
401             }
402             if {[string length $distance] == 0} {
403                 set distance 1000
404             }
405             puts "distance=$distance olddistance=$olddistance"
406             if {[expr $distance < $olddistance]} {
407                 set outf [RobotFileOpen unvisited $host $path]
408                 RobotWriteRecord $outf $tourl $distance
409                 RobotFileClose $outf
410             }
411         }
412     }
413     if {[catch {RobotFileUnlink unvisited $URL($url,hostport) $URL($url,path)}]} {
414         puts "unlink failed"
415         exit 1
416     }
417 }
418
419 proc RobotTextHtml {url out} {
420     global URL maxDistance
421
422     set distance 0
423     if {$maxDistance < 1000 && [info exists URL($url,dist)]} {
424         set distance [expr $URL($url,dist) + 1]
425     }
426     htmlSwitch $URL($url,buf) \
427         title {
428             puts $out "<title>$body</title>"
429         } -nonest meta {
430             puts -nonewline $out "<meta"
431             foreach a [array names parm] {
432                 puts -nonewline $out " $a"
433                 puts -nonewline $out {="}
434                 puts -nonewline $out $parm($a)
435                 puts -nonewline $out {"}
436             }
437             puts $out {></meta>}
438         } body {
439             regsub -all -nocase {<script([^<]|(<!.*>))*</script>} $body {} abody
440             regsub -all {<[^\>]+>} $abody {} nbody
441             puts $out "<documentcontent>"
442             puts $out $nbody
443             puts $out "</documentcontent>"
444         } -nonest a {
445             if {![info exists parm(href)]} {
446                 puts "no href"
447                 continue
448             }
449             if {[expr $distance <= $maxDistance]} {
450                 set href [string trim $parm(href)]
451                 if {![RobotHref $url href host path]} continue
452                 
453                 puts $out "<cr>"
454                 puts $out "<identifier>$href</identifier>"
455                 puts $out "<description>$body</description>"
456                 puts $out "</cr>"
457
458                 if {![RobotFileExist visited $host $path]} {
459                     set olddistance 1000
460                     if {![RobotFileExist bad $host $path]} {
461                         if {[RobotFileExist unvisited $host $path]} {
462                             set inf [RobotFileOpen unvisited $host $path r]
463                             RobotReadRecord $inf oldurl olddistance
464                             RobotFileClose $inf
465                         }
466                     } else {
467                         set olddistance 0
468                     }
469                     if {[string length $olddistance] == 0} {
470                         set olddistance 1000
471                     }
472                     if {[expr $distance < $olddistance]} {
473                         set outf [RobotFileOpen unvisited $host $path]
474                         RobotWriteRecord $outf $url $distance
475                         RobotFileClose $outf
476                     }
477                 } elseif {[string compare $href $url]} {
478                     set inf [RobotFileOpen visited $host $path r]
479                     RobotReadRecord $inf xurl olddistance
480                     close $inf
481                     if {[string length $olddistance] == 0} {
482                         set olddistance 1000
483                     }
484                     if {[expr $distance < $olddistance]} {
485                         puts "OK remarking url=$url href=$href"
486                         puts "olddistance = $olddistance"
487                         puts "newdistance = $distance"
488                         set outf [RobotFileOpen unvisited $host $path]
489                         RobotWriteRecord $outf $url $distance
490                         RobotFileClose $outf
491                     }
492                 }
493             }
494         } -nonest area {
495             if {![info exists parm(href)]} {
496                 puts "no href"
497                 continue
498             }
499             if {[expr $distance <= $maxDistance]} {
500                 set href [string trim $parm(href)]
501                 if {![RobotHref $url href host path]} continue
502                 
503                 puts $out "<cr>"
504                 puts $out "<identifier>$href</identifier>"
505                 puts $out "<description></description>"
506                 puts $out "</cr>"
507
508                 if {![RobotFileExist visited $host $path]} {
509                     set olddistance 1000
510                     if {![RobotFileExist bad $host $path]} {
511                         if {[RobotFileExist unvisited $host $path]} {
512                             set inf [RobotFileOpen unvisited $host $path r]
513                             RobotReadRecord $inf oldurl olddistance
514                             RobotFileClose $inf
515                         }
516                     } else {
517                         set olddistance 0
518                     }
519                     if {[string length $olddistance] == 0} {
520                         set olddistance 1000
521                     }
522                     if {[expr $distance < $olddistance]} {
523                         set outf [RobotFileOpen unvisited $host $path]
524                         RobotWriteRecord $outf $url $distance
525                         RobotFileClose $outf
526                     }
527                 } elseif {[string compare $href $url]} {
528                     set inf [RobotFileOpen visited $host $path r]
529                     RobotReadRecord $inf xurl olddistance
530                     close $inf
531                     if {[string length $olddistance] == 0} {
532                         set olddistance 1000
533                     }
534                     if {[expr $distance < $olddistance]} {
535                         puts "OK remarking url=$url href=$href"
536                         puts "olddistance = $olddistance"
537                         puts "newdistance = $distance"
538                         set outf [RobotFileOpen unvisited $host $path]
539                         RobotWriteRecord $outf $url $distance
540                         RobotFileClose $outf
541                     }
542                 }
543             }
544         }
545 }
546
547 proc RobotsTxt {url} {
548     global agent URL
549
550     RobotsTxt0 URL(URL($url,hostport),robots) $URL($url,buf)
551 }
552
553 proc RobotsTxt0 {v buf} {
554     global URL agent
555     set section 0
556     foreach l [split $buf \n] {
557         if {[regexp {([-A-Za-z]+):[ ]*([^\# ]+)} $l match cmd arg]} {
558             puts "cmd=$cmd arg=$arg"
559             switch -- [string tolower $cmd] {
560                 user-agent {
561                     if {$section} break
562                     set pat [string tolower $arg]*
563                     set section [string match $pat $agent]
564                 }
565                 disallow {
566                     if {$section} {
567                         puts "rule [list 0 $arg]"
568                         lappend $v [list 0 $arg]
569                     }
570                 }
571                 allow {
572                     if {$section} {
573                         puts "rule [list 1 $arg]"
574                         lappend $v [list 1 $arg]
575                     }
576                 }
577             }
578         }
579     }
580 }
581
582 proc RobotTextPlain {url out} {
583     global URL
584
585     puts $out "<documentcontent>"
586     regsub -all {<} $URL($url,buf) {\&lt;} content
587     puts $out $content
588     puts $out "</documentcontent>"
589
590     if {![string compare $URL($url,path) /robots.txt]} {
591         RobotsTxt $url
592     }
593 }
594
595 proc Robot200 {url} {
596     global URL domains
597     
598     set out [RobotFileOpen raw $URL($url,hostport) $URL($url,path)]
599     puts -nonewline $out $URL($url,buf)
600     RobotFileClose $out
601
602     set out [RobotFileOpen visited $URL($url,hostport) $URL($url,path)]
603     puts $out "<zmbot>"
604
605     set distance 1000
606     if {[RobotFileExist unvisited $URL($url,hostport) $URL($url,path)]} {
607         set inf [RobotFileOpen unvisited $URL($url,hostport) $URL($url,path) r]
608         RobotReadRecord $inf fromurl distance
609         RobotFileClose $inf
610     }
611     set URL($url,dist) $distance
612     puts $out "<distance>"
613     puts $out "  $distance"
614     puts $out "</distance>"
615     headSave $url $out
616     puts "Parsing $url distance=$distance"
617     switch $URL($url,head,content-type) {
618         text/html {
619             if {[string length $distance]} {
620                 RobotTextHtml $url $out
621             }
622         }
623         text/plain {
624             RobotTextPlain $url $out
625         }
626         application/pdf {
627             set pdff [open test.pdf w]
628             puts -nonewline $pdff $URL($url,buf)
629             close $pdff
630         }
631     }
632     puts $out "</zmbot>"
633     RobotFileClose $out
634     # puts "Parsing done"
635     RobotFileUnlink unvisited $URL($url,hostport) $URL($url,path)
636 }
637
638 proc RobotReadContent {url sock binary} {
639     global URL
640
641     set buffer [read $sock 16384]
642     set readCount [string length $buffer]
643
644     if {$readCount <= 0} {
645         Robot200 $url
646         RobotRestart $url $sock
647     } elseif {!$binary && [string first \0 $buffer] >= 0} {
648         Robot200 $url
649         RobotRestart $url $sock
650     } else {
651         # puts "Got $readCount bytes"
652         set URL($url,buf) $URL($url,buf)$buffer
653     }
654 }
655
656 proc RobotReadHeader {url sock} {
657     global URL
658
659     puts "RobotReadHeader $url"
660     if {[catch {set buffer [read $sock 2148]}]} {
661         RobotError $url 404
662         RobotRestart $url $sock
663     }
664     set readCount [string length $buffer]
665     
666     if {$readCount <= 0} {
667         RobotError $url 404
668         RobotRestart $url $sock
669     } else {
670         # puts "Got $readCount bytes"
671         set URL($url,buf) $URL($url,buf)$buffer
672         
673         set n [string first \r\n\r\n $URL($url,buf)]
674         if {$n > 1} {
675             set code 0
676             set version {}
677             set headbuf [string range $URL($url,buf) 0 $n]
678             incr n 4
679             set URL($url,buf) [string range $URL($url,buf) $n end]
680             
681             regexp {^HTTP/([0-9.]+)[ ]+([0-9]+)} $headbuf x version code
682             set lines [split $headbuf \n]
683             foreach line $lines {
684                 if {[regexp {^([^:]+):[ ]+([^;]*)} $line x name value]} {
685                     set URL($url,head,[string tolower $name]) [string trim $value]
686                 }
687             }
688             puts "code = $code"
689             set URL($url,state) skip
690             switch $code {
691                 301 {
692                     RobotRedirect $url $URL($url,head,location) 301
693                     RobotRestart $url $sock
694                 }
695                 302 {
696                     RobotRedirect $url $URL($url,head,location) 302
697                     RobotRestart $url $sock
698                 }
699                 200 {
700                     if {![info exists URL($url,head,content-type)]} {
701                         set URL($url,head,content-type) {}
702                     }
703                     set binary 0
704                     switch $URL($url,head,content-type) {
705                         application/pdf {
706                             set binary 1
707                         }
708                     }
709                     fileevent $sock readable [list RobotReadContent $url $sock $binary]
710                 }
711                 default {
712                     RobotError $url $code
713                     RobotRestart $url $sock
714                 }
715             }
716         }
717     }
718 }
719
720 proc RobotSockCancel {url sock} {
721
722     puts "RobotSockCancel sock=$sock url=$url"
723     RobotError $url 401
724     RobotRestart $url $sock
725 }
726
727 proc RobotConnect {url sock} {
728     global URL agent acceptLanguage
729
730     fconfigure $sock -translation {lf crlf} -blocking 0
731     fileevent $sock readable [list RobotReadHeader $url $sock]
732     puts $sock "GET $URL($url,path) HTTP/1.0"
733     puts $sock "Host: $URL($url,host)"
734     puts $sock "User-Agent: $agent"
735     if {[string length $acceptLanguage]} {
736         puts $sock "Accept-Language: $acceptLanguage"
737     }
738     puts $sock ""
739     flush $sock
740     set URL($sock,cancel) [after 30000 [list RobotSockCancel $url $sock]]
741 }
742
743 proc RobotNop {} {
744
745 }
746
747 proc RobotGetUrl {url phost} {
748     global URL robotsRunning
749     flush stdout
750     puts "RobotGetUrl --------- robotsRunning=$robotsRunning url=$url"
751     if {![regexp {([^:]+)://([^/]+)(.*)} $url x method hostport path]} {
752         return -1
753     }
754     if {![regexp {([^:]+):([0-9]+)} $hostport x host port]} {
755         set port 80
756         set host $hostport
757     }
758     set URL($url,method) $method
759     set URL($url,host) $host
760     set URL($url,hostport) $hostport
761     set URL($url,path) $path
762     set URL($url,state) head
763     set URL($url,buf) {}
764
765     if {[string compare $path /robots.txt]} {
766         set ok 1
767         if {![info exists URL($hostport,robots)]} {
768             puts "READING robots.txt for host $hostport"
769             if {[RobotFileExist visited $hostport /robots.txt]} {
770                 set inf [RobotFileOpen visited $hostport /robots.txt r]
771                 set buf [read $inf 32768]
772                 close $inf
773             } else {
774                 set buf "User-agent: *\nAllow: /\n"
775             }
776             RobotsTxt0 URL($hostport,robots) $buf
777         }
778         if {[info exists URL($hostport,robots)]} {
779             foreach l $URL($hostport,robots) {
780                 if {[string first [lindex $l 1] $path] == 0} {
781                     set ok [lindex $l 0]
782                     break
783                 }
784             }
785         }
786         if {!$ok} {
787             puts "skipped due to robots.txt"
788             return -1
789         }
790     }
791     if [catch {set sock [socket -async $host $port]}] {
792         return -1
793     }
794     RobotConnect $url $sock
795
796     return 0
797 }
798
799 if {![llength [info commands htmlSwitch]]} {
800     set e [info sharedlibextension]
801     if {[catch {load ./tclrobot$e}]} {
802         load tclrobot$e
803     }
804 }
805
806 set agent "zmbot/0.0"
807 if {![catch {set os [exec uname -s -r]}]} {
808     set agent "$agent ($os)"
809 }
810
811 puts "agent: $agent"
812
813 proc bgerror {m} {
814     global errorInfo
815     puts "BGERROR $m"
816     puts $errorInfo
817 }
818
819 set robotsRunning 0
820 set robotSeq 0
821 set workdir [pwd]
822 set idleTime 60000
823 set acceptLanguage {}
824
825 set i 0
826 set l [llength $argv]
827
828 # For testing only
829 if {0} {
830     set url "http://www.sportsfiskeren.dk/sportsfiskeren/corner/index.htm"
831     set href "../../data/../../data2/newsovs.asp?Mode=5"
832
833     set URL($url,path) /sportsfiskeren/corner/index.htm
834     set URL($url,hostport) www.sportsfiskeren.dk
835     RobotHref $url href host path
836     exit 0
837 }
838
839 if {$l < 2} {
840     puts {tclrobot: usage [-j jobs] [-i idle] [-c count] [-d domain] [url ..]}
841     puts " Example: -c 3 -d '*.dk' http://www.indexdata.dk/"
842     exit 1
843 }
844
845 while  {$i < $l} {
846     set arg [lindex $argv $i]
847     switch -glob -- $arg {
848         -j* {
849             set robotsMax [string range $arg 2 end]
850             if {![string length $robotsMax]} {
851                 set robotsMax [lindex $argv [incr i]]
852             }
853         }
854         -c* {
855             set maxDistance [string range $arg 2 end]
856             if {![string length $maxDistance]} {
857                 set maxDistance [lindex $argv [incr i]]
858             }
859         }
860         -d* {
861             set dom [string range $arg 2 end]
862             if {![string length $dom]} {
863                 set dom [lindex $argv [incr i]]
864             }
865             lappend domains $dom
866         }
867         -i* {
868             set idleTime [string range $arg 2 end]
869             if {![string length $idleTime]} {
870                 set idleTime [lindex $argv [incr i]]
871             }
872         }
873         -l* {
874             set acceptLanguage [string range $arg 2 end]
875             if {![string length $acceptLanguage]} {
876                 set acceptLanguage [lindex $argv [incr i]]
877             }
878         }
879         default {
880             set href $arg
881             if {[RobotHref http://www.indexdata.dk/ href host path]} {
882                 if {![RobotFileExist visited $host $path]} {
883                     set outf [RobotFileOpen unvisited $host $path]
884                     RobotWriteRecord $outf href 0
885                     RobotFileClose $outf
886                 }
887             }
888         }
889     }
890     incr i
891 }
892
893 if {![info exist domains]} {
894     set domains {*}
895 }
896 if {![info exist maxDistance]} {
897     set maxDistance 50
898 }
899 if {![info exist robotsMax]} {
900     set robotsMax 5
901 }
902
903 puts "domains=$domains"
904 puts "max distance=$maxDistance"
905 puts "max jobs=$robotsMax"
906
907 RobotStart
908
909 while {$robotsRunning} {
910     vwait robotsRunning
911 }