From 78e34fbdc255fd3f71f5b43ce1acd1fa0678e1ce Mon Sep 17 00:00:00 2001
From: Joey Hess <joey@kodama.kitenet.net>
Date: Mon, 25 Aug 2008 19:52:34 -0400
Subject: filecheck: New plugin factoring out the PageSpec additions that were
 originally part of the attachment plugin.

---
 IkiWiki/Plugin/attachment.pm                    | 185 +----------------------
 IkiWiki/Plugin/filecheck.pm                     | 192 ++++++++++++++++++++++++
 debian/changelog                                |   2 +
 doc/ikiwiki/pagespec/attachment.mdwn            |   2 +-
 doc/ikiwiki/pagespec/attachment/discussion.mdwn |   2 +
 doc/plugins/attachment.mdwn                     |  13 +-
 doc/plugins/filecheck.mdwn                      |  16 ++
 7 files changed, 217 insertions(+), 195 deletions(-)
 create mode 100644 IkiWiki/Plugin/filecheck.pm
 create mode 100644 doc/plugins/filecheck.mdwn

diff --git a/IkiWiki/Plugin/attachment.pm b/IkiWiki/Plugin/attachment.pm
index c78a1c177..f1f792a5a 100644
--- a/IkiWiki/Plugin/attachment.pm
+++ b/IkiWiki/Plugin/attachment.pm
@@ -10,6 +10,7 @@ sub import { #{{{
 	hook(type => "checkconfig", id => "attachment", call => \&checkconfig);
 	hook(type => "formbuilder_setup", id => "attachment", call => \&formbuilder_setup);
 	hook(type => "formbuilder", id => "attachment", call => \&formbuilder);
+	IkiWiki::loadplugin("filecheck");
 } # }}}
 
 sub getsetup () { #{{{
@@ -288,192 +289,8 @@ sub attachment_list ($) { #{{{
 	return sort { $b->{mtime_raw} <=> $a->{mtime_raw} || $a->{link} cmp $b->{link} } @ret;
 } #}}}
 
-my %units=( #{{{	# size in bytes
-	B		=> 1,
-	byte		=> 1,
-	KB		=> 2 ** 10,
-	kilobyte 	=> 2 ** 10,
-	K		=> 2 ** 10,
-	KB		=> 2 ** 10,
-	kilobyte 	=> 2 ** 10,
-	M		=> 2 ** 20,
-	MB		=> 2 ** 20,
-	megabyte	=> 2 ** 20,
-	G		=> 2 ** 30,
-	GB		=> 2 ** 30,
-	gigabyte	=> 2 ** 30,
-	T		=> 2 ** 40,
-	TB		=> 2 ** 40,
-	terabyte	=> 2 ** 40,
-	P		=> 2 ** 50,
-	PB		=> 2 ** 50,
-	petabyte	=> 2 ** 50,
-	E		=> 2 ** 60,
-	EB		=> 2 ** 60,
-	exabyte		=> 2 ** 60,
-	Z		=> 2 ** 70,
-	ZB		=> 2 ** 70,
-	zettabyte	=> 2 ** 70,
-	Y		=> 2 ** 80,
-	YB		=> 2 ** 80,
-	yottabyte	=> 2 ** 80,
-	# ikiwiki, if you find you need larger data quantities, either modify
-	# yourself to add them, or travel back in time to 2008 and kill me.
-	#   -- Joey
-); #}}}
-
-sub parsesize ($) { #{{{
-	my $size=shift;
-
-	no warnings;
-	my $base=$size+0; # force to number
-	use warnings;
-	foreach my $unit (sort keys %units) {
-		if ($size=~/[0-9\s]\Q$unit\E$/i) {
-			return $base * $units{$unit};
-		}
-	}
-	return $base;
-} #}}}
-
-sub humansize ($) { #{{{
-	my $size=shift;
-
-	foreach my $unit (reverse sort { $units{$a} <=> $units{$b} || $b cmp $a } keys %units) {
-		if ($size / $units{$unit} > 0.25) {
-			return (int($size / $units{$unit} * 10)/10).$unit;
-		}
-	}
-	return $size; # near zero, or negative
-} #}}}
-
 package IkiWiki::PageSpec;
 
-sub match_maxsize ($$;@) { #{{{
-	my $page=shift;
-	my $maxsize=eval{IkiWiki::Plugin::attachment::parsesize(shift)};
-	if ($@) {
-		return IkiWiki::FailReason->new("unable to parse maxsize (or number too large)");
-	}
-
-	my %params=@_;
-	my $file=exists $params{file} ? $params{file} : $IkiWiki::pagesources{$page};
-	if (! defined $file) {
-		return IkiWiki::FailReason->new("no file specified");
-	}
-
-	if (-s $file > $maxsize) {
-		return IkiWiki::FailReason->new("file too large (".(-s $file)." >  $maxsize)");
-	}
-	else {
-		return IkiWiki::SuccessReason->new("file not too large");
-	}
-} #}}}
-
-sub match_minsize ($$;@) { #{{{
-	my $page=shift;
-	my $minsize=eval{IkiWiki::Plugin::attachment::parsesize(shift)};
-	if ($@) {
-		return IkiWiki::FailReason->new("unable to parse minsize (or number too large)");
-	}
-
-	my %params=@_;
-	my $file=exists $params{file} ? $params{file} : $IkiWiki::pagesources{$page};
-	if (! defined $file) {
-		return IkiWiki::FailReason->new("no file specified");
-	}
-
-	if (-s $file < $minsize) {
-		return IkiWiki::FailReason->new("file too small");
-	}
-	else {
-		return IkiWiki::SuccessReason->new("file not too small");
-	}
-} #}}}
-
-sub match_mimetype ($$;@) { #{{{
-	my $page=shift;
-	my $wanted=shift;
-
-	my %params=@_;
-	my $file=exists $params{file} ? $params{file} : $IkiWiki::pagesources{$page};
-	if (! defined $file) {
-		return IkiWiki::FailReason->new("no file specified");
-	}
-
-	# Use ::magic to get the mime type, the idea is to only trust
-	# data obtained by examining the actual file contents.
-	eval q{use File::MimeInfo::Magic};
-	if ($@) {
-		return IkiWiki::FailReason->new("failed to load File::MimeInfo::Magic ($@); cannot check MIME type");
-	}
-	my $mimetype=File::MimeInfo::Magic::magic($file);
-	if (! defined $mimetype) {
-		$mimetype="unknown";
-	}
-
-	my $regexp=IkiWiki::glob2re($wanted);
-	if ($mimetype!~/^$regexp$/i) {
-		return IkiWiki::FailReason->new("file MIME type is $mimetype, not $wanted");
-	}
-	else {
-		return IkiWiki::SuccessReason->new("file MIME type is $mimetype");
-	}
-} #}}}
-
-sub match_virusfree ($$;@) { #{{{
-	my $page=shift;
-	my $wanted=shift;
-
-	my %params=@_;
-	my $file=exists $params{file} ? $params{file} : $IkiWiki::pagesources{$page};
-	if (! defined $file) {
-		return IkiWiki::FailReason->new("no file specified");
-	}
-
-	if (! exists $IkiWiki::config{virus_checker} ||
-	    ! length $IkiWiki::config{virus_checker}) {
-		return IkiWiki::FailReason->new("no virus_checker configured");
-	}
-
-	# The file needs to be fed into the virus checker on stdin,
-	# because the file is not world-readable, and if clamdscan is
-	# used, clamd would fail to read it.
-	eval q{use IPC::Open2};
-	error($@) if $@;
-	open (IN, "<", $file) || return IkiWiki::FailReason->new("failed to read file");
-	binmode(IN);
-	my $sigpipe=0;
-	$SIG{PIPE} = sub { $sigpipe=1 };
-	my $pid=open2(\*CHECKER_OUT, "<&IN", $IkiWiki::config{virus_checker}); 
-	my $reason=<CHECKER_OUT>;
-	chomp $reason;
-	1 while (<CHECKER_OUT>);
-	close(CHECKER_OUT);
-	waitpid $pid, 0;
-	$SIG{PIPE}="DEFAULT";
-	if ($sigpipe || $?) {
-		if (! length $reason) {
-			$reason="virus checker $IkiWiki::config{virus_checker}; failed with no output";
-		}
-		return IkiWiki::FailReason->new("file seems to contain a virus ($reason)");
-	}
-	else {
-		return IkiWiki::SuccessReason->new("file seems virusfree ($reason)");
-	}
-} #}}}
-
-sub match_ispage ($$;@) { #{{{
-	my $filename=shift;
-
-	if (defined IkiWiki::pagetype($filename)) {
-		return IkiWiki::SuccessReason->new("file is a wiki page");
-	}
-	else {
-		return IkiWiki::FailReason->new("file is not a wiki page");
-	}
-} #}}}
-
 sub match_user ($$;@) { #{{{
 	shift;
 	my $user=shift;
diff --git a/IkiWiki/Plugin/filecheck.pm b/IkiWiki/Plugin/filecheck.pm
new file mode 100644
index 000000000..6f71be301
--- /dev/null
+++ b/IkiWiki/Plugin/filecheck.pm
@@ -0,0 +1,192 @@
+#!/usr/bin/perl
+package IkiWiki::Plugin::filecheck;
+
+use warnings;
+use strict;
+use IkiWiki 2.00;
+
+my %units=( #{{{	# size in bytes
+	B		=> 1,
+	byte		=> 1,
+	KB		=> 2 ** 10,
+	kilobyte 	=> 2 ** 10,
+	K		=> 2 ** 10,
+	KB		=> 2 ** 10,
+	kilobyte 	=> 2 ** 10,
+	M		=> 2 ** 20,
+	MB		=> 2 ** 20,
+	megabyte	=> 2 ** 20,
+	G		=> 2 ** 30,
+	GB		=> 2 ** 30,
+	gigabyte	=> 2 ** 30,
+	T		=> 2 ** 40,
+	TB		=> 2 ** 40,
+	terabyte	=> 2 ** 40,
+	P		=> 2 ** 50,
+	PB		=> 2 ** 50,
+	petabyte	=> 2 ** 50,
+	E		=> 2 ** 60,
+	EB		=> 2 ** 60,
+	exabyte		=> 2 ** 60,
+	Z		=> 2 ** 70,
+	ZB		=> 2 ** 70,
+	zettabyte	=> 2 ** 70,
+	Y		=> 2 ** 80,
+	YB		=> 2 ** 80,
+	yottabyte	=> 2 ** 80,
+	# ikiwiki, if you find you need larger data quantities, either modify
+	# yourself to add them, or travel back in time to 2008 and kill me.
+	#   -- Joey
+); #}}}
+
+sub parsesize ($) { #{{{
+	my $size=shift;
+
+	no warnings;
+	my $base=$size+0; # force to number
+	use warnings;
+	foreach my $unit (sort keys %units) {
+		if ($size=~/[0-9\s]\Q$unit\E$/i) {
+			return $base * $units{$unit};
+		}
+	}
+	return $base;
+} #}}}
+
+sub humansize ($) { #{{{
+	my $size=shift;
+
+	foreach my $unit (reverse sort { $units{$a} <=> $units{$b} || $b cmp $a } keys %units) {
+		if ($size / $units{$unit} > 0.25) {
+			return (int($size / $units{$unit} * 10)/10).$unit;
+		}
+	}
+	return $size; # near zero, or negative
+} #}}}
+
+package IkiWiki::PageSpec;
+
+sub match_maxsize ($$;@) { #{{{
+	my $page=shift;
+	my $maxsize=eval{IkiWiki::Plugin::attachment::parsesize(shift)};
+	if ($@) {
+		return IkiWiki::FailReason->new("unable to parse maxsize (or number too large)");
+	}
+
+	my %params=@_;
+	my $file=exists $params{file} ? $params{file} : $IkiWiki::pagesources{$page};
+	if (! defined $file) {
+		return IkiWiki::FailReason->new("no file specified");
+	}
+
+	if (-s $file > $maxsize) {
+		return IkiWiki::FailReason->new("file too large (".(-s $file)." >  $maxsize)");
+	}
+	else {
+		return IkiWiki::SuccessReason->new("file not too large");
+	}
+} #}}}
+
+sub match_minsize ($$;@) { #{{{
+	my $page=shift;
+	my $minsize=eval{IkiWiki::Plugin::attachment::parsesize(shift)};
+	if ($@) {
+		return IkiWiki::FailReason->new("unable to parse minsize (or number too large)");
+	}
+
+	my %params=@_;
+	my $file=exists $params{file} ? $params{file} : $IkiWiki::pagesources{$page};
+	if (! defined $file) {
+		return IkiWiki::FailReason->new("no file specified");
+	}
+
+	if (-s $file < $minsize) {
+		return IkiWiki::FailReason->new("file too small");
+	}
+	else {
+		return IkiWiki::SuccessReason->new("file not too small");
+	}
+} #}}}
+
+sub match_mimetype ($$;@) { #{{{
+	my $page=shift;
+	my $wanted=shift;
+
+	my %params=@_;
+	my $file=exists $params{file} ? $params{file} : $IkiWiki::pagesources{$page};
+	if (! defined $file) {
+		return IkiWiki::FailReason->new("no file specified");
+	}
+
+	# Use ::magic to get the mime type, the idea is to only trust
+	# data obtained by examining the actual file contents.
+	eval q{use File::MimeInfo::Magic};
+	if ($@) {
+		return IkiWiki::FailReason->new("failed to load File::MimeInfo::Magic ($@); cannot check MIME type");
+	}
+	my $mimetype=File::MimeInfo::Magic::magic($file);
+	if (! defined $mimetype) {
+		$mimetype="unknown";
+	}
+
+	my $regexp=IkiWiki::glob2re($wanted);
+	if ($mimetype!~/^$regexp$/i) {
+		return IkiWiki::FailReason->new("file MIME type is $mimetype, not $wanted");
+	}
+	else {
+		return IkiWiki::SuccessReason->new("file MIME type is $mimetype");
+	}
+} #}}}
+
+sub match_virusfree ($$;@) { #{{{
+	my $page=shift;
+	my $wanted=shift;
+
+	my %params=@_;
+	my $file=exists $params{file} ? $params{file} : $IkiWiki::pagesources{$page};
+	if (! defined $file) {
+		return IkiWiki::FailReason->new("no file specified");
+	}
+
+	if (! exists $IkiWiki::config{virus_checker} ||
+	    ! length $IkiWiki::config{virus_checker}) {
+		return IkiWiki::FailReason->new("no virus_checker configured");
+	}
+
+	# The file needs to be fed into the virus checker on stdin,
+	# because the file is not world-readable, and if clamdscan is
+	# used, clamd would fail to read it.
+	eval q{use IPC::Open2};
+	error($@) if $@;
+	open (IN, "<", $file) || return IkiWiki::FailReason->new("failed to read file");
+	binmode(IN);
+	my $sigpipe=0;
+	$SIG{PIPE} = sub { $sigpipe=1 };
+	my $pid=open2(\*CHECKER_OUT, "<&IN", $IkiWiki::config{virus_checker}); 
+	my $reason=<CHECKER_OUT>;
+	chomp $reason;
+	1 while (<CHECKER_OUT>);
+	close(CHECKER_OUT);
+	waitpid $pid, 0;
+	$SIG{PIPE}="DEFAULT";
+	if ($sigpipe || $?) {
+		if (! length $reason) {
+			$reason="virus checker $IkiWiki::config{virus_checker}; failed with no output";
+		}
+		return IkiWiki::FailReason->new("file seems to contain a virus ($reason)");
+	}
+	else {
+		return IkiWiki::SuccessReason->new("file seems virusfree ($reason)");
+	}
+} #}}}
+
+sub match_ispage ($$;@) { #{{{
+	my $filename=shift;
+
+	if (defined IkiWiki::pagetype($filename)) {
+		return IkiWiki::SuccessReason->new("file is a wiki page");
+	}
+	else {
+		return IkiWiki::FailReason->new("file is not a wiki page");
+	}
+} #}}}
diff --git a/debian/changelog b/debian/changelog
index 648a0b41c..c6f5fa6ee 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -14,6 +14,8 @@ ikiwiki (2.62) UNRELEASED; urgency=low
     chain will be used. (willu)
   * Drop suggests on texlive-science, add suggests on dvipng.
   * listdirectives: New plugin. (willu)
+  * filecheck: New plugin factoring out the PageSpec additions that were
+    originally part of the attachment plugin.
 
  -- Joey Hess <joeyh@debian.org>  Thu, 21 Aug 2008 16:20:58 -0400
 
diff --git a/doc/ikiwiki/pagespec/attachment.mdwn b/doc/ikiwiki/pagespec/attachment.mdwn
index de7c7417f..6b86c510b 100644
--- a/doc/ikiwiki/pagespec/attachment.mdwn
+++ b/doc/ikiwiki/pagespec/attachment.mdwn
@@ -13,7 +13,7 @@ check all attachments for virii, something like this could be used:
   
 	virusfree() and ((user(joey) and podcast/*.mp3 and mimetype(audio/mpeg) and maxsize(15mb)) or (!ispage() and maxsize(50kb)))
 
-The regular [[ikiwiki/PageSpec]] syntax is expanded with thw following
+The regular [[ikiwiki/PageSpec]] syntax is expanded with the following
 additional tests:
 
 * maxsize(size)
diff --git a/doc/ikiwiki/pagespec/attachment/discussion.mdwn b/doc/ikiwiki/pagespec/attachment/discussion.mdwn
index ab9cb0653..373242b3f 100644
--- a/doc/ikiwiki/pagespec/attachment/discussion.mdwn
+++ b/doc/ikiwiki/pagespec/attachment/discussion.mdwn
@@ -11,3 +11,5 @@ I am interested for [[todo/mbox]] --[[DavidBremner]]
 >> I don't think `ip()` and `user()` necessarily make sense for a mail box 
 >> that is already on the disk, so no, I don't think I'll miss
 >> them. --[[DavidBremner]] 
+
+>>> Done, [[plugins/filecheck]] --[[Joey]]
diff --git a/doc/plugins/attachment.mdwn b/doc/plugins/attachment.mdwn
index b04a04ad2..2aa8490ed 100644
--- a/doc/plugins/attachment.mdwn
+++ b/doc/plugins/attachment.mdwn
@@ -22,13 +22,6 @@ Bear in mind that if you let anyone upload a particular kind of file
 
 If you enable this plugin, be sure to lock it down, via the
 `allowed_attachments` setup file option. This is a special 
-[[enhanced_PageSpec|ikiwiki/pagespec/attachment]].
-
-This plugin will use the [[!cpan File::MimeInfo::Magic]] perl module, if
-available, for mimetype checking.
-
-The `virusfree` [[PageSpec|ikiwiki/pagespec/attachment]] requires that
-ikiwiki be configured with a virus scanner program via the `virus_checker`
-option in the setup file. If using `clamav`, with `clamd`, set it to
-"clamdscan -". Or to use clamav without the `clamd` daemon, you
-could set it to "clamscan -".
+[[enhanced_PageSpec|ikiwiki/pagespec/attachment]] using tests provided by
+the [[filecheck]] plugin. That plugin will be automatically enabled when
+this plugin is enabled.
diff --git a/doc/plugins/filecheck.mdwn b/doc/plugins/filecheck.mdwn
new file mode 100644
index 000000000..f4563d58e
--- /dev/null
+++ b/doc/plugins/filecheck.mdwn
@@ -0,0 +1,16 @@
+[[!template id=plugin name=filecheck core=0 author="[[Joey]]"]]
+[[!tag type/useful]]
+
+This plugin enhances the regular [[ikiwiki/PageSpec]] syntax with
+some additional tests, for things like file size, mime type, and virus
+status. These tests are mostly useful for the [[attachment]] plugin, and
+are documented [[here|ikiwiki/pagespec/attachment]].
+
+This plugin will use the [[!cpan File::MimeInfo::Magic]] perl module, if
+available, for mimetype checking.
+
+The `virusfree` [[PageSpec|ikiwiki/pagespec/attachment]] requires that
+ikiwiki be configured with a virus scanner program via the `virus_checker`
+option in the setup file. If using `clamav`, with `clamd`, set it to
+"clamdscan -". Or to use clamav without the `clamd` daemon, you
+could set it to "clamscan -".
-- 
cgit v1.2.3