root/main/trunk/greenstone2/perllib/plugins/CommonUtil.pm @ 31494

Revision 31494, 21.0 KB (checked in by kjdon, 4 years ago)

updated text string keys based on new plugin names

Line 
1###########################################################################
2#
3# CommonUtil.pm -- base class for file and directory plugins - aims to
4# handle all encoding stuff, blocking stuff, to keep it in one place
5# A component of the Greenstone digital library software
6# from the New Zealand Digital Library Project at the
7# University of Waikato, New Zealand.
8#
9# Copyright (C) 2017 New Zealand Digital Library Project
10#
11# This program is free software; you can redistribute it and/or modify
12# it under the terms of the GNU General Public License as published by
13# the Free Software Foundation; either version 2 of the License, or
14# (at your option) any later version.
15#
16# This program is distributed in the hope that it will be useful,
17# but WITHOUT ANY WARRANTY; without even the implied warranty of
18# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19# GNU General Public License for more details.
20#
21# You should have received a copy of the GNU General Public License
22# along with this program; if not, write to the Free Software
23# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24#
25###########################################################################
26
27package CommonUtil;
28
29use strict;
30no strict 'subs';
31no strict 'refs'; # allow filehandles to be variables and viceversa
32
33use encodings;
34use Unicode::Normalize 'normalize';
35
36use PrintInfo;
37use Encode;
38use Unicode::Normalize 'normalize';
39
40BEGIN {
41    @CommonUtil::ISA = ( 'PrintInfo' );
42}
43
44our $encoding_list =
45    [ { 'name' => "ascii",
46    'desc' => "{CommonUtil.encoding.ascii}" },
47      { 'name' => "utf8",
48    'desc' => "{CommonUtil.encoding.utf8}" },
49      { 'name' => "unicode",
50    'desc' => "{CommonUtil.encoding.unicode}" } ];
51
52
53my $e = $encodings::encodings;
54foreach my $enc (sort {$e->{$a}->{'name'} cmp $e->{$b}->{'name'}} keys (%$e))
55{
56    my $hashEncode =
57    {'name' => $enc,
58     'desc' => $e->{$enc}->{'name'}};
59   
60    push(@{$encoding_list},$hashEncode);
61}
62
63our $encoding_plus_auto_list =
64    [ { 'name' => "auto",
65    'desc' => "{CommonUtil.filename_encoding.auto}" },
66      { 'name' => "auto-language-analysis",
67    'desc' => "{CommonUtil.filename_encoding.auto_language_analysis}" }, # textcat
68      { 'name' => "auto-filesystem-encoding",
69    'desc' => "{CommonUtil.filename_encoding.auto_filesystem_encoding}" }, # locale
70      { 'name' => "auto-fl",
71    'desc' => "{CommonUtil.filename_encoding.auto_fl}" }, # locale followed by textcat
72      { 'name' => "auto-lf",
73    'desc' => "{CommonUtil.filename_encoding.auto_lf}" } ]; # texcat followed by locale
74
75push(@{$encoding_plus_auto_list},@{$encoding_list});
76
77my $arguments =
78    [  { 'name' => "block_exp",
79     'desc' => "{CommonUtil.block_exp}",
80     'type' => "regexp",
81     'deft' => "",
82     'reqd' => "no" },
83       { 'name' => "no_blocking",
84     'desc' => "{CommonUtil.no_blocking}",
85     'type' => "flag",
86     'reqd' => "no"},
87       { 'name' => "filename_encoding",
88     'desc' => "{CommonUtil.filename_encoding}",
89     'type' => "enum",
90     'deft' => "auto",
91     'list' => $encoding_plus_auto_list,
92     'reqd' => "no" }
93    ];
94
95my $options = { 'name'     => "CommonUtil",
96        'desc'     => "{CommonUtil.desc}",
97        'abstract' => "yes",
98        'inherits' => "no",
99        'args'     => $arguments };
100
101
102sub new {
103
104    my ($class) = shift (@_);
105    my ($pluginlist,$inputargs,$hashArgOptLists,$auxiliary) = @_;
106    push(@$pluginlist, $class);
107
108    push(@{$hashArgOptLists->{"ArgList"}},@{$arguments});
109    push(@{$hashArgOptLists->{"OptList"}},$options);
110
111    my $self = new PrintInfo($pluginlist, $inputargs, $hashArgOptLists,$auxiliary);
112
113    return bless $self, $class;
114 
115}
116
117sub init {   
118    my $self = shift (@_);
119    my ($verbosity, $outhandle, $failhandle) = @_;
120
121    print STDERR "guess encoding = ".$self->guess_filesystem_encoding()."\n";
122    print STDERR "get encoding = ".$self->get_filesystem_encoding()."\n";
123
124    # verbosity is passed through from the processor
125    $self->{'verbosity'} = $verbosity;
126
127    # as are the outhandle and failhandle
128    $self->{'outhandle'} = $outhandle if defined $outhandle;
129    $self->{'failhandle'} = $failhandle;
130
131}
132
133# converts raw filesystem filename to perl unicode format
134sub raw_filename_to_unicode {
135    my $self = shift (@_);
136    my ($file) = @_;
137
138    my $unicode_file = "";
139    ### need it in perl unicode, not raw filesystem
140    my $filename_encoding =  $self->guess_filesystem_encoding(); 
141       
142    # copied this from set_Source_metadata in BaseImporter
143    if ((defined $filename_encoding) && ($filename_encoding ne "ascii")) {
144    # Use filename_encoding to map raw filename to a Perl unicode-aware string
145    $unicode_file = decode($filename_encoding,$file);       
146    }
147    else {
148    # otherwise generate %xx encoded version of filename for char > 127
149    $unicode_file = &unicode::raw_filename_to_url_encoded($file);
150    }
151    return $unicode_file;
152
153}
154# just converts path as is to utf8.
155sub filepath_to_utf8 {
156    my $self = shift (@_); 
157    my ($file, $file_encoding) = @_;
158    my $filemeta = $file;
159
160    my $filename_encoding = $self->{'filename_encoding'}; # filename encoding setting
161
162    # Whenever filename-encoding is set to any of the auto settings, we
163    # check if the filename is already in UTF8. If it is, then we're done.
164    if($filename_encoding =~ m/auto/) {
165    if(&unicode::check_is_utf8($filemeta))
166    {
167        $filename_encoding = "utf8";
168        return $filemeta;
169    }
170    }
171   
172    # Auto setting, but filename is not utf8
173    if ($filename_encoding eq "auto")
174    {
175    # try textcat
176    $filename_encoding = $self->textcat_encoding($filemeta);
177   
178    # check the locale next
179    $filename_encoding = $self->locale_encoding() if $filename_encoding eq "undefined";
180   
181   
182    # now try the encoding of the document, if available
183    if ($filename_encoding eq "undefined" && defined $file_encoding) {
184        $filename_encoding = $file_encoding;
185    }
186
187    }
188
189    elsif ($filename_encoding eq "auto-language-analysis")
190    {   
191    $filename_encoding = $self->textcat_encoding($filemeta);
192
193    # now try the encoding of the document, if available
194    if ($filename_encoding eq "undefined" && defined $file_encoding) {
195        $filename_encoding = $file_encoding;
196    }
197    }
198
199    elsif ($filename_encoding eq "auto-filesystem-encoding")
200    {   
201    # try locale
202    $filename_encoding = $self->locale_encoding();
203    }
204
205    elsif ($filename_encoding eq "auto-fl")
206    {
207    # filesystem-encoding (locale) then language-analysis (textcat)
208    $filename_encoding = $self->locale_encoding();
209   
210    # try textcat
211    $filename_encoding = $self->textcat_encoding($filemeta) if $filename_encoding eq "undefined";
212   
213    # else assume filename encoding is encoding of file content, if that's available
214    if ($filename_encoding eq "undefined" && defined $file_encoding) {
215        $filename_encoding = $file_encoding;
216    }
217    }
218   
219    elsif ($filename_encoding eq "auto-lf")
220    {
221    # language-analysis (textcat) then filesystem-encoding (locale)
222    $filename_encoding = $self->textcat_encoding($filemeta);
223   
224    # guess filename encoding from encoding of file content, if available
225    if ($filename_encoding eq "undefined" && defined $file_encoding) {
226        $filename_encoding = $file_encoding;
227    }
228
229    # try locale
230    $filename_encoding = $self->locale_encoding() if $filename_encoding eq "undefined";
231    }
232   
233    # if still undefined, use utf8 as fallback
234    if ($filename_encoding eq "undefined") {
235    $filename_encoding = "utf8";
236    }
237
238    #print STDERR "**** UTF8 encoding the filename $filemeta ";
239   
240    # if the filename encoding is set to utf8 but it isn't utf8 already--such as when
241    # 1. the utf8 fallback is used, or 2. if the system locale is used and happens to
242    # be always utf8 (in which case the filename's encoding is also set as utf8 even
243    # though the filename need not be if it originates from another system)--in such
244    # cases attempt to make the filename utf8 to match.
245    if($filename_encoding eq "utf8" && !&unicode::check_is_utf8($filemeta)) {
246    &unicode::ensure_utf8(\$filemeta);
247    }
248
249    # convert non-unicode encodings to utf8
250    if ($filename_encoding !~ m/(?:ascii|utf8|unicode)/) {
251    $filemeta = &unicode::unicode2utf8(
252                       &unicode::convert2unicode($filename_encoding, \$filemeta)
253                       );
254    }
255
256    #print STDERR " from encoding $filename_encoding -> $filemeta\n";
257    return $filemeta;
258}
259
260# gets the filename with no path, converts to utf8, and then dm safes it.
261# filename_encoding set by user
262sub filename_to_utf8_metadata
263{
264    my $self = shift (@_); 
265    my ($file, $file_encoding) = @_;
266
267    my $outhandle = $self->{'outhandle'};
268
269    print $outhandle "****!!!!**** CommonUtil::filename_to_utf8_metadata now deprecated\n";
270    my ($cpackage,$cfilename,$cline,$csubr,$chas_args,$cwantarray) = caller(0);
271    print $outhandle "Calling method: $cfilename:$cline $cpackage->$csubr\n";
272
273    my ($filemeta) = $file =~ /([^\\\/]+)$/; # getting the tail of the filepath (skips all string parts containing slashes upto the end)
274    $filemeta = $self->filepath_to_utf8($filemeta, $file_encoding);
275
276    return $filemeta;
277}
278
279sub locale_encoding {
280    my $self = shift(@_);
281   
282    if (!defined $self->{'filesystem_encoding'}) {
283    $self->{'filesystem_encoding'} = $self->get_filesystem_encoding();
284    }
285
286    #print STDERR "*** filename encoding determined based on locale: " . $self->{'filesystem_encoding'} . "\n";
287    return $self->{'filesystem_encoding'}; # can be the string "undefined"
288}
289
290
291sub textcat_encoding {
292    my $self = shift(@_);
293    my ($filemeta) = @_;
294
295    # analyse filenames without extensions and digits (and trimmed of
296    # surrounding whitespace), so that irrelevant chars don't confuse
297    # textcat
298    my $strictfilemeta = $filemeta;
299    $strictfilemeta =~ s/\.[^\.]+$//g;
300    $strictfilemeta =~ s/\d//g;
301    $strictfilemeta =~ s/^\s*//g;
302    $strictfilemeta =~ s/\s*$//g;
303   
304    my $filename_encoding = $self->encoding_from_language_analysis($strictfilemeta);
305    if(!defined $filename_encoding) {
306    $filename_encoding = "undefined";
307    }
308
309    return $filename_encoding; # can be the string "undefined"
310}
311
312# performs textcat
313sub encoding_from_language_analysis {
314    my $self = shift(@_);
315    my ($text) = @_;
316
317    my $outhandle = $self->{'outhandle'};
318    my $best_encoding = undef;
319   
320    # get the language/encoding of the textstring using textcat
321    require textcat;  # Only load the textcat module if it is required
322    $self->{'textcat'} = new textcat() unless defined($self->{'textcat'});
323    my $results = $self->{'textcat'}->classify_cached_filename(\$text);
324
325
326    if (scalar @$results < 0) {
327    return undef;
328    }
329   
330    # We have some results, we choose the first
331    my ($language, $encoding) = $results->[0] =~ /^([^-]*)(?:-(.*))?$/;
332   
333    $best_encoding = $encoding;
334    if (!defined $best_encoding) {
335    return undef;
336    }
337   
338    if (defined $best_encoding && $best_encoding =~ m/^iso_8859/ && &unicode::check_is_utf8($text)) {
339    # the text is valid utf8, so assume that's the real encoding (since textcat is based on probabilities)
340    $best_encoding = 'utf8';
341    }
342   
343   
344    # check for equivalents where textcat doesn't have some encodings...
345    # eg MS versions of standard encodings
346    if (defined $best_encoding && $best_encoding =~ /^iso_8859_(\d+)/) {
347    my $iso = $1; # which variant of the iso standard?
348    # iso-8859 sets don't use chars 0x80-0x9f, windows codepages do
349    if ($text =~ /[\x80-\x9f]/) {
350        # Western Europe
351        if ($iso == 1 or $iso == 15) { $best_encoding = 'windows_1252' }
352        elsif ($iso == 2) {$best_encoding = 'windows_1250'} # Central Europe
353        elsif ($iso == 5) {$best_encoding = 'windows_1251'} # Cyrillic
354        elsif ($iso == 6) {$best_encoding = 'windows_1256'} # Arabic
355        elsif ($iso == 7) {$best_encoding = 'windows_1253'} # Greek
356        elsif ($iso == 8) {$best_encoding = 'windows_1255'} # Hebrew
357        elsif ($iso == 9) {$best_encoding = 'windows_1254'} # Turkish
358    }
359    }
360   
361    if (defined $best_encoding && $best_encoding !~ /^(ascii|utf8|unicode)$/ &&
362    !defined $encodings::encodings->{$best_encoding})
363    {
364    if ($self->{'verbosity'}) {
365        gsprintf($outhandle, "CommonUtil: {ReadTextFile.unsupported_encoding}\n", $text, $best_encoding, "undef");
366    }
367    $best_encoding = undef;
368    }
369   
370    return $best_encoding;
371}
372
373
374
375sub deduce_filename_encoding
376{
377    my $self = shift (@_); 
378    my ($file,$metadata,$plugin_filename_encoding) = @_;
379
380    my $gs_filename_encoding = $metadata->{"gs.filenameEncoding"};
381    my $deduced_filename_encoding = undef;
382   
383    # Start by looking for manually assigned metadata
384    if (defined $gs_filename_encoding) {
385    if (ref ($gs_filename_encoding) eq "ARRAY") {
386        my $outhandle = $self->{'outhandle'};
387       
388        $deduced_filename_encoding = $gs_filename_encoding->[0];
389       
390        my $num_vals = scalar(@$gs_filename_encoding);
391        if ($num_vals>1) {
392        print $outhandle "Warning: gs.filenameEncoding multiply defined for $file\n";
393        print $outhandle "         Selecting first value: $deduced_filename_encoding\n";
394        }
395    }
396    else {
397        $deduced_filename_encoding = $gs_filename_encoding;
398    }
399    }
400   
401    if (!defined $deduced_filename_encoding || ($deduced_filename_encoding =~ m/^\s*$/)) {
402    # Look to see if plugin specifies this value
403
404    if (defined $plugin_filename_encoding) {
405        # First look to see if we're using any of the "older" (i.e. deprecated auto-... plugin options)
406        if ($plugin_filename_encoding =~ m/^auto-.*$/) {
407        my $outhandle = $self->{'outhandle'};
408        print $outhandle "Warning: $plugin_filename_encoding is no longer supported\n";
409        print $outhandle "         default to 'auto'\n";
410        $self->{'filename_encoding'} = $plugin_filename_encoding = "auto";
411        }
412       
413        if ($plugin_filename_encoding ne "auto") {
414        # We've been given a specific filenamne encoding
415        # => so use it!
416        $deduced_filename_encoding = $plugin_filename_encoding;
417        }
418    }
419    }
420   
421    if (!defined $deduced_filename_encoding || ($deduced_filename_encoding =~ m/^\s*$/)) {
422
423    # Look to file system to provide a character encoding
424
425    # If Windows NTFS, then -- assuming we work with long file names got through
426    # Win32::GetLongFilePath() -- then the underlying file system is UTF16
427
428    if (($ENV{'GSDLOS'} =~ m/^windows$/i) && ($^O ne "cygwin")) {
429        # Can do better than working with the DOS character encoding returned by locale     
430        $deduced_filename_encoding = "unicode";
431    }
432    else {
433        # Unix of some form or other
434
435        # See if we can determine the file system encoding through locale
436        $deduced_filename_encoding = $self->locale_encoding();
437       
438        # if locale shows us filesystem is utf8, check to see filename is consistent
439        # => if not, then we have an "alien" filename on our hands
440
441        if (defined $deduced_filename_encoding && $deduced_filename_encoding =~ m/^utf-?8$/i) {
442        if (!&unicode::check_is_utf8($file)) {
443            # "alien" filename, so revert
444            $deduced_filename_encoding = undef;
445        }
446        }
447    }
448    }
449   
450#    if (!defined $deduced_filename_encoding || ($deduced_filename_encoding =~ m/^\s*$/)) {
451#       # Last chance, apply textcat to deduce filename encoding
452#       $deduced_filename_encoding = $self->textcat_encoding($file);
453#    }
454
455    if ($self->{'verbosity'}>3) {
456    my $outhandle = $self->{'outhandle'};
457
458    if (defined $deduced_filename_encoding) {
459        print $outhandle "  Deduced filename encoding as: $deduced_filename_encoding\n";
460    }
461    else {
462        print $outhandle "  No filename encoding deduced\n";
463    }
464    }
465   
466    return $deduced_filename_encoding;
467}
468
469
470sub guess_filesystem_encoding
471{
472   my $self = shift (@_);
473    # Look to file system to provide a character encoding
474   my $deduced_filename_encoding = "";
475    # If Windows NTFS, then -- assuming we work with long file names got through
476    # Win32::GetLongFilePath() -- then the underlying file system is UTF16
477
478    if (($ENV{'GSDLOS'} =~ m/^windows$/i) && ($^O ne "cygwin")) {
479        # Can do better than working with the DOS character encoding returned by locale     
480        $deduced_filename_encoding = "unicode";
481    }
482    else {
483        # Unix of some form or other
484
485        # See if we can determine the file system encoding through locale
486        $deduced_filename_encoding = $self->locale_encoding(); #utf8??
487       
488    }
489        print STDERR "guessing filesystem encoding is $deduced_filename_encoding\n";
490        return $deduced_filename_encoding;
491}
492
493
494# uses locale
495sub get_filesystem_encoding
496{
497
498    my $self = shift(@_);
499
500    my $outhandle = $self->{'outhandle'};
501    my $filesystem_encoding = undef;
502
503    eval {
504    # Works for Windows as well, returning the DOS code page in use
505    use POSIX qw(locale_h);
506   
507    # With only one parameter, setlocale retrieves the
508    # current value
509    my $current_locale = setlocale(LC_CTYPE);
510   
511    my $char_encoding = undef;
512    if ($current_locale =~ m/\./) {
513        ($char_encoding) = ($current_locale =~ m/^.*\.(.*?)$/);
514        $char_encoding = lc($char_encoding);
515    }
516    else {
517        if ($current_locale =~ m/^(posix|c)$/i) {
518        $char_encoding = "ascii";
519        }
520    }
521
522    if (defined $char_encoding) {
523        if ($char_encoding =~ m/^(iso)(8859)-?(\d{1,2})$/) {
524        $char_encoding = "$1\_$2\_$3";
525        }
526
527        $char_encoding =~ s/-/_/g;
528        $char_encoding =~ s/^utf_8$/utf8/;
529       
530        if ($char_encoding =~ m/^\d+$/) {
531        if (defined $encodings::encodings->{"windows_$char_encoding"}) {
532            $char_encoding = "windows_$char_encoding";
533        }
534        elsif (defined $encodings::encodings->{"dos_$char_encoding"}) {
535            $char_encoding = "dos_$char_encoding";
536        }
537        }
538       
539        if (($char_encoding =~ m/(?:ascii|utf8|unicode)/)
540        || (defined $encodings::encodings->{$char_encoding})) {
541        $filesystem_encoding = $char_encoding;
542        }
543        else {
544        print $outhandle "Warning: Unsupported character encoding '$char_encoding' from locale '$current_locale'\n";
545        }
546    }
547   
548
549    };
550    if ($@) {
551    print $outhandle "$@\n";
552    print $outhandle "Warning: Unable to establish locale.  Will assume filesystem is UTF-8\n";
553   
554    }
555
556    return $filesystem_encoding;
557}
558
559
560
561# write_file -- used by ConvertToPlug, for example in post processing
562#
563# where should this go, is here the best place??
564sub utf8_write_file {
565    my $self = shift (@_);
566    my ($textref, $filename) = @_;
567   
568    if (!open (FILE, ">:utf8", $filename)) {
569    gsprintf(STDERR, "ConvertToPlug::write_file {ConvertToPlug.could_not_open_for_writing} ($!)\n", $filename);
570    die "\n";
571    }
572    print FILE $$textref;
573   
574    close FILE;
575}
576
577sub block_raw_filename {
578
579    my $self = shift (@_);
580    my ($block_hash,$filename_full_path) = @_;
581
582    my $unicode_filename = $self->raw_filename_to_unicode($filename_full_path);
583    return $self->block_filename($block_hash, $unicode_filename);
584}
585
586# block unicode string filename
587sub block_filename
588{
589    my $self = shift (@_);
590    my ($block_hash,$filename_full_path) = @_;
591    print STDERR "in block filename $filename_full_path\n";
592    print STDERR &unicode::debug_unicode_string($filename_full_path)."\n";
593     
594    if (($ENV{'GSDLOS'} =~ m/^windows$/) && ($^O ne "cygwin")) {
595       # block hash contains long names, lets make sure that we were passed a long name
596       $filename_full_path = &util::upgrade_if_dos_filename($filename_full_path);
597       # lower case the entire thing, eg for cover.jpg when its actually cover.JPG
598       my $lower_filename_full_path = lc($filename_full_path);
599       $block_hash->{'file_blocks'}->{$lower_filename_full_path} = 1;
600   
601    }
602    elsif ($ENV{'GSDLOS'} =~ m/^darwin$/) {
603    # we need to normalize the filenames
604        my $composed_filename_full_path = normalize('C', $filename_full_path);
605        print STDERR "darwin, composed filename =". &unicode::debug_unicode_string($composed_filename_full_path)."\n";
606        $block_hash->{'file_blocks'}->{$composed_filename_full_path} = 1;
607   }
608 
609    else {
610    $block_hash->{'file_blocks'}->{$filename_full_path} = 1;
611    }
612}
613
614
615# filename is raw filesystem name
616sub raw_file_is_blocked {
617     my $self = shift (@_);
618     my ($block_hash, $filename_full_path) = @_;
619
620     my $unicode_filename_full_path = $self->raw_filename_to_unicode($filename_full_path);
621     return $self->file_is_blocked($block_hash, $unicode_filename_full_path);
622}
623
624# filename must be perl unicode string
625sub file_is_blocked {
626    my $self = shift (@_);
627    my ($block_hash, $filename_full_path) = @_;
628
629    #
630    print STDERR "in file is blocked $filename_full_path\n";
631    print STDERR &unicode::debug_unicode_string($filename_full_path)."\n";
632    if (($ENV{'GSDLOS'} =~ m/^windows$/) && ($^O ne "cygwin")) {
633    # convert to long filenames if needed
634    $filename_full_path = &util::upgrade_if_dos_filename($filename_full_path);
635    # all block paths are lowercased.
636    my $lower_filename = lc ($filename_full_path);
637    if (defined $block_hash->{'file_blocks'}->{$lower_filename}) {
638        $self->{'num_blocked'} ++;
639        return 1;
640    }
641    }
642    elsif ($ENV{'GSDLOS'} =~ m/^darwin$/) {
643
644    # on mac, we want composed form in the block hash   
645        my $composed_form = normalize('C', $filename_full_path);
646        print STDERR "gsdlos = darwin, composed = ". &unicode::debug_unicode_string($composed_form) ."\n";
647        if (defined $block_hash->{'file_blocks'}->{$composed_form}) {
648            $self->{'num_blocked'} ++;
649            print STDERR "BLOCKED 1\n";
650            return 1;
651        }
652    }
653
654    else {
655    if (defined $block_hash->{'file_blocks'}->{$filename_full_path}) {
656        $self->{'num_blocked'} ++;
657        print STDERR "BLOCKED\n";
658        return 1;
659    }
660    }
661    # check Directory plugin's own block_exp
662    if ($self->{'block_exp'} ne "" && $filename_full_path =~ /$self->{'block_exp'}/) {
663    $self->{'num_blocked'} ++;
664    return 1; # blocked
665    }
666    print STDERR "NOT BLOCKED\n";
667    return 0;
668}
669
670
6711;
672
Note: See TracBrowser for help on using the browser.