#!/usr/bin/perl ########################################################################### # twiki_xmlrpc.cgi: # Wiki XML-RPC API for TWiki # # Maintained by l.m.orchard http://www.decafbad.com # See: http://www.decafbad.com/twiki/bin/view/Main/XmlRpcToWiki # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details, published at # http://www.gnu.org/copyleft/gpl.html ########################################################################### use strict; use Data::Dumper qw(Dumper); use lib ( '/home/deusx/lib/perl' ); use lib ( '.' ); use lib ( '../lib' ); use TWiki; our $twiki_web = 'Main'; $SOAP::Constants::DO_NOT_USE_XML_PARSER = 1; use XMLRPC::Transport::HTTP; my $server = XMLRPC::Transport::HTTP::CGI->new; $server->dispatch_to('wiki'); $server->handle; ########################################################################### ### wiki methods ########################################################################### package wiki; use Date::Parse; ########################################################################### ### _twiki_meta_to_pageinfo: ### Extract wiki API page info from TWiki metadata ########################################################################### sub _twiki_meta_to_pageinfo { my ($pagename, $meta) = @_; ### Dig the topic info out of the TWiki metadata my $topicinfo = $meta->{TOPICINFO}->[0]; my $version; (undef, $version) = split(/\./, $topicinfo->{version}); my ($sec, $min, $hr, $dd, $mm, $yy, $wd, $yd, $isdst) = localtime($topicinfo->{date}); $yy += 1900; $mm++; my $last_modified = sprintf('%04d%02d%02dT%02d:%02d:%02d', $yy,$mm,$dd,$hr,$min,$sec); my $pageinfo = { name => $pagename, lastModified => SOAP::Data->type(dateTime => $last_modified), author => $topicinfo->{author}, version => $version }; return $pageinfo; } ########################################################################### ### Wiki XML-RPC API Methods ########################################################################### sub filterData { my ($pkg, $data, $content_type, $params) = @_; ### Hack to handle Mac text. $data =~ s/\r/\n/g; $data =~ s/\n\n/\n/g; &TWiki::initialize("/Main/FilterData", "", "FilterData", "", undef ); $data = &TWiki::decodeSpecialChars( $data ); $data =~ s/ {3}/\t/go; $data = &TWiki::handleCommonTags( $data, "FilterData", $twiki_web ); $data = &TWiki::getRenderedVersion( $data, $twiki_web ); $data =~ s/\<\;/\/g; return { data => SOAP::Data->type(base64 => $data), contentType => "text/html" } } ########################################################################### # * array getRecentChanges ( Date timestamp ): # Get list of changed pages since timestamp, which should be in # UTC. The result is an array, where each element is a struct: # * name (string) : # Name of the page. The name is UTF-8 with URL encoding # to make it ASCII. # * lastModified (date) : # Date of last modification, in UTC. # * author (string) : # Name of the author (if available). Again, name is # UTF-8 with URL encoding. # * version (int) : # Current version. ########################################################################### sub getRecentChanges { my ($pkg, $date) = @_; my $time = str2time($date); my @changes = (); opendir(DIR, $TWiki::dataDir."/".$twiki_web); my @pages = readdir(DIR); closedir(DIR); ### Filter for *.txt filenames and strip the extension @pages = map { /(.*)\.txt/; $_ = $1 } grep { (stat($TWiki::dataDir."/".$twiki_web."/".$_))[9] > $time } grep { /.*\.txt$/ } @pages; foreach my $pagename (@pages) { my ($meta, $pagetext) = &TWiki::Store::readTopic ($twiki_web, $pagename); push @changes, _twiki_meta_to_pageinfo($pagename, $meta); } return \@changes; } ########################################################################### # * int getRPCVersionSupported(): # Returns 1 with this version of the Wiki API. ########################################################################### sub getRPCVersionSupported { return 1; } ########################################################################### # * base64 getPage( String pagename ): # Get the raw Wiki text of page, latest version. Page name must be # UTF-8, with URL encoding. Returned value is a binary object, # with UTF-8 encoded page data. # # * base64 getPage( String pagename, int version ): # Get the raw Wiki text of page. Returns UTF-8, expects UTF-8 with # URL encoding. ########################################################################### sub getPage { my ($pkg, $pagename) = @_; my ($meta, $pagetext) = &TWiki::Store::readTopic($twiki_web, $pagename); return SOAP::Data->type(base64 => $pagetext); } ########################################################################### # * base64 getPageVersion( String pagename, int version ): # Get the raw Wiki text of page. Returns UTF-8, expects UTF-8 with # URL encoding. ########################################################################### sub getPageVersion { my ($pkg, $pagename, $version) = @_; my ($meta, $pagetext) = &TWiki::Store::readTopicVersion ($twiki_web, $pagename, "1.$version"); return SOAP::Data->type(base64 => $pagetext); } ########################################################################### # * base64 getPageHTML( String pagename ): # Return page in rendered HTML. Returns UTF-8, expects UTF-8 with # URL encoding. ########################################################################### ### HACK: To avoid trying to re-implement or cut & paste the complexity ### of TWiki's view script, I'll try just calling the script directly ### and then doctor up the results. This might not be the best approach. sub getPageHTML { my ($pkg, $pagename, $version) = @_; my $pagetext = ''; my @lines; return undef if (! &TWiki::Store::topicExists( $twiki_web, $pagename )); $version =~ /(\d+)/; my $rev = $1; @lines = `./view topic=$pagename`; ### Lop off the Content-type header (are there more headers? ### ie. cookies? status?) $pagetext = join("", @lines[2..scalar(@lines)]); return SOAP::Data->type(base64 => $pagetext); } ########################################################################### # * base64 getPageHTMLVersion( String pagename, int version ): # Return page in rendered HTML, UTF-8. ########################################################################### ### HACK: To avoid trying to re-implement or cut & paste the complexity ### of TWiki's view script, I'll try just calling the script directly ### and then doctor up the results. This might not be the best approach. sub getPageHTMLVersion { my ($pkg, $pagename, $version) = @_; my $pagetext = ''; my @lines; return undef if (! &TWiki::Store::topicExists( $twiki_web, $pagename )); $version =~ /(\d+)/; my $rev = $1; @lines = `./view topic=$pagename rev=$rev`; ### Lop off the Content-type header (are there more headers? ### ie. cookies? status?) $pagetext = join("", @lines[2..scalar(@lines)]); return SOAP::Data->type(base64 => $pagetext); } ########################################################################### # * array getAllPages(): # Returns a list of all pages. The result is an array of strings, # again UTF-8 in URL encoding. ########################################################################### sub getAllPages { opendir(DIR, $TWiki::dataDir."/".$twiki_web); my @pages = readdir(DIR); closedir(DIR); ### Filter for *.txt filenames and strip the extension @pages = map { /(.*)\.txt/; $_ = $1 } grep { /.*\.txt$/ } @pages; return \@pages; } ########################################################################### # * struct getPageInfo( string pagename ) : # returns a struct with elements # * name (string): the canonical page name, URL-encoded UTF-8. # * lastModified (date): Last modification date, UTC. # * author (string): author name, URL-encoded UTF-8. # * version (int): current version ########################################################################### sub getPageInfo { my ($pkg, $pagename) = @_; my ( $meta, $pagetext ) = &TWiki::Store::readTopic ( $twiki_web, $pagename ); return _twiki_meta_to_pageinfo($pagename, $meta); } ########################################################################### # * struct getPageInfoVersion( string pagename, int version ) : # returns a struct just like plain getPageInfo(), but this time # for a specific version. ########################################################################### sub getPageInfoVersion { my ($pkg, $pagename, $version) = @_; my ($meta, $pagetext) = &TWiki::Store::readTopicVersion ( $twiki_web, $pagename, "1.$version" ); return _twiki_meta_to_pageinfo($pagename, $meta); } ########################################################################### ### * boolean wiki.putPage( String pagename, base64 text ): Set the ### text of a page, returning true on success ########################################################################### sub putPage { my ($pkg, $pagename, $pagetext) = @_; my $text = $pagetext; $text = &TWiki::decodeSpecialChars( $text ); $text =~ s/ {3}/\t/go; my ($meta, $tmp) = &TWiki::Store::readTopic( $twiki_web, $pagename ); my $error = &TWiki::Store::saveTopic ($twiki_web, $pagename, $text, $meta, "", undef, 1); return SOAP::Data->type(boolean => 1); }