+ eval q{use CGI::FormBuilder};
+ my $form = CGI::FormBuilder->new(
+ fields => [qw(do rcsinfo from page content comments)],
+ header => 1,
+ method => 'POST',
+ validate => {
+ content => '/.+/',
+ },
+ required => [qw{content}],
+ javascript => 0,
+ params => $q,
+ action => $q->request_uri,
+ table => 0,
+ template => "$config{templatedir}/editpage.tmpl"
+ );
+ my @buttons=("Save Page", "Preview", "Cancel");
+
+ my ($page)=$form->param('page')=~/$config{wiki_file_regexp}/;
+ if (! defined $page || ! length $page || $page ne $q->param('page') ||
+ $page=~/$config{wiki_file_prune_regexp}/ || $page=~/^\//) {
+ error("bad page name");
+ }
+ $page=lc($page);
+
+ my $file=$page.$config{default_pageext};
+ my $newfile=1;
+ if (exists $pagesources{lc($page)}) {
+ $file=$pagesources{lc($page)};
+ $newfile=0;
+ }
+
+ $form->field(name => "do", type => 'hidden');
+ $form->field(name => "from", type => 'hidden');
+ $form->field(name => "rcsinfo", type => 'hidden');
+ $form->field(name => "page", value => "$page", force => 1);
+ $form->field(name => "comments", type => "text", size => 80);
+ $form->field(name => "content", type => "textarea", rows => 20,
+ cols => 80);
+ $form->tmpl_param("can_commit", $config{svn});
+ $form->tmpl_param("indexlink", indexlink());
+ $form->tmpl_param("helponformattinglink",
+ htmllink("", "HelpOnFormatting", 1));
+ if (! $form->submitted) {
+ $form->field(name => "rcsinfo", value => rcs_prepedit($file),
+ force => 1);
+ }
+
+ if ($form->submitted eq "Cancel") {
+ print $q->redirect("$config{url}/".htmlpage($page));
+ return;
+ }
+ elsif ($form->submitted eq "Preview") {
+ $form->tmpl_param("page_preview",
+ htmlize($config{default_pageext},
+ linkify($form->field('content'), $page)));
+ }
+ else {
+ $form->tmpl_param("page_preview", "");
+ }
+ $form->tmpl_param("page_conflict", "");
+
+ if (! $form->submitted || $form->submitted eq "Preview" ||
+ ! $form->validate) {
+ if ($form->field("do") eq "create") {
+ if (exists $pagesources{lc($page)}) {
+ # hmm, someone else made the page in the
+ # meantime?
+ print $q->redirect("$config{url}/".htmlpage($page));
+ return;
+ }
+
+ my @page_locs;
+ my $best_loc;
+ my ($from)=$form->param('from')=~/$config{wiki_file_regexp}/;
+ if (! defined $from || ! length $from ||
+ $from ne $form->param('from') ||
+ $from=~/$config{wiki_file_prune_regexp}/ || $from=~/^\//) {
+ @page_locs=$best_loc=$page;
+ }
+ else {
+ my $dir=$from."/";
+ $dir=~s![^/]+/$!!;
+ push @page_locs, $dir.$page;
+ push @page_locs, "$from/$page";
+ $best_loc="$from/$page";
+ while (length $dir) {
+ $dir=~s![^/]+/$!!;
+ push @page_locs, $dir.$page;
+ }
+
+ @page_locs = grep { ! exists
+ $pagesources{lc($_)} } @page_locs;
+ }
+
+ $form->tmpl_param("page_select", 1);
+ $form->field(name => "page", type => 'select',
+ options => \@page_locs, value => $best_loc);
+ $form->title("creating $page");
+ }
+ elsif ($form->field("do") eq "edit") {
+ if (! defined $form->field('content') ||
+ ! length $form->field('content')) {
+ my $content="";
+ if (exists $pagesources{lc($page)}) {
+ $content=readfile("$config{srcdir}/$pagesources{lc($page)}");
+ $content=~s/\n/\r\n/g;
+ }
+ $form->field(name => "content", value => $content,
+ force => 1);
+ }
+ $form->tmpl_param("page_select", 0);
+ $form->field(name => "page", type => 'hidden');
+ $form->title("editing $page");
+ }
+
+ print $form->render(submit => \@buttons);
+ }
+ else {
+ # save page
+ my $content=$form->field('content');
+ $content=~s/\r\n/\n/g;
+ $content=~s/\r/\n/g;
+ writefile("$config{srcdir}/$file", $content);
+
+ my $message="web commit ";
+ if ($session->param("name")) {
+ $message.="by ".$session->param("name");
+ }
+ else {
+ $message.="from $ENV{REMOTE_ADDR}";
+ }
+ if (defined $form->field('comments') &&
+ length $form->field('comments')) {
+ $message.=": ".$form->field('comments');
+ }
+
+ if ($config{svn}) {
+ if ($newfile) {
+ rcs_add($file);
+ }
+ # prevent deadlock with post-commit hook
+ unlockwiki();
+ # presumably the commit will trigger an update
+ # of the wiki
+ my $conflict=rcs_commit($file, $message,
+ $form->field("rcsinfo"));
+
+ if (defined $conflict) {
+ $form->field(name => "rcsinfo", value => rcs_prepedit($file),
+ force => 1);
+ $form->tmpl_param("page_conflict", 1);
+ $form->field("content", value => $conflict, force => 1);
+ $form->field("do", "edit)");
+ $form->tmpl_param("page_select", 0);
+ $form->field(name => "page", type => 'hidden');
+ $form->title("editing $page");
+ print $form->render(submit => \@buttons);
+ return;
+ }
+ }
+ else {
+ loadindex();
+ refresh();
+ saveindex();
+ }
+
+ # The trailing question mark tries to avoid broken
+ # caches and get the most recent version of the page.
+ print $q->redirect("$config{url}/".htmlpage($page)."?updated");
+ }
+} #}}}
+
+sub cgi () { #{{{
+ eval q{use CGI};
+ eval q{use CGI::Session};
+
+ my $q=CGI->new;
+
+ my $do=$q->param('do');
+ if (! defined $do || ! length $do) {
+ error("\"do\" parameter missing");
+ }
+
+ # This does not need a session.
+ if ($do eq 'recentchanges') {
+ cgi_recentchanges($q);
+ return;
+ }
+
+ CGI::Session->name("ikiwiki_session");
+
+ my $oldmask=umask(077);
+ my $session = CGI::Session->new("driver:db_file", $q,
+ { FileName => "$config{srcdir}/.ikiwiki/sessions.db" });
+ umask($oldmask);
+
+ # Everything below this point needs the user to be signed in.
+ if ((! $config{anonok} && ! defined $session->param("name") ||
+ ! userinfo_get($session->param("name"), "regdate")) || $do eq 'signin') {
+ cgi_signin($q, $session);
+
+ # Force session flush with safe umask.
+ my $oldmask=umask(077);
+ $session->flush;
+ umask($oldmask);
+
+ return;
+ }
+
+ if ($do eq 'create' || $do eq 'edit') {
+ cgi_editpage($q, $session);
+ }
+ else {
+ error("unknown do parameter");
+ }
+} #}}}
+
+sub setup () { # {{{
+ my $setup=possibly_foolish_untaint($config{setup});
+ delete $config{setup};
+ open (IN, $setup) || error("read $setup: $!\n");
+ local $/=undef;
+ my $code=<IN>;
+ ($code)=$code=~/(.*)/s;
+ close IN;
+
+ eval $code;
+ error($@) if $@;
+ exit;
+} #}}}
+
+# main {{{
+lockwiki();
+setup() if $config{setup};
+if ($config{wrapper}) {
+ gen_wrapper(%config);
+ exit;
+}