From 461804a5e4e267dce332e0b953a164ba6b82a91e Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Mon, 18 Jan 2010 12:09:54 -0500 Subject: clarify error --- IkiWiki/Plugin/remove.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'IkiWiki/Plugin/remove.pm') diff --git a/IkiWiki/Plugin/remove.pm b/IkiWiki/Plugin/remove.pm index 2b8cf0414..3c1e0c713 100644 --- a/IkiWiki/Plugin/remove.pm +++ b/IkiWiki/Plugin/remove.pm @@ -51,7 +51,7 @@ sub check_canremove ($$$) { IkiWiki::Plugin::attachment::check_canattach($session, $page, $file); } else { - error("renaming of attachments is not allowed"); + error("removal of attachments is not allowed"); } } -- cgit v1.2.3 From 20ba12802b3897bf48d8a7704a57e9cede2466bd Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Fri, 12 Feb 2010 04:22:15 -0500 Subject: add section information --- IkiWiki/Plugin/404.pm | 1 + IkiWiki/Plugin/aggregate.pm | 1 + IkiWiki/Plugin/amazon_s3.pm | 1 + IkiWiki/Plugin/attachment.pm | 1 + IkiWiki/Plugin/autoindex.pm | 1 + IkiWiki/Plugin/comments.pm | 1 + IkiWiki/Plugin/editdiff.pm | 1 + IkiWiki/Plugin/edittemplate.pm | 1 + IkiWiki/Plugin/getsource.pm | 1 + IkiWiki/Plugin/google.pm | 1 + IkiWiki/Plugin/goto.pm | 1 + IkiWiki/Plugin/mirrorlist.pm | 1 + IkiWiki/Plugin/norcs.pm | 1 + IkiWiki/Plugin/pingee.pm | 1 + IkiWiki/Plugin/pinger.pm | 1 + IkiWiki/Plugin/remove.pm | 1 + IkiWiki/Plugin/rename.pm | 1 + IkiWiki/Plugin/repolist.pm | 1 + IkiWiki/Plugin/rsync.pm | 1 + IkiWiki/Plugin/search.pm | 1 + IkiWiki/Plugin/testpagespec.pm | 1 + IkiWiki/Plugin/underlay.pm | 1 + IkiWiki/Plugin/websetup.pm | 1 + IkiWiki/Plugin/wmd.pm | 2 ++ doc/plugins/write.mdwn | 3 ++- 25 files changed, 27 insertions(+), 1 deletion(-) (limited to 'IkiWiki/Plugin/remove.pm') diff --git a/IkiWiki/Plugin/404.pm b/IkiWiki/Plugin/404.pm index 85486e559..8adfd5dd9 100644 --- a/IkiWiki/Plugin/404.pm +++ b/IkiWiki/Plugin/404.pm @@ -21,6 +21,7 @@ sub getsetup () { # server admin action too safe => 0, rebuild => 0, + section => "web", } } diff --git a/IkiWiki/Plugin/aggregate.pm b/IkiWiki/Plugin/aggregate.pm index 5a9eb433d..c18d413e6 100644 --- a/IkiWiki/Plugin/aggregate.pm +++ b/IkiWiki/Plugin/aggregate.pm @@ -43,6 +43,7 @@ sub getsetup () { plugin => { safe => 1, rebuild => undef, + section => "special-purpose", }, aggregateinternal => { type => "boolean", diff --git a/IkiWiki/Plugin/amazon_s3.pm b/IkiWiki/Plugin/amazon_s3.pm index cfd8cd347..f2f4dbcf2 100644 --- a/IkiWiki/Plugin/amazon_s3.pm +++ b/IkiWiki/Plugin/amazon_s3.pm @@ -45,6 +45,7 @@ sub getsetup () { plugin => { safe => 0, rebuild => 0, + section => "special-purpose", }, amazon_s3_key_id => { type => "string", diff --git a/IkiWiki/Plugin/attachment.pm b/IkiWiki/Plugin/attachment.pm index cbe6efc21..ad1dd9bca 100644 --- a/IkiWiki/Plugin/attachment.pm +++ b/IkiWiki/Plugin/attachment.pm @@ -19,6 +19,7 @@ sub getsetup () { plugin => { safe => 1, rebuild => 0, + section => "web", }, allowed_attachments => { type => "pagespec", diff --git a/IkiWiki/Plugin/autoindex.pm b/IkiWiki/Plugin/autoindex.pm index 555856b11..e50464dca 100644 --- a/IkiWiki/Plugin/autoindex.pm +++ b/IkiWiki/Plugin/autoindex.pm @@ -16,6 +16,7 @@ sub getsetup () { plugin => { safe => 1, rebuild => 0, + section => "special-purpose", }, } diff --git a/IkiWiki/Plugin/comments.pm b/IkiWiki/Plugin/comments.pm index caed0d58c..1e71749a4 100644 --- a/IkiWiki/Plugin/comments.pm +++ b/IkiWiki/Plugin/comments.pm @@ -38,6 +38,7 @@ sub getsetup () { plugin => { safe => 1, rebuild => 1, + section => "web", }, comments_pagespec => { type => 'pagespec', diff --git a/IkiWiki/Plugin/editdiff.pm b/IkiWiki/Plugin/editdiff.pm index 7df6a9ffb..d8f53a42e 100644 --- a/IkiWiki/Plugin/editdiff.pm +++ b/IkiWiki/Plugin/editdiff.pm @@ -19,6 +19,7 @@ sub getsetup () { plugin => { safe => 1, rebuild => 0, + section => "web", }, } diff --git a/IkiWiki/Plugin/edittemplate.pm b/IkiWiki/Plugin/edittemplate.pm index a163b0d84..5f0551d92 100644 --- a/IkiWiki/Plugin/edittemplate.pm +++ b/IkiWiki/Plugin/edittemplate.pm @@ -23,6 +23,7 @@ sub getsetup () { plugin => { safe => 1, rebuild => undef, + section => "web", }, } diff --git a/IkiWiki/Plugin/getsource.pm b/IkiWiki/Plugin/getsource.pm index d1555430e..b362de726 100644 --- a/IkiWiki/Plugin/getsource.pm +++ b/IkiWiki/Plugin/getsource.pm @@ -17,6 +17,7 @@ sub getsetup () { plugin => { safe => 1, rebuild => 1, + section => "web", }, getsource_mimetype => { type => "string", diff --git a/IkiWiki/Plugin/google.pm b/IkiWiki/Plugin/google.pm index 483fa1707..48ad4c8ce 100644 --- a/IkiWiki/Plugin/google.pm +++ b/IkiWiki/Plugin/google.pm @@ -17,6 +17,7 @@ sub getsetup () { plugin => { safe => 1, rebuild => 1, + section => "web", }, } diff --git a/IkiWiki/Plugin/goto.pm b/IkiWiki/Plugin/goto.pm index 439552f62..03bd682b3 100644 --- a/IkiWiki/Plugin/goto.pm +++ b/IkiWiki/Plugin/goto.pm @@ -14,6 +14,7 @@ sub getsetup () { plugin => { safe => 1, rebuild => 0, + section => "web", } } diff --git a/IkiWiki/Plugin/mirrorlist.pm b/IkiWiki/Plugin/mirrorlist.pm index d0a6107ef..92be7913e 100644 --- a/IkiWiki/Plugin/mirrorlist.pm +++ b/IkiWiki/Plugin/mirrorlist.pm @@ -15,6 +15,7 @@ sub getsetup () { plugin => { safe => 1, rebuild => 1, + section => "web", }, mirrorlist => { type => "string", diff --git a/IkiWiki/Plugin/norcs.pm b/IkiWiki/Plugin/norcs.pm index bfe84c0e1..e6a05a3c5 100644 --- a/IkiWiki/Plugin/norcs.pm +++ b/IkiWiki/Plugin/norcs.pm @@ -25,6 +25,7 @@ sub getsetup () { plugin => { safe => 0, # rcs plugin rebuild => 0, + section => "rcs", }, } diff --git a/IkiWiki/Plugin/pingee.pm b/IkiWiki/Plugin/pingee.pm index f5386d0ca..aafce9e70 100644 --- a/IkiWiki/Plugin/pingee.pm +++ b/IkiWiki/Plugin/pingee.pm @@ -15,6 +15,7 @@ sub getsetup () { plugin => { safe => 1, rebuild => undef, + section => "special-purpose", }, } diff --git a/IkiWiki/Plugin/pinger.pm b/IkiWiki/Plugin/pinger.pm index c20ecb5d4..a797fc7bd 100644 --- a/IkiWiki/Plugin/pinger.pm +++ b/IkiWiki/Plugin/pinger.pm @@ -21,6 +21,7 @@ sub getsetup () { plugin => { safe => 1, rebuild => 0, + section => "special-purpose", }, pinger_timeout => { type => "integer", diff --git a/IkiWiki/Plugin/remove.pm b/IkiWiki/Plugin/remove.pm index 3c1e0c713..f59d0269e 100644 --- a/IkiWiki/Plugin/remove.pm +++ b/IkiWiki/Plugin/remove.pm @@ -18,6 +18,7 @@ sub getsetup () { plugin => { safe => 1, rebuild => 0, + section => "web", }, } diff --git a/IkiWiki/Plugin/rename.pm b/IkiWiki/Plugin/rename.pm index 8213d21f6..3908443ca 100644 --- a/IkiWiki/Plugin/rename.pm +++ b/IkiWiki/Plugin/rename.pm @@ -18,6 +18,7 @@ sub getsetup () { plugin => { safe => 1, rebuild => 0, + section => "web", }, } diff --git a/IkiWiki/Plugin/repolist.pm b/IkiWiki/Plugin/repolist.pm index f69ec3988..ba7c5f0aa 100644 --- a/IkiWiki/Plugin/repolist.pm +++ b/IkiWiki/Plugin/repolist.pm @@ -15,6 +15,7 @@ sub getsetup () { plugin => { safe => 1, rebuild => undef, + section => "web", }, repositories => { type => "string", diff --git a/IkiWiki/Plugin/rsync.pm b/IkiWiki/Plugin/rsync.pm index e38801e4a..8dd983be7 100644 --- a/IkiWiki/Plugin/rsync.pm +++ b/IkiWiki/Plugin/rsync.pm @@ -16,6 +16,7 @@ sub getsetup () { plugin => { safe => 0, rebuild => 0, + section => "special-purpose", }, rsync_command => { type => "string", diff --git a/IkiWiki/Plugin/search.pm b/IkiWiki/Plugin/search.pm index 393c17e0f..fb68396a1 100644 --- a/IkiWiki/Plugin/search.pm +++ b/IkiWiki/Plugin/search.pm @@ -20,6 +20,7 @@ sub getsetup () { plugin => { safe => 1, rebuild => 1, + section => "web", }, omega_cgi => { type => "string", diff --git a/IkiWiki/Plugin/testpagespec.pm b/IkiWiki/Plugin/testpagespec.pm index 440fca33b..17a77cb69 100644 --- a/IkiWiki/Plugin/testpagespec.pm +++ b/IkiWiki/Plugin/testpagespec.pm @@ -15,6 +15,7 @@ sub getsetup () { plugin => { safe => 1, rebuild => undef, + section => "special-purpose", }, } diff --git a/IkiWiki/Plugin/underlay.pm b/IkiWiki/Plugin/underlay.pm index 116fe7324..ab74fc37e 100644 --- a/IkiWiki/Plugin/underlay.pm +++ b/IkiWiki/Plugin/underlay.pm @@ -18,6 +18,7 @@ sub getsetup () { plugin => { safe => 0, rebuild => undef, + section => "special-purpose", }, add_underlays => { type => "string", diff --git a/IkiWiki/Plugin/websetup.pm b/IkiWiki/Plugin/websetup.pm index 445552e40..5c19c9b63 100644 --- a/IkiWiki/Plugin/websetup.pm +++ b/IkiWiki/Plugin/websetup.pm @@ -18,6 +18,7 @@ sub getsetup () { plugin => { safe => 1, rebuild => 0, + section => "web", }, websetup_force_plugins => { type => "string", diff --git a/IkiWiki/Plugin/wmd.pm b/IkiWiki/Plugin/wmd.pm index 9ddd237ab..5361d2914 100644 --- a/IkiWiki/Plugin/wmd.pm +++ b/IkiWiki/Plugin/wmd.pm @@ -17,6 +17,8 @@ sub getsetup () { return plugin => { safe => 1, + rebuild => 0, + section => "web", }, } diff --git a/doc/plugins/write.mdwn b/doc/plugins/write.mdwn index 68454d56c..fbaabb6a0 100644 --- a/doc/plugins/write.mdwn +++ b/doc/plugins/write.mdwn @@ -498,7 +498,8 @@ describes the plugin as a whole. For example: and undef if a rebuild could be needed in some circumstances, but is not strictly required. * `section` can optionally specify which section in the config file - the plugin fits in. + the plugin fits in. The convention is to name the sections the + same as the tags used for [[plugins|plugin]] on this wiki. ### genwrapper -- cgit v1.2.3 From 243b0dd082cf4b66dfef55b2c9b459109bee7398 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Fri, 26 Mar 2010 00:16:21 -0400 Subject: fix the other half of the filecheck filename bug --- IkiWiki/Plugin/remove.pm | 2 +- IkiWiki/Plugin/rename.pm | 4 ++-- debian/changelog | 2 +- doc/bugs/filecheck_failing_to_find_files.mdwn | 2 ++ 4 files changed, 6 insertions(+), 4 deletions(-) (limited to 'IkiWiki/Plugin/remove.pm') diff --git a/IkiWiki/Plugin/remove.pm b/IkiWiki/Plugin/remove.pm index f59d0269e..0fc180f69 100644 --- a/IkiWiki/Plugin/remove.pm +++ b/IkiWiki/Plugin/remove.pm @@ -49,7 +49,7 @@ sub check_canremove ($$$) { # This is sorta overkill, but better safe than sorry. if (! defined pagetype($pagesources{$page})) { if (IkiWiki::Plugin::attachment->can("check_canattach")) { - IkiWiki::Plugin::attachment::check_canattach($session, $page, $file); + IkiWiki::Plugin::attachment::check_canattach($session, $page, "$config{srcdir}/$file"); } else { error("removal of attachments is not allowed"); diff --git a/IkiWiki/Plugin/rename.pm b/IkiWiki/Plugin/rename.pm index 3908443ca..1a9da6363 100644 --- a/IkiWiki/Plugin/rename.pm +++ b/IkiWiki/Plugin/rename.pm @@ -50,7 +50,7 @@ sub check_canrename ($$$$$$) { IkiWiki::check_canedit($src, $q, $session); if ($attachment) { if (IkiWiki::Plugin::attachment->can("check_canattach")) { - IkiWiki::Plugin::attachment::check_canattach($session, $src, $srcfile); + IkiWiki::Plugin::attachment::check_canattach($session, $src, "$config{srcdir}/$srcfile"); } else { error("renaming of attachments is not allowed"); @@ -85,7 +85,7 @@ sub check_canrename ($$$$$$) { if ($attachment) { # Note that $srcfile is used here, not $destfile, # because it wants the current file, to check it. - IkiWiki::Plugin::attachment::check_canattach($session, $dest, $srcfile); + IkiWiki::Plugin::attachment::check_canattach($session, $dest, "$config{srcdir}/$srcfile"); } } diff --git a/debian/changelog b/debian/changelog index 7249cdfa4..da1ab890e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -15,7 +15,7 @@ ikiwiki (3.20100324) UNRELEASED; urgency=low * Allow wrappers to be built using tcc. * Add support for setup files written in YAML. * Add --set-yaml switch for setting more complex config file options. - * filecheck: Fix bug that prevented the pagespecs from matching when + * filecheck: Fix bugs that prevented the pagespecs from matching when not called by attachment plugin. -- Joey Hess Sat, 13 Mar 2010 14:48:10 -0500 diff --git a/doc/bugs/filecheck_failing_to_find_files.mdwn b/doc/bugs/filecheck_failing_to_find_files.mdwn index f8d8e83e6..6501508e4 100644 --- a/doc/bugs/filecheck_failing_to_find_files.mdwn +++ b/doc/bugs/filecheck_failing_to_find_files.mdwn @@ -25,6 +25,8 @@ It turns out that the filecheck plugin couldn't find the file, because it was me >>>>>> Yes, it works! --[[KathrynAndersen]] +applied && [[done]] +
 diff --git a/IkiWiki/Plugin/remove.pm b/IkiWiki/Plugin/remove.pm
 index f59d026..0fc180f 100644
-- 
cgit v1.2.3


From 4c320176c080038f95131f39ecaca3101b4b1745 Mon Sep 17 00:00:00 2001
From: Joey Hess 
Date: Thu, 6 May 2010 22:27:12 -0400
Subject: simplify formbuilder stylesheet specification

Since all forms are wrapped in a template that defines the actual
stylesheets, formbuilder just has to be told to turn on stylesheet mode,
not what file is the style sheet.
---
 IkiWiki/CGI.pm             | 4 ++--
 IkiWiki/Plugin/remove.pm   | 2 +-
 IkiWiki/Plugin/rename.pm   | 2 +-
 IkiWiki/Plugin/websetup.pm | 2 +-
 4 files changed, 5 insertions(+), 5 deletions(-)

(limited to 'IkiWiki/Plugin/remove.pm')

diff --git a/IkiWiki/CGI.pm b/IkiWiki/CGI.pm
index 07369ac10..49a505514 100644
--- a/IkiWiki/CGI.pm
+++ b/IkiWiki/CGI.pm
@@ -108,7 +108,7 @@ sub cgi_signin ($$) {
 		action => $config{cgiurl},
 		header => 0,
 		template => {type => 'div'},
-		stylesheet => baseurl()."style.css",
+		stylesheet => 1,
 	);
 	my $buttons=["Login"];
 	
@@ -187,7 +187,7 @@ sub cgi_prefs ($$) {
 		params => $q,
 		action => $config{cgiurl},
 		template => {type => 'div'},
-		stylesheet => baseurl()."style.css",
+		stylesheet => 1,
 		fieldsets => [
 			[login => gettext("Login")],
 			[preferences => gettext("Preferences")],
diff --git a/IkiWiki/Plugin/remove.pm b/IkiWiki/Plugin/remove.pm
index 0fc180f69..a46294e78 100644
--- a/IkiWiki/Plugin/remove.pm
+++ b/IkiWiki/Plugin/remove.pm
@@ -103,7 +103,7 @@ sub confirmation_form ($$) {
 		javascript => 0,
 		params => $q,
 		action => $config{cgiurl},
-		stylesheet => IkiWiki::baseurl()."style.css",
+		stylesheet => 1,
 		fields => [qw{do page}],
 	);
 	
diff --git a/IkiWiki/Plugin/rename.pm b/IkiWiki/Plugin/rename.pm
index 69e615ead..537e91317 100644
--- a/IkiWiki/Plugin/rename.pm
+++ b/IkiWiki/Plugin/rename.pm
@@ -126,7 +126,7 @@ sub rename_form ($$$) {
 		javascript => 0,
 		params => $q,
 		action => $config{cgiurl},
-		stylesheet => IkiWiki::baseurl()."style.css",
+		stylesheet => 1,
 		fields => [qw{do page new_name attachment}],
 	);
 	
diff --git a/IkiWiki/Plugin/websetup.pm b/IkiWiki/Plugin/websetup.pm
index 4d2e611eb..9cb5eb13c 100644
--- a/IkiWiki/Plugin/websetup.pm
+++ b/IkiWiki/Plugin/websetup.pm
@@ -293,7 +293,7 @@ sub showform ($$) {
 		],
 		action => $config{cgiurl},
 		template => {type => 'div'},
-		stylesheet => IkiWiki::baseurl()."style.css",
+		stylesheet => 1,
 	);
 	
 	$form->field(name => "do", type => "hidden", value => "setup",
-- 
cgit v1.2.3


From 8ff761afa24febdb280c672b3b31d6145990f050 Mon Sep 17 00:00:00 2001
From: Joey Hess 
Date: Fri, 14 May 2010 14:21:45 -0400
Subject: remove, rename: Add guards against XSRF attacks.

---
 IkiWiki/Plugin/remove.pm | 4 ++++
 IkiWiki/Plugin/rename.pm | 4 ++++
 debian/changelog         | 1 +
 3 files changed, 9 insertions(+)

(limited to 'IkiWiki/Plugin/remove.pm')

diff --git a/IkiWiki/Plugin/remove.pm b/IkiWiki/Plugin/remove.pm
index a46294e78..d23b2cc10 100644
--- a/IkiWiki/Plugin/remove.pm
+++ b/IkiWiki/Plugin/remove.pm
@@ -107,6 +107,8 @@ sub confirmation_form ($$) {
 		fields => [qw{do page}],
 	);
 	
+	$f->field(name => "sid", type => "hidden", value => $session->id,
+		force => 1);
 	$f->field(name => "do", type => "hidden", value => "remove", force => 1);
 
 	return $f, ["Remove", "Cancel"];
@@ -188,6 +190,8 @@ sub sessioncgi ($$) {
 			postremove($session);
 		}
 		elsif ($form->submitted eq 'Remove' && $form->validate) {
+			IkiWiki::checksessionexpiry($q, $session, $q->param('sid'));
+
 			my @pages=$form->field("page");
 	
 			# Validate removal by checking that the page exists,
diff --git a/IkiWiki/Plugin/rename.pm b/IkiWiki/Plugin/rename.pm
index 537e91317..0da90a538 100644
--- a/IkiWiki/Plugin/rename.pm
+++ b/IkiWiki/Plugin/rename.pm
@@ -131,6 +131,8 @@ sub rename_form ($$$) {
 	);
 	
 	$f->field(name => "do", type => "hidden", value => "rename", force => 1);
+	$f->field(name => "sid", type => "hidden", value => $session->id,
+		force => 1);
 	$f->field(name => "page", type => "hidden", value => $page, force => 1);
 	$f->field(name => "new_name", value => pagetitle($page, 1), size => 60);
 	if (!$q->param("attachment")) {
@@ -286,6 +288,8 @@ sub sessioncgi ($$) {
 			postrename($session);
 		}
 		elsif ($form->submitted eq 'Rename' && $form->validate) {
+			IkiWiki::checksessionexpiry($q, $session, $q->param('sid'));
+
 			# Queue of rename actions to perfom.
 			my @torename;
 
diff --git a/debian/changelog b/debian/changelog
index e6c5e42ae..a09c8e228 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -30,6 +30,7 @@ ikiwiki (3.20100505) UNRELEASED; urgency=low
     (And also negative years.)
   * calendar: Display year in title of month calendar.
   * Use xhtml friendly pubdate setting.
+  * remove, rename: Add guards against XSRF attacks.
 
  -- Joey Hess   Wed, 05 May 2010 18:07:29 -0400
 
-- 
cgit v1.2.3


From 4292802ee5f93f7ec7644c5d0a30f7ffeb95e566 Mon Sep 17 00:00:00 2001
From: Joey Hess 
Date: Wed, 23 Jun 2010 16:32:20 -0400
Subject: stop using REMOTE_ADDR

Everywhere that REMOTE_ADDR was used, a session object is available, so
instead use its remote_addr method.

In IkiWiki::Receive, stop setting a dummy REMOTE_ADDR.

Note that it's possible for a session cookie to be obtained using one IP
address, and then used from another IP. In this case, the first IP will now
be used. I think that should be ok.
---
 IkiWiki/CGI.pm                      |  2 +-
 IkiWiki/Plugin/attachment.pm        |  5 +++--
 IkiWiki/Plugin/blogspam.pm          |  3 ++-
 IkiWiki/Plugin/comments.pm          | 10 ++++++----
 IkiWiki/Plugin/editpage.pm          |  3 ++-
 IkiWiki/Plugin/lockedit.pm          |  2 +-
 IkiWiki/Plugin/moderatedcomments.pm |  4 ++--
 IkiWiki/Plugin/passwordauth.pm      |  2 +-
 IkiWiki/Plugin/poll.pm              |  3 ++-
 IkiWiki/Plugin/remove.pm            |  3 ++-
 IkiWiki/Plugin/rename.pm            |  8 +++++---
 IkiWiki/Receive.pm                  |  1 -
 12 files changed, 27 insertions(+), 19 deletions(-)

(limited to 'IkiWiki/Plugin/remove.pm')

diff --git a/IkiWiki/CGI.pm b/IkiWiki/CGI.pm
index 28020b500..f2a32a958 100644
--- a/IkiWiki/CGI.pm
+++ b/IkiWiki/CGI.pm
@@ -283,7 +283,7 @@ sub check_banned ($$) {
 
 	foreach my $b (@{$config{banned_users}}) {
 		if (pagespec_match("", $b,
-			ip => $ENV{REMOTE_ADDR},
+			ip => $session->remote_addr(),
 			name => defined $name ? $name : "",
 		)) {
 			$banned=1;
diff --git a/IkiWiki/Plugin/attachment.pm b/IkiWiki/Plugin/attachment.pm
index ce688ca40..216e00b3d 100644
--- a/IkiWiki/Plugin/attachment.pm
+++ b/IkiWiki/Plugin/attachment.pm
@@ -58,7 +58,7 @@ sub check_canattach ($$;$) {
 			$config{allowed_attachments},
 			file => $file,
 			user => $session->param("name"),
-			ip => $ENV{REMOTE_ADDR},
+			ip => $session->remote_addr(),
 		);
 	}
 
@@ -185,7 +185,8 @@ sub formbuilder (@) {
 			IkiWiki::disable_commit_hook();
 			IkiWiki::rcs_commit($filename, gettext("attachment upload"),
 				IkiWiki::rcs_prepedit($filename),
-				$session->param("name"), $ENV{REMOTE_ADDR});
+				$session->param("name"),
+				$session->remote_addr());
 			IkiWiki::enable_commit_hook();
 			IkiWiki::rcs_update();
 		}
diff --git a/IkiWiki/Plugin/blogspam.pm b/IkiWiki/Plugin/blogspam.pm
index c4e5cf390..8db3780e8 100644
--- a/IkiWiki/Plugin/blogspam.pm
+++ b/IkiWiki/Plugin/blogspam.pm
@@ -58,6 +58,7 @@ sub checkconfig () {
 
 sub checkcontent (@) {
 	my %params=@_;
+	my $session=$params{session};
 	
  	if (exists $config{blogspam_pagespec}) {
 		return undef
@@ -88,7 +89,7 @@ sub checkcontent (@) {
 	push @options, "exclude=stopwords";
 
 	my %req=(
-		ip => $ENV{REMOTE_ADDR},
+		ip => $session->remote_addr(),
 		comment => defined $params{diff} ? $params{diff} : $params{content},
 		subject => defined $params{subject} ? $params{subject} : "",
 		name => defined $params{author} ? $params{author} : "",
diff --git a/IkiWiki/Plugin/comments.pm b/IkiWiki/Plugin/comments.pm
index d1558001a..4770209c9 100644
--- a/IkiWiki/Plugin/comments.pm
+++ b/IkiWiki/Plugin/comments.pm
@@ -402,8 +402,8 @@ sub editcomment ($$) {
 		$username =~ s/"/"/g;
 		$content .= " username=\"$username\"\n";
 	}
-	elsif (defined $ENV{REMOTE_ADDR}) {
-		my $ip = $ENV{REMOTE_ADDR};
+	elsif (defined $session->remote_addr()) {
+		my $ip = $session->remote_addr();
 		if ($ip =~ m/^([.0-9]+)$/) {
 			$content .= " ip=\"$1\"\n";
 		}
@@ -514,7 +514,8 @@ sub editcomment ($$) {
 			IkiWiki::rcs_add($file);
 			IkiWiki::disable_commit_hook();
 			$conflict = IkiWiki::rcs_commit_staged($message,
-				$session->param('name'), $ENV{REMOTE_ADDR});
+				$session->param('name'),
+				$session->remote_addr());
 			IkiWiki::enable_commit_hook();
 			IkiWiki::rcs_update();
 		}
@@ -603,7 +604,8 @@ sub commentmoderation ($$) {
 				my $message = gettext("Comment moderation");
 				IkiWiki::disable_commit_hook();
 				$conflict=IkiWiki::rcs_commit_staged($message,
-					$session->param('name'), $ENV{REMOTE_ADDR});
+					$session->param('name'),
+					$session->remote_addr());
 				IkiWiki::enable_commit_hook();
 				IkiWiki::rcs_update();
 			}
diff --git a/IkiWiki/Plugin/editpage.pm b/IkiWiki/Plugin/editpage.pm
index 3ba6c519e..a8e75121f 100644
--- a/IkiWiki/Plugin/editpage.pm
+++ b/IkiWiki/Plugin/editpage.pm
@@ -403,7 +403,8 @@ sub cgi_editpage ($$) {
 			disable_commit_hook();
 			$conflict=rcs_commit($file, $message,
 				$form->field("rcsinfo"),
-				$session->param("name"), $ENV{REMOTE_ADDR});
+				$session->param("name"),
+				$session->remote_addr());
 			enable_commit_hook();
 			rcs_update();
 		}
diff --git a/IkiWiki/Plugin/lockedit.pm b/IkiWiki/Plugin/lockedit.pm
index 1466e8337..5b50fd115 100644
--- a/IkiWiki/Plugin/lockedit.pm
+++ b/IkiWiki/Plugin/lockedit.pm
@@ -38,7 +38,7 @@ sub canedit ($$) {
 	if (defined $config{locked_pages} && length $config{locked_pages} &&
 	    pagespec_match($page, $config{locked_pages},
 		    user => $session->param("name"),
-		    ip => $ENV{REMOTE_ADDR},
+		    ip => $session->remote_addr(),
 	    )) {
 		if ((! defined $user ||
 		    ! IkiWiki::userinfo_get($session->param("name"), "regdate")) &&
diff --git a/IkiWiki/Plugin/moderatedcomments.pm b/IkiWiki/Plugin/moderatedcomments.pm
index ff2c2b160..5957833fc 100644
--- a/IkiWiki/Plugin/moderatedcomments.pm
+++ b/IkiWiki/Plugin/moderatedcomments.pm
@@ -48,11 +48,11 @@ sub checkcontent (@) {
 	}
 
 	my $session=$params{session};
-	my $user=$session->param("name") if $session;
+	my $user=$session->param("name");
 	if (pagespec_match($params{page}, $config{moderate_pagespec},
 			location => $params{page},
 			(defined $user ? (user => $user) : ()),
-			(defined $ENV{REMOTE_ADDR} ? (ip => $ENV{REMOTE_ADDR}) : ()),
+			(defined $session->remote_addr() ? (ip => $session->remote_addr()) : ()),
 	)) {
 		return gettext("comment needs moderation");
 	}
diff --git a/IkiWiki/Plugin/passwordauth.pm b/IkiWiki/Plugin/passwordauth.pm
index baddca093..35ebd961f 100644
--- a/IkiWiki/Plugin/passwordauth.pm
+++ b/IkiWiki/Plugin/passwordauth.pm
@@ -297,7 +297,7 @@ sub formbuilder (@) {
 					),
 					wikiurl => $config{url},
 					wikiname => $config{wikiname},
-					REMOTE_ADDR => $ENV{REMOTE_ADDR},
+					remote_addr => $session->remote_addr(),
 				);
 				
 				eval q{use Mail::Sendmail};
diff --git a/IkiWiki/Plugin/poll.pm b/IkiWiki/Plugin/poll.pm
index 6bc4579c2..e50efa5e0 100644
--- a/IkiWiki/Plugin/poll.pm
+++ b/IkiWiki/Plugin/poll.pm
@@ -136,7 +136,8 @@ sub sessioncgi ($$) {
 			IkiWiki::disable_commit_hook();
 			IkiWiki::rcs_commit($pagesources{$page}, "poll vote ($choice)",
 				IkiWiki::rcs_prepedit($pagesources{$page}),
-				$session->param("name"), $ENV{REMOTE_ADDR});
+				$session->param("name"),
+				$session->remote_addr());
 			IkiWiki::enable_commit_hook();
 			IkiWiki::rcs_update();
 		}
diff --git a/IkiWiki/Plugin/remove.pm b/IkiWiki/Plugin/remove.pm
index d23b2cc10..b664cbf74 100644
--- a/IkiWiki/Plugin/remove.pm
+++ b/IkiWiki/Plugin/remove.pm
@@ -214,7 +214,8 @@ sub sessioncgi ($$) {
 					IkiWiki::rcs_remove($file);
 				}
 				IkiWiki::rcs_commit_staged(gettext("removed"),
-					$session->param("name"), $ENV{REMOTE_ADDR});
+					$session->param("name"),
+					$session->remote_addr());
 				IkiWiki::enable_commit_hook();
 				IkiWiki::rcs_update();
 			}
diff --git a/IkiWiki/Plugin/rename.pm b/IkiWiki/Plugin/rename.pm
index 0da90a538..977c09e67 100644
--- a/IkiWiki/Plugin/rename.pm
+++ b/IkiWiki/Plugin/rename.pm
@@ -350,7 +350,9 @@ sub sessioncgi ($$) {
 			}
 			IkiWiki::rcs_commit_staged(
 				sprintf(gettext("rename %s to %s"), $srcfile, $destfile),
-				$session->param("name"), $ENV{REMOTE_ADDR}) if $config{rcs};
+				$session->param("name"),
+				$session->remote_addr(),
+			) if $config{rcs};
 
 			# Then link fixups.
 			foreach my $rename (@torename) {
@@ -575,8 +577,8 @@ sub fixlinks ($$$) {
 					$file,
 					sprintf(gettext("update for rename of %s to %s"), $rename->{srcfile}, $rename->{destfile}),
 					$token,
-					$session->param("name"), 
-					$ENV{REMOTE_ADDR}
+					$session->param("name"),
+					$session->remote_addr(),
 				);
 				push @fixedlinks, $page if ! defined $conflict;
 			}
diff --git a/IkiWiki/Receive.pm b/IkiWiki/Receive.pm
index ae1bd8bef..fdd463025 100644
--- a/IkiWiki/Receive.pm
+++ b/IkiWiki/Receive.pm
@@ -57,7 +57,6 @@ sub test () {
 	eval q{use CGI};
 	error($@) if $@;
 	my $cgi=CGI->new;
-	$ENV{REMOTE_ADDR}='unknown' unless exists $ENV{REMOTE_ADDR};
 
 	# And dummy up a session object.
 	require IkiWiki::CGI;
-- 
cgit v1.2.3


From ecdfd1b8644bc926db008054ab6192e18351afed Mon Sep 17 00:00:00 2001
From: Joey Hess 
Date: Wed, 23 Jun 2010 17:35:21 -0400
Subject: rcs_commit and rcs_commit_staged api changes

Using named parameters for these is overdue. Passing the session in a
parameter instead of passing username and IP separately will later allow
storing other session info, like username or part of the email.

Note that these functions are not part of the exported API,
and the prototype change will catch (most) skew, so I am not changing
API versions. Any third-party plugins that call them will need updated
though.
---
 IkiWiki.pm                   |   4 +-
 IkiWiki/Plugin/attachment.pm |  10 ++--
 IkiWiki/Plugin/autoindex.pm  |   4 +-
 IkiWiki/Plugin/bzr.pm        |  43 +++++++++--------
 IkiWiki/Plugin/comments.pm   |  14 +++---
 IkiWiki/Plugin/cvs.pm        |  59 ++++++++++++-----------
 IkiWiki/Plugin/darcs.pm      |  75 +++++++++++++++---------------
 IkiWiki/Plugin/editpage.pm   |  10 ++--
 IkiWiki/Plugin/git.pm        |  52 +++++++++++++--------
 IkiWiki/Plugin/mercurial.pm  |  32 ++++++-------
 IkiWiki/Plugin/monotone.pm   |  85 +++++++++++++++-------------------
 IkiWiki/Plugin/norcs.pm      |   6 +--
 IkiWiki/Plugin/poll.pm       |  10 ++--
 IkiWiki/Plugin/remove.pm     |   7 +--
 IkiWiki/Plugin/rename.pm     |   5 +-
 IkiWiki/Plugin/svn.pm        |  59 ++++++++++++-----------
 IkiWiki/Plugin/tag.pm        |   2 +-
 IkiWiki/Plugin/tla.pm        |  34 ++++++++------
 debian/changelog             |   5 +-
 doc/plugins/write.mdwn       |  16 ++++---
 ikiwiki-calendar.in          |   2 +-
 ikiwiki.spec                 |   2 +-
 po/ikiwiki.pot               | 108 +++++++++++++++++++++----------------------
 t/bazaar.t                   |  25 ++++++++--
 t/cvs.t                      |   6 ++-
 t/git.t                      |  12 +++--
 t/mercurial.t                |  11 ++++-
 t/svn.t                      |   6 ++-
 28 files changed, 380 insertions(+), 324 deletions(-)

(limited to 'IkiWiki/Plugin/remove.pm')

diff --git a/IkiWiki.pm b/IkiWiki.pm
index 203da3ba2..35b38df46 100644
--- a/IkiWiki.pm
+++ b/IkiWiki.pm
@@ -1840,11 +1840,11 @@ sub rcs_prepedit ($) {
 	$hooks{rcs}{rcs_prepedit}{call}->(@_);
 }
 
-sub rcs_commit ($$$;$$) {
+sub rcs_commit (@) {
 	$hooks{rcs}{rcs_commit}{call}->(@_);
 }
 
-sub rcs_commit_staged ($$$) {
+sub rcs_commit_staged (@) {
 	$hooks{rcs}{rcs_commit_staged}{call}->(@_);
 }
 
diff --git a/IkiWiki/Plugin/attachment.pm b/IkiWiki/Plugin/attachment.pm
index 216e00b3d..ee105a170 100644
--- a/IkiWiki/Plugin/attachment.pm
+++ b/IkiWiki/Plugin/attachment.pm
@@ -183,10 +183,12 @@ sub formbuilder (@) {
 		if ($config{rcs}) {
 			IkiWiki::rcs_add($filename);
 			IkiWiki::disable_commit_hook();
-			IkiWiki::rcs_commit($filename, gettext("attachment upload"),
-				IkiWiki::rcs_prepedit($filename),
-				$session->param("name"),
-				$session->remote_addr());
+			IkiWiki::rcs_commit(
+				file => $filename,
+				message => gettext("attachment upload"),
+				token => IkiWiki::rcs_prepedit($filename),
+				session => $session,
+			);
 			IkiWiki::enable_commit_hook();
 			IkiWiki::rcs_update();
 		}
diff --git a/IkiWiki/Plugin/autoindex.pm b/IkiWiki/Plugin/autoindex.pm
index c3eb53300..11595e217 100644
--- a/IkiWiki/Plugin/autoindex.pm
+++ b/IkiWiki/Plugin/autoindex.pm
@@ -117,8 +117,8 @@ sub refresh () {
 		}
 		if ($config{rcs}) {
 			IkiWiki::rcs_commit_staged(
-				gettext("automatic index generation"),
-				undef, undef);
+				message => gettext("automatic index generation"),
+			);
 			IkiWiki::enable_commit_hook();
 		}
 	}
diff --git a/IkiWiki/Plugin/bzr.pm b/IkiWiki/Plugin/bzr.pm
index 44ab9a86a..562d5d389 100644
--- a/IkiWiki/Plugin/bzr.pm
+++ b/IkiWiki/Plugin/bzr.pm
@@ -123,8 +123,13 @@ sub rcs_prepedit ($) {
 	return "";
 }
 
-sub bzr_author ($$) {
-	my ($user, $ipaddr) = @_;
+sub bzr_author ($) {
+	my $session=shift;
+
+	return unless defined $session;
+
+	my $user=$session->param("name");
+	my $ipaddr=$session->remote_addr();
 
 	if (defined $user) {
 		return IkiWiki::possibly_foolish_untaint($user);
@@ -137,18 +142,19 @@ sub bzr_author ($$) {
 	}
 }
 
-sub rcs_commit ($$$;$$$) {
-	my ($file, $message, $rcstoken, $user, $ipaddr, $emailuser) = @_;
+sub rcs_commit (@) {
+	my %params=@_;
 
-	$user = bzr_author($user, $ipaddr);
+	my $user=bzr_author($params{session});
 
-	$message = IkiWiki::possibly_foolish_untaint($message);
-	if (! length $message) {
-		$message = "no message given";
+	$params{message} = IkiWiki::possibly_foolish_untaint($params{message});
+	if (! length $params{message}) {
+		$params{message} = "no message given";
 	}
 
-	my @cmdline = ("bzr", "commit", "--quiet", "-m", $message, "--author", $user,
-	               $config{srcdir}."/".$file);
+	my @cmdline = ("bzr", "commit", "--quiet", "-m", $params{message},
+	               (defined $user ? ("--author", $user) : ()),
+	               $config{srcdir}."/".$params{file});
 	if (system(@cmdline) != 0) {
 		warn "'@cmdline' failed: $!";
 	}
@@ -156,19 +162,18 @@ sub rcs_commit ($$$;$$$) {
 	return undef; # success
 }
 
-sub rcs_commit_staged ($$$;$) {
-	# Commits all staged changes. Changes can be staged using rcs_add,
-	# rcs_remove, and rcs_rename.
-	my ($message, $user, $ipaddr, $emailuser)=@_;
+sub rcs_commit_staged (@) {
+	my %params=@_;
 
-	$user = bzr_author($user, $ipaddr);
+	my $user=bzr_author($params{session});
 
-	$message = IkiWiki::possibly_foolish_untaint($message);
-	if (! length $message) {
-		$message = "no message given";
+	$params{message} = IkiWiki::possibly_foolish_untaint($params{message});
+	if (! length $params{message}) {
+		$params{message} = "no message given";
 	}
 
-	my @cmdline = ("bzr", "commit", "--quiet", "-m", $message, "--author", $user,
+	my @cmdline = ("bzr", "commit", "--quiet", "-m", $params{message},
+	               (defined $user ? ("--author", $user) : ()),
 	               $config{srcdir});
 	if (system(@cmdline) != 0) {
 		warn "'@cmdline' failed: $!";
diff --git a/IkiWiki/Plugin/comments.pm b/IkiWiki/Plugin/comments.pm
index 4770209c9..41c6948e8 100644
--- a/IkiWiki/Plugin/comments.pm
+++ b/IkiWiki/Plugin/comments.pm
@@ -513,9 +513,10 @@ sub editcomment ($$) {
 
 			IkiWiki::rcs_add($file);
 			IkiWiki::disable_commit_hook();
-			$conflict = IkiWiki::rcs_commit_staged($message,
-				$session->param('name'),
-				$session->remote_addr());
+			$conflict = IkiWiki::rcs_commit_staged(
+				message => $message,
+				session => $session,
+			);
 			IkiWiki::enable_commit_hook();
 			IkiWiki::rcs_update();
 		}
@@ -603,9 +604,10 @@ sub commentmoderation ($$) {
 			if ($config{rcs} and $config{comments_commit}) {
 				my $message = gettext("Comment moderation");
 				IkiWiki::disable_commit_hook();
-				$conflict=IkiWiki::rcs_commit_staged($message,
-					$session->param('name'),
-					$session->remote_addr());
+				$conflict=IkiWiki::rcs_commit_staged(
+					message => $message,
+					session => $session,
+				);
 				IkiWiki::enable_commit_hook();
 				IkiWiki::rcs_update();
 			}
diff --git a/IkiWiki/Plugin/cvs.pm b/IkiWiki/Plugin/cvs.pm
index a9fe162a1..c6687d780 100644
--- a/IkiWiki/Plugin/cvs.pm
+++ b/IkiWiki/Plugin/cvs.pm
@@ -183,41 +183,47 @@ sub rcs_prepedit ($) {
 	return defined $rev ? $rev : "";
 }
 
-sub rcs_commit ($$$;$$$) {
+sub commitmessage (@) {
+	my %params=@_;
+	
+	if (defined $params{session}) {
+		if (defined $params{session}->param("name")) {
+			return "web commit by ".
+				$params{session}->param("name").
+				(length $params{message} ? ": $params{message}" : "");
+		}
+		elsif (defined $params{session}->remote_addr()) {
+			return "web commit from ".
+				$params{session}->remote_addr().
+				(length $params{message} ? ": $params{message}" : "");
+		}
+	}
+	return $params{message};
+}
+
+sub rcs_commit (@) {
 	# Tries to commit the page; returns undef on _success_ and
 	# a version of the page with the rcs's conflict markers on failure.
 	# The file is relative to the srcdir.
-	my $file=shift;
-	my $message=shift;
-	my $rcstoken=shift;
-	my $user=shift;
-	my $ipaddr=shift;
-	my $emailuser=shift;
+	my %params=@_;
 
 	return unless cvs_is_controlling;
 
-	if (defined $user) {
-		$message="web commit by $user".(length $message ? ": $message" : "");
-	}
-	elsif (defined $ipaddr) {
-		$message="web commit from $ipaddr".(length $message ? ": $message" : "");
-	}
-
 	# Check to see if the page has been changed by someone
 	# else since rcs_prepedit was called.
-	my ($oldrev)=$rcstoken=~/^([0-9]+)$/; # untaint
-	my $rev=cvs_info("Repository revision", "$config{srcdir}/$file");
+	my ($oldrev)=$params{token}=~/^([0-9]+)$/; # untaint
+	my $rev=cvs_info("Repository revision", "$config{srcdir}/$params{file}");
 	if (defined $rev && defined $oldrev && $rev != $oldrev) {
 		# Merge their changes into the file that we've
 		# changed.
-		cvs_runcvs('update', $file) ||
+		cvs_runcvs('update', $params{file}) ||
 			warn("cvs merge from $oldrev to $rev failed\n");
 	}
 
 	if (! cvs_runcvs('commit', '-m',
-			 IkiWiki::possibly_foolish_untaint $message)) {
-		my $conflict=readfile("$config{srcdir}/$file");
-		cvs_runcvs('update', '-C', $file) ||
+			 IkiWiki::possibly_foolish_untaint(commitmessage(%params)))) {
+		my $conflict=readfile("$config{srcdir}/$params{file}");
+		cvs_runcvs('update', '-C', $params{file}) ||
 			warn("cvs revert failed\n");
 		return $conflict;
 	}
@@ -225,20 +231,13 @@ sub rcs_commit ($$$;$$$) {
 	return undef # success
 }
 
-sub rcs_commit_staged ($$$;$) {
+sub rcs_commit_staged (@) {
 	# Commits all staged changes. Changes can be staged using rcs_add,
 	# rcs_remove, and rcs_rename.
-	my ($message, $user, $ipaddr, $emailuser)=@_;
-
-	if (defined $user) {
-		$message="web commit by $user".(length $message ? ": $message" : "");
-	}
-	elsif (defined $ipaddr) {
-		$message="web commit from $ipaddr".(length $message ? ": $message" : "");
-	}
+	my %params=@_;
 
 	if (! cvs_runcvs('commit', '-m',
-			 IkiWiki::possibly_foolish_untaint $message)) {
+			 IkiWiki::possibly_foolish_untaint(commitmessage(%params)))) {
 		warn "cvs staged commit failed\n";
 		return 1; # failure
 	}
diff --git a/IkiWiki/Plugin/darcs.pm b/IkiWiki/Plugin/darcs.pm
index 345456c01..0dfc8708d 100644
--- a/IkiWiki/Plugin/darcs.pm
+++ b/IkiWiki/Plugin/darcs.pm
@@ -140,14 +140,31 @@ sub rcs_prepedit ($) {
 	return $rev;
 }
 
-sub rcs_commit ($$$;$$$) {
+sub commitauthor (@) {
+	my %params=@_;
+	
+	my $author="anon\@web";
+	if (defined $params{session}) {
+		if (defined $params{session}->param("name")) {
+			return $params{session}->param("name").'@web';
+		}
+		elsif (defined $params{session}->remote_addr()) {
+			return $params{session}->remote_addr().'@web';
+		}
+	}
+	return 'anon@web';
+}
+
+sub rcs_commit (@) {
 	# Commit the page.  Returns 'undef' on success and a version of the page
 	# with conflict markers on failure.
+	my %params=@_;
 
-	my ($file, $message, $rcstoken, $user, $ipaddr, $emailuser) = @_;
+	my ($file, $message, $token) =
+		($params{file}, $params{message}, $params{token});
 
 	# Compute if the "revision" of $file changed.
-	my $changed = darcs_rev($file) ne $rcstoken;
+	my $changed = darcs_rev($file) ne $token;
 
 	# Yes, the following is a bit convoluted.
 	if ($changed) {
@@ -155,7 +172,7 @@ sub rcs_commit ($$$;$$$) {
 		rename("$config{srcdir}/$file", "$config{srcdir}/$file.save") or
 			error("failed to rename $file to $file.save: $!");
 
-		# Roll the repository back to $rcstoken.
+		# Roll the repository back to $token.
 
 		# TODO.  Can we be sure that no changes are lost?  I think that
 		# we can, if we make sure that the 'darcs push' below will always
@@ -166,37 +183,28 @@ sub rcs_commit ($$$;$$$) {
 		# TODO: 'yes | ...' needed?  Doesn't seem so.
 		silentsystem('darcs', "revert", "--repodir", $config{srcdir}, "--all") == 0 ||
 			error("'darcs revert' failed");
-		# Remove all patches starting at $rcstoken.
+		# Remove all patches starting at $token.
 		my $child = open(DARCS_OBLITERATE, "|-");
 		if (! $child) {
 			open(STDOUT, ">/dev/null");
 			exec('darcs', "obliterate", "--repodir", $config{srcdir},
-			   "--match", "hash " . $rcstoken) and
+			   "--match", "hash " . $token) and
 			   error("'darcs obliterate' failed");
 		}
 		1 while print DARCS_OBLITERATE "y";
 		close(DARCS_OBLITERATE);
-		# Restore the $rcstoken one.
+		# Restore the $token one.
 		silentsystem('darcs', "pull", "--quiet", "--repodir", $config{srcdir},
-			"--match", "hash " . $rcstoken, "--all") == 0 ||
+			"--match", "hash " . $token, "--all") == 0 ||
 			error("'darcs pull' failed");
 	
-		# We're back at $rcstoken.  Re-install the modified file.
+		# We're back at $token.  Re-install the modified file.
 		rename("$config{srcdir}/$file.save", "$config{srcdir}/$file") or
 			error("failed to rename $file.save to $file: $!");
 	}
 
 	# Record the changes.
-	my $author;
-	if (defined $user) {
-		$author = "$user\@web";
-	}
-	elsif (defined $ipaddr) {
-		$author = "$ipaddr\@web";
-	}
-	else {
-		$author = "anon\@web";
-	}
+	my $author=commitauthor(%params);
 	if (!defined $message || !length($message)) {
 		$message = "empty message";
 	}
@@ -211,13 +219,13 @@ sub rcs_commit ($$$;$$$) {
 
 	# If this updating yields any conflicts, we'll record them now to resolve
 	# them.  If nothing is recorded, there are no conflicts.
-	$rcstoken = darcs_rev($file);
+	$token = darcs_rev($file);
 	# TODO: Use only the first line here, i.e. only the patch name?
 	writefile("$file.log", $config{srcdir}, 'resolve conflicts: ' . $message);
 	silentsystem('darcs', 'record', '--repodir', $config{srcdir}, '--all',
 		'-m', 'resolve conflicts: ' . $message, '--author', $author, $file) == 0 ||
 		error("'darcs record' failed");
-	my $conflicts = darcs_rev($file) ne $rcstoken;
+	my $conflicts = darcs_rev($file) ne $token;
 	unlink("$config{srcdir}/$file.log") or
 		error("failed to remove '$file.log'");
 
@@ -239,25 +247,18 @@ sub rcs_commit ($$$;$$$) {
 	}
 }
 
-sub rcs_commit_staged ($$$;$) {
-	my ($message, $user, $ipaddr, $emailuser) = @_;
+sub rcs_commit_staged (@) {
+	my %params=@_;
 
-	my $author;
-	if (defined $user) {
-		$author = "$user\@web";
-	}
-	elsif (defined $ipaddr) {
-		$author = "$ipaddr\@web";
-	}
-	else {
-		$author = "anon\@web";
-	}
-	if (!defined $message || !length($message)) {
-		$message = "empty message";
+	my $author=commitauthor(%params);
+	if (!defined $params{message} || !length($params{message})) {
+		$params{message} = "empty message";
 	}
 
-	silentsystem('darcs', "record", "--repodir", $config{srcdir}, "-a", "-A", $author,
-		"-m", $message)	== 0 || error("'darcs record' failed");
+	silentsystem('darcs', "record", "--repodir", $config{srcdir},
+		"-a", "-A", $author,
+		"-m", $params{message},
+	) == 0 || error("'darcs record' failed");
 
 	# Push the changes to the main repository.
 	silentsystem('darcs', 'push', '--quiet', '--repodir', $config{srcdir}, '--all') == 0 ||
diff --git a/IkiWiki/Plugin/editpage.pm b/IkiWiki/Plugin/editpage.pm
index a8e75121f..1a04a72b5 100644
--- a/IkiWiki/Plugin/editpage.pm
+++ b/IkiWiki/Plugin/editpage.pm
@@ -401,10 +401,12 @@ sub cgi_editpage ($$) {
 			# signaling to it that it should not try to
 			# do anything.
 			disable_commit_hook();
-			$conflict=rcs_commit($file, $message,
-				$form->field("rcsinfo"),
-				$session->param("name"),
-				$session->remote_addr());
+			$conflict=rcs_commit(
+				file => $file,
+				message => $message,
+				token => $form->field("rcsinfo"),
+				session => $session,
+			);
 			enable_commit_hook();
 			rcs_update();
 		}
diff --git a/IkiWiki/Plugin/git.pm b/IkiWiki/Plugin/git.pm
index b56f229d7..b02fc118d 100644
--- a/IkiWiki/Plugin/git.pm
+++ b/IkiWiki/Plugin/git.pm
@@ -464,43 +464,55 @@ sub rcs_prepedit ($) {
 	return git_sha1($file);
 }
 
-sub rcs_commit ($$$;$$$) {
+sub rcs_commit (@) {
 	# Try to commit the page; returns undef on _success_ and
 	# a version of the page with the rcs's conflict markers on
 	# failure.
-
-	my ($file, $message, $rcstoken, $user, $ipaddr, $emailuser) = @_;
+	my %params=@_;
 
 	# Check to see if the page has been changed by someone else since
 	# rcs_prepedit was called.
-	my $cur    = git_sha1($file);
-	my ($prev) = $rcstoken =~ /^($sha1_pattern)$/; # untaint
+	my $cur    = git_sha1($params{file});
+	my ($prev) = $params{token} =~ /^($sha1_pattern)$/; # untaint
 
 	if (defined $cur && defined $prev && $cur ne $prev) {
-		my $conflict = merge_past($prev, $file, $dummy_commit_msg);
+		my $conflict = merge_past($prev, $params{file}, $dummy_commit_msg);
 		return $conflict if defined $conflict;
 	}
 
-	rcs_add($file);	
-	return rcs_commit_staged($message, $user, $ipaddr);
+	rcs_add($params{file});
+	return rcs_commit_staged(
+		message => $params{message},
+		session => $params{session},
+	);
 }
 
-sub rcs_commit_staged ($$$;$) {
+sub rcs_commit_staged (@) {
 	# Commits all staged changes. Changes can be staged using rcs_add,
 	# rcs_remove, and rcs_rename.
-	my ($message, $user, $ipaddr, $emailuser)=@_;
-
-	# Set the commit author and email to the web committer.
+	my %params=@_;
+	
 	my %env=%ENV;
-	if (defined $user || defined $ipaddr) {
-		my $u=encode_utf8(defined $user ? $user : $ipaddr);
-		$ENV{GIT_AUTHOR_NAME}=$u;
-		$ENV{GIT_AUTHOR_EMAIL}="$u\@web";
+
+	if (defined $params{session}) {
+		# Set the commit author and email based on web session info.
+		my $u;
+		if (defined $params{session}->param("name")) {
+			$u=$params{session}->param("name");
+		}
+		elsif (defined $params{session}->remote_addr()) {
+			$u=$params{session}->remote_addr();
+		}
+		if (defined $u) {
+			$u=encode_utf8($u);
+			$ENV{GIT_AUTHOR_NAME}=$u;
+			$ENV{GIT_AUTHOR_EMAIL}="$u\@web";
+		}
 	}
 
-	$message = IkiWiki::possibly_foolish_untaint($message);
+	$params{message} = IkiWiki::possibly_foolish_untaint($params{message});
 	my @opts;
-	if ($message !~ /\S/) {
+	if ($params{message} !~ /\S/) {
 		# Force git to allow empty commit messages.
 		# (If this version of git supports it.)
 		my ($version)=`git --version` =~ /git version (.*)/;
@@ -508,13 +520,13 @@ sub rcs_commit_staged ($$$;$) {
 			push @opts, '--cleanup=verbatim';
 		}
 		else {
-			$message.=".";
+			$params{message}.=".";
 		}
 	}
 	push @opts, '-q';
 	# git commit returns non-zero if file has not been really changed.
 	# so we should ignore its exit status (hence run_or_non).
-	if (run_or_non('git', 'commit', @opts, '-m', $message)) {
+	if (run_or_non('git', 'commit', @opts, '-m', $params{message})) {
 		if (length $config{gitorigin_branch}) {
 			run_or_cry('git', 'push', $config{gitorigin_branch});
 		}
diff --git a/IkiWiki/Plugin/mercurial.pm b/IkiWiki/Plugin/mercurial.pm
index 1793ab4bb..edf915ae9 100644
--- a/IkiWiki/Plugin/mercurial.pm
+++ b/IkiWiki/Plugin/mercurial.pm
@@ -126,26 +126,26 @@ sub rcs_prepedit ($) {
 	return "";
 }
 
-sub rcs_commit ($$$;$$$) {
-	my ($file, $message, $rcstoken, $user, $ipaddr, $emailuser) = @_;
+sub rcs_commit (@) {
+	my %params=@_;
 
-	if (defined $user) {
-		$user = IkiWiki::possibly_foolish_untaint($user);
-	}
-	elsif (defined $ipaddr) {
-		$user = "Anonymous from ".IkiWiki::possibly_foolish_untaint($ipaddr);
-	}
-	else {
-		$user = "Anonymous";
+	my $user="Anonymous";
+	if (defined $params{session}) {
+		if (defined $params{session}->param("name")) {
+			$user = $params{session}->param("name");
+		}
+		elsif (defined $params{session}->remote_addr()) {
+			$user = "Anonymous from ".$params{session}->remote_addr();
+		}
 	}
 
-	$message = IkiWiki::possibly_foolish_untaint($message);
-	if (! length $message) {
-		$message = "no message given";
+	if (! length $params{message}) {
+		$params{message} = "no message given";
 	}
 
 	my @cmdline = ("hg", "-q", "-R", $config{srcdir}, "commit", 
-	               "-m", $message, "-u", $user);
+	               "-m", IkiWiki::possibly_foolish_untaint($params{message}),
+	               "-u", IkiWiki::possibly_foolish_untaint($user));
 	if (system(@cmdline) != 0) {
 		warn "'@cmdline' failed: $!";
 	}
@@ -153,10 +153,10 @@ sub rcs_commit ($$$;$$$) {
 	return undef; # success
 }
 
-sub rcs_commit_staged ($$$;$) {
+sub rcs_commit_staged (@) {
 	# Commits all staged changes. Changes can be staged using rcs_add,
 	# rcs_remove, and rcs_rename.
-	my ($message, $user, $ipaddr, $emailuser)=@_;
+	my %params=@_;
 	
 	error("rcs_commit_staged not implemented for mercurial"); # TODO
 }
diff --git a/IkiWiki/Plugin/monotone.pm b/IkiWiki/Plugin/monotone.pm
index 55d8039e0..95fbcee76 100644
--- a/IkiWiki/Plugin/monotone.pm
+++ b/IkiWiki/Plugin/monotone.pm
@@ -293,32 +293,33 @@ sub rcs_prepedit ($) {
 	return get_rev();
 }
 
-sub rcs_commit ($$$;$$$) {
+sub commitauthor (@) {
+	my %params=@_;
+
+	if (defined $params{session}) {
+		if (defined $params{session}->param("name")) {
+			return "Web user: " . $params{session}->param("name");
+		}
+		elsif (defined $params{session}->remote_addr()) {
+			return "Web IP: " . $params{session}->remote_addr();
+		}
+	}
+	return "Web: Anonymous";
+}
+
+
+sub rcs_commit (@) {
 	# Tries to commit the page; returns undef on _success_ and
 	# a version of the page with the rcs's conflict markers on failure.
 	# The file is relative to the srcdir.
-	my $file=shift;
-	my $message=shift;
-	my $rcstoken=shift;
-	my $user=shift;
-	my $ipaddr=shift;
-	my $emailuser=shift;
-	my $author;
+	my %params=@_;
 
-	if (defined $user) {
-		$author="Web user: " . $user;
-	}
-	elsif (defined $ipaddr) {
-		$author="Web IP: " . $ipaddr;
-	}
-	else {
-		$author="Web: Anonymous";
-	}
+	my $author=IkiWiki::possibly_foolish_untaint(commitauthor(%params)),
 
 	chdir $config{srcdir}
 	    or error("Cannot chdir to $config{srcdir}: $!");
 
-	my ($oldrev)= $rcstoken=~ m/^($sha1_pattern)$/; # untaint
+	my ($oldrev) = $params{token} =~ m/^($sha1_pattern)$/; # untaint
 	my $rev = get_rev();
 	if (defined $rev && defined $oldrev && $rev ne $oldrev) {
 		my $automator = Monotone->new();
@@ -327,8 +328,8 @@ sub rcs_commit ($$$;$$$) {
 		# Something has been committed, has this file changed?
 		my ($out, $err);
 		$automator->setOpts("r", $oldrev, "r", $rev);
-		($out, $err) = $automator->call("content_diff", $file);
-		debug("Problem committing $file") if ($err ne "");
+		($out, $err) = $automator->call("content_diff", $params{file});
+		debug("Problem committing $params{file}") if ($err ne "");
 		my $diff = $out;
 		
 		if ($diff) {
@@ -337,11 +338,11 @@ sub rcs_commit ($$$;$$$) {
 			#
 			# first get the contents
 			debug("File changed: forming branch");
-			my $newfile=readfile("$config{srcdir}/$file");
+			my $newfile=readfile("$config{srcdir}/$params{file}");
 			
 			# then get the old content ID from the diff
-			if ($diff !~ m/^---\s$file\s+($sha1_pattern)$/m) {
-				error("Unable to find previous file ID for $file");
+			if ($diff !~ m/^---\s$params{file}\s+($sha1_pattern)$/m) {
+				error("Unable to find previous file ID for $params{file}");
 			}
 			my $oldFileID = $1;
 
@@ -352,13 +353,13 @@ sub rcs_commit ($$$;$$$) {
 			my $branch = $1;
 
 			# then put the new content into the DB (and record the new content ID)
-			my $newRevID = commit_file_to_new_rev($automator, $file, $oldFileID, $newfile, $oldrev, $branch, $author, $message);
+			my $newRevID = commit_file_to_new_rev($automator, $params{file}, $oldFileID, $newfile, $oldrev, $branch, $author, $params{message});
 
 			$automator->close();
 
 			# if we made it to here then the file has been committed... revert the local copy
-			if (system("mtn", "--root=$config{mtnrootdir}", "revert", $file) != 0) {
-				debug("Unable to revert $file after merge on conflicted commit!");
+			if (system("mtn", "--root=$config{mtnrootdir}", "revert", $params{file}) != 0) {
+				debug("Unable to revert $params{file} after merge on conflicted commit!");
 			}
 			debug("Divergence created! Attempting auto-merge.");
 
@@ -407,7 +408,7 @@ sub rcs_commit ($$$;$$$) {
 				# for cleanup note, this relies on the fact
 				# that ikiwiki seems to call rcs_prepedit()
 				# again after we return
-				return readfile("$config{srcdir}/$file");
+				return readfile("$config{srcdir}/$params{file}");
 			}
 			return undef;
 		}
@@ -419,11 +420,12 @@ sub rcs_commit ($$$;$$$) {
 
 	if (system("mtn", "--root=$config{mtnrootdir}", "commit", "--quiet",
 	           "--author", $author, "--key", $config{mtnkey}, "-m",
-		   IkiWiki::possibly_foolish_untaint($message), $file) != 0) {
+	           IkiWiki::possibly_foolish_untaint($params{message}),
+	           $params{file}) != 0) {
 		debug("Traditional commit failed! Returning data as conflict.");
-		my $conflict=readfile("$config{srcdir}/$file");
+		my $conflict=readfile("$config{srcdir}/$params{file}");
 		if (system("mtn", "--root=$config{mtnrootdir}", "revert",
-		           "--quiet", $file) != 0) {
+		           "--quiet", $params{file}) != 0) {
 			debug("monotone revert failed");
 		}
 		return $conflict;
@@ -439,32 +441,21 @@ sub rcs_commit ($$$;$$$) {
 	return undef # success
 }
 
-sub rcs_commit_staged ($$$;$) {
+sub rcs_commit_staged (@) {
 	# Commits all staged changes. Changes can be staged using rcs_add,
 	# rcs_remove, and rcs_rename.
-	my ($message, $user, $ipaddr, $emailuser)=@_;
-	
+	my %params=@_;
+
 	# Note - this will also commit any spurious changes that happen to be
 	# lying around in the working copy.  There shouldn't be any, but...
 	
 	chdir $config{srcdir}
 	    or error("Cannot chdir to $config{srcdir}: $!");
 
-	my $author;
-
-	if (defined $user) {
-		$author="Web user: " . $user;
-	}
-	elsif (defined $ipaddr) {
-		$author="Web IP: " . $ipaddr;
-	}
-	else {
-		$author="Web: Anonymous";
-	}
-
 	if (system("mtn", "--root=$config{mtnrootdir}", "commit", "--quiet",
-	           "--author", $author, "--key", $config{mtnkey}, "-m",
-		   IkiWiki::possibly_foolish_untaint($message)) != 0) {
+	           "--author", IkiWiki::possibly_foolish_untaint(commitauthor(%params)),
+	           "--key", $config{mtnkey}, "-m",
+		   IkiWiki::possibly_foolish_untaint($params{message})) != 0) {
 		error("Monotone commit failed");
 	}
 }
diff --git a/IkiWiki/Plugin/norcs.pm b/IkiWiki/Plugin/norcs.pm
index 5131a1502..a3bb6240e 100644
--- a/IkiWiki/Plugin/norcs.pm
+++ b/IkiWiki/Plugin/norcs.pm
@@ -38,13 +38,11 @@ sub rcs_prepedit ($) {
 	return ""
 }
 
-sub rcs_commit ($$$;$$$) {
-	my ($file, $message, $rcstoken, $user, $ipaddr, $emailuser) = @_;
+sub rcs_commit (@) {
 	return undef # success
 }
 
-sub rcs_commit_staged ($$$;$) {
-	my ($message, $user, $ipaddr, $emailuser)=@_;
+sub rcs_commit_staged (@) {
 	return undef # success
 }
 
diff --git a/IkiWiki/Plugin/poll.pm b/IkiWiki/Plugin/poll.pm
index e50efa5e0..b333e2cdc 100644
--- a/IkiWiki/Plugin/poll.pm
+++ b/IkiWiki/Plugin/poll.pm
@@ -134,10 +134,12 @@ sub sessioncgi ($$) {
 		$oldchoice=$session->param($choice_param);
 		if ($config{rcs}) {
 			IkiWiki::disable_commit_hook();
-			IkiWiki::rcs_commit($pagesources{$page}, "poll vote ($choice)",
-				IkiWiki::rcs_prepedit($pagesources{$page}),
-				$session->param("name"),
-				$session->remote_addr());
+			IkiWiki::rcs_commit(
+				file => $pagesources{$page},
+				message => "poll vote ($choice)",
+				token => IkiWiki::rcs_prepedit($pagesources{$page}),
+				session => $session,
+			);
 			IkiWiki::enable_commit_hook();
 			IkiWiki::rcs_update();
 		}
diff --git a/IkiWiki/Plugin/remove.pm b/IkiWiki/Plugin/remove.pm
index b664cbf74..95f148183 100644
--- a/IkiWiki/Plugin/remove.pm
+++ b/IkiWiki/Plugin/remove.pm
@@ -213,9 +213,10 @@ sub sessioncgi ($$) {
 				foreach my $file (@files) {
 					IkiWiki::rcs_remove($file);
 				}
-				IkiWiki::rcs_commit_staged(gettext("removed"),
-					$session->param("name"),
-					$session->remote_addr());
+				IkiWiki::rcs_commit_staged(
+					message => gettext("removed"),
+					session => $session,
+				);
 				IkiWiki::enable_commit_hook();
 				IkiWiki::rcs_update();
 			}
diff --git a/IkiWiki/Plugin/rename.pm b/IkiWiki/Plugin/rename.pm
index 977c09e67..61d39d4b5 100644
--- a/IkiWiki/Plugin/rename.pm
+++ b/IkiWiki/Plugin/rename.pm
@@ -349,9 +349,8 @@ sub sessioncgi ($$) {
 				$pagesources{$rename->{src}}=$rename->{destfile};
 			}
 			IkiWiki::rcs_commit_staged(
-				sprintf(gettext("rename %s to %s"), $srcfile, $destfile),
-				$session->param("name"),
-				$session->remote_addr(),
+				message => sprintf(gettext("rename %s to %s"), $srcfile, $destfile),
+				session => $session,
 			) if $config{rcs};
 
 			# Then link fixups.
diff --git a/IkiWiki/Plugin/svn.pm b/IkiWiki/Plugin/svn.pm
index ffacb8cf9..f1e608408 100644
--- a/IkiWiki/Plugin/svn.pm
+++ b/IkiWiki/Plugin/svn.pm
@@ -144,44 +144,50 @@ sub rcs_prepedit ($) {
 	}
 }
 
-sub rcs_commit ($$$;$$$) {
+sub commitmessage (@) {
+	my %params=@_;
+
+	if (defined $params{session}) {
+		if (defined $params{session}->param("name")) {
+			return "web commit by ".
+				$params{session}->param("name").
+				(length $params{message} ? ": $params{message}" : "");
+		}
+		elsif (defined $params{session}->remote_addr()) {
+			return "web commit from ".
+				$params{session}->remote_addr().
+				(length $params{message} ? ": $params{message}" : "");
+		}
+	}
+	return $params{message};
+}
+
+sub rcs_commit (@) {
 	# Tries to commit the page; returns undef on _success_ and
 	# a version of the page with the rcs's conflict markers on failure.
 	# The file is relative to the srcdir.
-	my $file=shift;
-	my $message=shift;
-	my $rcstoken=shift;
-	my $user=shift;
-	my $ipaddr=shift;
-	my $emailuser=shift;
-
-	if (defined $user) {
-		$message="web commit by $user".(length $message ? ": $message" : "");
-	}
-	elsif (defined $ipaddr) {
-		$message="web commit from $ipaddr".(length $message ? ": $message" : "");
-	}
+	my %params=@_;
 
 	if (-d "$config{srcdir}/.svn") {
 		# Check to see if the page has been changed by someone
 		# else since rcs_prepedit was called.
-		my ($oldrev)=$rcstoken=~/^([0-9]+)$/; # untaint
-		my $rev=svn_info("Revision", "$config{srcdir}/$file");
+		my ($oldrev)=$params{token}=~/^([0-9]+)$/; # untaint
+		my $rev=svn_info("Revision", "$config{srcdir}/$params{file}");
 		if (defined $rev && defined $oldrev && $rev != $oldrev) {
 			# Merge their changes into the file that we've
 			# changed.
 			if (system("svn", "merge", "--quiet", "-r$oldrev:$rev",
-			           "$config{srcdir}/$file", "$config{srcdir}/$file") != 0) {
+			           "$config{srcdir}/$params{file}", "$config{srcdir}/$params{file}") != 0) {
 				warn("svn merge -r$oldrev:$rev failed\n");
 			}
 		}
 
 		if (system("svn", "commit", "--quiet", 
 		           "--encoding", "UTF-8", "-m",
-		           IkiWiki::possibly_foolish_untaint($message),
+		           IkiWiki::possibly_foolish_untaint(commitmessage(%params)),
 			   $config{srcdir}) != 0) {
-			my $conflict=readfile("$config{srcdir}/$file");
-			if (system("svn", "revert", "--quiet", "$config{srcdir}/$file") != 0) {
+			my $conflict=readfile("$config{srcdir}/$params{file}");
+			if (system("svn", "revert", "--quiet", "$config{srcdir}/$params{file}") != 0) {
 				warn("svn revert failed\n");
 			}
 			return $conflict;
@@ -190,21 +196,14 @@ sub rcs_commit ($$$;$$$) {
 	return undef # success
 }
 
-sub rcs_commit_staged ($$$;$) {
+sub rcs_commit_staged (@) {
 	# Commits all staged changes. Changes can be staged using rcs_add,
 	# rcs_remove, and rcs_rename.
-	my ($message, $user, $ipaddr, $emailuser)=@_;
-	
-	if (defined $user) {
-		$message="web commit by $user".(length $message ? ": $message" : "");
-	}
-	elsif (defined $ipaddr) {
-		$message="web commit from $ipaddr".(length $message ? ": $message" : "");
-	}
+	my %params=@_;
 	
 	if (system("svn", "commit", "--quiet",
 	           "--encoding", "UTF-8", "-m",
-	           IkiWiki::possibly_foolish_untaint($message),
+	           IkiWiki::possibly_foolish_untaint(commitmessage(%params)),
 		   $config{srcdir}) != 0) {
 		warn("svn commit failed\n");
 		return 1; # failure	
diff --git a/IkiWiki/Plugin/tag.pm b/IkiWiki/Plugin/tag.pm
index 62f030f4e..55064a9a3 100644
--- a/IkiWiki/Plugin/tag.pm
+++ b/IkiWiki/Plugin/tag.pm
@@ -90,7 +90,7 @@ sub gentag ($) {
 			if ($config{rcs}) {
 				IkiWiki::disable_commit_hook();
 				IkiWiki::rcs_add($tagfile);
-				IkiWiki::rcs_commit_staged($message, undef, undef);
+				IkiWiki::rcs_commit_staged(message => $message);
 				IkiWiki::enable_commit_hook();
 			}
 		});
diff --git a/IkiWiki/Plugin/tla.pm b/IkiWiki/Plugin/tla.pm
index 80c015e3c..da4385446 100644
--- a/IkiWiki/Plugin/tla.pm
+++ b/IkiWiki/Plugin/tla.pm
@@ -98,19 +98,23 @@ sub rcs_prepedit ($) {
 	}
 }
 
-sub rcs_commit ($$$;$$$) {
-	my $file=shift;
-	my $message=shift;
-	my $rcstoken=shift;
-	my $user=shift;
-	my $ipaddr=shift;
-	my $emailuser=shift;
-
-	if (defined $user) {
-		$message="web commit by $user".(length $message ? ": $message" : "");
-	}
-	elsif (defined $ipaddr) {
-		$message="web commit from $ipaddr".(length $message ? ": $message" : "");
+sub rcs_commit (@) {
+	my %params=@_;
+
+	my ($file, $message, $rcstoken)=
+		($params{file}, $params{message}, $params{token});
+
+	if (defined $params{session}) {
+		if (defined $params{session}->param("name")) {
+			$message="web commit by ".
+				$params{session}->param("name").
+				(length $message ? ": $message" : "");
+		}
+		elsif (defined $params{session}->remote_addr()) {
+			$message="web commit from ".
+				$params{session}->remote_addr().
+				(length $message ? ": $message" : "");
+		}
 	}
 
 	if (-d "$config{srcdir}/{arch}") {
@@ -140,10 +144,10 @@ sub rcs_commit ($$$;$$$) {
 	return undef # success
 }
 
-sub rcs_commit_staged ($$$;$) {
+sub rcs_commit_staged (@) {
 	# Commits all staged changes. Changes can be staged using rcs_add,
 	# rcs_remove, and rcs_rename.
-	my ($message, $user, $ipaddr, $emailuser)=@_;
+	my %params=@_;
 	
 	error("rcs_commit_staged not implemented for tla"); # TODO
 }
diff --git a/debian/changelog b/debian/changelog
index 2dfebd0b2..f7452a070 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,9 +1,8 @@
 ikiwiki (3.20100624) UNRELEASED; urgency=low
 
   * API: Add new optional field usershort to rcs_recentchanges.
-  * API: rcs_commit and rcs_commit_staged are passed a new parameter
-    that may contain the username component of the email address of
-    the user making the commit.
+  * API: rcs_commit and rcs_commit_staged are now passed named
+    parameters.
 
  -- Joey Hess   Wed, 23 Jun 2010 15:30:04 -0400
 
diff --git a/doc/plugins/write.mdwn b/doc/plugins/write.mdwn
index ab2934bf1..a2b954bd4 100644
--- a/doc/plugins/write.mdwn
+++ b/doc/plugins/write.mdwn
@@ -1051,18 +1051,20 @@ token, that will be passed into `rcs_commit` when committing. For example,
 it might return the current revision ID of the file, and use that
 information later when merging changes.
 
-#### `rcs_commit($$$;$$$)`
+#### `rcs_commit(@)`
+
+Passed named parameters: `file`, `message`, `token` (from `rcs_prepedit`),
+and `session` (optional).
 
-Passed a file, message, token (from `rcs_prepedit`), user, ip address,
-and optionally the username component of the committer's email address.
 Should try to commit the file. Returns `undef` on *success* and a version
 of the page with the rcs's conflict markers on failure.
 
-#### `rcs_commit_staged($$$;$)`
+#### `rcs_commit_staged(@)`
+
+Passed named parameters: `message`, and `session` (optional).
 
-Passed a message, user, ip address, and optionally the username component of
-the committer's email address. Should commit all staged changes.
-Returns undef on success, and an error message on failure.
+Should commit all staged changes. Returns undef on success, and an
+error message on failure.
 
 Changes can be staged by calls to `rcs_add`, `rcs_remove`, and
 `rcs_rename`.
diff --git a/ikiwiki-calendar.in b/ikiwiki-calendar.in
index 04352b970..60df99855 100755
--- a/ikiwiki-calendar.in
+++ b/ikiwiki-calendar.in
@@ -59,7 +59,7 @@ foreach my $y ($startyear..$endyear) {
 	}
 }
 
-IkiWiki::rcs_commit_staged(gettext("calendar update"), undef, undef)
+IkiWiki::rcs_commit_staged(message => gettext("calendar update"))
 	if $config{rcs};
 
 exec("ikiwiki", "-setup", $setup, "-refresh");
diff --git a/ikiwiki.spec b/ikiwiki.spec
index 9a4bbf6bc..9644fd396 100644
--- a/ikiwiki.spec
+++ b/ikiwiki.spec
@@ -1,5 +1,5 @@
 Name:           ikiwiki
-Version: 3.20100623
+Version: 3.20100624
 Release:        1%{?dist}
 Summary:        A wiki compiler
 
diff --git a/po/ikiwiki.pot b/po/ikiwiki.pot
index 437cdbdcc..e50fa0f68 100644
--- a/po/ikiwiki.pot
+++ b/po/ikiwiki.pot
@@ -8,7 +8,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2010-06-10 15:02-0400\n"
+"POT-Creation-Date: 2010-06-23 17:10-0400\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME \n"
 "Language-Team: LANGUAGE \n"
@@ -52,7 +52,7 @@ msgstr ""
 msgid "You are banned."
 msgstr ""
 
-#: ../IkiWiki/CGI.pm:426 ../IkiWiki/CGI.pm:427 ../IkiWiki.pm:1316
+#: ../IkiWiki/CGI.pm:426 ../IkiWiki/CGI.pm:427 ../IkiWiki.pm:1317
 msgid "Error"
 msgstr ""
 
@@ -163,19 +163,19 @@ msgstr ""
 msgid "prohibited by allowed_attachments"
 msgstr ""
 
-#: ../IkiWiki/Plugin/attachment.pm:141
+#: ../IkiWiki/Plugin/attachment.pm:144
 msgid "bad attachment filename"
 msgstr ""
 
-#: ../IkiWiki/Plugin/attachment.pm:183
+#: ../IkiWiki/Plugin/attachment.pm:188
 msgid "attachment upload"
 msgstr ""
 
-#: ../IkiWiki/Plugin/autoindex.pm:117
+#: ../IkiWiki/Plugin/autoindex.pm:120
 msgid "automatic index generation"
 msgstr ""
 
-#: ../IkiWiki/Plugin/blogspam.pm:109
+#: ../IkiWiki/Plugin/blogspam.pm:110
 msgid ""
 "Sorry, but that looks like spam to blogspam: "
@@ -248,19 +248,19 @@ msgstr ""
 msgid "Added a comment: %s"
 msgstr ""
 
-#: ../IkiWiki/Plugin/comments.pm:552 ../IkiWiki/Plugin/websetup.pm:272
+#: ../IkiWiki/Plugin/comments.pm:554 ../IkiWiki/Plugin/websetup.pm:268
 msgid "you are not logged in as an admin"
 msgstr ""
 
-#: ../IkiWiki/Plugin/comments.pm:603
+#: ../IkiWiki/Plugin/comments.pm:605
 msgid "Comment moderation"
 msgstr ""
 
-#: ../IkiWiki/Plugin/comments.pm:641
+#: ../IkiWiki/Plugin/comments.pm:645
 msgid "comment moderation"
 msgstr ""
 
-#: ../IkiWiki/Plugin/comments.pm:790
+#: ../IkiWiki/Plugin/comments.pm:802
 #, perl-format
 msgid "%i comment"
 msgid_plural "%i comments"
@@ -270,7 +270,7 @@ msgstr[1] ""
 #. translators: Here "Comment" is a verb;
 #. translators: the user clicks on it to
 #. translators: post a comment.
-#: ../IkiWiki/Plugin/comments.pm:800
+#: ../IkiWiki/Plugin/comments.pm:812
 msgid "Comment"
 msgstr ""
 
@@ -305,9 +305,9 @@ msgstr ""
 msgid "creating %s"
 msgstr ""
 
-#: ../IkiWiki/Plugin/editpage.pm:312 ../IkiWiki/Plugin/editpage.pm:334
-#: ../IkiWiki/Plugin/editpage.pm:345 ../IkiWiki/Plugin/editpage.pm:390
-#: ../IkiWiki/Plugin/editpage.pm:429
+#: ../IkiWiki/Plugin/editpage.pm:312 ../IkiWiki/Plugin/editpage.pm:332
+#: ../IkiWiki/Plugin/editpage.pm:343 ../IkiWiki/Plugin/editpage.pm:388
+#: ../IkiWiki/Plugin/editpage.pm:430
 #, perl-format
 msgid "editing %s"
 msgstr ""
@@ -320,12 +320,12 @@ msgstr ""
 msgid "match not specified"
 msgstr ""
 
-#: ../IkiWiki/Plugin/edittemplate.pm:64
+#: ../IkiWiki/Plugin/edittemplate.pm:70
 #, perl-format
 msgid "edittemplate %s registered for %s"
 msgstr ""
 
-#: ../IkiWiki/Plugin/edittemplate.pm:125 ../IkiWiki/Plugin/inline.pm:339
+#: ../IkiWiki/Plugin/edittemplate.pm:131 ../IkiWiki/Plugin/inline.pm:339
 #: ../IkiWiki/Plugin/template.pm:44
 msgid "failed to process template:"
 msgstr ""
@@ -356,18 +356,18 @@ msgstr ""
 msgid "%s is an attachment, not a page."
 msgstr ""
 
-#: ../IkiWiki/Plugin/git.pm:687 ../IkiWiki/Plugin/git.pm:705
-#: ../IkiWiki/Receive.pm:130
+#: ../IkiWiki/Plugin/git.pm:724 ../IkiWiki/Plugin/git.pm:742
+#: ../IkiWiki/Receive.pm:129
 #, perl-format
 msgid "you are not allowed to change %s"
 msgstr ""
 
-#: ../IkiWiki/Plugin/git.pm:727
+#: ../IkiWiki/Plugin/git.pm:764
 #, perl-format
 msgid "you cannot act on a file with mode %s"
 msgstr ""
 
-#: ../IkiWiki/Plugin/git.pm:731
+#: ../IkiWiki/Plugin/git.pm:768
 msgid "you are not allowed to change file modes"
 msgstr ""
 
@@ -513,7 +513,7 @@ msgstr ""
 msgid "more"
 msgstr ""
 
-#: ../IkiWiki/Plugin/openid.pm:58
+#: ../IkiWiki/Plugin/openid.pm:70
 #, perl-format
 msgid "failed to load openid module: "
 msgstr ""
@@ -610,7 +610,7 @@ msgstr ""
 msgid "rebuilding all pages to fix meta titles"
 msgstr ""
 
-#: ../IkiWiki/Plugin/po.pm:394 ../IkiWiki/Render.pm:769
+#: ../IkiWiki/Plugin/po.pm:394 ../IkiWiki/Render.pm:784
 #, perl-format
 msgid "building %s"
 msgstr ""
@@ -619,48 +619,48 @@ msgstr ""
 msgid "updated PO files"
 msgstr ""
 
-#: ../IkiWiki/Plugin/po.pm:456
+#: ../IkiWiki/Plugin/po.pm:455
 msgid ""
 "Can not remove a translation. If the master page is removed, however, its "
 "translations will be removed as well."
 msgstr ""
 
-#: ../IkiWiki/Plugin/po.pm:476
+#: ../IkiWiki/Plugin/po.pm:475
 msgid ""
 "Can not rename a translation. If the master page is renamed, however, its "
 "translations will be renamed as well."
 msgstr ""
 
-#: ../IkiWiki/Plugin/po.pm:876
+#: ../IkiWiki/Plugin/po.pm:875
 #, perl-format
 msgid "POT file (%s) does not exist"
 msgstr ""
 
-#: ../IkiWiki/Plugin/po.pm:890
+#: ../IkiWiki/Plugin/po.pm:889
 #, perl-format
 msgid "failed to copy underlay PO file to %s"
 msgstr ""
 
-#: ../IkiWiki/Plugin/po.pm:899
+#: ../IkiWiki/Plugin/po.pm:898
 #, perl-format
 msgid "failed to update %s"
 msgstr ""
 
-#: ../IkiWiki/Plugin/po.pm:905
+#: ../IkiWiki/Plugin/po.pm:904
 #, perl-format
 msgid "failed to copy the POT file to %s"
 msgstr ""
 
-#: ../IkiWiki/Plugin/po.pm:941
+#: ../IkiWiki/Plugin/po.pm:940
 msgid "N/A"
 msgstr ""
 
-#: ../IkiWiki/Plugin/po.pm:954
+#: ../IkiWiki/Plugin/po.pm:953
 #, perl-format
 msgid "failed to translate %s"
 msgstr ""
 
-#: ../IkiWiki/Plugin/po.pm:1038
+#: ../IkiWiki/Plugin/po.pm:1037
 msgid "removed obsolete PO files"
 msgstr ""
 
@@ -803,7 +803,7 @@ msgstr ""
 msgid "Please select the attachments to remove."
 msgstr ""
 
-#: ../IkiWiki/Plugin/remove.pm:216
+#: ../IkiWiki/Plugin/remove.pm:217
 msgid "removed"
 msgstr ""
 
@@ -853,7 +853,7 @@ msgstr ""
 msgid "rename %s to %s"
 msgstr ""
 
-#: ../IkiWiki/Plugin/rename.pm:576
+#: ../IkiWiki/Plugin/rename.pm:577
 #, perl-format
 msgid "update for rename of %s to %s"
 msgstr ""
@@ -988,26 +988,26 @@ msgstr ""
 msgid "enable %s?"
 msgstr ""
 
-#: ../IkiWiki/Plugin/websetup.pm:276
+#: ../IkiWiki/Plugin/websetup.pm:272
 msgid "setup file for this wiki is not known"
 msgstr ""
 
-#: ../IkiWiki/Plugin/websetup.pm:292
+#: ../IkiWiki/Plugin/websetup.pm:288
 msgid "main"
 msgstr ""
 
-#: ../IkiWiki/Plugin/websetup.pm:435
+#: ../IkiWiki/Plugin/websetup.pm:431
 msgid ""
 "The configuration changes shown below require a wiki rebuild to take effect."
 msgstr ""
 
-#: ../IkiWiki/Plugin/websetup.pm:439
+#: ../IkiWiki/Plugin/websetup.pm:435
 msgid ""
 "For the configuration changes shown below to fully take effect, you may need "
 "to rebuild the wiki."
 msgstr ""
 
-#: ../IkiWiki/Plugin/websetup.pm:476
+#: ../IkiWiki/Plugin/websetup.pm:472
 #, perl-format
 msgid "Error: %s exited nonzero (%s). Discarding setup changes."
 msgstr ""
@@ -1017,7 +1017,7 @@ msgstr ""
 msgid "cannot determine id of untrusted committer %s"
 msgstr ""
 
-#: ../IkiWiki/Receive.pm:86
+#: ../IkiWiki/Receive.pm:85
 #, perl-format
 msgid "bad file name %s"
 msgstr ""
@@ -1034,47 +1034,47 @@ msgid ""
 "allow this"
 msgstr ""
 
-#: ../IkiWiki/Render.pm:311
+#: ../IkiWiki/Render.pm:316
 #, perl-format
 msgid "skipping bad filename %s"
 msgstr ""
 
-#: ../IkiWiki/Render.pm:327
+#: ../IkiWiki/Render.pm:332
 #, perl-format
 msgid "%s has multiple possible source pages"
 msgstr ""
 
-#: ../IkiWiki/Render.pm:369
+#: ../IkiWiki/Render.pm:372
 #, perl-format
 msgid "querying %s for file creation and modification times.."
 msgstr ""
 
-#: ../IkiWiki/Render.pm:431
+#: ../IkiWiki/Render.pm:446
 #, perl-format
 msgid "removing obsolete %s"
 msgstr ""
 
-#: ../IkiWiki/Render.pm:505
+#: ../IkiWiki/Render.pm:520
 #, perl-format
 msgid "building %s, which links to %s"
 msgstr ""
 
-#: ../IkiWiki/Render.pm:514
+#: ../IkiWiki/Render.pm:529
 #, perl-format
 msgid "removing %s, no longer built by %s"
 msgstr ""
 
-#: ../IkiWiki/Render.pm:597 ../IkiWiki/Render.pm:679
+#: ../IkiWiki/Render.pm:612 ../IkiWiki/Render.pm:694
 #, perl-format
 msgid "building %s, which depends on %s"
 msgstr ""
 
-#: ../IkiWiki/Render.pm:692
+#: ../IkiWiki/Render.pm:707
 #, perl-format
 msgid "building %s, to update its backlinks"
 msgstr ""
 
-#: ../IkiWiki/Render.pm:821
+#: ../IkiWiki/Render.pm:836
 #, perl-format
 msgid "ikiwiki: cannot build %s"
 msgstr ""
@@ -1179,31 +1179,31 @@ msgstr ""
 msgid "cannot use multiple rcs plugins"
 msgstr ""
 
-#: ../IkiWiki.pm:606
+#: ../IkiWiki.pm:607
 #, perl-format
 msgid "failed to load external plugin needed for %s plugin: %s"
 msgstr ""
 
-#: ../IkiWiki.pm:1298
+#: ../IkiWiki.pm:1299
 #, perl-format
 msgid "preprocessing loop detected on %s at depth %i"
 msgstr ""
 
-#: ../IkiWiki.pm:1993
+#: ../IkiWiki.pm:1994
 msgid "yes"
 msgstr ""
 
-#: ../IkiWiki.pm:2070
+#: ../IkiWiki.pm:2071
 #, perl-format
 msgid "invalid sort type %s"
 msgstr ""
 
-#: ../IkiWiki.pm:2091
+#: ../IkiWiki.pm:2092
 #, perl-format
 msgid "unknown sort type %s"
 msgstr ""
 
-#: ../IkiWiki.pm:2227
+#: ../IkiWiki.pm:2228
 #, perl-format
 msgid "cannot match pages: %s"
 msgstr ""
diff --git a/t/bazaar.t b/t/bazaar.t
index 0bdd883d5..3e54ec4dc 100755
--- a/t/bazaar.t
+++ b/t/bazaar.t
@@ -24,11 +24,19 @@ IkiWiki::checkconfig();
 
 system "bzr init $config{srcdir}";
 
+use CGI::Session;
+my $session=CGI::Session->new;
+$session->param("name", "Joe User");
+
 # Web commit
 my $test1 = readfile("t/test1.mdwn");
 writefile('test1.mdwn', $config{srcdir}, $test1);
 IkiWiki::rcs_add("test1.mdwn");
-IkiWiki::rcs_commit("test1.mdwn", "Added the first page", "moo", "Joe User");
+IkiWiki::rcs_commit(
+	file => "test1.mdwn",
+	message => "Added the first page",
+	token => "moo",
+	session => $session);
 
 my @changes;
 @changes = IkiWiki::rcs_recentchanges(3);
@@ -66,7 +74,10 @@ ok($mtime >= time() - 20);
 writefile('test3.mdwn', $config{srcdir}, $test1);
 IkiWiki::rcs_add("test3.mdwn");
 IkiWiki::rcs_rename("test3.mdwn", "test4.mdwn");
-IkiWiki::rcs_commit_staged("Added the 4th page", "moo", "Joe User");
+IkiWiki::rcs_commit_staged(
+	message => "Added the 4th page",
+	session => $session,
+);
 
 @changes = IkiWiki::rcs_recentchanges(4);
 
@@ -75,7 +86,10 @@ is($changes[0]{pages}[0]{"page"}, "test4");
 
 ok(mkdir($config{srcdir}."/newdir"));
 IkiWiki::rcs_rename("test4.mdwn", "newdir/test5.mdwn");
-IkiWiki::rcs_commit_staged("Added the 5th page", "moo", "Joe User");
+IkiWiki::rcs_commit_staged(
+	message => "Added the 5th page",
+	session => $session,
+);
 
 @changes = IkiWiki::rcs_recentchanges(4);
 
@@ -83,6 +97,9 @@ is($#changes, 3);
 is($changes[0]{pages}[0]{"page"}, "newdir/test5");
 
 IkiWiki::rcs_remove("newdir/test5.mdwn");
-IkiWiki::rcs_commit_staged("Remove the 5th page", "moo", "Joe User");
+IkiWiki::rcs_commit_staged(
+	message => "Remove the 5th page",
+	session => $session,
+);
 
 system "rm -rf $dir";
diff --git a/t/cvs.t b/t/cvs.t
index 2808973be..96359ab6e 100755
--- a/t/cvs.t
+++ b/t/cvs.t
@@ -46,7 +46,11 @@ system "cvs -d $cvsrepo co -d $config{srcdir} ikiwiki >/dev/null";
 my $test1 = readfile("t/test1.mdwn");
 writefile('test1.mdwn', $config{srcdir}, $test1);
 IkiWiki::rcs_add("test1.mdwn");
-IkiWiki::rcs_commit("test1.mdwn", "Added the first page", "moo");
+IkiWiki::rcs_commit(
+	files => "test1.mdwn",
+	message => "Added the first page",
+	token => "moo"
+);
 
 my @changes;
 @changes = IkiWiki::rcs_recentchanges(3);
diff --git a/t/git.t b/t/git.t
index f1c24b359..ee778ebf0 100755
--- a/t/git.t
+++ b/t/git.t
@@ -38,7 +38,11 @@ is($changes[0]{pages}[0]{"page"}, ".gitignore");
 my $test1 = readfile("t/test1.mdwn");
 writefile('test1.mdwn', $config{srcdir}, $test1);
 IkiWiki::rcs_add("test1.mdwn");
-IkiWiki::rcs_commit("test1.mdwn", "Added the first page", "moo");
+IkiWiki::rcs_commit(
+	file => "test1.mdwn",
+	message => "Added the first page",
+	token => "moo",
+);
 
 @changes = IkiWiki::rcs_recentchanges(3);
 
@@ -68,7 +72,7 @@ is($changes[1]{pages}[0]{"page"}, "test1");
 writefile('test3.mdwn', $config{srcdir}, $test1);
 IkiWiki::rcs_add("test3.mdwn");
 IkiWiki::rcs_rename("test3.mdwn", "test4.mdwn");
-IkiWiki::rcs_commit_staged("Added the 4th page", "moo", "Joe User");
+IkiWiki::rcs_commit_staged(message => "Added the 4th page");
 
 @changes = IkiWiki::rcs_recentchanges(4);
 
@@ -77,7 +81,7 @@ is($changes[0]{pages}[0]{"page"}, "test4");
 
 ok(mkdir($config{srcdir}."/newdir"));
 IkiWiki::rcs_rename("test4.mdwn", "newdir/test5.mdwn");
-IkiWiki::rcs_commit_staged("Added the 5th page", "moo", "Joe User");
+IkiWiki::rcs_commit_staged(message => "Added the 5th page");
 
 @changes = IkiWiki::rcs_recentchanges(4);
 
@@ -85,6 +89,6 @@ is($#changes, 3);
 is($changes[0]{pages}[0]{"page"}, "newdir/test5");
 
 IkiWiki::rcs_remove("newdir/test5.mdwn");
-IkiWiki::rcs_commit_staged("Remove the 5th page", "moo", "Joe User");
+IkiWiki::rcs_commit_staged(message => "Remove the 5th page");
 
 system "rm -rf $dir";
diff --git a/t/mercurial.t b/t/mercurial.t
index 954b17526..b64ea8e56 100755
--- a/t/mercurial.t
+++ b/t/mercurial.t
@@ -22,13 +22,22 @@ $config{srcdir} = "$dir/repo";
 IkiWiki::loadplugins();
 IkiWiki::checkconfig();
 
+use CGI::Session;
+my $session=CGI::Session->new;
+$session->param("name", "Joe User");
+
 system "hg init $config{srcdir}";
 
 # Web commit
 my $test1 = readfile("t/test1.mdwn");
 writefile('test1.mdwn', $config{srcdir}, $test1);
 IkiWiki::rcs_add("test1.mdwn");
-IkiWiki::rcs_commit("test1.mdwn", "Added the first page", "moo", "Joe User");
+IkiWiki::rcs_commit(
+	file => "test1.mdwn",
+	message => "Added the first page",
+	token => "moo",
+	session => $session,
+);
 
 my @changes;
 @changes = IkiWiki::rcs_recentchanges(3);
diff --git a/t/svn.t b/t/svn.t
index 5223b4409..82b71b5fc 100755
--- a/t/svn.t
+++ b/t/svn.t
@@ -36,7 +36,11 @@ system "svn co file://$svnrepo/trunk $config{srcdir} >/dev/null";
 my $test1 = readfile("t/test1.mdwn");
 writefile('test1.mdwn', $config{srcdir}, $test1);
 IkiWiki::rcs_add("test1.mdwn");
-IkiWiki::rcs_commit("test1.mdwn", "Added the first page", "moo");
+IkiWiki::rcs_commit(
+	file => "test1.mdwn",
+	message => "Added the first page",
+	token => "moo",
+);
 
 my @changes;
 @changes = IkiWiki::rcs_recentchanges(3);
-- 
cgit v1.2.3