• Skip to content
  • Skip to link menu
KDE 4.1 API Reference
  • KDE API Reference
  • KDE-PIM Libraries
  • Sitemap
  • Contact Us
 

KBlog Client Library

blogger1.cpp

00001 /*
00002   This file is part of the kblog library.
00003 
00004   Copyright (c) 2004 Reinhold Kainhofer <reinhold@kainhofer.com>
00005   Copyright (c) 2006-2007 Christian Weilbach <christian_weilbach@web.de>
00006   Copyright (c) 2007-2008 Mike Arthur <mike@mikearthur.co.uk>
00007 
00008   This library is free software; you can redistribute it and/or
00009   modify it under the terms of the GNU Library General Public
00010   License as published by the Free Software Foundation; either
00011   version 2 of the License, or (at your option) any later version.
00012 
00013   This library is distributed in the hope that it will be useful,
00014   but WITHOUT ANY WARRANTY; without even the implied warranty of
00015   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016   Library General Public License for more details.
00017 
00018   You should have received a copy of the GNU Library General Public License
00019   along with this library; see the file COPYING.LIB.  If not, write to
00020   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00021   Boston, MA 02110-1301, USA.
00022 */
00023 
00024 #include "blogger1.h"
00025 #include "blogger1_p.h"
00026 #include "blogpost.h"
00027 
00028 #include <kxmlrpcclient/client.h>
00029 
00030 #include <KDebug>
00031 #include <KDateTime>
00032 #include <KLocale>
00033 
00034 #include <QList>
00035 
00036 #include <QStringList>
00037 
00038 using namespace KBlog;
00039 
00040 Blogger1::Blogger1( const KUrl &server, QObject *parent )
00041   : Blog( server, *new Blogger1Private, parent )
00042 {
00043   kDebug() << "Blogger1()";
00044   setUrl( server );
00045 }
00046 
00047 Blogger1::Blogger1( const KUrl &server, Blogger1Private &dd, QObject *parent )
00048   : Blog( server, dd, parent )
00049 {
00050   kDebug() << "Blogger1()";
00051   setUrl( server );
00052 }
00053 
00054 Blogger1::~Blogger1()
00055 {
00056   kDebug() << "~Blogger1()";
00057 }
00058 
00059 QString Blogger1::interfaceName() const
00060 {
00061   return QLatin1String( "Blogger 1.0" );
00062 }
00063 
00064 void Blogger1::setUrl( const KUrl &server )
00065 {
00066   Q_D( Blogger1 );
00067   Blog::setUrl( server );
00068   delete d->mXmlRpcClient;
00069   d->mXmlRpcClient = new KXmlRpc::Client( server );
00070   d->mXmlRpcClient->setUserAgent( userAgent() );
00071 }
00072 
00073 void Blogger1::fetchUserInfo()
00074 {
00075     Q_D( Blogger1 );
00076     kDebug() << "Fetch user's info...";
00077     QList<QVariant> args( d->blogger1Args() );
00078     d->mXmlRpcClient->call(
00079       "blogger.getUserInfo", args,
00080       this, SLOT(slotFetchUserInfo(const QList<QVariant>&,const QVariant&)),
00081       this, SLOT(slotError(int,const QString&,const QVariant&)) );
00082 }
00083 
00084 void Blogger1::listBlogs()
00085 {
00086     Q_D( Blogger1 );
00087     kDebug() << "Fetch List of Blogs...";
00088     QList<QVariant> args( d->blogger1Args() );
00089     d->mXmlRpcClient->call(
00090       "blogger.getUsersBlogs", args,
00091       this, SLOT(slotListBlogs(const QList<QVariant>&,const QVariant&)),
00092       this, SLOT(slotError(int,const QString&,const QVariant&)) );
00093 }
00094 
00095 void Blogger1::listRecentPosts( int number )
00096 {
00097     Q_D( Blogger1 );
00098     kDebug() << "Fetching List of Posts...";
00099     QList<QVariant> args( d->defaultArgs( blogId() ) );
00100     args << QVariant( number );
00101     d->mXmlRpcClient->call(
00102       d->getCallFromFunction( Blogger1Private::GetRecentPosts ), args,
00103       this, SLOT(slotListRecentPosts(const QList<QVariant>&,const QVariant&)),
00104       this, SLOT(slotError(int,const QString&,const QVariant&)),
00105       QVariant( number ) );
00106 }
00107 
00108 void Blogger1::fetchPost( KBlog::BlogPost *post )
00109 {
00110   if ( !post ) {
00111     kError() << "Blogger1::modifyPost: post is null pointer";
00112     return;
00113   }
00114 
00115   Q_D( Blogger1 );
00116   kDebug() << "Fetching Post with url" << post->postId();
00117   QList<QVariant> args( d->defaultArgs( post->postId() ) );
00118   unsigned int i= d->mCallCounter++;
00119   d->mCallMap[ i ] = post;
00120   d->mXmlRpcClient->call(
00121     d->getCallFromFunction( Blogger1Private::FetchPost ), args,
00122     this, SLOT(slotFetchPost(const QList<QVariant>&,const QVariant&)),
00123     this, SLOT(slotError(int, const QString&,const QVariant&)),
00124     QVariant( i ) );
00125 }
00126 
00127 void Blogger1::modifyPost( KBlog::BlogPost *post )
00128 {
00129   Q_D( Blogger1 );
00130 
00131   if ( !post ) {
00132     kError() << "Blogger1::modifyPost: post is null pointer";
00133     return;
00134   }
00135 
00136   kDebug() << "Uploading Post with postId" << post->postId();
00137   unsigned int i= d->mCallCounter++;
00138   d->mCallMap[ i ] = post;
00139   QList<QVariant> args( d->defaultArgs( post->postId() ) );
00140   d->readArgsFromPost( &args, *post );
00141   d->mXmlRpcClient->call(
00142     d->getCallFromFunction( Blogger1Private::ModifyPost ), args,
00143     this, SLOT(slotModifyPost(const QList<QVariant>&,const QVariant&)),
00144     this, SLOT(slotError(int,const QString&,const QVariant&)),
00145     QVariant( i ) );
00146 }
00147 
00148 void Blogger1::createPost( KBlog::BlogPost *post )
00149 {
00150   Q_D( Blogger1 );
00151 
00152   if ( !post ) {
00153     kError() << "Blogger1::createPost: post is null pointer";
00154     return;
00155   }
00156 
00157   unsigned int i= d->mCallCounter++;
00158   d->mCallMap[ i ] = post;
00159   kDebug() << "Creating new Post with blogid" << blogId();
00160   QList<QVariant> args( d->defaultArgs( blogId() ) );
00161   d->readArgsFromPost( &args, *post );
00162   d->mXmlRpcClient->call(
00163     d->getCallFromFunction( Blogger1Private::CreatePost ), args,
00164     this, SLOT(slotCreatePost(const QList<QVariant>&,const QVariant&)),
00165     this, SLOT(slotError(int, const QString&,const QVariant&)),
00166     QVariant( i ) );
00167 }
00168 
00169 void Blogger1::removePost( KBlog::BlogPost *post )
00170 {
00171   Q_D( Blogger1 );
00172 
00173   if ( !post ) {
00174     kError() << "Blogger1::removePost: post is null pointer";
00175     return;
00176   }
00177 
00178  unsigned int i = d->mCallCounter++;
00179  d->mCallMap[ i ] = post;
00180  kDebug() << "Blogger1::removePost: postId=" << post->postId();
00181  QList<QVariant> args( d->blogger1Args( post->postId() ) );
00182  args << QVariant( true ); // Publish must be set to remove post.
00183  d->mXmlRpcClient->call(
00184    "blogger.deletePost", args,
00185    this, SLOT(slotRemovePost(const QList<QVariant>&,const QVariant&)),
00186    this, SLOT(slotError(int,const QString&,const QVariant&)),
00187    QVariant( i ) );
00188 }
00189 
00190 Blogger1Private::Blogger1Private() :
00191 mXmlRpcClient(0)
00192 {
00193   mCallCounter = 1;
00194 }
00195 
00196 Blogger1Private::~Blogger1Private()
00197 {
00198   kDebug() << "~Blogger1Private()";
00199   delete mXmlRpcClient;
00200 }
00201 
00202 QList<QVariant> Blogger1Private::defaultArgs( const QString &id )
00203 {
00204   kDebug();
00205   Q_Q ( Blogger1 );
00206   QList<QVariant> args;
00207   args << QVariant( QString( "0123456789ABCDEF" ) );
00208   if( !id.isEmpty() ) {
00209     args << QVariant( id );
00210   }
00211   args << QVariant( q->username() )
00212        << QVariant( q->password() );
00213   return args;
00214 }
00215 
00216 // reimplemenet defaultArgs, since we may not use it virtually everywhere
00217 QList<QVariant> Blogger1Private::blogger1Args( const QString &id )
00218 {
00219   kDebug();
00220   Q_Q ( Blogger1 );
00221   QList<QVariant> args;
00222   args << QVariant( QString( "0123456789ABCDEF" ) );
00223   if( !id.isEmpty() ) {
00224     args << QVariant( id );
00225   }
00226   args << QVariant( q->username() )
00227        << QVariant( q->password() );
00228   return args;
00229 }
00230 
00231 void Blogger1Private::slotFetchUserInfo( const QList<QVariant> &result, const QVariant &id )
00232 {
00233   Q_Q( Blogger1 );
00234   Q_UNUSED( id );
00235 
00236   kDebug() << "Blog::slotFetchUserInfo";
00237   kDebug() << "TOP:" << result[0].typeName();
00238   QMap<QString,QString> userInfo;
00239   if ( result[0].type() != QVariant::Map ) {
00240     kError() << "Could not fetch user's info out of the result from the server,"
00241                  << "not a map.";
00242     emit q->error( Blogger1::ParsingError,
00243                         i18n( "Could not fetch user's info out of the result "
00244                               "from the server, not a map." ) );
00245     return;
00246   }
00247   const QMap<QString,QVariant> resultMap = result[0].toMap();
00248   userInfo["nickname"]=resultMap["nickname"].toString();
00249   userInfo["userid"]=resultMap["userid"].toString();
00250   userInfo["url"]=resultMap["url"].toString();
00251   userInfo["email"]=resultMap["email"].toString();
00252   userInfo["lastname"]=resultMap["lastname"].toString();
00253   userInfo["firstname"]=resultMap["firstname"].toString();
00254 
00255   emit q->fetchedUserInfo( userInfo );
00256 }
00257 
00258 void Blogger1Private::slotListBlogs( const QList<QVariant> &result, const QVariant &id )
00259 {
00260   Q_Q( Blogger1 );
00261   Q_UNUSED( id );
00262 
00263   kDebug() << "Blog::slotListBlogs";
00264   kDebug() << "TOP:" << result[0].typeName();
00265   QList<QMap<QString,QString> > blogsList;
00266   if ( result[0].type() != QVariant::List ) {
00267     kError() << "Could not fetch blogs out of the result from the server,"
00268                  << "not a list.";
00269     emit q->error( Blogger1::ParsingError,
00270                         i18n( "Could not fetch blogs out of the result "
00271                               "from the server, not a list." ) );
00272     return;
00273   }
00274   const QList<QVariant> posts = result[0].toList();
00275   QList<QVariant>::ConstIterator it = posts.begin();
00276   QList<QVariant>::ConstIterator end = posts.end();
00277   for ( ; it != end; ++it ) {
00278     kDebug() << "MIDDLE:" << ( *it ).typeName();
00279     const QMap<QString, QVariant> postInfo = ( *it ).toMap();
00280     QMap<QString,QString> blogInfo;
00281     blogInfo[ "id" ] = postInfo["blogid"].toString();
00282     blogInfo[ "name" ] = postInfo["blogName"].toString();
00283     kDebug() << "Blog information retrieved: ID =" << blogInfo["id"]
00284         << ", Name =" << blogInfo["name"];
00285     blogsList << blogInfo;
00286   }
00287   emit q->listedBlogs( blogsList );
00288 }
00289 
00290 void Blogger1Private::slotListRecentPosts( const QList<QVariant> &result, const QVariant &id )
00291 {
00292   Q_Q( Blogger1 );
00293   int count = id.toInt(); // not sure if needed, actually the API should
00294 // not give more posts
00295 
00296   kDebug() << "Blog::slotListRecentPosts";
00297   kDebug() << "TOP:" << result[0].typeName();
00298 
00299   QList <BlogPost> fetchedPostList;
00300 
00301   if ( result[0].type() != QVariant::List ) {
00302     kError() << "Could not fetch list of posts out of the"
00303                  << "result from the server, not a list.";
00304     emit q->error( Blogger1::ParsingError,
00305                    i18n( "Could not fetch list of posts out of the result "
00306                          "from the server, not a list." ) );
00307     return;
00308   }
00309   const QList<QVariant> postReceived = result[0].toList();
00310   QList<QVariant>::ConstIterator it = postReceived.begin();
00311   QList<QVariant>::ConstIterator end = postReceived.end();
00312   for ( ; it != end; ++it ) {
00313     BlogPost post;
00314     kDebug() << "MIDDLE:" << ( *it ).typeName();
00315     const QMap<QString, QVariant> postInfo = ( *it ).toMap();
00316     if ( readPostFromMap( &post, postInfo ) ) {
00317       kDebug() << "Post with ID:"
00318                     << post.postId()
00319                     << "appended in fetchedPostList";
00320       post.setStatus( BlogPost::Fetched );
00321       fetchedPostList.append( post );
00322     } else {
00323       kError() << "readPostFromMap failed!";
00324       emit q->error( Blogger1::ParsingError, i18n( "Could not read post." ) );
00325     }
00326     if ( --count == 0 ) {
00327       break;
00328     }
00329   }
00330   kDebug() << "Emitting listRecentPostsFinished()";
00331   emit q->listedRecentPosts( fetchedPostList );
00332 }
00333 
00334 void Blogger1Private::slotFetchPost( const QList<QVariant> &result, const QVariant &id )
00335 {
00336   Q_Q( Blogger1 );
00337   kDebug() << "Blog::slotFetchPost";
00338 
00339   KBlog::BlogPost *post = mCallMap[ id.toInt() ];
00340   mCallMap.remove( id.toInt() );
00341 
00342   //array of structs containing ISO.8601
00343   // dateCreated, String userid, String postid, String content;
00344   // TODO: Time zone for the dateCreated!
00345   kDebug () << "TOP:" << result[0].typeName();
00346   if ( result[0].type() == QVariant::Map && readPostFromMap( post, result[0].toMap() ) ) {
00347     kDebug() << "Emitting fetchedPost()";
00348     emit q->fetchedPost( post );
00349   }
00350   else {
00351     kError() << "Could not fetch post out of the result from "
00352                   << "the server.";
00353     post->setError( i18n( "Could not fetch post out of the "
00354                               "result from the server." ) );
00355     post->setStatus( BlogPost::Error );
00356     emit q->errorPost( Blogger1::ParsingError,
00357                        i18n( "Could not fetch post out of the result "
00358                            "from the server." ), post );
00359   }
00360 }
00361 
00362 void Blogger1Private::slotCreatePost( const QList<QVariant> &result, const QVariant &id )
00363 {
00364   Q_Q( Blogger1 );
00365   KBlog::BlogPost *post = mCallMap[ id.toInt() ];
00366   mCallMap.remove( id.toInt() );
00367 
00368   kDebug() << "Blog::slotCreatePost";
00369   //array of structs containing ISO.8601
00370   // dateCreated, String userid, String postid, String content;
00371   // TODO: Time zone for the dateCreated!
00372   kDebug () << "TOP:" << result[0].typeName();
00373   if ( result[0].type() != QVariant::String && result[0].type() != QVariant::Int ) {
00374     kError() << "Could not read the postId, not a string or an integer.";
00375     emit q->errorPost( Blogger1::ParsingError,
00376                           i18n( "Could not read the postId, not a string or an integer." ),
00377                           post );
00378     return;
00379   }
00380   QString serverID;
00381   if ( result[0].type() == QVariant::String ) {
00382     serverID = result[0].toString();
00383   }
00384   if ( result[0].type() == QVariant::Int ) {
00385     serverID = QString( "%1" ).arg( result[0].toInt() );
00386   }
00387   post->setPostId( serverID );
00388   post->setStatus( KBlog::BlogPost::Created );
00389   kDebug() << "emitting createdPost()"
00390                 << "for title: \"" << post->title()
00391                 << "\" server id: " << serverID;
00392   emit q->createdPost( post );
00393 }
00394 
00395 void Blogger1Private::slotModifyPost( const QList<QVariant> &result, const QVariant &id )
00396 {
00397   Q_Q( Blogger1 );
00398   KBlog::BlogPost *post = mCallMap[ id.toInt() ];
00399   mCallMap.remove( id.toInt() );
00400 
00401   kDebug() << "Blog::slotModifyPost";
00402   //array of structs containing ISO.8601
00403   // dateCreated, String userid, String postid, String content;
00404   // TODO: Time zone for the dateCreated!
00405   kDebug() << "TOP:" << result[0].typeName();
00406   if ( result[0].type() != QVariant::Bool ) {
00407     kError() << "Could not read the result, not a boolean.";
00408     emit q->errorPost( Blogger1::ParsingError,
00409                           i18n( "Could not read the result, not a boolean." ),
00410                           post );
00411     return;
00412   }
00413   post->setStatus( KBlog::BlogPost::Modified );
00414   kDebug() << "emitting modifiedPost() for title: \""
00415       << post->title() << "\"";
00416   emit q->modifiedPost( post );
00417 }
00418 
00419 void Blogger1Private::slotRemovePost( const QList<QVariant> &result, const QVariant &id )
00420 {
00421   Q_Q( Blogger1 );
00422   KBlog::BlogPost *post = mCallMap[ id.toInt() ];
00423   mCallMap.remove( id.toInt() );
00424 
00425   kDebug() << "Blog::slotRemovePost";
00426   //array of structs containing ISO.8601
00427   // dateCreated, String userid, String postid, String content;
00428   // TODO: Time zone for the dateCreated!
00429   kDebug() << "TOP:" << result[0].typeName();
00430   if ( result[0].type() != QVariant::Bool ) {
00431     kError() << "Could not read the result, not a boolean.";
00432     emit q->errorPost( Blogger1::ParsingError,
00433                           i18n( "Could not read the result, not a boolean." ),
00434                           post );
00435     return;
00436   }
00437   post->setStatus( KBlog::BlogPost::Removed );
00438   kDebug() << "emitting removedPost()";
00439   emit q->removedPost( post );
00440 }
00441 
00442 void Blogger1Private::slotError( int number,
00443                                  const QString &errorString,
00444                                  const QVariant &id )
00445 {
00446   Q_Q( Blogger1 );
00447   Q_UNUSED( number );
00448   BlogPost *post = mCallMap[ id.toInt() ];
00449 
00450   emit q->errorPost( Blogger1::XmlRpc, errorString, post );
00451 }
00452 
00453 bool Blogger1Private::readPostFromMap(
00454     BlogPost *post, const QMap<QString, QVariant> &postInfo )
00455 {
00456   // FIXME: integrate error handling
00457   if ( !post ) {
00458     return false;
00459   }
00460   QStringList mapkeys = postInfo.keys();
00461   kDebug() << endl << "Keys:" << mapkeys.join( ", " );
00462   kDebug() << endl;
00463 
00464   KDateTime dt( postInfo["dateCreated"].toDateTime(), KDateTime::UTC );
00465   if ( dt.isValid() && !dt.isNull() ) {
00466     post->setCreationDateTime( dt );
00467   }
00468   dt = KDateTime ( postInfo["lastModified"].toDateTime(), KDateTime::UTC );
00469   if ( dt.isValid() && !dt.isNull() ) {
00470     post->setModificationDateTime( dt );
00471   }
00472   post->setPostId( postInfo["postid"].toString() );
00473 
00474   QString title( postInfo["title"].toString() );
00475   QString description( postInfo["description"].toString() );
00476   QString contents( postInfo["content"].toString() );
00477   QStringList category;
00478 
00479   // Check for hacked title/category support (e.g. in Wordpress)
00480   QRegExp titleMatch = QRegExp( "<title>([^<]*)</title>" );
00481   QRegExp categoryMatch = QRegExp( "<category>([^<]*)</category>" );
00482   contents.remove( titleMatch );
00483   if ( titleMatch.numCaptures() > 0 ) {
00484     // Get the title value from the regular expression match
00485     title = titleMatch.cap( 1 );
00486   }
00487   contents.remove( categoryMatch );
00488   if ( categoryMatch.numCaptures() > 0 ) {
00489     // Get the category value from the regular expression match
00490     category = categoryMatch.capturedTexts();
00491   }
00492 
00493   post->setTitle( title );
00494   post->setContent( contents );
00495   post->setCategories( category );
00496   return true;
00497 }
00498 
00499 bool Blogger1Private::readArgsFromPost( QList<QVariant> *args, const BlogPost &post )
00500 {
00501   if ( !args ) {
00502     return false;
00503   }
00504   QStringList categories = post.categories();
00505   QString content = "<title>" + post.title() + "</title>";
00506   QStringList::const_iterator it;
00507   for ( it = categories.constBegin(); it != categories.constEnd(); ++it ) {
00508     content += "<category>" + *it + "</category>";
00509   }
00510   content += post.content();
00511   *args << QVariant( content );
00512   *args << QVariant( !post.isPrivate() );
00513   return true;
00514 }
00515 
00516 QString Blogger1Private::getCallFromFunction( FunctionToCall type )
00517 {
00518   switch ( type ) {
00519     case GetRecentPosts: return "blogger.getRecentPosts";
00520     case CreatePost:        return "blogger.newPost";
00521     case ModifyPost:       return "blogger.editPost";
00522     case FetchPost:        return "blogger.getPost";
00523     default: return QString();
00524   }
00525 }
00526 
00527 #include "blogger1.moc"

KBlog Client Library

Skip menu "KBlog Client Library"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

KDE-PIM Libraries

Skip menu "KDE-PIM Libraries"
  • akonadi
  • kabc
  • kblog
  • kcal
  • kimap
  • kioslave
  •   imap4
  •   mbox
  • kldap
  • kmime
  • kpimidentities
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Generated for KDE-PIM Libraries by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal