1/*
2 This file is part of the kblog library.
3
4 Copyright (c) 2007 Christian Weilbach <christian_weilbach@web.de>
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
20*/
21
22#include "gdata.h"
23#include "gdata_p.h"
24#include "blogpost.h"
25#include "blogcomment.h"
26
27#include <syndication/loader.h>
28#include <syndication/item.h>
29#include <syndication/category.h>
30
31#include <kio/netaccess.h>
32#include <kio/job.h>
33#include <KDebug>
34#include <KLocalizedString>
35#include <KDateTime>
36
37#include <QByteArray>
38#include <QRegExp>
39#include <QDomDocument>
40
41#define TIMEOUT 600
42
43using namespace KBlog;
44
45GData::GData( const KUrl &server, QObject *parent )
46 : Blog( server, *new GDataPrivate, parent )
47{
48 kDebug();
49 setUrl( server );
50}
51
52GData::~GData()
53{
54 kDebug();
55}
56
57QString GData::interfaceName() const
58{
59 kDebug();
60 return QLatin1String( "Google Blogger Data" );
61}
62
63QString GData::fullName() const
64{
65 kDebug();
66 return d_func()->mFullName;
67}
68
69void GData::setFullName( const QString &fullName )
70{
71 kDebug();
72 Q_D( GData );
73 d->mFullName = fullName;
74}
75
76QString GData::profileId() const
77{
78 kDebug();
79 return d_func()->mProfileId;
80}
81
82void GData::setProfileId( const QString &pid )
83{
84 kDebug();
85 Q_D( GData );
86 d->mProfileId = pid;
87}
88
89void GData::fetchProfileId()
90{
91 kDebug();
92 QByteArray data;
93 KIO::StoredTransferJob *job = KIO::storedGet( url(), KIO::NoReload, KIO::HideProgressInfo );
94 KUrl blogUrl = url();
95 connect( job, SIGNAL(result(KJob*)),
96 this, SLOT(slotFetchProfileId(KJob*)) );
97}
98
99void GData::listBlogs()
100{
101 kDebug();
102 Syndication::Loader *loader = Syndication::Loader::create();
103 connect( loader,
104 SIGNAL(loadingComplete(Syndication::Loader*,Syndication::FeedPtr,Syndication::ErrorCode)),
105 this,
106 SLOT(slotListBlogs(Syndication::Loader*,Syndication::FeedPtr,Syndication::ErrorCode)) );
107 loader->loadFrom( QString::fromLatin1("http://www.blogger.com/feeds/%1/blogs").arg(profileId()) );
108}
109
110void GData::listRecentPosts( const QStringList &labels, int number,
111 const KDateTime &upMinTime, const KDateTime &upMaxTime,
112 const KDateTime &pubMinTime, const KDateTime &pubMaxTime )
113{
114 kDebug();
115 Q_D( GData );
116 QString urlString( QLatin1String("http://www.blogger.com/feeds/") + blogId() + QLatin1String("/posts/default") );
117 if ( ! labels.empty() ) {
118 urlString += QLatin1String("/-/") + labels.join( QLatin1String("/") );
119 }
120 kDebug() << "listRecentPosts()";
121 KUrl url( urlString );
122
123 if ( !upMinTime.isNull() ) {
124 url.addQueryItem( QLatin1String("updated-min"), upMinTime.toString() );
125 }
126
127 if ( !upMaxTime.isNull() ) {
128 url.addQueryItem( QLatin1String("updated-max"), upMaxTime.toString() );
129 }
130
131 if ( !pubMinTime.isNull() ) {
132 url.addQueryItem( QLatin1String("published-min"), pubMinTime.toString() );
133 }
134
135 if ( !pubMaxTime.isNull() ) {
136 url.addQueryItem( QLatin1String("published-max"), pubMaxTime.toString() );
137 }
138
139 Syndication::Loader *loader = Syndication::Loader::create();
140 if ( number > 0 ) {
141 d->mListRecentPostsMap[ loader ] = number;
142 }
143 connect( loader,
144 SIGNAL(loadingComplete(Syndication::Loader*,Syndication::FeedPtr,Syndication::ErrorCode)),
145 this,
146 SLOT(slotListRecentPosts(Syndication::Loader*,Syndication::FeedPtr,Syndication::ErrorCode)) );
147 loader->loadFrom( url.url() );
148}
149
150void GData::listRecentPosts( int number )
151{
152 kDebug();
153 listRecentPosts( QStringList(), number );
154}
155
156void GData::listComments( KBlog::BlogPost *post )
157{
158 kDebug();
159 Q_D( GData );
160 Syndication::Loader *loader = Syndication::Loader::create();
161 d->mListCommentsMap[ loader ] = post;
162 connect( loader,
163 SIGNAL(loadingComplete(Syndication::Loader*,Syndication::FeedPtr,Syndication::ErrorCode)),
164 this,
165 SLOT(slotListComments(Syndication::Loader*,Syndication::FeedPtr,Syndication::ErrorCode)) );
166 loader->loadFrom( QString(QLatin1String("http://www.blogger.com/feeds/") + blogId() + QLatin1Char('/') +
167 post->postId() + QLatin1String("/comments/default")) );
168}
169
170void GData::listAllComments()
171{
172 kDebug();
173 Syndication::Loader *loader = Syndication::Loader::create();
174 connect( loader,
175 SIGNAL(loadingComplete(Syndication::Loader*,Syndication::FeedPtr,Syndication::ErrorCode)),
176 this,
177 SLOT(slotListAllComments(Syndication::Loader*,Syndication::FeedPtr,Syndication::ErrorCode)) );
178 loader->loadFrom( QString::fromLatin1("http://www.blogger.com/feeds/%1/comments/default").arg(blogId()) );
179}
180
181void GData::fetchPost( KBlog::BlogPost *post )
182{
183 kDebug();
184 Q_D( GData );
185
186 if ( !post ) {
187 kError() << "post is null pointer";
188 return;
189 }
190
191 kDebug();
192 Syndication::Loader *loader = Syndication::Loader::create();
193 d->mFetchPostMap[ loader ] = post;
194 connect( loader,
195 SIGNAL(loadingComplete(Syndication::Loader*,Syndication::FeedPtr,Syndication::ErrorCode)),
196 this,
197 SLOT(slotFetchPost(Syndication::Loader*,Syndication::FeedPtr,Syndication::ErrorCode)) );
198 loader->loadFrom( QString::fromLatin1("http://www.blogger.com/feeds/%1/posts/default").arg(blogId()));
199}
200
201void GData::modifyPost( KBlog::BlogPost *post )
202{
203 kDebug();
204 Q_D( GData );
205
206 if ( !post ) {
207 kError() << "post is null pointer";
208 return;
209 }
210
211 if ( !d->authenticate() ) {
212 kError() << "Authentication failed.";
213 emit errorPost( Atom, i18n( "Authentication failed." ), post );
214 return;
215 }
216
217 QString atomMarkup = QLatin1String("<entry xmlns='http://www.w3.org/2005/Atom'>");
218 atomMarkup += QLatin1String("<id>tag:blogger.com,1999:blog-") + blogId();
219 atomMarkup += QLatin1String(".post-") + post->postId() + QLatin1String("</id>");
220 atomMarkup += QLatin1String("<published>") + post->creationDateTime().toString() + QLatin1String("</published>");
221 atomMarkup += QLatin1String("<updated>") + post->modificationDateTime().toString() + QLatin1String("</updated>");
222 atomMarkup += QLatin1String("<title type='text'>") + post->title() + QLatin1String("</title>");
223 if ( post->isPrivate() ) {
224 atomMarkup += QLatin1String("<app:control xmlns:app='http://purl.org/atom/app#'>");
225 atomMarkup += QLatin1String("<app:draft>yes</app:draft></app:control>");
226 }
227 atomMarkup += QLatin1String("<content type='xhtml'>");
228 atomMarkup += QLatin1String("<div xmlns='http://www.w3.org/1999/xhtml'>");
229 atomMarkup += post->content();
230 atomMarkup += QLatin1String("</div></content>");
231 QList<QString>::ConstIterator it = post->tags().constBegin();
232 QList<QString>::ConstIterator end = post->tags().constEnd();
233 for ( ; it != end; ++it ) {
234 atomMarkup += QLatin1String("<category scheme='http://www.blogger.com/atom/ns#' term='") + ( *it ) + QLatin1String("' />");
235 }
236 atomMarkup += QLatin1String("<author>");
237 if ( !fullName().isEmpty() ) {
238 atomMarkup += QLatin1String("<name>") + fullName() + QLatin1String("</name>");
239 }
240 atomMarkup += QLatin1String("<email>") + username() + QLatin1String("</email>");
241 atomMarkup += QLatin1String("</author>");
242 atomMarkup += QLatin1String("</entry>");
243 QByteArray postData;
244 QDataStream stream( &postData, QIODevice::WriteOnly );
245 stream.writeRawData( atomMarkup.toUtf8(), atomMarkup.toUtf8().length() );
246
247 KIO::StoredTransferJob *job = KIO::storedHttpPost( postData,
248 KUrl( QLatin1String("http://www.blogger.com/feeds/") + blogId() + QLatin1String("/posts/default/") + post->postId() ),
249 KIO::HideProgressInfo );
250
251 Q_ASSERT( job );
252
253 d->mModifyPostMap[ job ] = post;
254
255 job->addMetaData( QLatin1String("content-type"), QLatin1String("Content-Type: application/atom+xml; charset=utf-8") );
256 job->addMetaData( QLatin1String("ConnectTimeout"), QLatin1String("50") );
257 job->addMetaData( QLatin1String("UserAgent"), userAgent() );
258 job->addMetaData( QLatin1String("customHTTPHeader"),
259 QLatin1String("Authorization: GoogleLogin auth=") + d->mAuthenticationString +
260 QLatin1String("\r\nX-HTTP-Method-Override: PUT") );
261
262 connect( job, SIGNAL(result(KJob*)),
263 this, SLOT(slotModifyPost(KJob*)) );
264}
265
266void GData::createPost( KBlog::BlogPost *post )
267{
268 kDebug();
269 Q_D( GData );
270
271 if ( !post ) {
272 kError() << "post is null pointer";
273 return;
274 }
275
276 if ( !d->authenticate() ) {
277 kError() << "Authentication failed.";
278 emit errorPost( Atom, i18n( "Authentication failed." ), post );
279 return;
280 }
281
282 QString atomMarkup = QLatin1String("<entry xmlns='http://www.w3.org/2005/Atom'>");
283 atomMarkup += QLatin1String("<title type='text'>") + post->title() + QLatin1String("</title>");
284 if ( post->isPrivate() ) {
285 atomMarkup += QLatin1String("<app:control xmlns:app='http://purl.org/atom/app#'>");
286 atomMarkup += QLatin1String("<app:draft>yes</app:draft></app:control>");
287 }
288 atomMarkup += QLatin1String("<content type='xhtml'>");
289 atomMarkup += QLatin1String("<div xmlns='http://www.w3.org/1999/xhtml'>");
290 atomMarkup += post->content(); // FIXME check for Utf
291 atomMarkup += QLatin1String("</div></content>");
292 QList<QString>::ConstIterator it = post->tags().constBegin();
293 QList<QString>::ConstIterator end = post->tags().constEnd();
294 for ( ; it != end; ++it ) {
295 atomMarkup += QLatin1String("<category scheme='http://www.blogger.com/atom/ns#' term='") + ( *it ) + QLatin1String("' />");
296 }
297 atomMarkup += QLatin1String("<author>");
298 if ( !fullName().isEmpty() ) {
299 atomMarkup += QLatin1String("<name>") + fullName() + QLatin1String("</name>");
300 }
301 atomMarkup += QLatin1String("<email>") + username() + QLatin1String("</email>");
302 atomMarkup += QLatin1String("</author>");
303 atomMarkup += QLatin1String("</entry>");
304
305 QByteArray postData;
306 QDataStream stream( &postData, QIODevice::WriteOnly );
307 stream.writeRawData( atomMarkup.toUtf8(), atomMarkup.toUtf8().length() );
308
309 KIO::StoredTransferJob *job = KIO::storedHttpPost( postData,
310 KUrl( QLatin1String("http://www.blogger.com/feeds/") + blogId() + QLatin1String("/posts/default") ),
311 KIO::HideProgressInfo );
312
313 Q_ASSERT ( job );
314 d->mCreatePostMap[ job ] = post;
315
316 job->addMetaData( QLatin1String("content-type"), QLatin1String("Content-Type: application/atom+xml; charset=utf-8") );
317 job->addMetaData( QLatin1String("ConnectTimeout"), QLatin1String("50") );
318 job->addMetaData( QLatin1String("UserAgent"), userAgent() );
319 job->addMetaData( QLatin1String("customHTTPHeader"),
320 QLatin1String("Authorization: GoogleLogin auth=") + d->mAuthenticationString );
321
322 connect( job, SIGNAL(result(KJob*)),
323 this, SLOT(slotCreatePost(KJob*)) );
324}
325
326void GData::removePost( KBlog::BlogPost *post )
327{
328 kDebug();
329 Q_D( GData );
330
331 if ( !post ) {
332 kError() << "post is null pointer";
333 return;
334 }
335
336 if ( !d->authenticate() ) {
337 kError() << "Authentication failed.";
338 emit errorPost( Atom, i18n( "Authentication failed." ), post );
339 return;
340 }
341
342 QByteArray postData;
343
344 KIO::StoredTransferJob *job = KIO::storedHttpPost( postData,
345 KUrl( QLatin1String("http://www.blogger.com/feeds/") + blogId() + QLatin1String("/posts/default/") + post->postId() ),
346 KIO::HideProgressInfo );
347
348 d->mRemovePostMap[ job ] = post;
349
350 if ( !job ) {
351 kWarning() << "Unable to create KIO job for http://www.blogger.com/feeds/"
352 << blogId() << QLatin1String("/posts/default/") + post->postId();
353 }
354
355 job->addMetaData( QLatin1String("ConnectTimeout"), QLatin1String("50") );
356 job->addMetaData( QLatin1String("UserAgent"), userAgent() );
357 job->addMetaData( QLatin1String("customHTTPHeader"),
358 QLatin1String("Authorization: GoogleLogin auth=") + d->mAuthenticationString +
359 QLatin1String("\r\nX-HTTP-Method-Override: DELETE") );
360
361 connect( job, SIGNAL(result(KJob*)),
362 this, SLOT(slotRemovePost(KJob*)) );
363}
364
365void GData::createComment( KBlog::BlogPost *post, KBlog::BlogComment *comment )
366{
367 kDebug();
368
369 if ( !comment ) {
370 kError() << "comment is null pointer";
371 return;
372 }
373
374 if ( !post ) {
375 kError() << "post is null pointer";
376 return;
377 }
378
379 Q_D( GData );
380 if ( !d->authenticate() ) {
381 kError() << "Authentication failed.";
382 emit errorComment( Atom, i18n( "Authentication failed." ), post, comment );
383 return;
384 }
385 QString atomMarkup = QLatin1String("<entry xmlns='http://www.w3.org/2005/Atom'>");
386 atomMarkup += QLatin1String("<title type=\"text\">") + comment->title() + QLatin1String("</title>");
387 atomMarkup += QLatin1String("<content type=\"html\">") + comment->content() + QLatin1String("</content>");
388 atomMarkup += QLatin1String("<author>");
389 atomMarkup += QLatin1String("<name>") + comment->name() + QLatin1String("</name>");
390 atomMarkup += QLatin1String("<email>") + comment->email() + QLatin1String("</email>");
391 atomMarkup += QLatin1String("</author></entry>");
392
393 QByteArray postData;
394 kDebug() << postData;
395 QDataStream stream( &postData, QIODevice::WriteOnly );
396 stream.writeRawData( atomMarkup.toUtf8(), atomMarkup.toUtf8().length() );
397
398 KIO::StoredTransferJob *job = KIO::storedHttpPost( postData,
399 KUrl( QLatin1String("http://www.blogger.com/feeds/") + blogId() + QLatin1String("/") + post->postId() + QLatin1String("/comments/default") ),
400 KIO::HideProgressInfo );
401
402 d->mCreateCommentMap[ job ][post] = comment;
403
404 if ( !job ) {
405 kWarning() << "Unable to create KIO job for http://www.blogger.com/feeds/"
406 << blogId() << "/" << post->postId() << "/comments/default";
407 }
408
409 job->addMetaData( QLatin1String("content-type"), QLatin1String("Content-Type: application/atom+xml; charset=utf-8") );
410 job->addMetaData( QLatin1String("ConnectTimeout"), QLatin1String("50") );
411 job->addMetaData( QLatin1String("customHTTPHeader"),
412 QLatin1String("Authorization: GoogleLogin auth=") + d->mAuthenticationString );
413 job->addMetaData( QLatin1String("UserAgent"), userAgent() );
414
415 connect( job, SIGNAL(result(KJob*)),
416 this, SLOT(slotCreateComment(KJob*)) );
417}
418
419void GData::removeComment( KBlog::BlogPost *post, KBlog::BlogComment *comment )
420{
421 kDebug();
422 Q_D( GData );
423 kDebug();
424
425 if ( !comment ) {
426 kError() << "comment is null pointer";
427 return;
428 }
429
430 if ( !post ) {
431 kError() << "post is null pointer";
432 return;
433 }
434
435 if ( !d->authenticate() ) {
436 kError() << "Authentication failed.";
437 emit errorComment( Atom, i18n( "Authentication failed." ), post, comment );
438 return;
439 }
440
441 QByteArray postData;
442
443 KIO::StoredTransferJob *job = KIO::storedHttpPost(postData,
444 KUrl( QLatin1String("http://www.blogger.com/feeds/") + blogId() + QLatin1String("/") + post->postId() +
445 QLatin1String("/comments/default/") + comment->commentId() ), KIO::HideProgressInfo );
446 d->mRemoveCommentMap[ job ][ post ] = comment;
447
448 if ( !job ) {
449 kWarning() << "Unable to create KIO job for http://www.blogger.com/feeds/"
450 << blogId() << post->postId()
451 << "/comments/default/" << comment->commentId();
452 }
453
454 job->addMetaData( QLatin1String("ConnectTimeout"), QLatin1String("50") );
455 job->addMetaData( QLatin1String("UserAgent"), userAgent() );
456 job->addMetaData( QLatin1String("customHTTPHeader"),
457 QLatin1String("Authorization: GoogleLogin auth=") +
458 d->mAuthenticationString + QLatin1String("\r\nX-HTTP-Method-Override: DELETE") );
459
460 connect( job, SIGNAL(result(KJob*)),
461 this, SLOT(slotRemoveComment(KJob*)) );
462}
463
464GDataPrivate::GDataPrivate():mAuthenticationString(), mAuthenticationTime()
465{
466 kDebug();
467}
468
469GDataPrivate::~GDataPrivate()
470{
471 kDebug();
472}
473
474bool GDataPrivate::authenticate()
475{
476 kDebug();
477 Q_Q( GData );
478 QByteArray data;
479 KUrl authGateway( QLatin1String("https://www.google.com/accounts/ClientLogin") );
480 authGateway.addQueryItem( QLatin1String("Email"), q->username() );
481 authGateway.addQueryItem( QLatin1String("Passwd"), q->password() );
482 authGateway.addQueryItem( QLatin1String("source"), q->userAgent() );
483 authGateway.addQueryItem( QLatin1String("service"), QLatin1String("blogger") );
484 if ( !mAuthenticationTime.isValid() ||
485 QDateTime::currentDateTime().toTime_t() - mAuthenticationTime.toTime_t() > TIMEOUT ||
486 mAuthenticationString.isEmpty() ) {
487 KIO::Job *job = KIO::http_post( authGateway, QByteArray(), KIO::HideProgressInfo );
488 if ( KIO::NetAccess::synchronousRun( job, (QWidget*)0, &data, &authGateway ) ) {
489 QRegExp rx( QLatin1String("Auth=(.+)") );
490 if ( rx.indexIn( QLatin1String(data) ) != -1 ) {
491 kDebug() << "RegExp got authentication string:" << rx.cap( 1 );
492 mAuthenticationString = rx.cap( 1 );
493 mAuthenticationTime = QDateTime::currentDateTime();
494 return true;
495 }
496 }
497 return false;
498 }
499 return true;
500}
501
502void GDataPrivate::slotFetchProfileId( KJob *job )
503{
504 kDebug();
505 if ( !job ) {
506 kError() << "job is a null pointer.";
507 return;
508 }
509 Q_Q( GData );
510 KIO::StoredTransferJob *stj = qobject_cast<KIO::StoredTransferJob*>( job );
511 const QString data = QString::fromUtf8( stj->data(), stj->data().size() );
512 if ( !job->error() ) {
513 QRegExp pid( QLatin1String("http://www.blogger.com/profile/(\\d+)") );
514 if ( pid.indexIn( data ) != -1 ) {
515 q->setProfileId( pid.cap( 1 ) );
516 kDebug() << "QRegExp bid( 'http://www.blogger.com/profile/(\\d+)' matches" << pid.cap( 1 );
517 emit q->fetchedProfileId( pid.cap( 1 ) );
518 } else {
519 kError() << "QRegExp bid( 'http://www.blogger.com/profile/(\\d+)' "
520 << " could not regexp the Profile ID";
521 emit q->error( GData::Other, i18n( "Could not regexp the Profile ID." ) );
522 emit q->fetchedProfileId( QString() );
523 }
524 } else {
525 kError() << "Job Error: " << job->errorString();
526 emit q->error( GData::Other, job->errorString() );
527 emit q->fetchedProfileId( QString() );
528 }
529}
530
531void GDataPrivate::slotListBlogs( Syndication::Loader *loader,
532 Syndication::FeedPtr feed,
533 Syndication::ErrorCode status ) {
534 kDebug();
535 Q_Q( GData );
536 if ( !loader ) {
537 kError() << "loader is a null pointer.";
538 return;
539 }
540 if ( status != Syndication::Success ) {
541 emit q->error( GData::Atom, i18n( "Could not get blogs." ) );
542 return;
543 }
544
545 QList<QMap<QString,QString> > blogsList;
546
547 QList<Syndication::ItemPtr> items = feed->items();
548 QList<Syndication::ItemPtr>::ConstIterator it = items.constBegin();
549 QList<Syndication::ItemPtr>::ConstIterator end = items.constEnd();
550 for ( ; it != end; ++it ) {
551 QRegExp rx( QLatin1String("blog-(\\d+)") );
552 QMap<QString,QString> blogInfo;
553 if ( rx.indexIn( ( *it )->id() ) != -1 ) {
554 kDebug() << "QRegExp rx( 'blog-(\\d+)' matches" << rx.cap( 1 );
555 blogInfo[QLatin1String("id")] = rx.cap( 1 );
556 blogInfo[QLatin1String("title")] = ( *it )->title();
557 blogInfo[QLatin1String("url")] = ( *it )->link();
558 blogInfo[QLatin1String("summary")] = ( *it )->description(); //TODO fix/add more
559 blogsList << blogInfo;
560 } else {
561 kError() << "QRegExp rx( 'blog-(\\d+)' does not match anything in:"
562 << ( *it )->id();
563 emit q->error( GData::Other, i18n( "Could not regexp the blog id path." ) );
564 }
565 }
566 kDebug() << "Emitting listedBlogs(); ";
567 emit q->listedBlogs( blogsList );
568}
569
570void GDataPrivate::slotListComments( Syndication::Loader *loader,
571 Syndication::FeedPtr feed,
572 Syndication::ErrorCode status )
573{
574 kDebug();
575 Q_Q( GData );
576 if ( !loader ) {
577 kError() << "loader is a null pointer.";
578 return;
579 }
580 BlogPost *post = mListCommentsMap[ loader ];
581 mListCommentsMap.remove( loader );
582
583 if ( status != Syndication::Success ) {
584 emit q->errorPost( GData::Atom, i18n( "Could not get comments." ), post );
585 return;
586 }
587
588 QList<KBlog::BlogComment> commentList;
589
590 QList<Syndication::ItemPtr> items = feed->items();
591 QList<Syndication::ItemPtr>::ConstIterator it = items.constBegin();
592 QList<Syndication::ItemPtr>::ConstIterator end = items.constEnd();
593 for ( ; it != end; ++it ) {
594 BlogComment comment;
595 QRegExp rx( QLatin1String("post-(\\d+)") );
596 if ( rx.indexIn( ( *it )->id() ) == -1 ) {
597 kError() << "QRegExp rx( 'post-(\\d+)' does not match" << rx.cap( 1 );
598 emit q->error( GData::Other, i18n( "Could not regexp the comment id path." ) );
599 } else {
600 comment.setCommentId( rx.cap( 1 ) );
601 }
602 kDebug() << "QRegExp rx( 'post-(\\d+)' matches" << rx.cap( 1 );
603 comment.setTitle( ( *it )->title() );
604 comment.setContent( ( *it )->content() );
605// FIXME: assuming UTC for now
606 comment.setCreationDateTime(
607 KDateTime( QDateTime::fromTime_t( ( *it )->datePublished() ),
608 KDateTime::Spec::UTC() ) );
609 comment.setModificationDateTime(
610 KDateTime( QDateTime::fromTime_t( ( *it )->dateUpdated() ),
611 KDateTime::Spec::UTC() ) );
612 commentList.append( comment );
613 }
614 kDebug() << "Emitting listedComments()";
615 emit q->listedComments( post, commentList );
616}
617
618void GDataPrivate::slotListAllComments( Syndication::Loader *loader,
619 Syndication::FeedPtr feed,
620 Syndication::ErrorCode status )
621{
622 kDebug();
623 Q_Q( GData );
624 if ( !loader ) {
625 kError() << "loader is a null pointer.";
626 return;
627 }
628
629 if ( status != Syndication::Success ) {
630 emit q->error( GData::Atom, i18n( "Could not get comments." ) );
631 return;
632 }
633
634 QList<KBlog::BlogComment> commentList;
635
636 QList<Syndication::ItemPtr> items = feed->items();
637 QList<Syndication::ItemPtr>::ConstIterator it = items.constBegin();
638 QList<Syndication::ItemPtr>::ConstIterator end = items.constEnd();
639 for ( ; it != end; ++it ) {
640 BlogComment comment;
641 QRegExp rx( QLatin1String("post-(\\d+)") );
642 if ( rx.indexIn( ( *it )->id() ) == -1 ) {
643 kError() << "QRegExp rx( 'post-(\\d+)' does not match" << rx.cap( 1 );
644 emit q->error( GData::Other, i18n( "Could not regexp the comment id path." ) );
645 } else {
646 comment.setCommentId( rx.cap( 1 ) );
647 }
648
649 kDebug() << "QRegExp rx( 'post-(\\d+)' matches" << rx.cap( 1 );
650 comment.setTitle( ( *it )->title() );
651 comment.setContent( ( *it )->content() );
652// FIXME: assuming UTC for now
653 comment.setCreationDateTime(
654 KDateTime( QDateTime::fromTime_t( ( *it )->datePublished() ),
655 KDateTime::Spec::UTC() ) );
656 comment.setModificationDateTime(
657 KDateTime( QDateTime::fromTime_t( ( *it )->dateUpdated() ),
658 KDateTime::Spec::UTC() ) );
659 commentList.append( comment );
660 }
661 kDebug() << "Emitting listedAllComments()";
662 emit q->listedAllComments( commentList );
663}
664
665void GDataPrivate::slotListRecentPosts( Syndication::Loader *loader,
666 Syndication::FeedPtr feed,
667 Syndication::ErrorCode status ) {
668 kDebug();
669 Q_Q( GData );
670 if ( !loader ) {
671 kError() << "loader is a null pointer.";
672 return;
673 }
674
675 if ( status != Syndication::Success ) {
676 emit q->error( GData::Atom, i18n( "Could not get posts." ) );
677 return;
678 }
679 int number = 0;
680
681 if ( mListRecentPostsMap.contains( loader ) ) {
682 number = mListRecentPostsMap[ loader ];
683 }
684 mListRecentPostsMap.remove( loader );
685
686 QList<KBlog::BlogPost> postList;
687
688 QList<Syndication::ItemPtr> items = feed->items();
689 QList<Syndication::ItemPtr>::ConstIterator it = items.constBegin();
690 QList<Syndication::ItemPtr>::ConstIterator end = items.constEnd();
691 for ( ; it != end; ++it ) {
692 BlogPost post;
693 QRegExp rx( QLatin1String("post-(\\d+)") );
694 if ( rx.indexIn( ( *it )->id() ) == -1 ) {
695 kError() << "QRegExp rx( 'post-(\\d+)' does not match" << rx.cap( 1 );
696 emit q->error( GData::Other, i18n( "Could not regexp the post id path." ) );
697 } else {
698 post.setPostId( rx.cap( 1 ) );
699 }
700
701 kDebug() << "QRegExp rx( 'post-(\\d+)' matches" << rx.cap( 1 );
702 post.setTitle( ( *it )->title() );
703 post.setContent( ( *it )->content() );
704 post.setLink( ( *it )->link() );
705 QStringList labels;
706 int catCount = ( *it )->categories().count();
707 QList< Syndication::CategoryPtr > cats = ( *it )->categories();
708 for ( int i=0; i < catCount; ++i ) {
709 if ( cats[i].get()->label().isEmpty() ) {
710 labels.append( cats[i].get()->term() );
711 } else {
712 labels.append( cats[i].get()->label() );
713 }
714 }
715 post.setTags( labels );
716// FIXME: assuming UTC for now
717 post.setCreationDateTime(
718 KDateTime( QDateTime::fromTime_t( ( *it )->datePublished() ),
719 KDateTime::Spec::UTC() ).toLocalZone() );
720 post.setModificationDateTime(
721 KDateTime( QDateTime::fromTime_t( ( *it )->dateUpdated() ),
722 KDateTime::Spec::UTC() ).toLocalZone() );
723 post.setStatus( BlogPost::Fetched );
724 postList.append( post );
725 if ( number-- == 0 ) {
726 break;
727 }
728 }
729 kDebug() << "Emitting listedRecentPosts()";
730 emit q->listedRecentPosts( postList );
731}
732
733void GDataPrivate::slotFetchPost( Syndication::Loader *loader,
734 Syndication::FeedPtr feed,
735 Syndication::ErrorCode status )
736{
737 kDebug();
738 Q_Q( GData );
739 if ( !loader ) {
740 kError() << "loader is a null pointer.";
741 return;
742 }
743
744 bool success = false;
745
746 BlogPost *post = mFetchPostMap.take( loader );
747 kError() << "Post" << post;
748 post->postId();
749
750 if ( status != Syndication::Success ) {
751 emit q->errorPost( GData::Atom, i18n( "Could not get posts." ), post );
752 return;
753 }
754
755 QString postId = post->postId();
756 QList<Syndication::ItemPtr> items = feed->items();
757 QList<Syndication::ItemPtr>::ConstIterator it = items.constBegin();
758 QList<Syndication::ItemPtr>::ConstIterator end = items.constEnd();
759 for ( ; it != end; ++it ) {
760 QRegExp rx( QLatin1String("post-(\\d+)") );
761 if ( rx.indexIn( ( *it )->id() ) != -1 &&
762 rx.cap( 1 ) == postId ) {
763 kDebug() << "QRegExp rx( 'post-(\\d+)' matches" << rx.cap( 1 );
764 post->setPostId( rx.cap( 1 ) );
765 post->setTitle( ( *it )->title() );
766 post->setContent( ( *it )->content() );
767 post->setStatus( BlogPost::Fetched );
768 post->setLink( ( *it )->link() );
769 post->setCreationDateTime(
770 KDateTime( QDateTime::fromTime_t( ( *it )->datePublished() ),
771 KDateTime::Spec::UTC() ).toLocalZone() );
772 post->setModificationDateTime(
773 KDateTime( QDateTime::fromTime_t( ( *it )->dateUpdated() ),
774 KDateTime::Spec::UTC() ).toLocalZone() );
775 kDebug() << "Emitting fetchedPost( postId=" << postId << ");";
776 success = true;
777 emit q->fetchedPost( post );
778 break;
779 }
780 }
781 if ( !success ) {
782 kError() << "QRegExp rx( 'post-(\\d+)' does not match"
783 << mFetchPostMap[ loader ]->postId() << ".";
784 emit q->errorPost( GData::Other, i18n( "Could not regexp the blog id path." ), post );
785 }
786}
787
788void GDataPrivate::slotCreatePost( KJob *job )
789{
790 kDebug();
791 if ( !job ) {
792 kError() << "job is a null pointer.";
793 return;
794 }
795 KIO::StoredTransferJob *stj = qobject_cast<KIO::StoredTransferJob*>( job );
796 const QString data = QString::fromUtf8( stj->data(), stj->data().size() );
797
798 Q_Q( GData );
799
800 KBlog::BlogPost *post = mCreatePostMap[ job ];
801 mCreatePostMap.remove( job );
802
803 if ( job->error() != 0 ) {
804 kError() << "slotCreatePost error:" << job->errorString();
805 emit q->errorPost( GData::Atom, job->errorString(), post );
806 return;
807 }
808
809 QRegExp rxId( QLatin1String("post-(\\d+)") ); //FIXME check and do better handling, esp the creation date time
810 if ( rxId.indexIn( data ) == -1 ) {
811 kError() << "Could not regexp the id out of the result:" << data;
812 emit q->errorPost( GData::Atom,
813 i18n( "Could not regexp the id out of the result." ), post );
814 return;
815 }
816 kDebug() << "QRegExp rx( 'post-(\\d+)' ) matches" << rxId.cap( 1 );
817
818 QRegExp rxPub( QLatin1String("<published>(.+)</published>") );
819 if ( rxPub.indexIn( data ) == -1 ) {
820 kError() << "Could not regexp the published time out of the result:" << data;
821 emit q->errorPost( GData::Atom,
822 i18n( "Could not regexp the published time out of the result." ), post );
823 return;
824 }
825 kDebug() << "QRegExp rx( '<published>(.+)</published>' ) matches" << rxPub.cap( 1 );
826
827 QRegExp rxUp( QLatin1String("<updated>(.+)</updated>") );
828 if ( rxUp.indexIn( data ) == -1 ) {
829 kError() << "Could not regexp the update time out of the result:" << data;
830 emit q->errorPost( GData::Atom,
831 i18n( "Could not regexp the update time out of the result." ), post );
832 return;
833 }
834 kDebug() << "QRegExp rx( '<updated>(.+)</updated>' ) matches" << rxUp.cap( 1 );
835
836 post->setPostId( rxId.cap( 1 ) );
837 post->setCreationDateTime( KDateTime().fromString( rxPub.cap( 1 ) ).toLocalZone() );
838 post->setModificationDateTime( KDateTime().fromString( rxUp.cap( 1 ) ) );
839 post->setStatus( BlogPost::Created );
840 kDebug() << "Emitting createdPost()";
841 emit q->createdPost( post );
842}
843
844void GDataPrivate::slotModifyPost( KJob *job )
845{
846 kDebug();
847 if ( !job ) {
848 kError() << "job is a null pointer.";
849 return;
850 }
851 KIO::StoredTransferJob *stj = qobject_cast<KIO::StoredTransferJob*>( job );
852 const QString data = QString::fromUtf8( stj->data(), stj->data().size() );
853
854 KBlog::BlogPost *post = mModifyPostMap[ job ];
855 mModifyPostMap.remove( job );
856 Q_Q( GData );
857 if ( job->error() != 0 ) {
858 kError() << "slotModifyPost error:" << job->errorString();
859 emit q->errorPost( GData::Atom, job->errorString(), post );
860 return;
861 }
862
863 QRegExp rxId( QLatin1String("post-(\\d+)") ); //FIXME check and do better handling, esp creation date time
864 if ( rxId.indexIn( data ) == -1 ) {
865 kError() << "Could not regexp the id out of the result:" << data;
866 emit q->errorPost( GData::Atom,
867 i18n( "Could not regexp the id out of the result." ), post );
868 return;
869 }
870 kDebug() << "QRegExp rx( 'post-(\\d+)' ) matches" << rxId.cap( 1 );
871
872 QRegExp rxPub( QLatin1String("<published>(.+)</published>") );
873 if ( rxPub.indexIn( data ) == -1 ) {
874 kError() << "Could not regexp the published time out of the result:" << data;
875 emit q->errorPost( GData::Atom,
876 i18n( "Could not regexp the published time out of the result." ), post );
877 return;
878 }
879 kDebug() << "QRegExp rx( '<published>(.+)</published>' ) matches" << rxPub.cap( 1 );
880
881 QRegExp rxUp( QLatin1String("<updated>(.+)</updated>") );
882 if ( rxUp.indexIn( data ) == -1 ) {
883 kError() << "Could not regexp the update time out of the result:" << data;
884 emit q->errorPost( GData::Atom,
885 i18n( "Could not regexp the update time out of the result." ), post );
886 return;
887 }
888 kDebug() << "QRegExp rx( '<updated>(.+)</updated>' ) matches" << rxUp.cap( 1 );
889 post->setPostId( rxId.cap( 1 ) );
890 post->setCreationDateTime( KDateTime().fromString( rxPub.cap( 1 ) ) );
891 post->setModificationDateTime( KDateTime().fromString( rxUp.cap( 1 ) ) );
892 post->setStatus( BlogPost::Modified );
893 emit q->modifiedPost( post );
894}
895
896void GDataPrivate::slotRemovePost( KJob *job )
897{
898 kDebug();
899 if ( !job ) {
900 kError() << "job is a null pointer.";
901 return;
902 }
903 KIO::StoredTransferJob *stj = qobject_cast<KIO::StoredTransferJob*>( job );
904 const QString data = QString::fromUtf8( stj->data(), stj->data().size() );
905
906 KBlog::BlogPost *post = mRemovePostMap[ job ];
907 mRemovePostMap.remove( job );
908 Q_Q( GData );
909 if ( job->error() != 0 ) {
910 kError() << "slotRemovePost error:" << job->errorString();
911 emit q->errorPost( GData::Atom, job->errorString(), post );
912 return;
913 }
914
915 post->setStatus( BlogPost::Removed );
916 kDebug() << "Emitting removedPost()";
917 emit q->removedPost( post );
918}
919
920void GDataPrivate::slotCreateComment( KJob *job )
921{
922 kDebug();
923 if ( !job ) {
924 kError() << "job is a null pointer.";
925 return;
926 }
927 KIO::StoredTransferJob *stj = qobject_cast<KIO::StoredTransferJob*>( job );
928 const QString data = QString::fromUtf8( stj->data(), stj->data().size() );
929 kDebug() << "Dump data: " << data;
930
931 Q_Q( GData );
932
933 KBlog::BlogComment *comment = mCreateCommentMap[ job ].values().first();
934 KBlog::BlogPost *post = mCreateCommentMap[ job ].keys().first();
935 mCreateCommentMap.remove( job );
936
937 if ( job->error() != 0 ) {
938 kError() << "slotCreateComment error:" << job->errorString();
939 emit q->errorComment( GData::Atom, job->errorString(), post, comment );
940 return;
941 }
942
943// TODO check for result and fit appropriately
944 QRegExp rxId( QLatin1String("post-(\\d+)") );
945 if ( rxId.indexIn( data ) == -1 ) {
946 kError() << "Could not regexp the id out of the result:" << data;
947 emit q->errorPost( GData::Atom,
948 i18n( "Could not regexp the id out of the result." ), post );
949 return;
950 }
951 kDebug() << "QRegExp rx( 'post-(\\d+)' ) matches" << rxId.cap( 1 );
952
953 QRegExp rxPub( QLatin1String("<published>(.+)</published>") );
954 if ( rxPub.indexIn( data ) == -1 ) {
955 kError() << "Could not regexp the published time out of the result:" << data;
956 emit q->errorPost( GData::Atom,
957 i18n( "Could not regexp the published time out of the result." ), post );
958 return;
959 }
960 kDebug() << "QRegExp rx( '<published>(.+)</published>' ) matches" << rxPub.cap( 1 );
961
962 QRegExp rxUp( QLatin1String("<updated>(.+)</updated>") );
963 if ( rxUp.indexIn( data ) == -1 ) {
964 kError() << "Could not regexp the update time out of the result:" << data;
965 emit q->errorPost( GData::Atom,
966 i18n( "Could not regexp the update time out of the result." ), post );
967 return;
968 }
969 kDebug() << "QRegExp rx( '<updated>(.+)</updated>' ) matches" << rxUp.cap( 1 );
970 comment->setCommentId( rxId.cap( 1 ) );
971 comment->setCreationDateTime( KDateTime().fromString( rxPub.cap( 1 ) ) );
972 comment->setModificationDateTime( KDateTime().fromString( rxUp.cap( 1 ) ) );
973 comment->setStatus( BlogComment::Created );
974 kDebug() << "Emitting createdComment()";
975 emit q->createdComment( post, comment );
976}
977
978void GDataPrivate::slotRemoveComment( KJob *job )
979{
980 kDebug();
981 if ( !job ) {
982 kError() << "job is a null pointer.";
983 return;
984 }
985 KIO::StoredTransferJob *stj = qobject_cast<KIO::StoredTransferJob*>( job );
986 const QString data = QString::fromUtf8( stj->data(), stj->data().size() );
987
988 Q_Q( GData );
989
990 KBlog::BlogComment *comment = mRemoveCommentMap[ job ].values().first();
991 KBlog::BlogPost *post = mRemoveCommentMap[ job ].keys().first();
992 mRemoveCommentMap.remove( job );
993
994 if ( job->error() != 0 ) {
995 kError() << "slotRemoveComment error:" << job->errorString();
996 emit q->errorComment( GData::Atom, job->errorString(), post, comment );
997 return;
998 }
999
1000 comment->setStatus( BlogComment::Created );
1001 kDebug() << "Emitting removedComment()";
1002 emit q->removedComment( post, comment );
1003}
1004
1005#include "moc_gdata.cpp"
1006