00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
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(5323) << "Blogger1()";
00044 setUrl( server );
00045 }
00046
00047 Blogger1::Blogger1( const KUrl &server, Blogger1Private &dd, QObject *parent )
00048 : Blog( server, dd, parent )
00049 {
00050 kDebug(5323) << "Blogger1()";
00051 setUrl( server );
00052 }
00053
00054 Blogger1::~Blogger1()
00055 {
00056 kDebug(5323) << "~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(5323) << "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(5323) << "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(5323) << "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(5323) << "Blogger1::modifyPost: post is null pointer";
00112 return;
00113 }
00114
00115 Q_D( Blogger1 );
00116 kDebug(5323) << "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(5323) << "Blogger1::modifyPost: post is null pointer";
00133 return;
00134 }
00135
00136 kDebug(5323) << "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(5323) << "Blogger1::createPost: post is null pointer";
00154 return;
00155 }
00156
00157 unsigned int i= d->mCallCounter++;
00158 d->mCallMap[ i ] = post;
00159 kDebug(5323) << "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(5323) << "Blogger1::removePost: post is null pointer";
00175 return;
00176 }
00177
00178 unsigned int i = d->mCallCounter++;
00179 d->mCallMap[ i ] = post;
00180 kDebug(5323) << "Blogger1::removePost: postId=" << post->postId();
00181 QList<QVariant> args( d->blogger1Args( post->postId() ) );
00182 args << QVariant( true );
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(5323) << "~Blogger1Private()";
00199 delete mXmlRpcClient;
00200 }
00201
00202 QList<QVariant> Blogger1Private::defaultArgs( const QString &id )
00203 {
00204 Q_Q ( Blogger1 );
00205 QList<QVariant> args;
00206 args << QVariant( QString( "0123456789ABCDEF" ) );
00207 if( !id.isEmpty() ) {
00208 args << QVariant( id );
00209 }
00210 args << QVariant( q->username() )
00211 << QVariant( q->password() );
00212 return args;
00213 }
00214
00215
00216 QList<QVariant> Blogger1Private::blogger1Args( const QString &id )
00217 {
00218 Q_Q( Blogger1 );
00219 QList<QVariant> args;
00220 args << QVariant( QString( "0123456789ABCDEF" ) );
00221 if( !id.isEmpty() ) {
00222 args << QVariant( id );
00223 }
00224 args << QVariant( q->username() )
00225 << QVariant( q->password() );
00226 return args;
00227 }
00228
00229 void Blogger1Private::slotFetchUserInfo( const QList<QVariant> &result, const QVariant &id )
00230 {
00231 Q_Q( Blogger1 );
00232 Q_UNUSED( id );
00233
00234 kDebug(5323) << "Blog::slotFetchUserInfo";
00235 kDebug(5323) << "TOP:" << result[0].typeName();
00236 QMap<QString,QString> userInfo;
00237 if ( result[0].type() != QVariant::Map ) {
00238 kError(5323) << "Could not fetch user's info out of the result from the server,"
00239 << "not a map.";
00240 emit q->error( Blogger1::ParsingError,
00241 i18n( "Could not fetch user's info out of the result "
00242 "from the server, not a map." ) );
00243 } else {
00244 const QMap<QString,QVariant> resultMap = result[0].toMap();
00245 userInfo["nickname"]=resultMap["nickname"].toString();
00246 userInfo["userid"]=resultMap["userid"].toString();
00247 userInfo["url"]=resultMap["url"].toString();
00248 userInfo["email"]=resultMap["email"].toString();
00249 userInfo["lastname"]=resultMap["lastname"].toString();
00250 userInfo["firstname"]=resultMap["firstname"].toString();
00251
00252 emit q->fetchedUserInfo( userInfo );
00253 }
00254 }
00255
00256 void Blogger1Private::slotListBlogs( const QList<QVariant> &result, const QVariant &id )
00257 {
00258 Q_Q( Blogger1 );
00259 Q_UNUSED( id );
00260
00261 kDebug(5323) << "Blog::slotListBlogs";
00262 kDebug(5323) << "TOP:" << result[0].typeName();
00263 QList<QMap<QString,QString> > blogsList;
00264 if ( result[0].type() != QVariant::List ) {
00265 kError(5323) << "Could not fetch blogs out of the result from the server,"
00266 << "not a list.";
00267 emit q->error( Blogger1::ParsingError,
00268 i18n( "Could not fetch blogs out of the result "
00269 "from the server, not a list." ) );
00270 } else {
00271 const QList<QVariant> posts = result[0].toList();
00272 QList<QVariant>::ConstIterator it = posts.begin();
00273 QList<QVariant>::ConstIterator end = posts.end();
00274 for ( ; it != end; ++it ) {
00275 kDebug(5323) << "MIDDLE:" << ( *it ).typeName();
00276 const QMap<QString, QVariant> postInfo = ( *it ).toMap();
00277 QMap<QString,QString> blogInfo;
00278 blogInfo[ "id" ] = postInfo["blogid"].toString();
00279 blogInfo[ "name" ] = postInfo["blogName"].toString();
00280 kDebug(5323) << "Blog information retrieved: ID =" << blogInfo["id"]
00281 << ", Name =" << blogInfo["name"];
00282 blogsList << blogInfo;
00283 }
00284 emit q->listedBlogs( blogsList );
00285 }
00286 }
00287
00288 void Blogger1Private::slotListRecentPosts( const QList<QVariant> &result, const QVariant &id )
00289 {
00290 Q_Q( Blogger1 );
00291 int count = id.toInt();
00292
00293
00294 kDebug(5323) << "Blog::slotListRecentPosts";
00295 kDebug(5323) << "TOP:" << result[0].typeName();
00296
00297 QList <BlogPost> fetchedPostList;
00298
00299 if ( result[0].type() != QVariant::List ) {
00300 kError(5323) << "Could not fetch list of posts out of the"
00301 << "result from the server, not a list.";
00302 emit q->error( Blogger1::ParsingError,
00303 i18n( "Could not fetch list of posts out of the result "
00304 "from the server, not a list." ) );
00305 } else {
00306 const QList<QVariant> postReceived = result[0].toList();
00307 QList<QVariant>::ConstIterator it = postReceived.begin();
00308 QList<QVariant>::ConstIterator end = postReceived.end();
00309 for ( ; it != end; ++it ) {
00310 BlogPost post;
00311 kDebug(5323) << "MIDDLE:" << ( *it ).typeName();
00312 const QMap<QString, QVariant> postInfo = ( *it ).toMap();
00313 if ( readPostFromMap( &post, postInfo ) ) {
00314 kDebug(5323) << "Post with ID:"
00315 << post.postId()
00316 << "appended in fetchedPostList";
00317 post.setStatus( BlogPost::Fetched );
00318 fetchedPostList.append( post );
00319 } else {
00320 kError(5323) << "readPostFromMap failed!";
00321 emit q->error( Blogger1::ParsingError, i18n( "Could not read post." ) );
00322 }
00323 if ( --count == 0 ) {
00324 break;
00325 }
00326 }
00327 }
00328 kDebug(5323) << "Emitting listRecentPostsFinished()";
00329 emit q->listedRecentPosts( fetchedPostList );
00330 }
00331
00332 void Blogger1Private::slotFetchPost( const QList<QVariant> &result, const QVariant &id )
00333 {
00334 Q_Q( Blogger1 );
00335 kDebug(5323) << "Blog::slotFetchPost";
00336
00337 KBlog::BlogPost *post = mCallMap[ id.toInt() ];
00338 mCallMap.remove( id.toInt() );
00339
00340
00341
00342
00343 kDebug (5323) << "TOP:" << result[0].typeName();
00344 if ( result[0].type() != QVariant::Map ) {
00345 kError(5323) << "Could not fetch post out of the result from "
00346 << "the server.";
00347 emit q->errorPost( Blogger1::ParsingError,
00348 i18n( "Could not fetch post out of the result "
00349 "from the server." ), post );
00350 post->setError( i18n( "Could not fetch post out of the "
00351 "result from the server." ) );
00352 post->setStatus( BlogPost::Error );
00353 } else {
00354 const QMap<QString, QVariant> postInfo = result[0].toMap();
00355 if ( readPostFromMap( post, postInfo ) ) {
00356 kDebug(5323) << "Emitting fetchedPost( post.postId()="
00357 << post->postId() << ");";
00358 post->setStatus( BlogPost::Fetched );
00359 emit q->fetchedPost( post );
00360 } else {
00361 kError(5323) << "readPostFromMap failed!";
00362 emit q->errorPost( Blogger1::ParsingError,
00363 i18n( "Could not read post." ), post );
00364 post->setError( i18n( "Could not read post." ) );
00365 post->setStatus( BlogPost::Error );
00366 }
00367 }
00368
00369 }
00370
00371 void Blogger1Private::slotCreatePost( const QList<QVariant> &result, const QVariant &id )
00372 {
00373 Q_Q( Blogger1 );
00374 KBlog::BlogPost *post = mCallMap[ id.toInt() ];
00375 mCallMap.remove( id.toInt() );
00376
00377 kDebug(5323) << "Blog::slotCreatePost";
00378
00379
00380
00381 kDebug (5323) << "TOP:" << result[0].typeName();
00382 if ( result[0].type() != QVariant::String && result[0].type() != QVariant::Int ) {
00383 kError(5323) << "Could not read the postId, not a string or an integer.";
00384 emit q->errorPost( Blogger1::ParsingError,
00385 i18n( "Could not read the postId, not a string or an integer." ),
00386 post );
00387 } else {
00388 QString id;
00389 if ( result[0].type() == QVariant::String ) {
00390 id = result[0].toString();
00391 }
00392 if ( result[0].type() == QVariant::Int ) {
00393 id = QString( "%1" ).arg( result[0].toInt() );
00394 }
00395 post->setPostId( id );
00396 post->setStatus( KBlog::BlogPost::Created );
00397 emit q->createdPost( post );
00398 kDebug(5323) << "emitting createdPost()"
00399 << "for title: \"" << post->title()
00400 << "\" server id: " << id;
00401 }
00402
00403 }
00404
00405 void Blogger1Private::slotModifyPost( const QList<QVariant> &result, const QVariant &id )
00406 {
00407 Q_Q( Blogger1 );
00408 KBlog::BlogPost *post = mCallMap[ id.toInt() ];
00409 mCallMap.remove( id.toInt() );
00410
00411 kDebug(5323) << "Blog::slotModifyPost";
00412
00413
00414
00415 kDebug(5323) << "TOP:" << result[0].typeName();
00416 if ( result[0].type() != QVariant::Bool ) {
00417 kError(5323) << "Could not read the result, not a boolean.";
00418 emit q->errorPost( Blogger1::ParsingError,
00419 i18n( "Could not read the result, not a boolean." ),
00420 post );
00421 } else {
00422 post->setStatus( KBlog::BlogPost::Modified );
00423 emit q->modifiedPost( post );
00424 kDebug(5323) << "emitting modifiedPost() for title: \""
00425 << post->title() << "\"";
00426 }
00427 }
00428
00429 void Blogger1Private::slotRemovePost( const QList<QVariant> &result, const QVariant &id )
00430 {
00431 Q_Q( Blogger1 );
00432 KBlog::BlogPost *post = mCallMap[ id.toInt() ];
00433 mCallMap.remove( id.toInt() );
00434
00435 kDebug(5323) << "Blog::slotRemovePost";
00436
00437
00438
00439 kDebug(5323) << "TOP:" << result[0].typeName();
00440 if ( result[0].type() != QVariant::Bool ) {
00441 kError(5323) << "Could not read the result, not a boolean.";
00442 emit q->errorPost( Blogger1::ParsingError,
00443 i18n( "Could not read the result, not a boolean." ),
00444 post );
00445 } else {
00446 post->setStatus( KBlog::BlogPost::Removed );
00447 emit q->removedPost( post );
00448 kDebug(5323) << "emitting removedPost()";
00449 }
00450 }
00451
00452 void Blogger1Private::slotError( int number,
00453 const QString &errorString,
00454 const QVariant &id )
00455 {
00456 Q_Q( Blogger1 );
00457 Q_UNUSED( number );
00458 BlogPost *post = mCallMap[ id.toInt() ];
00459
00460 emit q->errorPost( Blogger1::XmlRpc, errorString, post );
00461 }
00462
00463 bool Blogger1Private::readPostFromMap(
00464 BlogPost *post, const QMap<QString, QVariant> &postInfo )
00465 {
00466
00467 if ( !post ) {
00468 return false;
00469 }
00470 QStringList mapkeys = postInfo.keys();
00471 kDebug(5323) << endl << "Keys:" << mapkeys.join( ", " );
00472 kDebug(5323) << endl;
00473
00474 KDateTime dt( postInfo["dateCreated"].toDateTime(), KDateTime::UTC );
00475 if ( dt.isValid() && !dt.isNull() ) {
00476 post->setCreationDateTime( dt );
00477 }
00478 dt = KDateTime ( postInfo["lastModified"].toDateTime(), KDateTime::UTC );
00479 if ( dt.isValid() && !dt.isNull() ) {
00480 post->setModificationDateTime( dt );
00481 }
00482 post->setPostId( postInfo["postid"].toString() );
00483
00484 QString title( postInfo["title"].toString() );
00485 QString description( postInfo["description"].toString() );
00486 QString contents( postInfo["content"].toString() );
00487 QStringList category;
00488
00489
00490 QRegExp titleMatch = QRegExp( "<title>([^<]*)</title>" );
00491 QRegExp categoryMatch = QRegExp( "<category>([^<]*)</category>" );
00492 contents.remove( titleMatch );
00493 if ( titleMatch.numCaptures() > 0 ) {
00494
00495 title = titleMatch.cap( 1 );
00496 }
00497 contents.remove( categoryMatch );
00498 if ( categoryMatch.numCaptures() > 0 ) {
00499
00500 category = categoryMatch.capturedTexts();
00501 }
00502
00503 post->setTitle( title );
00504 post->setContent( contents );
00505 post->setCategories( category );
00506 return true;
00507 }
00508
00509 bool Blogger1Private::readArgsFromPost( QList<QVariant> *args, const BlogPost &post )
00510 {
00511 if ( !args ) {
00512 return false;
00513 }
00514 QStringList categories = post.categories();
00515 QString content = "<title>" + post.title() + "</title>";
00516 QStringList::const_iterator it;
00517 for ( it = categories.constBegin(); it != categories.constEnd(); ++it ) {
00518 content += "<category>" + *it + "</category>";
00519 }
00520 content += post.content();
00521 *args << QVariant( content );
00522 *args << QVariant( !post.isPrivate() );
00523 return true;
00524 }
00525
00526 QString Blogger1Private::getCallFromFunction( FunctionToCall type )
00527 {
00528 switch ( type ) {
00529 case GetRecentPosts: return "blogger.getRecentPosts";
00530 case CreatePost: return "blogger.newPost";
00531 case ModifyPost: return "blogger.editPost";
00532 case FetchPost: return "blogger.getPost";
00533 default: return QString();
00534 }
00535 }
00536
00537 #include "blogger1.moc"