Dropbox
Work in Progress. This isn’t official and finished tutorial yet
Writing upload/update plugins with Webupload Framework
Accounts & SSO
Upload/update plugins work best if you add service extension to Accounts & SSO framework. This framework offers the user a way to manage accounts (create/remove) and it offers single sign-on service to applications. Accounts & SSO documentation is here.
Most important part of things implemented to Accounts & SSO side is the service definition file. We will not cover Accounts related parts of it, but simply check the extension part our framework uses (content inside webService tag).
Here are the locations where the different files should be installed on device:
.service file: /usr/share/accounts/services/
.provider file: /usr/share/accounts/providers/
SSO plugin: /usr/lib/signon/
webupload-engine plugin: /usr/lib/webupload/plugins/
Note that the value of uploadPlugin attribute in the .service file must match the name of the webupload-engine plugin binary.
Example of dropbox-share-example.service file
<?xml version="1.0" encoding="UTF-8" ?>
<service id="dropbox-share-example">
<type>sharing</type>
<provider>dropbox</provider>
<name>qtn_acc_sel_pro_ser_sharing</name>
<icon>my-id-for-dropbox-icon</icon>
<template>
<setting name="enabled" type="b">true</setting>
</template>
<!-- Extension part needed for upload services
mainly defines the upload/update plugin name. -->
<webService version="0.1" uploadPlugin="dropbox">
<presentation>
<name>Dropbox</name> <!-- name used in Share UI -->
<!-- allows title to have multiple lines -->
<title multiline="1" order="1">
</title>
<!-- asking framework to not to show the description field -->
<description hide="1" />
</presentation>
<postOptions>
<!-- In Dropbox you can select the destination folder for the file.
Asking framework to show it in the Share UI -->
<option id="folder" type="changeable" default="root_" order="3">
<caption>Folder</caption>
<value id="root_">Root</value>
<update>
<command>Update</command>
</update>
<add>
<command>Create new folder</command>
<caption>Title</caption>
<tooltip>Add title</tooltip>
<!-- limit the length of folder name to 100 chars -->
<input maxLength="100"/
<button>Create</button>
</add>
</option>
</postOptions>
<media>
<formats>
<!-- As an example, this will ask framwork to present dropbox
if shared content in a jpeg image or any video. Or if each
shared content is in one of these groups. -->
<mime>image/jpeg</mime>
<mime>video/*</mime>
</formats>
</media>
</webService>
</service>
Example of a provider file
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE provider>
<provider version="1.0" id="dropbox">
<name>qtn_drop_title</name>
<translations>dropbox</translations>
<description>qtn_drop_setup_desc</description>
<short-description>qtn_drop_desc</short-description>
<icon>icon-m-service-dropbox</icon>
<sign-up-link>http://m.dropbox.com/register/</sign-up-link>
<account-setup>
<register type="formular"/>
<setting name="remember" type="boolean"/>
<authsession>
<validate method="dropbox" mechanism="Dropbox"/>
<method name="dropbox">
<mechanism name="Dropbox"/>
</method>
</authsession>
</account-setup>
</provider>
Example header of SSO plugin class
#ifndef _DROPBOX_SSO_PLUGIN_
#define _DROPBOX_SSO_PLUGIN_
#include <SignOn/authpluginif.h>
#include <QString>
#include <QStringList>
#include <QVariant>
#include "dropboxrequest.h"
#include "logger.h"
// Path to make sure we compile with new data class
#include "../inc/dropboxsessiondata.h"
// SSO plugin functionality to Dropbox
class DropboxPlugin : public AuthPluginInterface {
Q_OBJECT
Q_INTERFACES(AuthPluginInterface);
public:
// Create new instance of plugin
DropboxPlugin (QObject * parent = 0);
virtual ~DropboxPlugin();
public Q_SLOTS:
QString type() const;
QStringList mechanisms() const;
void cancel ();
void process (const SignOn::SessionData & inData,
const QString & mechanism = 0);
void tokenRequestDone (int error);
private:
// Internal function for setting mechanism
bool setMechanism (const QString &mechanism);
// Internal function for mechanism to mode conversion
static DropboxRequest::Mode mechanismToMode (
const QString & mechanism);
// Internal function for mode to mechanism conversion
QString modeToMechanism (DropboxRequest::Mode mode) const;
// Internal function for marking request as current
void setCurrentRequest (DropboxRequest * request);
// Internal function for reading values from cache, will emit singal
bool readCache (const QString & developerKey,
const QString & secretKey,
const QString & eMail);
// Internal function for writing return values to cache
void writeCache (DropboxSessionData & data);
// Internal function for generating unique key for storing token
static QString generateTokenKey (const QString & developerKey,
const QString & secretKey,
const QString & eMail);
// Internal function for reading token from credentials storage
// Will check if caller is trusted before allowing access
bool readFromCredentials (DropboxSessionData & input);
// Internal function for writing token to credentials storage
// Will check if caller is trusted before allowing access
bool writeToCredentials (DropboxSessionData & input);
DropboxRequest::Mode m_curMode;
DropboxRequest * m_currentRequest;
DropboxSessionData m_inputData;
QString m_developerKey;
QString m_secretKey;
bool m_trustedToken;
Logger *m_logger;
};
#endif //#ifndef _DROPBOX_SSO_PLUGIN_
Example source file of SSO plugin
#include "dropboxssoplugin.h"
#include "dropboxcommon.h"
#include "dropboxrequest.h"
#include "dropboxtokenrequest.h"
#include <QSettings>
#include <QCryptographicHash>
DropboxPlugin::DropboxPlugin (QObject * parent) :
AuthPluginInterface (parent),
m_curMode (DropboxRequest::DROPBOX_MODE), m_currentRequest (0),
// API Developer and secret keys.
// Remember to update the checksum below as well.
m_developerKey ("INSERT_DEVELOPER_KEY"),
m_secretKey ("INSERT_SECRET_KEY"),
m_trustedToken (false), m_logger (0) {
}
DropboxPlugin::~DropboxPlugin () {
if (m_currentRequest != 0) {
delete m_currentRequest;
}
if (m_logger != 0) {
delete m_logger;
m_logger = 0;
}
}
inline bool isTrustedCredentials (const QString & a, const QString b) {
QCryptographicHash hasher (QCryptographicHash::Sha1);
hasher.addData (a.toAscii());
hasher.addData (b.toAscii());
//sha1 sum of keys written togetter (developer key first)
//remember to change this when keys change (or read it from key provider)
QByteArray result ("INSERT_DEVELOPER+SECRET_KEY_SHA1_SUM");
bool isTrusted = (hasher.result().toHex() == result);
if (isTrusted == false) {
qDebug() << hasher.result ().toHex()
<< "(developer+secret key:" << a+b << ")"
<< "not matching with" << result;
}
return isTrusted;
}
QString DropboxPlugin::type() const {
return "dropbox";
}
QStringList DropboxPlugin::mechanisms() const {
QStringList list;
for (int i = DropboxRequest::INVALID_MODE + 1;
i < DropboxRequest::LAST_MODE; ++i) {
list << modeToMechanism ((DropboxRequest::Mode)i);
}
return list;
}
bool DropboxPlugin::setMechanism (const QString &mechanism) {
DropboxRequest::Mode newMode = mechanismToMode (mechanism);
if (newMode > DropboxRequest::INVALID_MODE &&
newMode < DropboxRequest::LAST_MODE) {
DBG_STREAM << "Set mechanism to" << mechanism;
m_curMode = newMode;
return true;
} else {
WARN_STREAM << "Can't set mechanism to" << mechanism;
return false;
}
}
void DropboxPlugin::process (const SignOn::SessionData & inData,
const QString & mechanism) {
if (m_logger == 0) {
m_logger = new Logger ("dropbox-sso");
}
// Remember input values
m_inputData = inData;
m_inputData.setEMail (inData.UserName());
m_inputData.setPassword (inData.Secret());
if (!setMechanism (mechanism)) {
DBG_STREAM << "Mechanism" << mechanism << "is not valid";
Q_EMIT (
error (SignOn::Error (SignOn::Error::MechanismNotAvailable)));
return;
}
bool refresh = m_inputData.RefreshToken();
QString eMail = m_inputData.EMail();
QString password = m_inputData.Password();
m_trustedToken = isTrustedCredentials (m_developerKey, m_secretKey);
DBG_STREAM << "Checking credentials";
if(refresh == false) {
if (readFromCredentials (m_inputData)) {
return;
}
}
// Try to get token from cache if allowed
if (refresh == false) {
if (readCache (m_developerKey, m_secretKey, eMail)) {
DBG_STREAM << "readCache == true";
return;
}
} else {
DBG_STREAM << "Token refresh request received. Cache ignored";
}
// Check that we have all data needed
if (m_developerKey.isEmpty() || m_secretKey.isEmpty()) {
WARN_STREAM << "Data missing:" << m_developerKey.isEmpty()
<< m_secretKey.isEmpty();
Q_EMIT (error(SignOn::Error (SignOn::Error::MissingData,
QString("Missing developer and/or secret key"))));
return;
}
DropboxTokenRequest * request = new DropboxTokenRequest (this);
request->setDeveloperKey (m_developerKey);
request->setSecretKey (m_secretKey);
request->setEMail (eMail);
request->setPassword (password);
request->setMode (m_curMode);
m_inputData.setToken ("");
m_inputData.setTokenSecret ("");
setCurrentRequest (request);
QObject::connect (request, SIGNAL (done(int)), this,
SLOT (tokenRequestDone (int)));
DBG_STREAM << "Start token request (with developer/secret key)...";
request->start ();
}
DropboxRequest::Mode DropboxPlugin::mechanismToMode (
const QString & mechanism) {
if (mechanism == "Dropbox") {
return DropboxRequest::DROPBOX_MODE;
} else {
WARN_STREAM << "Unknown mechanism" << mechanism;
return DropboxRequest::INVALID_MODE;
}
}
QString DropboxPlugin::modeToMechanism (DropboxRequest::Mode mode) const {
switch (mode) {
case DropboxRequest::DROPBOX_MODE:
return "Dropbox";
default:
WARN_STREAM << "Unknown mode" << mode;
return "";
}
}
void DropboxPlugin::cancel () {
if (m_currentRequest != 0) {
m_currentRequest->cancel();
} else {
WARN_STREAM << "Nothing to cancel";
}
}
void DropboxPlugin::tokenRequestDone (int request_error) {
DropboxSessionData myData = m_inputData;
DropboxTokenRequest * tokenRequest =
qobject_cast <DropboxTokenRequest*> (QObject::sender());
QString token;
QString tokenSecret;
QString errorMessage;
if (tokenRequest == 0) {
errorMessage = "Signal received from wrong class or slot called" \
" as function";
CRIT_STREAM << errorMessage;
Q_EMIT (error(SignOn::Error(SignOn::Error::Unknown, errorMessage)));
return;
}
tokenRequest->deleteLater();
if (m_currentRequest == tokenRequest) {
m_currentRequest = 0;
}
if (request_error == 0) {
token = tokenRequest->token();
tokenSecret = tokenRequest->tokenSecret();
if (!token.isEmpty() && !tokenSecret.isEmpty()) {
myData.setDeveloperKey (m_developerKey);
myData.setSecretKey (m_secretKey);
myData.setToken (token);
myData.setTokenSecret (tokenSecret);
myData.setResponse (tokenRequest->response());
DBG_STREAM << "Writing credentials";
if (writeToCredentials (myData)== false) {
writeCache (myData);
}
}
// Only send result if process wasn't cancelled
Q_EMIT (result(myData));
} else {
Q_EMIT (error(SignOn::Error(request_error, errorMessage)));
}
}
void DropboxPlugin::setCurrentRequest (DropboxRequest * request) {
m_currentRequest = request;
}
QString DropboxPlugin::generateTokenKey (const QString & developerKey,
const QString & secretKey, const QString & eMail) {
QCryptographicHash hasher (QCryptographicHash::Sha1);
QByteArray bArray = developerKey.toAscii();
hasher.addData (bArray.constData(), bArray.size());
bArray = secretKey.toAscii();
hasher.addData (bArray.constData(), bArray.size());
bArray = eMail.toAscii();
hasher.addData (bArray.constData(), bArray.size());
return hasher.result().toHex();
}
bool DropboxPlugin::readCache (const QString & developerKey,
const QString & secretKey, const QString & eMail) {
QString key = generateTokenKey (developerKey, secretKey, eMail);
QSettings settings ("nokia", "dropbox-sso");
settings.beginReadArray (key);
QString token = settings.value ("token", QString("")).toString();
QString tokenSecret =
settings.value ("tokensecret", QString("")).toString();
if (token.isEmpty()) {
DBG_STREAM << "Old token not found in cache";
return false;
}
DBG_STREAM << "Read from cache" << key;
DropboxSessionData myData = m_inputData;
myData.setToken (token);
myData.setTokenSecret (tokenSecret);
myData.setEMail (eMail);
Q_EMIT (result(myData));
return true;
}
void DropboxPlugin::writeCache (DropboxSessionData & data) {
QString key = generateTokenKey (data.DeveloperKey(),
data.SecretKey(), data.EMail());
QSettings settings ("nokia", "dropbox-sso");
settings.beginReadArray (key);
settings.setValue ("token", data.Token ());
settings.setValue ("tokensecret", data.TokenSecret ());
settings.setValue ("email", data.EMail ());
}
bool DropboxPlugin::readFromCredentials (DropboxSessionData & input) {
if (m_trustedToken == false) {
return false;
}
//Check that we have password
if (input.SecretKey().isEmpty() == true) {
DBG_STREAM << "Can not find token from credentials";
return false;
}
//Copy secret to token
DropboxSessionData myData = m_inputData;
myData.setToken (m_inputData.Token());
myData.setTokenSecret (m_inputData.TokenSecret());
myData.setEMail (m_inputData.EMail ());
//Emit signal and return true
Q_EMIT (result(myData));
return true;
}
bool DropboxPlugin::writeToCredentials (DropboxSessionData & input) {
QString developerKey = m_developerKey;
QString secretKey = m_secretKey;
//Check that keys are trusted
if (isTrustedCredentials(developerKey, secretKey) == false) {
DBG_STREAM << "Untrusted client (will not write)";
return false;
}
DBG_STREAM << "Emitting store";
Q_EMIT (store (input));
return true;
}
SIGNON_DECL_AUTH_PLUGIN(DropboxPlugin)
Upload/update plugin
An upload/update plugin for a service implements the interfaces defined by the libwebupload library. The plugin can then be used by the webupload engine or other applications to upload to the relevant service. The plugin can also be used to provide additional functionality like retrieving list of albums, or creating a new album.
Upload/update plugins run as independent processes started and controlled by the webupload engine (during an upload) or the share-ui application (during an update).
Implementation
All upload/update plugins have to implement the PluginInterface class. This class has two functions – one provides a handle to the re-implemented PostInterface class which supports upload to the service, and the other provides a handle to the re-implemented UpdateInterface class which supports updates on the service account.
Example header of plugin class
#ifndef _DROPBOX_PLUGIN_H_
#define _DROPBOX_PLUGIN_H_
#include <QObject>
#include <WebUpload/PluginInterface>
#include <WebUpload/PluginBase>
//uses pluginbase as parent (it's just actual qobject where interface is pure c++ interface class)
class DropboxPlugin : public WebUpload::PluginBase {
Q_OBJECT
public:
DropboxPlugin(QObject * parent = 0);
virtual ~DropboxPlugin();
//Function always called first. If false is returned, plugin will not be used after calling this
virtual bool init();
//Function returning instance of post class
virtual WebUpload::PostInterface * getPost();
//Function returning instanse of update class (null if you do not need one)
virtual WebUpload::UpdateInterface * getUpdate();
};
#endif
Example source file of plugin
#include "dropboxplugin.h"
#include "dropboxpost.h"
#include "dropboxupdate.h"
#include <WebUpload/PluginApplication>
//Important macro. This will add the main function that is needed to run plugin binary
//The name of the plugin class is passed as argument
PLUGIN_MAIN_FUNCTION (DropboxPlugin)
// just dummy constructor and destroyer are enough for this example
DropboxPlugin::DropboxPlugin (QObject * parent) : WebUpload::PluginBase (parent) {}
DropboxPlugin::~DropboxPlugin() {}
// do your inits here and return false if something went wrong (actually you do not have to
// reimplement this if you do not do anything here, base class has implementation like this
// already)
bool DropboxPlugin::init() {
return true;
}
// this function allows your code to tell what post class to use. Usually it's our own
WebUpload::PostInterface * DropboxPlugin::getPost() {
return new DropboxPost (this);
}
// Tell what update class to use by creating instance you want
// (if you do not reimplement this function null will be returned, so only reimplement
// if you need update features)
WebUpload::UpdateInterface * DropboxPlugin::getUpdate() {
return new DropboxUpdate(this);
}
Posting/Uploading
Post classes are used to upload content to web services. For each transfer, a new instance is made. One transfer can anyway contain multiple items. This framework uses names Entry for transfer and Media for item in transfer. So each Entry will contain one or more media items (depending what user has selected to be shared and what service is accepting).
Example header of post class
#ifndef _DROPBOX_POST_H_
#define _DROPBOX_POST_H_
#include <WebUpload/PostSimpleHttp>
#include "dropboxuploadrequest.h"
#include "datatypes.h"
namespace WebUpload {
class Entry;
class ServiceOption;
}
class QNetworkReply;
class DropboxPost : public WebUpload::PostSimpleHttp {
Q_OBJECT
public:
DropboxPost (QObject *parent = 0);
~DropboxPost ();
protected:
// Implementation for WebUpload::PostBase::getAuthPtr
WebUpload::AuthBase * getAuthPtr ();
// Implementation for WebUpload::PostBase::fixError
virtual void fixError (WebUpload::Entry * entry, WebUpload::Error error);
// Implementation for WebUpload::PostSimpleHttp::generateRequest
virtual QNetworkReply * generateRequest (WebUpload::Media *media);
// Implementation for WebUpload::PostSimpleHttp::handleResponse
virtual void handleResponse (QNetworkReply *media);
private:
// Internal function for handling successful upload
void handleUploadSuccess();
// Internal function for handling upload HTTP errors
// (Dropbox uses lots of HTTP error codes)
void handleHttpError (int httpError);
// Internal function for handling upload errors
void handleUploadError(int errorCode, const QString& errorName);
private:
enum RequestType {
REQUEST_UPLOAD,
REQUEST_OTHER
};
DropboxUploadRequest m_request;
RequestType m_requestType;
QString m_uploadedMediaURL;
WebUpload::Media* m_media;
WebUpload::Entry* m_entry;
};
#endif // _DROPBOX_POST_H_
Example source file of post
#include "dropboxpost.h"
#include "dropboxresponseparser.h"
#include "dropboxupdate.h"
#include <WebUpload/Account>
#include <WebUpload/ServiceOptionValue>
#include <QDebug>
DropboxPost::DropboxPost (QObject *parent) : WebUpload::PostSimpleHttp (parent),
m_requestType (REQUEST_UPLOAD), m_media (0), m_entry (0) {
m_request.setNetAM(netAM);
}
DropboxPost::~DropboxPost () {
}
WebUpload::AuthBase * DropboxPost::getAuthPtr () {
return m_request.getAuthPtr ();
}
void DropboxPost::fixError (WebUpload::Entry * entry, WebUpload::Error error) {
if (canRetry (error)) {
Q_EMIT (errorFixed ());
return;
} else if (error.code() == WebUpload::Error::CODE_CUSTOM) {
QVariant data = error.data ();
if (data.isValid () && data.canConvert<int> ()) {
int val = data.toInt ();
if (val == 0xff) {
m_request.setTokenExpired ();
Q_EMIT (errorFixed ());
return;
}
}
}
Q_EMIT (errorFixFailed (error));
}
QNetworkReply* DropboxPost::generateRequest (WebUpload::Media* media) {
m_media = media;
if (media != 0 && m_entry == 0) {
const WebUpload::Entry* constEntry = media->entry();
m_entry = (WebUpload::Entry*)constEntry;
}
QNetworkReply* networkReply = 0;
m_requestType = REQUEST_UPLOAD;
networkReply = m_request.generateUploadRequest(media);
return networkReply;
}
void DropboxPost::handleResponse (QNetworkReply* response) {
// This is the complete response message sent by Dropbox
QByteArray responseData;
if (response != 0) {
responseData = response->readAll();
} else {
qCritical() << "got null network reply";
}
if(response->attribute(
QNetworkRequest::HttpStatusCodeAttribute).toInt() == 200) {
// Parse response and try to get the information about the upload
DropboxResponseParser parser;
bool parsingOk = parser.parseResponse(responseData);
if (!parsingOk) {
handleUploadError(-1, "");
return;
}
bool successCheck = parser.checkIfSuccess ();
switch (m_requestType) {
case REQUEST_UPLOAD:
{
if (successCheck) {
handleUploadSuccess();
} else {
int errorCode = parser.errorCode();
QString errorName = parser.errorName();
handleUploadError(errorCode, errorName);
}
break;
}
default:
{
// Unspecified request type, assume error
handleUploadError(-1, "Unspecified request type");
}
}
} else {
handleHttpError(response->attribute(
QNetworkRequest::HttpStatusCodeAttribute).toInt());
}
}
void DropboxPost::handleHttpError (int httpError) {
WebUpload::Error error;
switch (httpError) {
case 401:
{
WebUpload::SharedAccount account;
if (m_entry != 0) {
account = m_entry->account();
}
QString accountName;
if (!account.isNull ()) {
accountName = account->name ();
}
account.clear ();
QString message = "Account not authorized";
QString desc = "Account is currently not authorized. \
Do you want to reauthorize it?";
QString retryMsg = "Reauthorize";
error = WebUpload::Error::custom (message, desc, retryMsg);
error.setData (0xff);
break;
}
default:
{
error = WebUpload::Error::serviceError("");
break;
}
}
Q_EMIT (mediaError(error));
}
void DropboxPost::handleUploadSuccess() {
Q_EMIT (mediaDone(m_uploadedMediaURL));
}
void DropboxPost::handleUploadError(int errorCode, const QString& errorName) {
WebUpload::Error error;
switch (errorCode) {
default:
error = WebUpload::Error::serviceError(errorName);
break;
}
Q_EMIT (mediaError(error));
}
Updating
Update classes are used by UI to update options offered to user, for example, refresh folders user currently has on Dropbox service. It can also offer method to add new folder.
Example header of update class
#ifndef DROPBOX_UPDATE_H
#define DROPBOX_UPDATE_H
#include <WebUpload/UpdateSimpleHttp>
#include "dropboxrequest.h"
#include "datatypes.h"
class DropboxFolder;
namespace WebUpload {
class Account;
}
class DropboxUpdate : public WebUpload::UpdateSimpleHttp {
Q_OBJECT
public:
DropboxUpdate (QObject *parent = 0);
virtual ~DropboxUpdate();
// Implements WebUpload::UpdateBase::getAuthPtr
WebUpload::AuthBase * getAuthPtr ();
protected:
// Implements WebUploadUpdate::SimpleHttp::generateUpdateRequest
QNetworkReply* generateUpdateRequest();
// Implements WebUploadUpdate::SimpleHttp::generateAddRequest
QNetworkReply* generateAddRequest (const QString &valueName);
// Implements WebUpload::UpdateSimpleHttp::handleResponse
void handleResponse(QNetworkReply* response);
private:
void updateFolders(QList<DropboxFolder>& folders);
void handleRequestError(int errorCode, const QString& errorName);
void addDefaultFolderToFolderList (QList<DropboxFolder>& folderList);
void addFolderToFolderList (const QString & path,
const QString & name,
WebUpload::ServiceOption * option);
private:
RequestType requestType;
DropboxRequest request;
QString folderOptionName;
};
#endif
Example source file of update
#include "dropboxupdate.h"
#include "dropboxresponseparser.h"
#include "dropboxfolder.h"
#include <WebUpload/ServiceOption>
#include <WebUpload/ServiceOptionValue>
#include <WebUpload/Account>
DropboxUpdate::DropboxUpdate (QObject* parent) :
WebUpload::UpdateSimpleHttp (parent), folderOptionName("folder")
{
request.setNetAM(netAM);
}
DropboxUpdate::~DropboxUpdate()
{
}
WebUpload::AuthBase * DropboxUpdate::getAuthPtr()
{
return request.getAuthPtr ();
}
QNetworkReply* DropboxUpdate::generateUpdateRequest()
{
requestType = REQUEST_UPDATE;
return request.generateUpdateRequest();
}
QNetworkReply* DropboxUpdate::generateAddRequest (const QString &valueName)
{
requestType = REQUEST_CREATE_FOLDER;
return request.generateAddFolderRequest(valueName, "/");
}
void DropboxUpdate::handleResponse(QNetworkReply* response)
{
// This is the complete response message sent by Dropbox
QByteArray responseData;
if (response != 0) {
responseData = response->readAll();
}
// Parse response and try to get the information about the uploaded image
DropboxResponseParser parser;
bool parsingOk = parser.parseResponse(responseData);
if (parsingOk) {
// If the response is valid (not broken message etc.), check the
// actual content. It may either report the request was successful or
// describe an error, if one occurred.
bool requestWasSuccessful = parser.checkIfSuccess();
if (requestWasSuccessful) {
if (requestType == REQUEST_UPDATE) {
QList<DropboxFolder> folderList = parser.folders();
addDefaultFolderToFolderList(folderList);
updateFolders(folderList);
} else if (requestType == REQUEST_CREATE_FOLDER) {
Q_EMIT (optionAdded(true));
} else {
Q_EMIT (optionFailed(WebUpload::Error::CODE_CUSTOM));
}
} else {
int errorCode = parser.errorCode();
QString errorName = parser.errorName();
handleRequestError(errorCode, errorName);
}
} else {
qCritical() << "Error parsing the response: " << responseData;
handleRequestError(-1, "");
}
}
void DropboxUpdate::updateFolders(QList<DropboxFolder>& folders)
{
WebUpload::ServiceOption* curOption = currentOption();
if (curOption != 0) {
QList<WebUpload::ServiceOptionValue> folderList =
*reinterpret_cast<QList<WebUpload::ServiceOptionValue>*>(&folders);
curOption->updateValues(folderList);
Q_EMIT (optionDone());
} else {
qWarning() << "Unable to update folder list";
Q_EMIT (optionFailed(WebUpload::Error::CODE_CUSTOM));
}
}
void DropboxUpdate::handleRequestError(int errorCode,
const QString& errorName)
{
Q_EMIT (optionFailed (WebUpload::Error::CODE_CUSTOM));
}
void DropboxUpdate::addFolderToFolderList (const QString & path,
const QString & name,
WebUpload::ServiceOption * option)
{
WebUpload::ServiceOptionValue folder(path, name);
QList<WebUpload::ServiceOptionValue> folderList = option->values();
folderList.prepend(folder);
option->updateValues(folderList, true);
option->setActiveValueId(name);
}
void DropboxUpdate::addDefaultFolderToFolderList (QList<DropboxFolder>& folderList)
{
const QString defaultFolderId = "none_";
const QString defaultFolderName = "None";
DropboxFolder defaultFolder(defaultFolderId, defaultFolderName);
// This should be always the first list item
folderList.prepend(defaultFolder);
}

