• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.8.5 API Reference
  • KDE Home
  • 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 McQuaid <mike@mikemcquaid.com>
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();
00044   setUrl( server );
00045 }
00046 
00047 Blogger1::Blogger1( const KUrl &server, Blogger1Private &dd, QObject *parent )
00048   : Blog( server, dd, parent )
00049 {
00050   kDebug();
00051   setUrl( server );
00052 }
00053 
00054 Blogger1::~Blogger1()
00055 {
00056   kDebug();
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(QList<QVariant>,QVariant)),
00081       this, SLOT(slotError(int,QString,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(QList<QVariant>,QVariant)),
00092       this, SLOT(slotError(int,QString,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(QList<QVariant>,QVariant)),
00104       this, SLOT(slotError(int,QString,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(QList<QVariant>,QVariant)),
00123     this, SLOT(slotError(int,QString,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(QList<QVariant>,QVariant)),
00144     this, SLOT(slotError(int,QString,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(QList<QVariant>,QVariant)),
00165     this, SLOT(slotError(int,QString,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(QList<QVariant>,QVariant)),
00186    this, SLOT(slotError(int,QString,QVariant)),
00187    QVariant( i ) );
00188 }
00189 
00190 Blogger1Private::Blogger1Private() :
00191 mXmlRpcClient(0)
00192 {
00193   kDebug();
00194   mCallCounter = 1;
00195 }
00196 
00197 Blogger1Private::~Blogger1Private()
00198 {
00199   kDebug();
00200   delete mXmlRpcClient;
00201 }
00202 
00203 QList<QVariant> Blogger1Private::defaultArgs( const QString &id )
00204 {
00205   kDebug();
00206   Q_Q ( Blogger1 );
00207   QList<QVariant> args;
00208   args << QVariant( QString( "0123456789ABCDEF" ) );
00209   if( !id.isEmpty() ) {
00210     args << QVariant( id );
00211   }
00212   args << QVariant( q->username() )
00213        << QVariant( q->password() );
00214   return args;
00215 }
00216 
00217 // reimplemenet defaultArgs, since we may not use it virtually everywhere
00218 QList<QVariant> Blogger1Private::blogger1Args( const QString &id )
00219 {
00220   kDebug();
00221   Q_Q ( Blogger1 );
00222   QList<QVariant> args;
00223   args << QVariant( QString( "0123456789ABCDEF" ) );
00224   if( !id.isEmpty() ) {
00225     args << QVariant( id );
00226   }
00227   args << QVariant( q->username() )
00228        << QVariant( q->password() );
00229   return args;
00230 }
00231 
00232 void Blogger1Private::slotFetchUserInfo( const QList<QVariant> &result, const QVariant &id )
00233 {
00234   Q_Q( Blogger1 );
00235   Q_UNUSED( id );
00236 
00237   kDebug();
00238   kDebug() << "TOP:" << result[0].typeName();
00239   QMap<QString,QString> userInfo;
00240   if ( result[0].type() != QVariant::Map ) {
00241     kError() << "Could not fetch user's info out of the result from the server,"
00242                  << "not a map.";
00243     emit q->error( Blogger1::ParsingError,
00244                         i18n( "Could not fetch user's info out of the result "
00245                               "from the server, not a map." ) );
00246     return;
00247   }
00248   const QMap<QString,QVariant> resultMap = result[0].toMap();
00249   userInfo["nickname"]=resultMap["nickname"].toString();
00250   userInfo["userid"]=resultMap["userid"].toString();
00251   userInfo["url"]=resultMap["url"].toString();
00252   userInfo["email"]=resultMap["email"].toString();
00253   userInfo["lastname"]=resultMap["lastname"].toString();
00254   userInfo["firstname"]=resultMap["firstname"].toString();
00255 
00256   emit q->fetchedUserInfo( userInfo );
00257 }
00258 
00259 void Blogger1Private::slotListBlogs( const QList<QVariant> &result, const QVariant &id )
00260 {
00261   Q_Q( Blogger1 );
00262   Q_UNUSED( id );
00263 
00264   kDebug();
00265   kDebug() << "TOP:" << result[0].typeName();
00266   QList<QMap<QString,QString> > blogsList;
00267   if ( result[0].type() != QVariant::List ) {
00268     kError() << "Could not fetch blogs out of the result from the server,"
00269                  << "not a list.";
00270     emit q->error( Blogger1::ParsingError,
00271                         i18n( "Could not fetch blogs out of the result "
00272                               "from the server, not a list." ) );
00273     return;
00274   }
00275   const QList<QVariant> posts = result[0].toList();
00276   QList<QVariant>::ConstIterator it = posts.begin();
00277   QList<QVariant>::ConstIterator end = posts.end();
00278   for ( ; it != end; ++it ) {
00279     kDebug() << "MIDDLE:" << ( *it ).typeName();
00280     const QMap<QString, QVariant> postInfo = ( *it ).toMap();
00281     QMap<QString,QString> blogInfo;
00282     blogInfo[ "id" ] = postInfo["blogid"].toString();
00283     blogInfo[ "url" ] = postInfo["url"].toString();
00284     blogInfo[ "apiUrl" ] = postInfo["xmlrpc"].toString();
00285     blogInfo[ "title" ] = postInfo["blogName"].toString();
00286     kDebug() << "Blog information retrieved: ID =" << blogInfo["id"]
00287         << ", Name =" << blogInfo["title"];
00288     blogsList << blogInfo;
00289   }
00290   emit q->listedBlogs( blogsList );
00291 }
00292 
00293 void Blogger1Private::slotListRecentPosts( const QList<QVariant> &result, const QVariant &id )
00294 {
00295   Q_Q( Blogger1 );
00296   int count = id.toInt(); // not sure if needed, actually the API should
00297 // not give more posts
00298 
00299   kDebug();
00300   kDebug() << "TOP:" << result[0].typeName();
00301 
00302   QList <BlogPost> fetchedPostList;
00303 
00304   if ( result[0].type() != QVariant::List ) {
00305     kError() << "Could not fetch list of posts out of the"
00306                  << "result from the server, not a list.";
00307     emit q->error( Blogger1::ParsingError,
00308                    i18n( "Could not fetch list of posts out of the result "
00309                          "from the server, not a list." ) );
00310     return;
00311   }
00312   const QList<QVariant> postReceived = result[0].toList();
00313   QList<QVariant>::ConstIterator it = postReceived.begin();
00314   QList<QVariant>::ConstIterator end = postReceived.end();
00315   for ( ; it != end; ++it ) {
00316     BlogPost post;
00317     kDebug() << "MIDDLE:" << ( *it ).typeName();
00318     const QMap<QString, QVariant> postInfo = ( *it ).toMap();
00319     if ( readPostFromMap( &post, postInfo ) ) {
00320       kDebug() << "Post with ID:"
00321                     << post.postId()
00322                     << "appended in fetchedPostList";
00323       post.setStatus( BlogPost::Fetched );
00324       fetchedPostList.append( post );
00325     } else {
00326       kError() << "readPostFromMap failed!";
00327       emit q->error( Blogger1::ParsingError, i18n( "Could not read post." ) );
00328     }
00329     if ( --count == 0 ) {
00330       break;
00331     }
00332   }
00333   kDebug() << "Emitting listRecentPostsFinished()";
00334   emit q->listedRecentPosts( fetchedPostList );
00335 }
00336 
00337 void Blogger1Private::slotFetchPost( const QList<QVariant> &result, const QVariant &id )
00338 {
00339   Q_Q( Blogger1 );
00340   kDebug();
00341 
00342   KBlog::BlogPost *post = mCallMap[ id.toInt() ];
00343   mCallMap.remove( id.toInt() );
00344 
00345   //array of structs containing ISO.8601
00346   // dateCreated, String userid, String postid, String content;
00347   // TODO: Time zone for the dateCreated!
00348   kDebug () << "TOP:" << result[0].typeName();
00349   if ( result[0].type() == QVariant::Map && readPostFromMap( post, result[0].toMap() ) ) {
00350     kDebug() << "Emitting fetchedPost()";
00351     post->setStatus( KBlog::BlogPost::Fetched );
00352     emit q->fetchedPost( post );
00353   } else {
00354     kError() << "Could not fetch post out of the result from the server.";
00355     post->setError( i18n( "Could not fetch post out of the result from the server." ) );
00356     post->setStatus( BlogPost::Error );
00357     emit q->errorPost( Blogger1::ParsingError,
00358                        i18n( "Could not fetch post out of the result 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();
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();
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 && result[0].type() != QVariant::Int ) {
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() << "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 && result[0].type() != QVariant::Int ) {
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   kDebug() << "An error occurred: " << errorString;
00449   BlogPost *post = mCallMap[ id.toInt() ];
00450 
00451   if(post)
00452     emit q->errorPost( Blogger1::XmlRpc, errorString, post );
00453   else
00454     emit q->error( Blogger1::XmlRpc, errorString );
00455 }
00456 
00457 bool Blogger1Private::readPostFromMap(
00458     BlogPost *post, const QMap<QString, QVariant> &postInfo )
00459 {
00460   // FIXME: integrate error handling
00461   if ( !post ) {
00462     return false;
00463   }
00464   QStringList mapkeys = postInfo.keys();
00465   kDebug() << endl << "Keys:" << mapkeys.join( ", " );
00466   kDebug() << endl;
00467 
00468   KDateTime dt( postInfo["dateCreated"].toDateTime(), KDateTime::UTC );
00469   if ( dt.isValid() && !dt.isNull() ) {
00470     post->setCreationDateTime( dt.toLocalZone() );
00471   }
00472   dt = KDateTime ( postInfo["lastModified"].toDateTime(), KDateTime::UTC );
00473   if ( dt.isValid() && !dt.isNull() ) {
00474     post->setModificationDateTime( dt.toLocalZone() );
00475   }
00476   post->setPostId( postInfo["postid"].toString().isEmpty() ? postInfo["postId"].toString() :
00477                    postInfo["postid"].toString() );
00478 
00479   QString title( postInfo["title"].toString() );
00480   QString description( postInfo["description"].toString() );
00481   QString contents;
00482   if( postInfo["content"].type() == QVariant::ByteArray ) {
00483     QByteArray tmpContent = postInfo["content"].toByteArray();
00484     contents = QString::fromUtf8(tmpContent.data(), tmpContent.size());
00485   } else {
00486     contents = postInfo["content"].toString();
00487   }
00488   QStringList category;
00489 
00490   // Check for hacked title/category support (e.g. in Wordpress)
00491   QRegExp titleMatch = QRegExp( "<title>([^<]*)</title>" );
00492   QRegExp categoryMatch = QRegExp( "<category>([^<]*)</category>" );
00493   if(contents.indexOf(titleMatch) != -1) {
00494     // Get the title value from the regular expression match
00495     title = titleMatch.cap( 1 );
00496   }
00497   if ( contents.indexOf(categoryMatch) != -1 ) {
00498       // Get the category value from the regular expression match
00499       category = categoryMatch.capturedTexts();
00500   }
00501   contents.remove( titleMatch );
00502   contents.remove( categoryMatch );
00503 
00504   post->setTitle( title );
00505   post->setContent( contents );
00506   post->setCategories( category );
00507   return true;
00508 }
00509 
00510 bool Blogger1Private::readArgsFromPost( QList<QVariant> *args, const BlogPost &post )
00511 {
00512   if ( !args ) {
00513     return false;
00514   }
00515   QStringList categories = post.categories();
00516   QString content = "<title>" + post.title() + "</title>";
00517   QStringList::const_iterator it;
00518   for ( it = categories.constBegin(); it != categories.constEnd(); ++it ) {
00519     content += "<category>" + *it + "</category>";
00520   }
00521   content += post.content();
00522   *args << QVariant( content );
00523   *args << QVariant( !post.isPrivate() );
00524   return true;
00525 }
00526 
00527 QString Blogger1Private::getCallFromFunction( FunctionToCall type )
00528 {
00529   switch ( type ) {
00530     case GetRecentPosts: return "blogger.getRecentPosts";
00531     case CreatePost:        return "blogger.newPost";
00532     case ModifyPost:       return "blogger.editPost";
00533     case FetchPost:        return "blogger.getPost";
00534     default: return QString();
00535   }
00536 }
00537 
00538 #include "blogger1.moc"
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Mon Aug 27 2012 22:07:42 by doxygen 1.7.5 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KBlog Client Library

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

kdepimlibs-4.8.5 API Reference

Skip menu "kdepimlibs-4.8.5 API Reference"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal