--- bxr\blosxom-xmlrpc.cgi Thu Mar 10 13:27:52 2005 +++ blosxom-xmlrpc.cgi Tue Oct 30 11:38:58 2007 @@ -99,11 +99,16 @@ use strict; use File::Find; use File::stat; +use File::Copy; use POSIX qw(strftime); use XMLRPC::Transport::HTTP; use CGI::Carp qw(fatalsToBrowser); use CGI; +if ( -e "config.cgi" ) { + package blosxom; + require 'config.cgi'; +} # Remove trailing / from url and datadir $datadir =~ s!/$!!; $url =~ s!/$!!; @@ -140,6 +144,12 @@ sub getPostIdFromFilename { debug( 4, "BXR.getPostIdFromFilename", @_ ); my $filename = shift @_; + if ((! -e $filename) and (-e $filename.".post")) { + open(FILE, "<$filename.post"); + $filename = "$datadir"; + $filename .= ; + close(FILE); + } $filename =~ s!$datadir!!; return $filename; } @@ -155,6 +165,12 @@ $postid = "$datadir/$postid"; } } + if ((! -e $postid) and (-e $postid.".post")) { + open(FILE, "<$postid.post"); + $postid = "$datadir"; + $postid .= ; + close(FILE); + } debug( 4, "BXR.getFilenameFromPostId exit", $postid ); return $postid; } @@ -174,7 +190,8 @@ sub getIsoTime { debug( 4, "BXR.getIsoTime", @_ ); my $time = shift @_ || time; - my $isoTime = strftime( "%Y-%m-%dT%TZ", gmtime($time) ); + #my $isoTime = strftime( "%Y-%m-%dT%TZ", gmtime($time) ); + my $isoTime = strftime( "%Y-%m-%dT%H:%M:%S", gmtime($time) ); debug( 4, "BXR.getIsoTime", $isoTime ); return $isoTime; } @@ -191,6 +208,43 @@ return $time; } +sub getCategoryIdFromName { + my $catname = shift; + my $realname = ''; + my $sep = $blosxom::categories_sep; + my @path = split(/::/, $catname); + my %realnames = reverse %blosxom::categories_aliases; + + foreach (@path) { + next if !$_; + $_ = $realnames{$_} if $realnames{$_}; + $realname .= qq!/$_!; + } + + $realname =~ s!^/!!; + $realname = "/" if (!$realname); + return $realname; +} + +sub getCategoryNameFromId { + my $catid = shift; + my $alias = ''; + my @path = split(/\//, $catid); + my %aliases = %blosxom::categories_aliases; + my $sep = $blosxom::categories_sep; + + foreach (@path) { + next if !$_; + $_ = $aliases{$_} if $aliases{$_}; + $alias .= qq!$sep$_!; + } + + $alias =~ s!^$sep!!; + $alias = "n/a" if (!$alias); + return $alias; +} + + # Debug Levels: # 1 = API Module Calls # 2 = Blosxom Module Calls @@ -200,7 +254,7 @@ my $messDebugLevel = shift @_; if ( $messDebugLevel <= $debugLevel ) { my $method = shift @_; - open FILE, ">>$datadir/bxrlog.txt" + open FILE, ">>/cgi-bin/bxrlog.log" or print STDERR "Can't open error log\n"; print FILE "$method:"; foreach (@_) { @@ -213,8 +267,16 @@ my $path_info = $ENV{'PATH_INFO'} || ''; -if ( $path_info =~ /rpc2/i ) { - XMLRPC::Transport::HTTP::CGI->dispatch_to( 'metaWeblog', 'blogger' ) +if ( $path_info =~ /RPC2/i ) { + my $request_method = $ENV{'REQUEST_METHOD'} || ''; + if ($ENV{"CONTENT_TYPE"} !~ /utf/) { + if ($ENV{"HTTP_USER_AGENT"} =~ /Windows Live Writer 1.0/) { + my $PostData; + read (STDIN, $PostData, 3); + } + } + + XMLRPC::Transport::HTTP::CGI->dispatch_to( 'metaWeblog', 'blogger', 'mt' ) ->handle; } elsif ( $path_info =~ /atom/i ) { # Do ATOM stuff here @@ -331,9 +393,9 @@ sub SetHtmlBegin { # set var with following html/css code (note: \n and extra white space will be included, don't use tabs!). # needs $PageTile, $Meta (optional) on entry, Printed as html header, mainly a color malleable style sheet. - $_[0] = qq( + $_[0] = qq( - + $PageTitle $Meta @@ -407,7 +469,7 @@ sub Error { # report fatal errors from Render (or other) and exit. - print qq(Content-Type: text/html; charset=ISO-8859-1) + print qq(Content-Type: text/html; charset=utf-8) if (shift); #print cgi header $PageTitle = 'Fatal Error'; $BlogText = qq($_[0] $_[1]); @@ -506,7 +568,7 @@ ? $cookie{'password'} = $c->param('password') : 0; unless ( BXR::auth( $cookie{'username'}, $cookie{'password'} ) ) { - print $c->header(); + print $c->header(-charset=>'utf-8'); $PageTitle = "Please Enter Password"; unless ( RenderExternalFlavour($BXR::weblogin) ) { SetHtmlVars(); @@ -528,7 +590,7 @@ -value => \%cookie, -expires => $expire ); - print $c->header( -cookie => $cookie ); + print $c->header( -cookie => $cookie, -charset => 'utf-8' ); return 1; } } @@ -1160,7 +1222,9 @@ my %struct; $struct{'postid'} = $filename; $struct{'dateCreated'} = File::stat::stat($filename)->mtime; - $struct{'title'} = shift @post; + my $title = shift @post; + $title =~ s!\x0D|\x0A!!g; + $struct{'title'} = $title; foreach (@post) { $struct{'description'} .= $_; } @@ -1175,6 +1239,18 @@ } } +sub decodeHtml { + my $str = shift @_; + $str =~ s/&#([0-9]+);/chr($1)/ge; + $str =~ s/&#[xX]([0-9A-Fa-f]+);/chr(hex $1)/ge; + $str =~ s!\x0D|\x0A!
\n!g; + $str =~ s/\>/>/g; + $str =~ s/\</$filename" or die "Can't Open File $filename: $!"; - print POST "$struct->{'title'}\n"; - print POST "$struct->{'description'}\n"; + #print POST $struct->{'title'}."\n"; + #print POST $struct->{'description'}."\n"; + #print POST HTML::Entities::decode_entities($struct->{'title'})."\n"; + #print POST HTML::Entities::decode_entities($struct->{'description'})."\n"; + print POST decodeHtml($struct->{'title'})."\n"; + print POST decodeHtml($struct->{'description'})."\n"; close POST; my $files = chmod $BXR::file_permission, $filename; } @@ -1286,10 +1366,17 @@ $filename =~ s/\s+/_/g; $filename =~ s/_+$//; + my $filedir = $filename; + if ($filedir =~ s!(.*)/([^/]*)!$1!) { + BXR::debug( 1, "blosxom.newMediaObject", $filedir ); + mkdir( $BXR::mediaObjectDir . '/' . $filedir, 0755 ); + } + $url = "$url/$filename"; $filename = "$start/$filename"; open FILE, ">$filename"; + binmode FILE; print FILE "$struct->{'bits'}"; close FILE; @@ -1319,10 +1406,18 @@ } else { my $date = BXR::getIsoTime( $post->{'dateCreated'} ); + $post->{'title'} = SOAP::Data->type(string => $post->{'title'}); + $post->{'description'} = SOAP::Data->type(string => $post->{'description'}); $post->{'dateCreated'} = SOAP::Data->type( dateTime => "$date" ); $post->{'postid'} = BXR::getPostIdFromFilename( $post->{'postid'} ); ( $post->{'link'} = $BXR::url . $post->{'postid'} ) =~ s/$BXR::file_extension/html/; + my @cats; + my $catList = $post->{'categories'}; + foreach ( @$catList ) { + push @cats, SOAP::Data->type(string => BXR::getCategoryNameFromId($_)); + } + $post->{'categories'} = \@cats; $post->{'permaLink'} = $post->{'link'}; return $post; } @@ -1349,6 +1444,7 @@ return \@retList; } +sub getCategoryList { return getCategories(@_) } sub getCategories { BXR::debug( 1, "metaWeblog.getCategories", @_ ); shift if UNIVERSAL::isa( $_[0] => __PACKAGE__ ); @@ -1361,10 +1457,12 @@ my $cats = blosxom::getCategories(); my %retList; foreach ( keys %{$cats} ) { - $_ = BXR::getCategoryFromFilename($_); $retList{'struct'}{$_}{'description'} = "No Description"; - $retList{'struct'}{$_}{'rssUrl'} = "$BXR::url/$_/index.rss"; $retList{'struct'}{$_}{'htmlUrl'} = "$BXR::url/$_"; + $retList{'struct'}{$_}{'rssUrl'} = "$BXR::url/$_/index.rss"; + #$retList{'struct'}{$_}{'title'} = BXR::getCategoryFromFilename($_); + $retList{'struct'}{$_}{'title'} = $_; + $retList{'struct'}{$_}{'categoryid'} = $_; } return %retList; } @@ -1400,10 +1498,10 @@ my $rc = BXR::getPostIdFromFilename( blosxom::editPost($struct) ); if ( $rc == 1 ) { - return "true"; + return SOAP::Data->type(boolean => "true"); } else { - return "false"; + return SOAP::Data->type(boolean => "false"); } } @@ -1456,7 +1554,7 @@ BXR::auth( $username, $password ); my %struct = ( - userid => 1, + userid => $BXR::username, firstname => $BXR::firstName, lastname => $BXR::lastName, nickname => $BXR::nickname, @@ -1570,6 +1668,120 @@ my $filename = BXR::getFilenameFromPostId($postid); my $rc = blosxom::deletePost($filename); +} + +package mt; +sub getPostCategories { + BXR::debug( 1, "mt.getPostCategories", @_ ); + shift if UNIVERSAL::isa( $_[0] => __PACKAGE__ ); + my $postid = shift; + my $username = shift; + my $password = shift; + my $category = BXR::getCategoryFromFilename($postid); + my @return; + push @return, { + categoryName => $category, + categoryId => $category, + isPrimary => SOAP::Data->type(boolean => "true") + }; + return \@return; +} +sub setPostCategories { + BXR::debug( 1, "mt.setPostCategories", @_ ); + shift if UNIVERSAL::isa( $_[0] => __PACKAGE__ ); + my $postid = shift; + my $username = shift; + my $password = shift; + my $category = shift @_; + my $filename = BXR::getFilenameFromPostId($postid); + BXR::debug( 1, "sizeof category", $#$category); + if ($#$category >= 0) { + my $fname = $filename; + $fname =~ s!.*/([^/]*)!$1!; + my $movepath = BXR::getFilenameFromPostId(@$category[0]->{categoryId}."/".$fname); + File::Copy::move $filename, $movepath; + open(FILE, ">$filename.post"); + print FILE @$category[0]->{categoryId}."/".$fname; + close(FILE); + } + return SOAP::Data->type(boolean => "true"); +} +sub publishPost { + BXR::debug( 1, "mt.publishPost", @_ ); + shift if UNIVERSAL::isa( $_[0] => __PACKAGE__ ); + my $postid = shift; + my $username = shift; + my $password = shift; + my $filename = BXR::getFilenameFromPostId($postid); + if ( $filename !~ /$BXR::file_extension$/ ) { + $_ = $filename; + my ($fname, $ext) = /(.*)\.([^\.]+)/; + my $movepath = $fname.".".$BXR::file_extension; + File::Copy::move $filename, $movepath; + } + return SOAP::Data->type(boolean => "true"); +} + +sub getCategoryList { + BXR::debug( 1, "mt.getCategoryList", @_ ); + shift if UNIVERSAL::isa( $_[0] => __PACKAGE__ ); + my $blogid = shift; + my $username = shift; + my $password = shift; + + BXR::auth( $username, $password ); + + my $cats = blosxom::getCategories(); + my @return; + foreach ( keys %{$cats} ) { + my $cid = BXR::getCategoryFromFilename($_); + my $cnm = BXR::getCategoryNameFromId($cid); + $cnm = $cid if ($ENV{"HTTP_USER_AGENT"} =~ /Windows Live Writer 1.0/); + push @return, { + categoryName => SOAP::Data->type(string => $cnm), + categoryId => $cid + }; + } + @return = sort {$a->{categoryId} cmp $b->{categoryId}} @return; + return \@return; +} + +sub getRecentPostTitles { + BXR::debug( 1, "mt.getRecentPostTitles", @_ ); + shift if UNIVERSAL::isa( $_[0] => __PACKAGE__ ); + my $blogid = shift @_; + my $username = shift @_; + my $password = shift @_; + my $numberOfPosts = shift @_; + + BXR::auth( $username, $password ); + + my $postIds = blosxom::getRecentPosts($numberOfPosts); + + my @retList; + + foreach ( @{$postIds} ) { + my $post = blosxom::getPost($_); + + my $date = BXR::getIsoTime( $post->{'dateCreated'} ); + $post->{'dateCreated'} = SOAP::Data->type( dateTime => "$date" ); + $post->{'postid'} = BXR::getPostIdFromFilename( $post->{'postid'} ); + $post->{'title'} = SOAP::Data->type(string => $post->{'title'}); + delete $post->{'description'}; + $post->{'userid'} = 1; + push @retList, $post; + } + + return \@retList; +} +sub getTrackbackPings { + my @data; + return \@data; +} + +sub supportedTextFilters { + my @data; + return \@data; } =head1 NAME