// Copyright 2005 by Omar Al Zabir. All rights are reserved.
//
// If you like this code then feel free to go ahead and use it.
// The only thing I ask is that you don't remove or alter my copyright notice.
//
// Your use of this software is entirely at your own risk. I make no claims or
// warrantees about the reliability or fitness of this code for any particular purpose.
// If you make changes or additions to this code please mark your code as being yours.
//
// website http://www.oazabir.com, email OmarAlZabir@gmail.com, msn oazabir@hotmail.com
using System;
using System.IO;
using System.Text;
using System.Xml;
using System.Web;
using System.Net;
using System.Net.Sockets;
using System.Diagnostics;
using System.Xml.XPath;
using System.Collections;
using System.Security.Cryptography;
using System.Configuration;
namespace RSSBlogAPI{
/// <summary>
/// Metaweblog API for WordPress and B2Evolution
/// </summary>
public class MetaWeblog : BlogAPIBase
{
private WebLog _WebLog;
private readonly string _GetCategoriesMethodName;
private readonly string _PostMethodName;
private readonly string _DateTimeFieldType;
public MetaWeblog( WebLog log )
{
this._WebLog = log;
// Different blog engines have different method names
if( log.Engine == EngineEnum.B2Evolution )
{
_GetCategoriesMethodName = "b2.getCategories";
_PostMethodName = "b2.newPost";
}
else
{
_GetCategoriesMethodName = "metaWeblog.getCategories";
_PostMethodName = "metaWeblog.newPost";
}
_DateTimeFieldType = "dateTime.iso8601";
}
public override bool HasCategories
{
get { return true; }
}
public override bool HasBlogId
{
get { return true; }
}
public override string EngineName
{
get { return "MetaWebLog (Movable type, dasBlog, wordpress)"; }
}
public override string HelpText
{
get { return "Movable type, dasBlog, wordpress"; }
}
public override void Test()
{
this.GetCategories();
}
/// <summary>
/// Get categories from the blog engine.
/// </summary>
/// <returns></returns>
public override Category [] GetCategories()
{
HttpWebRequest request = CreateRequest( "POST" );
byte [] xml = BuildXmlRpc( this._GetCategoriesMethodName, this.BlogId, this.Username, this.Password );
request.ContentLength = xml.Length;
using( Stream requestStream = request.GetRequestStream())
requestStream.Write( xml, 0, xml.Length );
using( HttpWebResponse response = request.GetResponse() as HttpWebResponse )
{
if ( response.StatusCode != HttpStatusCode.OK )
throw new ApplicationException( response.StatusDescription );
using( Stream responseStream = response.GetResponseStream() )
using( StreamReader reader = new StreamReader( responseStream, RSSCommon.Constants.DefaultEncoding ) )
return DeserializeCategoriesXml( reader );
}
}
/// <summary>
/// Post to weblog
/// </summary>
/// <param name="post"></param>
/// <returns></returns>
public override string PostItem( Post post )
{
HttpWebRequest request = CreateRequest( "POST" );
byte [] xml;
if( EngineEnum.B2Evolution == this._WebLog.Engine )
{
// B2 Supports special format
xml = BuildXmlRpc( this._PostMethodName,
this.BlogId, string.Empty,
this.Username, this.Password,
post.Text, true, post.Title, (post.Categories.Length > 0 ? post.Categories[0].Id.ToString() : "0"),
post.Date.ToString( "yyyy-MM-dd hh:mm:sszzz" ) );
}
else
{
xml = BuildXmlRpc( this._PostMethodName, this.BlogId,
this.Username, this.Password, post, true );
}
request.ContentLength = xml.Length;
using( Stream requestStream = request.GetRequestStream())
requestStream.Write( xml, 0, xml.Length );
using( HttpWebResponse response = request.GetResponse() as HttpWebResponse )
{
if ( response.StatusCode != HttpStatusCode.OK )
throw new ApplicationException( response.StatusDescription );
using( Stream responseStream = response.GetResponseStream() )
using( StreamReader reader = new StreamReader( responseStream, Encoding.UTF8 ) )
return DeserializePostXml( reader );
}
}
private Category [] DeserializeCategoriesXml( StreamReader reader )
{
ArrayList list = new ArrayList();
XPathDocument xDoc = new XPathDocument( reader );
XPathNavigator navigator = xDoc.CreateNavigator();
XPathNodeIterator fault = navigator.Select( "/methodResponse/fault/value" );
if ( fault.Count == 0 )
{
XPathNodeIterator values = navigator.Select( "/methodResponse/params/param/value/array/data/value" );
while( values.MoveNext() )
{
Category category = GetCategory( values.Current );
if ( category != null )
list.Add( category );
}
return list.ToArray( typeof( Category ) ) as Category [];
}
else
{
fault.MoveNext();
throw new ApplicationException("Invalid content in XML: " + fault.Current.Value);
}
}
private string DeserializePostXml( StreamReader reader )
{
ArrayList list = new ArrayList();
#if(DEBUG)
string response = reader.ReadToEnd();
Debug.WriteLine( response );
XPathDocument xDoc = new XPathDocument( new StringReader( response ) );
#else
XPathDocument xDoc = new XPathDocument( reader );
#endif
XPathNavigator navigator = xDoc.CreateNavigator();
XPathNodeIterator fault = navigator.Select( "/methodResponse/fault/value" );
if ( fault.Count != 0 )
{
fault.MoveNext();
throw new ApplicationException( GetFault( fault.Current ) );
}
else
{
XPathNodeIterator postID = navigator.Select( "/methodResponse/params/param/value/string" );
if( postID.Count != 0 )
{
return postID.Current.Value;
}
else
{
return string.Empty;
}
}
}
private Category GetCategory( XPathNavigator navigator )
{
Category category = new Category();
XPathNodeIterator members = navigator.Select( "struct/member" );
while( members.MoveNext() )
{
string memberName = ( string )members.Current.Evaluate( "string(name/text())" );
string memberValue = ( string )members.Current.Evaluate( "string(value/string/text())" );
if ( memberName.ToLower() == "categoryid" )
category.Id = memberValue;
else if ( memberName.ToLower() == "title" ||
memberName.ToLower() == "categoryname" )
category.Title = memberValue;
}
return ( category.Title != string.Empty && category.Id != string.Empty ) ? category : null;
}
private string GetFault( XPathNavigator navigator )
{
XPathNodeIterator members = navigator.Select( "struct/member" );
while( members.MoveNext() )
{
string memberName = ( string )members.Current.Evaluate( "string(name/text())" );
string memberValue = ( string )members.Current.Evaluate( "string(value/string/text())" );
if ( memberName.ToLower() == "faultstring" )
return memberValue;
}
return string.Empty;
}
private byte [] BuildXmlRpc( string method, params object [] args )
{
using( MemoryStream mStream = new MemoryStream() )
{
XmlTextWriter xWriter = new XmlTextWriter( mStream, Encoding.UTF8 );
xWriter.Indentation = 1;
xWriter.Formatting = Formatting.Indented;
xWriter.IndentChar = '\t';
xWriter.QuoteChar = '"';
xWriter.WriteStartDocument();
xWriter.WriteStartElement( "methodCall" );
xWriter.WriteElementString( "methodName", method );
xWriter.WriteStartElement( "params" );
foreach( object param in args )
{
xWriter.WriteStartElement( "param" );
xWriter.WriteStartElement( "value" );
if ( param is string )
xWriter.WriteElementString( "string", param.ToString() );
else if ( param is bool )
xWriter.WriteElementString( "boolean", ( ( bool ) param ) ? "1" : "0" );
else if( param is DateTime )
xWriter.WriteElementString( _DateTimeFieldType, ((DateTime)param).ToString( "yyyyMMddThh:mm:sszzz" ) );
else if ( param is Post )
{
xWriter.WriteStartElement( "struct" );
WritePost( xWriter, ( Post )param );
xWriter.WriteEndElement();
}
xWriter.WriteEndElement();
xWriter.WriteEndElement();
}
xWriter.WriteEndElement();
xWriter.WriteEndElement();
xWriter.Flush();
return mStream.ToArray();
}
}
private void WritePost( XmlTextWriter xWriter, Post post )
{
// This format is for Word Press
string date = post.Date.ToString( "yyyyMMddThh:mm:sszzz" );
//string date = "20050701T09:18:58Z";
WriteMember( xWriter, _DateTimeFieldType, "dateCreated", date );
//WriteMember( xWriter, "dateTime", "dateCreated", date );
//WriteMember( xWriter, "dateTime.iso8601", "dateCreated", date );
WriteMember( xWriter, "string", "description", post.Text );
WriteMember( xWriter, "string", "title", post.Title );
WriteCategories( xWriter, "categories", post.Categories );
WriteMember( xWriter, "string", "link", string.Empty );
WriteMember( xWriter, "string", "permalink", string.Empty );
WriteMember( xWriter, "string", "postid", string.Empty );
}
private void WriteMember( XmlTextWriter xWriter, string type, string name, string val )
{
xWriter.WriteStartElement( "member" );
xWriter.WriteElementString( "name", name );
xWriter.WriteStartElement( "value" );
xWriter.WriteElementString( type, val );
xWriter.WriteEndElement();
xWriter.WriteEndElement();
}
private void WriteCategories( XmlTextWriter xWriter, string name, Category [] val )
{
xWriter.WriteStartElement( "member" );
xWriter.WriteElementString( "name", "categories" );
xWriter.WriteStartElement( "value" );
xWriter.WriteStartElement( "array" );
xWriter.WriteStartElement( "data" );
foreach( Category cat in val )
{
xWriter.WriteStartElement( "value" );
xWriter.WriteElementString( "string", cat.Title );
xWriter.WriteEndElement();
}
xWriter.WriteEndElement();
xWriter.WriteEndElement();
xWriter.WriteEndElement();
xWriter.WriteEndElement();
}
}
}
|