File indexing completed on 2023-10-03 07:22:42

0001 /* ============================================================
0002  *
0003  * This file is a part of KDE project
0004  *
0005  *
0006  * Date        : 2008-12-26
0007  * Description : a kipi plugin to export images to Facebook web service
0008  *
0009  * Copyright (C) 2008-2010 by Luka Renko <lure at kubuntu dot org>
0010  * Copyright (c) 2011      by Dirk Tilger <dirk.kde@miriup.de>
0011  *
0012  * This program is free software; you can redistribute it
0013  * and/or modify it under the terms of the GNU General
0014  * Public License as published by the Free Software Foundation;
0015  * either version 2, or (at your option) any later version.
0016  *
0017  * This program is distributed in the hope that it will be useful,
0018  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0019  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0020  * GNU General Public License for more details.
0021  *
0022  * ============================================================ */
0023 
0024 #include "fbtalker.h"
0025 
0026 // C++ includes
0027 
0028 #include <ctime>
0029 
0030 // Qt includes
0031 
0032 #include <QJsonDocument>
0033 #include <QJsonParseError>
0034 #include <QJsonObject>
0035 #include <QJsonValue>
0036 #include <QJsonArray>
0037 #include <QByteArray>
0038 #include <QDomDocument>
0039 #include <QDomElement>
0040 #include <QtAlgorithms>
0041 #include <QVBoxLayout>
0042 #include <QLineEdit>
0043 #include <QPlainTextEdit>
0044 #include <QList>
0045 #include <QDesktopServices>
0046 #include <QApplication>
0047 #include <QPushButton>
0048 #include <QDialog>
0049 #include <QDialogButtonBox>
0050 #include <QUrlQuery>
0051 #include <QMessageBox>
0052 
0053 // Local includes
0054 
0055 #include "kpversion.h"
0056 #include "fbitem.h"
0057 #include "mpform.h"
0058 #include "kipiplugins_debug.h"
0059 
0060 namespace KIPIFacebookPlugin
0061 {
0062 
0063 bool operator< (const FbUser& first, const FbUser& second)
0064 {
0065     return first.name < second.name;
0066 }
0067 
0068 bool operator< (const FbAlbum& first, const FbAlbum& second)
0069 {
0070     return first.title < second.title;
0071 }
0072 
0073 // -----------------------------------------------------------------------------
0074 
0075 FbTalker::FbTalker(QWidget* const parent)
0076 {
0077     m_parent          = parent;
0078     m_loginInProgress = 0;
0079     m_sessionExpires  = 0;
0080     m_state           = FB_GETLOGGEDINUSER;
0081 
0082     m_apiVersion      = QString::fromLatin1("2.4");
0083     m_apiURL          = QUrl(QString::fromLatin1("https://graph.facebook.com"));
0084     m_secretKey       = QString::fromLatin1("5b0b5cd096e110cd4f4c72f517e2c544");
0085     m_appID           = QString::fromLatin1("400589753481372");
0086     m_dialog          = nullptr;
0087     m_reply           = nullptr;
0088 
0089     m_netMngr         = new QNetworkAccessManager(this);
0090 
0091     connect(m_netMngr, SIGNAL(finished(QNetworkReply*)),
0092             this, SLOT(slotFinished(QNetworkReply*)));
0093 }
0094 
0095 FbTalker::~FbTalker()
0096 {
0097     // do not logout - may reuse session for next upload
0098 
0099     if (m_reply)
0100     {
0101         m_reply->abort();
0102     }
0103 }
0104 
0105 bool FbTalker::loggedIn() const
0106 {
0107     return !m_accessToken.isEmpty();
0108 }
0109 
0110 QString FbTalker::getAccessToken() const
0111 {
0112     return m_accessToken;
0113 }
0114 
0115 unsigned int FbTalker::getSessionExpires() const
0116 {
0117     return m_sessionExpires;
0118 }
0119 
0120 FbUser FbTalker::getUser() const
0121 {
0122     return m_user;
0123 }
0124 
0125 void FbTalker::cancel()
0126 {
0127     if (m_reply)
0128     {
0129         m_reply->abort();
0130         m_reply = nullptr;
0131     }
0132 
0133     Q_EMIT signalBusy(false);
0134 }
0135 
0136 /** Compute MD5 signature using url queries keys and values:
0137     http://wiki.developers.facebook.com/index.php/How_Facebook_Authenticates_Your_Application
0138     This method was used for the legacy authentication scheme and has been obsoleted with OAuth2 authentication.
0139 */
0140 /*
0141 QString FbTalker::getApiSig(const QMap<QString, QString>& args)
0142 {
0143     QString concat;
0144     // NOTE: QMap iterator will sort alphabetically
0145     for (QMap<QString, QString>::const_iterator it = args.constBegin();
0146          it != args.constEnd();
0147          ++it)
0148     {
0149         concat.append(it.key());
0150         concat.append("=");
0151         concat.append(it.value());
0152     }
0153     if (args["session_key"].isEmpty())
0154         concat.append(m_secretKey);
0155     else
0156         concat.append(m_sessionSecret);
0157 
0158     KMD5 md5(concat.toUtf8());
0159     return md5.hexDigest().data();
0160 }
0161 */
0162 
0163 QString FbTalker::getCallString(const QMap<QString, QString>& args)
0164 {
0165     QString concat;
0166     QUrl url;
0167     QUrlQuery q;
0168 
0169     // NOTE: QMap iterator will sort alphabetically
0170     for (QMap<QString, QString>::const_iterator it = args.constBegin();
0171          it != args.constEnd();
0172          ++it)
0173     {
0174         /*if (!concat.isEmpty())
0175             concat.append("&");*/
0176 
0177         /*concat.append(it.key());
0178         concat.append("=");
0179         concat.append(it.value());*/
0180         q.addQueryItem(it.key(), it.value());
0181         url.setQuery(q);
0182     }
0183     concat.append(url.query());
0184 
0185     qCDebug(KIPIPLUGINS_LOG) << "CALL: " << concat;
0186 
0187     return concat;
0188 }
0189 
0190 void FbTalker::authenticate(const QString &accessToken, unsigned int sessionExpires)
0191 {
0192     m_loginInProgress = true;
0193 
0194     if (!accessToken.isEmpty() && ( sessionExpires == 0 || sessionExpires > (unsigned int)(time(nullptr) + 900)))
0195     {
0196         // sessionKey seems to be still valid for at least 15 minutes
0197         // - check if it still works
0198         m_accessToken    = accessToken;
0199         m_sessionExpires = sessionExpires;
0200 
0201         Q_EMIT signalLoginProgress(2, 9, i18n("Validate previous session..."));
0202 
0203         // get logged in user - this will check if session is still valid
0204         getLoggedInUser();
0205     }
0206     else
0207     {
0208         // session expired -> get new authorization token and session
0209         doOAuth();
0210     }
0211 }
0212 
0213 /**
0214  * upgrade session key to OAuth
0215  *
0216  * This method (or step) can be removed after June 2012 (a year after its
0217  * implementation), since it is only a convenience method for those people
0218  * who just upgraded and have an active session using the old authentication.
0219  */
0220 void FbTalker::exchangeSession(const QString& sessionKey)
0221 {
0222     if (m_reply)
0223     {
0224         m_reply->abort();
0225         m_reply = nullptr;
0226     }
0227 
0228     Q_EMIT signalBusy(true);
0229     Q_EMIT signalLoginProgress(1, 9, i18n("Upgrading to OAuth..."));
0230 
0231     QMap<QString, QString> args;
0232     args[QString::fromLatin1("client_id")]     = m_appID;
0233     args[QString::fromLatin1("client_secret")] = m_secretKey;
0234     args[QString::fromLatin1("sessions")]      = sessionKey;
0235 
0236     QByteArray tmp(getCallString(args).toUtf8());
0237 
0238     QNetworkRequest netRequest(QUrl(QLatin1String("https://graph.facebook.com/oauth/exchange_sessions")));
0239     netRequest.setHeader(QNetworkRequest::ContentTypeHeader, QLatin1String("application/x-www-form-urlencoded"));
0240 
0241     m_reply = m_netMngr->post(netRequest, tmp);
0242 
0243     m_state = FB_EXCHANGESESSION;
0244     m_buffer.resize(0);
0245 }
0246 
0247 /**
0248  * Authenticate using OAuth
0249  *
0250  * TODO (Dirk): There's some GUI code slipped in here,
0251  * that really doesn't feel like it's belonging here.
0252  */
0253 void FbTalker::doOAuth()
0254 {
0255     // just in case
0256     m_loginInProgress = true;
0257 
0258     // TODO (Dirk):
0259     // Find out whether this signalBusy is used here appropriately.
0260     Q_EMIT signalBusy(true);
0261 
0262     QUrl url(QString::fromLatin1("https://www.facebook.com/dialog/oauth"));
0263     QUrlQuery q(url);
0264     q.addQueryItem(QString::fromLatin1("client_id"), m_appID);
0265     q.addQueryItem(QString::fromLatin1("redirect_uri"),
0266                      QString::fromLatin1("https://www.facebook.com/connect/login_success.html"));
0267     // TODO (Dirk): Check which of these permissions can be optional.
0268     q.addQueryItem(QString::fromLatin1("scope"),
0269                      QString::fromLatin1("user_photos,publish_actions,user_friends"));
0270     q.addQueryItem(QString::fromLatin1("response_type"), QString::fromLatin1("token"));
0271     url.setQuery(q);
0272     qCDebug(KIPIPLUGINS_LOG) << "OAuth URL: " << url;
0273     QDesktopServices::openUrl(url);
0274 
0275     Q_EMIT signalBusy(false);
0276 
0277     m_dialog = new QDialog(QApplication::activeWindow(), {});
0278     m_dialog->setModal(true);
0279     m_dialog->setWindowTitle(i18n("Facebook Application Authorization"));
0280     QLineEdit* const textbox        = new QLineEdit();
0281     QDialogButtonBox* const buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, m_dialog);
0282     buttons->button(QDialogButtonBox::Ok)->setDefault(true);
0283 
0284     m_dialog->connect(buttons, SIGNAL(accepted()),
0285                       this, SLOT(slotAccept()));
0286 
0287     m_dialog->connect(buttons, SIGNAL(rejected()),
0288                       this, SLOT(slotReject()));
0289 
0290     QPlainTextEdit* const infobox = new QPlainTextEdit(i18n("Please follow the instructions in the browser window. "
0291                                                             "When done, copy the Internet address from your browser into the textbox below and press \"OK\"."));
0292     infobox->setReadOnly(true);
0293 
0294     QVBoxLayout* const vbx = new QVBoxLayout(m_dialog);
0295     vbx->addWidget(infobox);
0296     vbx->addWidget(textbox);
0297     vbx->addWidget(buttons);
0298     m_dialog->setLayout(vbx);
0299 
0300     m_dialog->exec();
0301 
0302     if( m_dialog->result()  == QDialog::Accepted )
0303     {
0304         // Error code and reason from the Facebook service
0305         QString errorReason;
0306         QString errorCode;
0307 
0308         url                        = QUrl( textbox->text() );
0309         QString fragment           = url.fragment();
0310         qCDebug(KIPIPLUGINS_LOG) << "Split out the fragment from the URL: " << fragment;
0311         QStringList params         = fragment.split(QLatin1Char('&'));
0312         QList<QString>::iterator i = params.begin();
0313 
0314         while( i != params.end() )
0315         {
0316             QStringList keyvalue = (*i).split(QLatin1Char('='));
0317 
0318             if( keyvalue.size() == 2 )
0319             {
0320                 if( ! keyvalue[0].compare( QString::fromLatin1("access_token") ) )
0321                 {
0322                     m_accessToken = keyvalue[1];
0323                 }
0324                 else if( ! keyvalue[0].compare( QString::fromLatin1("expires_in") ) )
0325                 {
0326                     m_sessionExpires = keyvalue[1].toUInt();
0327 
0328                     if( m_sessionExpires != 0 )
0329                     {
0330                         m_sessionExpires += QDateTime::currentMSecsSinceEpoch() / 1000;
0331                     }
0332                 }
0333                 else if( ! keyvalue[0].compare( QString::fromLatin1("error_reason") ) )
0334                 {
0335                     errorReason = keyvalue[1];
0336                 }
0337                 else if( ! keyvalue[0].compare( QString::fromLatin1("error") ) )
0338                 {
0339                     errorCode = keyvalue[1];
0340                 }
0341             }
0342 
0343             ++i;
0344         }
0345 
0346         if( !m_accessToken.isEmpty() && errorCode.isEmpty() && errorReason.isEmpty() )
0347         {
0348             return getLoggedInUser();
0349         }
0350     }
0351 
0352     authenticationDone(-1, i18n("Canceled by user."));
0353 
0354     // TODO (Dirk): Correct?
0355     Q_EMIT signalBusy(false);
0356 }
0357 
0358 void FbTalker::getLoggedInUser()
0359 {
0360     if (m_reply)
0361     {
0362         m_reply->abort();
0363         m_reply = nullptr;
0364     }
0365 
0366     Q_EMIT signalBusy(true);
0367     Q_EMIT signalLoginProgress(3);
0368 
0369     QUrl url(QString::fromLatin1("https://graph.facebook.com/me"));
0370     QUrlQuery q;
0371     q.addQueryItem(QString::fromLatin1("access_token"), m_accessToken);
0372     q.addQueryItem(QString::fromLatin1("fields"), QString::fromLatin1("id,name,link"));
0373     url.setQuery(q);
0374 
0375     QNetworkRequest netRequest(url);
0376     netRequest.setHeader(QNetworkRequest::ContentTypeHeader, QLatin1String("application/x-www-form-urlencoded"));
0377 
0378     m_reply = m_netMngr->get(netRequest);
0379 
0380     m_state = FB_GETLOGGEDINUSER;
0381     m_buffer.resize(0);
0382 }
0383 
0384 void FbTalker::logout()
0385 {
0386     if (m_reply)
0387     {
0388         m_reply->abort();
0389         m_reply = nullptr;
0390     }
0391 
0392     QMap<QString, QString> args;
0393     args[QString::fromLatin1("next")] = QString::fromLatin1("http://www.kde.org");
0394     args[QString::fromLatin1("access_token")] = m_accessToken;
0395 
0396     QUrl url(QString::fromLatin1("https://www.facebook.com/logout.php"));
0397     QUrlQuery q;
0398     q.addQueryItem(QString::fromLatin1("next"), QString::fromLatin1("http://www.kde.org"));
0399     q.addQueryItem(QString::fromLatin1("access_token"), m_accessToken);
0400     url.setQuery(q);
0401     qCDebug(KIPIPLUGINS_LOG) << "Logout URL: " << url;
0402     QDesktopServices::openUrl(url);
0403 
0404     Q_EMIT signalBusy(false);
0405 }
0406 
0407 void FbTalker::listAlbums(long long userID)
0408 {
0409     qCDebug(KIPIPLUGINS_LOG) << "Requesting albums for user " << userID;
0410 
0411     if (m_reply)
0412     {
0413         m_reply->abort();
0414         m_reply = nullptr;
0415     }
0416 
0417     Q_EMIT signalBusy(true);
0418 
0419     QUrl url(QString::fromLatin1("https://graph.facebook.com/me/albums"));
0420     QUrlQuery q;
0421     q.addQueryItem(QString::fromLatin1("fields"),
0422                      QString::fromLatin1("id,name,description,privacy,link,location"));
0423     q.addQueryItem(QString::fromLatin1("access_token"), m_accessToken);
0424     url.setQuery(q);
0425 
0426     QNetworkRequest netRequest(url);
0427     netRequest.setHeader(QNetworkRequest::ContentTypeHeader, QLatin1String("application/x-www-form-urlencoded"));
0428 
0429     m_reply = m_netMngr->get(netRequest);
0430 
0431     m_state = FB_LISTALBUMS;
0432     m_buffer.resize(0);
0433 }
0434 
0435 void FbTalker::createAlbum(const FbAlbum& album)
0436 {
0437     if (m_reply)
0438     {
0439         m_reply->abort();
0440         m_reply = nullptr;
0441     }
0442 
0443     Q_EMIT signalBusy(true);
0444 
0445     QMap<QString, QString> args;
0446     args[QString::fromLatin1("access_token")] = m_accessToken;
0447     args[QString::fromLatin1("name")]         = album.title;
0448 
0449     if (!album.location.isEmpty())
0450         args[QString::fromLatin1("location")] = album.location;
0451     if (!album.description.isEmpty())
0452         args[QString::fromLatin1("description")] = album.description;
0453 
0454     // TODO (Dirk): Wasn't that a requested feature in Bugzilla?
0455     switch (album.privacy)
0456     {
0457         case FB_ME:
0458             args[QString::fromLatin1("privacy")] = QString::fromLatin1("{'value':'SELF'}");
0459             break;
0460         case FB_FRIENDS:
0461             args[QString::fromLatin1("visible")] = QString::fromLatin1("friends");
0462             break;
0463         case FB_FRIENDS_OF_FRIENDS:
0464             args[QString::fromLatin1("visible")] = QString::fromLatin1("friends-of-friends");
0465             break;
0466         case FB_NETWORKS:
0467             args[QString::fromLatin1("visible")] = QString::fromLatin1("networks");
0468             break;
0469         case FB_EVERYONE:
0470             args[QString::fromLatin1("visible")] = QString::fromLatin1("everyone");
0471             break;
0472         case FB_CUSTOM:
0473             //TODO
0474             args[QString::fromLatin1("privacy")] = QString::fromLatin1("{'value':'CUSTOM'}");
0475             break;
0476     }
0477 
0478     QByteArray tmp(getCallString(args).toUtf8());
0479 
0480     QNetworkRequest netRequest(QUrl(QLatin1String("https://graph.facebook.com/me/albums")));
0481     netRequest.setHeader(QNetworkRequest::ContentTypeHeader, QLatin1String("application/x-www-form-urlencoded"));
0482 
0483     m_reply = m_netMngr->post(netRequest, tmp);
0484 
0485     m_state = FB_CREATEALBUM;
0486     m_buffer.resize(0);
0487 }
0488 
0489 bool FbTalker::addPhoto(const QString& imgPath, const QString& albumID, const QString& caption)
0490 {
0491     qCDebug(KIPIPLUGINS_LOG) << "Adding photo " << imgPath << " to album with id "
0492              << albumID << " using caption '" << caption << "'";
0493 
0494     if (m_reply)
0495     {
0496         m_reply->abort();
0497         m_reply = nullptr;
0498     }
0499 
0500     Q_EMIT signalBusy(true);
0501 
0502     QMap<QString, QString> args;
0503     args[QString::fromLatin1("access_token")] = m_accessToken;
0504 
0505     if (!caption.isEmpty())
0506         args[QString::fromLatin1("message")]  = caption;
0507 
0508     MPForm form;
0509 
0510     for (QMap<QString, QString>::const_iterator it = args.constBegin();
0511          it != args.constEnd();
0512          ++it)
0513     {
0514         form.addPair(it.key(), it.value());
0515     }
0516 
0517     if (!form.addFile(QUrl::fromLocalFile(imgPath).fileName(), imgPath))
0518     {
0519         Q_EMIT signalBusy(false);
0520         return false;
0521     }
0522 
0523     form.finish();
0524 
0525     qCDebug(KIPIPLUGINS_LOG) << "FORM: " << Qt::endl << form.formData();
0526 
0527     QNetworkRequest netRequest(QUrl(QLatin1String("https://graph.facebook.com/v2.4/") +
0528                                     albumID + QLatin1String("/photos")));
0529     netRequest.setHeader(QNetworkRequest::ContentTypeHeader, form.contentType());
0530 
0531     m_reply = m_netMngr->post(netRequest, form.formData());
0532 
0533     m_state = FB_ADDPHOTO;
0534     m_buffer.resize(0);
0535     return true;
0536 }
0537 
0538 QString FbTalker::errorToText(int errCode, const QString &errMsg)
0539 {
0540     QString transError;
0541     qCDebug(KIPIPLUGINS_LOG) << "errorToText: " << errCode << ": " << errMsg;
0542 
0543     switch (errCode)
0544     {
0545         case 0:
0546             transError = QString::fromLatin1("");
0547             break;
0548         case 2:
0549             transError = i18n("The service is not available at this time.");
0550             break;
0551         case 4:
0552             transError = i18n("The application has reached the maximum number of requests allowed.");
0553             break;
0554         case 102:
0555             transError = i18n("Invalid session key or session expired. Try to log in again.");
0556             break;
0557         case 120:
0558             transError = i18n("Invalid album ID.");
0559             break;
0560         case 321:
0561             transError = i18n("Album is full.");
0562             break;
0563         case 324:
0564             transError = i18n("Missing or invalid file.");
0565             break;
0566         case 325:
0567             transError = i18n("Too many unapproved photos pending.");
0568             break;
0569         default:
0570             transError = errMsg;
0571             break;
0572     }
0573 
0574     return transError;
0575 }
0576 
0577 void FbTalker::slotFinished(QNetworkReply* reply)
0578 {
0579     if (reply != m_reply)
0580     {
0581         return;
0582     }
0583 
0584     m_reply = nullptr;
0585 
0586     if (reply->error() != QNetworkReply::NoError)
0587     {
0588         if (m_loginInProgress)
0589         {
0590             authenticationDone(reply->error(), reply->errorString());
0591         }
0592         else if (m_state == FB_ADDPHOTO)
0593         {
0594             Q_EMIT signalBusy(false);
0595             Q_EMIT signalAddPhotoDone(reply->error(), reply->errorString());
0596         }
0597         else
0598         {
0599             Q_EMIT signalBusy(false);
0600             QMessageBox::critical(QApplication::activeWindow(),
0601                                   i18n("Error"), reply->errorString());
0602         }
0603 
0604         reply->deleteLater();
0605         return;
0606     }
0607 
0608     m_buffer.append(reply->readAll());
0609 
0610     switch(m_state)
0611     {
0612         case (FB_EXCHANGESESSION):
0613             parseExchangeSession(m_buffer);
0614             break;
0615         case (FB_GETLOGGEDINUSER):
0616             parseResponseGetLoggedInUser(m_buffer);
0617             break;
0618         case (FB_LISTALBUMS):
0619             parseResponseListAlbums(m_buffer);
0620             break;
0621         case (FB_CREATEALBUM):
0622             parseResponseCreateAlbum(m_buffer);
0623             break;
0624         case (FB_ADDPHOTO):
0625             parseResponseAddPhoto(m_buffer);
0626             break;
0627     }
0628 
0629     reply->deleteLater();
0630 }
0631 
0632 void FbTalker::authenticationDone(int errCode, const QString &errMsg)
0633 {
0634     if (errCode != 0)
0635     {
0636         m_accessToken.clear();
0637         m_user.clear();
0638     }
0639 
0640     Q_EMIT signalBusy(false);
0641     Q_EMIT signalLoginDone(errCode, errMsg);
0642     m_loginInProgress = false;
0643 }
0644 
0645 int FbTalker::parseErrorResponse(const QDomElement& e, QString& errMsg)
0646 {
0647     int errCode = -1;
0648 
0649     for (QDomNode node = e.firstChild();
0650          !node.isNull();
0651          node = node.nextSibling())
0652     {
0653         if (!node.isElement())
0654             continue;
0655 
0656         if (node.nodeName() == QString::fromLatin1("error_code"))
0657         {
0658             errCode = node.toElement().text().toInt();
0659             qCDebug(KIPIPLUGINS_LOG) << "Error Code:" << errCode;
0660         }
0661         else if (node.nodeName() == QString::fromLatin1("error_msg"))
0662         {
0663             errMsg = node.toElement().text();
0664             qCDebug(KIPIPLUGINS_LOG) << "Error Text:" << errMsg;
0665         }
0666     }
0667 
0668     return errCode;
0669 }
0670 
0671 void FbTalker::parseExchangeSession(const QByteArray& data)
0672 {
0673     qCDebug(KIPIPLUGINS_LOG) << "Parse exchange_session response:" << Qt::endl << data;
0674     QJsonParseError err;
0675     QJsonDocument doc = QJsonDocument::fromJson(data, &err);
0676 
0677     if(err.error == QJsonParseError::NoError)
0678     {
0679         QJsonObject jsonObject = doc.object();
0680         m_accessToken       = jsonObject[QString::fromLatin1("access_token")].toString();
0681         m_sessionExpires    = jsonObject[QString::fromLatin1("expires")].toInt();
0682         if( m_sessionExpires != 0 )
0683         {
0684             m_sessionExpires += QDateTime::currentMSecsSinceEpoch() / 1000;
0685         }
0686 
0687         if( m_accessToken.isEmpty() )
0688             // Session did not convert. Reauthenticate.
0689             doOAuth();
0690         else
0691             // Session converted to OAuth. Proceed normally.
0692             getLoggedInUser();
0693     }
0694     else
0695     {
0696         int errCode = -1;
0697         QString errMsg(QString::fromLatin1("Parse Error"));
0698         authenticationDone(errCode, errorToText(errCode, errMsg));
0699     }
0700 }
0701 
0702 void FbTalker::parseResponseGetLoggedInUser(const QByteArray& data)
0703 {
0704     qCDebug(KIPIPLUGINS_LOG)<<"Logged in data "<<data;
0705     int errCode = -1;
0706     QString errMsg;
0707     QJsonParseError err;
0708     QJsonDocument doc = QJsonDocument::fromJson(data, &err);
0709 
0710     if(err.error != QJsonParseError::NoError)
0711     {
0712         Q_EMIT signalBusy(false);
0713         return;
0714     }
0715 
0716     QJsonObject jsonObject = doc.object();
0717     m_user.id = jsonObject[QString::fromLatin1("id")].toString().toLongLong();
0718 
0719     if (!(QString::compare(jsonObject[QString::fromLatin1("id")].toString(),
0720                            QString::fromLatin1(""), Qt::CaseInsensitive) == 0))
0721     {
0722         errCode = 0;
0723     }
0724 
0725     m_user.name = jsonObject[QString::fromLatin1("name")].toString();
0726     m_user.profileURL = jsonObject[QString::fromLatin1("link")].toString();
0727 
0728     if(errCode!=0)
0729     {
0730         // it seems that session expired -> create new token and session
0731         m_accessToken.clear();
0732         m_sessionExpires = 0;
0733         m_user.clear();
0734 
0735         doOAuth();
0736     }
0737     else
0738         authenticationDone(0, QString::fromLatin1(""));
0739 }
0740 
0741 void FbTalker::parseResponseAddPhoto(const QByteArray& data)
0742 {
0743     qCDebug(KIPIPLUGINS_LOG) <<"Parse Add Photo data is "<<data;
0744     int errCode = -1;
0745     QString errMsg;
0746     QJsonParseError err;
0747     QJsonDocument doc = QJsonDocument::fromJson(data, &err);
0748 
0749     if(err.error != QJsonParseError::NoError)
0750     {
0751         Q_EMIT signalBusy(false);
0752         return;
0753     }
0754 
0755     QJsonObject jsonObject = doc.object();
0756 
0757     if(jsonObject.contains(QString::fromLatin1("id")))
0758     {
0759         qCDebug(KIPIPLUGINS_LOG) << "Id of photo exported is" << jsonObject[QString::fromLatin1("id")].toString();
0760         errCode = 0;
0761     }
0762 
0763     if(jsonObject.contains(QString::fromLatin1("error")))
0764     {
0765         QJsonObject obj = jsonObject[QString::fromLatin1("error")].toObject();
0766         errCode = obj[QString::fromLatin1("code")].toInt();
0767         errMsg  = obj[QString::fromLatin1("message")].toString();
0768     }
0769 
0770     Q_EMIT signalBusy(false);
0771     Q_EMIT signalAddPhotoDone(errCode, errorToText(errCode, errMsg));
0772 }
0773 
0774 void FbTalker::parseResponseCreateAlbum(const QByteArray& data)
0775 {
0776     qCDebug(KIPIPLUGINS_LOG) <<"Parse Create album data is"<<data;
0777     int errCode = -1;
0778     QString errMsg;
0779     QString newAlbumID;
0780     QJsonParseError err;
0781     QJsonDocument doc = QJsonDocument::fromJson(data, &err);
0782 
0783     if(err.error != QJsonParseError::NoError)
0784     {
0785         Q_EMIT signalBusy(false);
0786         return;
0787     }
0788 
0789     QJsonObject jsonObject = doc.object();
0790 
0791     if(jsonObject.contains(QString::fromLatin1("id")))
0792     {
0793         newAlbumID = jsonObject[QString::fromLatin1("id")].toString();
0794         qCDebug(KIPIPLUGINS_LOG) << "Id of album created is" << newAlbumID;
0795         errCode = 0;
0796     }
0797 
0798     if(jsonObject.contains(QString::fromLatin1("error")))
0799     {
0800         QJsonObject obj = jsonObject[QString::fromLatin1("error")].toObject();
0801         errCode = obj[QString::fromLatin1("code")].toInt();
0802         errMsg  = obj[QString::fromLatin1("message")].toString();
0803     }
0804 
0805     Q_EMIT signalBusy(false);
0806     Q_EMIT signalCreateAlbumDone(errCode, errorToText(errCode, errMsg),
0807                                newAlbumID);
0808 }
0809 
0810 void FbTalker::parseResponseListAlbums(const QByteArray& data)
0811 {
0812     int errCode = -1;
0813     QString errMsg;
0814     QJsonParseError err;
0815     QList <FbAlbum> albumsList;
0816     QJsonDocument doc = QJsonDocument::fromJson(data, &err);
0817 
0818     if(err.error != QJsonParseError::NoError)
0819     {
0820         Q_EMIT signalBusy(false);
0821         return;
0822     }
0823 
0824     QJsonObject jsonObject = doc.object();
0825 
0826     if (jsonObject.contains(QString::fromLatin1("data")))
0827     {
0828         QJsonArray jsonArray = jsonObject[QString::fromLatin1("data")].toArray();
0829         foreach (const QJsonValue & value, jsonArray)
0830         {
0831             QJsonObject obj = value.toObject();
0832             FbAlbum album;
0833             album.id          = obj[QString::fromLatin1("id")].toString();
0834             album.title       = obj[QString::fromLatin1("name")].toString();
0835             album.location    = obj[QString::fromLatin1("location")].toString();
0836             album.url         = obj[QString::fromLatin1("link")].toString();
0837             album.description = obj[QString::fromLatin1("description")].toString();
0838             if (QString::compare(obj[QString::fromLatin1("privacy")].toString(),
0839                                  QString::fromLatin1("friends"), Qt::CaseInsensitive) == 0)
0840             {
0841                 album.privacy = FB_FRIENDS;
0842             }
0843             else if (QString::compare(obj[QString::fromLatin1("privacy")].toString(),
0844                                       QString::fromLatin1("custom"), Qt::CaseInsensitive) == 0)
0845             {
0846                 album.privacy = FB_CUSTOM;
0847             }
0848             else if (QString::compare(obj[QString::fromLatin1("privacy")].toString(),
0849                                       QString::fromLatin1("everyone"), Qt::CaseInsensitive) == 0)
0850             {
0851                 album.privacy = FB_EVERYONE;
0852             }
0853 
0854             albumsList.append(album);
0855         }
0856         errCode = 0;
0857     }
0858 
0859     if (jsonObject.contains(QString::fromLatin1("error")))
0860     {
0861         QJsonObject obj = jsonObject[QString::fromLatin1("error")].toObject();
0862         errCode = obj[QString::fromLatin1("code")].toInt();
0863         errMsg  = obj[QString::fromLatin1("message")].toString();
0864     }
0865 
0866     std::sort(albumsList.begin(), albumsList.end());
0867 
0868     Q_EMIT signalBusy(false);
0869     Q_EMIT signalListAlbumsDone(errCode, errorToText(errCode, errMsg),
0870                               albumsList);
0871 }
0872 
0873 void FbTalker::slotAccept()
0874 {
0875     m_dialog->close();
0876     m_dialog->setResult(QDialog::Accepted);
0877 }
0878 
0879 void FbTalker::slotReject()
0880 {
0881     m_dialog->close();
0882     m_dialog->setResult(QDialog::Rejected);
0883 }
0884 
0885 } // namespace KIPIFacebookPlugin
0886 
0887 #include "moc_fbtalker.cpp"