X-Git-Url: http://git.vanrenterghem.biz/git.ikiwiki.info.git/blobdiff_plain/5b78246d11948e93f54ae32dd800e9adaf55a546..eba2dee941c18b3a1bd9c8af52c01ba7b5b46a64:/IkiWiki/Plugin/external.pm?ds=sidebyside

diff --git a/IkiWiki/Plugin/external.pm b/IkiWiki/Plugin/external.pm
index 9c31a70eb..4ce9c8bab 100644
--- a/IkiWiki/Plugin/external.pm
+++ b/IkiWiki/Plugin/external.pm
@@ -1,6 +1,6 @@
 #!/usr/bin/perl
 # Support for external plugins written in other languages.
-# Communication via XML RPC a pipe.
+# Communication via XML RPC to a pipe.
 # See externaldemo for an example of a plugin that uses this.
 package IkiWiki::Plugin::external;
 
@@ -20,7 +20,8 @@ sub import { #{{{
 	return unless defined $plugin;
 
 	my ($plugin_read, $plugin_write);
-	my $pid = open2($plugin_read, $plugin_write, $plugin);
+	my $pid = open2($plugin_read, $plugin_write,
+		IkiWiki::possibly_foolish_untaint($plugin));
 
 	# open2 doesn't respect "use open ':utf8'"
 	binmode($plugin_read, ':utf8');
@@ -28,6 +29,7 @@ sub import { #{{{
 
 	$plugins{$plugin}={in => $plugin_read, out => $plugin_write, pid => $pid,
 		accum => ""};
+	$RPC::XML::ENCODING="utf-8";
 
 	rpc_call($plugins{$plugin}, "import");
 } #}}}
@@ -57,14 +59,31 @@ sub rpc_call ($$;@) { #{{{
 			error("XML RPC parser failure: $r") unless ref $r;
 			if ($r->isa('RPC::XML::response')) {
 				my $value=$r->value;
-				if ($value->isa('RPC::XML::array')) {
+				if ($r->is_fault($value)) {
+					# throw the error as best we can
+					print STDERR $value->string."\n";
+					return "";
+				}
+				elsif ($value->isa('RPC::XML::array')) {
 					return @{$value->value};
 				}
 				elsif ($value->isa('RPC::XML::struct')) {
-					return %{$value->value};
-				}
-				elsif ($value->isa('RPC::XML::fault')) {
-					die $value->string;
+					my %hash=%{$value->value};
+
+					# XML-RPC v1 does not allow for
+					# nil/null/None/undef values to be
+					# transmitted, so until
+					# XML::RPC::Parser honours v2
+					# (<nil/>), external plugins send
+					# a hash with one key "null" pointing
+					# to an empty string.
+					if (exists $hash{null} &&
+					    $hash{null} eq "" &&
+					    int(keys(%hash)) == 1) {
+						return undef;
+					}
+
+					return %hash;
 				}
 				else {
 					return $value->value;
@@ -88,6 +107,14 @@ sub rpc_call ($$;@) { #{{{
 				error("XML RPC call error, unknown function: $name");
 			}
 
+			# XML-RPC v1 does not allow for nil/null/None/undef
+			# values to be transmitted, so until XML::RPC::Parser
+			# honours v2 (<nil/>), send a hash with one key "null"
+			# pointing to an empty string.
+			if (! defined $ret) {
+				$ret={"null" => ""};
+			}
+
 			my $string=eval { RPC::XML::response->new($ret)->as_string };
 			if ($@ && ref $ret) {
 				# One common reason for serialisation to
@@ -124,13 +151,46 @@ sub setvar ($$$;@) { #{{{
 	my $plugin=shift;
 	my $varname="IkiWiki::".shift;
 	my $key=shift;
+	my $value=shift;
 
 	no strict 'refs';
-	my $ret=$varname->{$key}=@_;
+	my $ret=$varname->{$key}=$value;
 	use strict 'refs';
 	return $ret;
 } #}}}
 
+sub getstate ($$$$) { #{{{
+	my $plugin=shift;
+	my $page=shift;
+	my $id=shift;
+	my $key=shift;
+
+	return $IkiWiki::pagestate{$page}{$id}{$key};
+} #}}}
+
+sub setstate ($$$$;@) { #{{{
+	my $plugin=shift;
+	my $page=shift;
+	my $id=shift;
+	my $key=shift;
+	my $value=shift;
+
+	return $IkiWiki::pagestate{$page}{$id}{$key}=$value;
+} #}}}
+
+sub getargv ($) { #{{{
+	my $plugin=shift;
+
+	return \@ARGV;
+} #}}}
+
+sub setargv ($@) { #{{{
+	my $plugin=shift;
+	my $array=shift;
+
+	@ARGV=@$array;
+} #}}}
+
 sub inject ($@) { #{{{
 	# Bind a given perl function name to a particular RPC request.
 	my $plugin=shift;
@@ -142,8 +202,16 @@ sub inject ($@) { #{{{
 	my $sub = sub {
 		IkiWiki::Plugin::external::rpc_call($plugin, $params{call}, @_)
 	};
+	$sub=memoize($sub) if $params{memoize};
+
+	# This will add it to the symbol table even if not present.
+	no warnings;
 	eval qq{*$params{name}=\$sub};
-	memoize($params{name}) if $params{memoize};
+	use warnings;
+
+	# This will ensure that everywhere it was exported to sees
+	# the injected version.
+	IkiWiki::inject(name => $params{name}, call => $sub);
 	return 1;
 } #}}}
 
@@ -157,7 +225,7 @@ sub hook ($@) { #{{{
 	delete $params{call};
 
 	IkiWiki::hook(%params, call => sub {
-		IkiWiki::Plugin::external::rpc_call($plugin, $callback, @_)
+		IkiWiki::Plugin::external::rpc_call($plugin, $callback, @_);
 	});
 } #}}}