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 May 14 2012 04:34:33 by doxygen 1.7.5 written by Dimitri van Heesch, © 1997-2006
Documentation copyright © 1996-2012 The KDE developers.
Generated on Mon May 14 2012 04:34:33 by doxygen 1.7.5 written by Dimitri van Heesch, © 1997-2006
KDE's Doxygen guidelines are available online.