File indexing completed on 2025-01-19 03:52:58
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2005-07-07 0007 * Description : a tool to export images to Flickr web service 0008 * 0009 * SPDX-FileCopyrightText: 2005-2009 by Vardhman Jain <vardhman at gmail dot com> 0010 * SPDX-FileCopyrightText: 2009-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0011 * SPDX-FileCopyrightText: 2017-2019 by Maik Qualmann <metzpinguin at gmail dot com> 0012 * 0013 * SPDX-License-Identifier: GPL-2.0-or-later 0014 * 0015 * ============================================================ */ 0016 0017 #include "flickrtalker.h" 0018 0019 // Qt includes 0020 0021 #include <QDomDocument> 0022 #include <QDomElement> 0023 #include <QByteArray> 0024 #include <QFileInfo> 0025 #include <QFile> 0026 #include <QMap> 0027 #include <QImage> 0028 #include <QPointer> 0029 #include <QUrlQuery> 0030 #include <QStringList> 0031 #include <QMessageBox> 0032 #include <QInputDialog> 0033 #include <QApplication> 0034 #include <QProgressDialog> 0035 #include <QDesktopServices> 0036 0037 // KDE includes 0038 0039 #include <klocalizedstring.h> 0040 0041 // Local includes 0042 0043 #include "digikam_debug.h" 0044 #include "digikam_config.h" 0045 #include "digikam_version.h" 0046 #include "previewloadthread.h" 0047 #include "webbrowserdlg.h" 0048 #include "flickrwindow.h" 0049 #include "flickrmpform.h" 0050 #include "wstoolutils.h" 0051 #include "dmetadata.h" 0052 0053 // OAuth2 library includes 0054 0055 #if defined(Q_CC_CLANG) 0056 # pragma clang diagnostic push 0057 # pragma clang diagnostic ignored "-Wextra-semi" 0058 #endif 0059 0060 #include "o1.h" 0061 #include "o0globals.h" 0062 #include "o1requestor.h" 0063 #include "o0settingsstore.h" 0064 #include "networkmanager.h" 0065 0066 #if defined(Q_CC_CLANG) 0067 # pragma clang diagnostic pop 0068 #endif 0069 0070 namespace DigikamGenericFlickrPlugin 0071 { 0072 0073 class Q_DECL_HIDDEN FlickrTalker::Private 0074 { 0075 public: 0076 0077 explicit Private() 0078 : parent (nullptr), 0079 netMngr (nullptr), 0080 reply (nullptr), 0081 settings (nullptr), 0082 state (FE_LOGOUT), 0083 iface (nullptr), 0084 o1 (nullptr), 0085 store (nullptr), 0086 requestor (nullptr), 0087 browser (nullptr) 0088 { 0089 apiUrl = QLatin1String("https://www.flickr.com/services/rest/"); 0090 authUrl = QLatin1String("https://www.flickr.com/services/oauth/authorize?perms=write"); 0091 tokenUrl = QLatin1String("https://www.flickr.com/services/oauth/request_token"); 0092 accessUrl = QLatin1String("https://www.flickr.com/services/oauth/access_token"); 0093 uploadUrl = QLatin1String("https://up.flickr.com/services/upload/"); 0094 callbackUrl = QLatin1String("https://www.flickr.com"); 0095 0096 apikey = QLatin1String("74f882bf4dabe22baaaace1f6d33c66b"); 0097 secret = QLatin1String("537d58e3ead2d6d5"); 0098 } 0099 0100 QWidget* parent; 0101 0102 QString serviceName; 0103 QString apiUrl; 0104 QString authUrl; 0105 QString tokenUrl; 0106 QString accessUrl; 0107 QString uploadUrl; 0108 QString callbackUrl; 0109 QString apikey; 0110 QString secret; 0111 QString maxSize; 0112 QString username; 0113 QString userId; 0114 QString lastTmpFile; 0115 0116 QNetworkAccessManager* netMngr; 0117 QNetworkReply* reply; 0118 0119 QSettings* settings; 0120 0121 State state; 0122 0123 DInfoInterface* iface; 0124 0125 O1* o1; 0126 O0SettingsStore* store; 0127 O1Requestor* requestor; 0128 WebBrowserDlg* browser; 0129 }; 0130 0131 FlickrTalker::FlickrTalker(QWidget* const parent, 0132 const QString& serviceName, 0133 DInfoInterface* const iface) 0134 : d(new Private) 0135 { 0136 d->parent = parent; 0137 d->serviceName = serviceName; 0138 d->iface = iface; 0139 m_photoSetsList = nullptr; 0140 m_authProgressDlg = nullptr; 0141 0142 d->netMngr = NetworkManager::instance()->getNetworkManager(this); 0143 0144 connect(d->netMngr, SIGNAL(finished(QNetworkReply*)), 0145 this, SLOT(slotFinished(QNetworkReply*))); 0146 0147 // Initialize selected photo set as empty. 0148 0149 m_selectedPhotoSet = FPhotoSet(); 0150 0151 // Initialize photo sets list. 0152 0153 m_photoSetsList = new QList<FPhotoSet>(); 0154 0155 d->o1 = new O1(this); 0156 d->o1->setLocalPort(80); 0157 d->o1->setClientId(d->apikey); 0158 d->o1->setClientSecret(d->secret); 0159 d->o1->setCallbackUrl(d->callbackUrl); 0160 d->o1->setAuthorizeUrl(QUrl(d->authUrl)); 0161 d->o1->setAccessTokenUrl(QUrl(d->accessUrl)); 0162 d->o1->setRequestTokenUrl(QUrl(d->tokenUrl)); 0163 d->o1->setUseExternalWebInterceptor(true); 0164 0165 d->settings = WSToolUtils::getOauthSettings(this); 0166 d->store = new O0SettingsStore(d->settings, QLatin1String(O2_ENCRYPTION_KEY), this); 0167 d->store->setGroupKey(d->serviceName); 0168 d->o1->setStore(d->store); 0169 0170 connect(d->o1, SIGNAL(linkingFailed()), 0171 this, SLOT(slotLinkingFailed())); 0172 0173 connect(d->o1, SIGNAL(linkingSucceeded()), 0174 this, SLOT(slotLinkingSucceeded())); 0175 0176 connect(d->o1, SIGNAL(openBrowser(QUrl)), 0177 this, SLOT(slotOpenBrowser(QUrl))); 0178 0179 d->requestor = new O1Requestor(d->netMngr, d->o1, this); 0180 } 0181 0182 FlickrTalker::~FlickrTalker() 0183 { 0184 if (d->reply) 0185 { 0186 d->reply->abort(); 0187 } 0188 0189 WSToolUtils::removeTemporaryDir(d->serviceName.toLatin1().constData()); 0190 0191 delete m_photoSetsList; 0192 delete d; 0193 } 0194 0195 void FlickrTalker::link(const QString& userName) 0196 { 0197 Q_EMIT signalBusy(true); 0198 0199 if (userName.isEmpty()) 0200 { 0201 d->store->setGroupKey(d->serviceName); 0202 } 0203 else 0204 { 0205 d->store->setGroupKey(d->serviceName + userName); 0206 } 0207 0208 d->o1->link(); 0209 } 0210 0211 void FlickrTalker::unLink() 0212 { 0213 d->o1->unlink(); 0214 } 0215 0216 void FlickrTalker::removeUserName(const QString& userName) 0217 { 0218 if (userName.startsWith(d->serviceName)) 0219 { 0220 d->settings->beginGroup(userName); 0221 d->settings->remove(QString()); 0222 d->settings->endGroup(); 0223 } 0224 } 0225 0226 void FlickrTalker::slotCatchUrl(const QUrl& url) 0227 { 0228 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Received URL from webview:" << url; 0229 0230 QString str = url.toString(); 0231 QUrlQuery query(str.section(QLatin1Char('?'), -1, -1)); 0232 0233 if (query.hasQueryItem(QLatin1String("oauth_token"))) 0234 { 0235 QMap<QString, QString> queryParams; 0236 queryParams.insert(QLatin1String("oauth_token"), 0237 query.queryItemValue(QLatin1String("oauth_token"))); 0238 queryParams.insert(QLatin1String("oauth_verifier"), 0239 query.queryItemValue(QLatin1String("oauth_verifier"))); 0240 0241 d->o1->onVerificationReceived(queryParams); 0242 } 0243 } 0244 0245 void FlickrTalker::slotLinkingFailed() 0246 { 0247 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "LINK to Flickr fail"; 0248 d->username = QString(); 0249 Q_EMIT signalBusy(false); 0250 } 0251 0252 void FlickrTalker::slotLinkingSucceeded() 0253 { 0254 if (!d->o1->linked()) 0255 { 0256 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "UNLINK to Flickr ok"; 0257 d->username = QString(); 0258 return; 0259 } 0260 0261 if (d->browser) 0262 { 0263 d->browser->close(); 0264 } 0265 0266 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "LINK to Flickr ok"; 0267 0268 d->username = d->o1->extraTokens()[QLatin1String("username")].toString(); 0269 d->userId = d->o1->extraTokens()[QLatin1String("user_nsid")].toString(); 0270 0271 if (d->store->groupKey() == d->serviceName) 0272 { 0273 d->settings->beginGroup(d->serviceName); 0274 QStringList keys = d->settings->allKeys(); 0275 d->settings->endGroup(); 0276 0277 Q_FOREACH (const QString& key, keys) 0278 { 0279 d->settings->beginGroup(d->serviceName); 0280 QVariant value = d->settings->value(key); 0281 d->settings->endGroup(); 0282 d->settings->beginGroup(d->serviceName + d->username); 0283 d->settings->setValue(key, value); 0284 d->settings->endGroup(); 0285 } 0286 0287 d->store->setGroupKey(d->serviceName + d->username); 0288 removeUserName(d->serviceName); 0289 } 0290 0291 Q_EMIT signalLinkingSucceeded(); 0292 } 0293 0294 void FlickrTalker::slotOpenBrowser(const QUrl& url) 0295 { 0296 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Open Browser... (" << url << ")"; 0297 0298 #ifdef HAVE_QWEBENGINE 0299 0300 delete d->browser; 0301 d->browser = new WebBrowserDlg(url, d->parent, true); 0302 d->browser->setModal(true); 0303 0304 connect(d->browser, SIGNAL(urlChanged(QUrl)), 0305 this, SLOT(slotCatchUrl(QUrl))); 0306 0307 connect(d->browser, SIGNAL(closeView(bool)), 0308 this, SIGNAL(signalBusy(bool))); 0309 0310 d->browser->show(); 0311 0312 #else 0313 0314 QDesktopServices::openUrl(url); 0315 QPointer<QInputDialog> textDlg = new QInputDialog(d->parent); 0316 0317 textDlg->setWindowTitle(i18nc("@title:window", "Enter Flickr Login URL")); 0318 textDlg->setLabelText(i18n("Copy the full URL from the external browser " 0319 "that contains the \"oauth_token\" entry:")); 0320 textDlg->resize(770, textDlg->sizeHint().height()); 0321 textDlg->setInputMode(QInputDialog::TextInput); 0322 textDlg->setTextEchoMode(QLineEdit::Normal); 0323 textDlg->setModal(true); 0324 0325 if (textDlg->exec() != QDialog::Accepted) 0326 { 0327 Q_EMIT signalBusy(false); 0328 delete textDlg; 0329 0330 return; 0331 } 0332 0333 slotCatchUrl(QUrl(textDlg->textValue().trimmed())); 0334 delete textDlg; 0335 0336 #endif 0337 0338 } 0339 0340 QString FlickrTalker::getMaxAllowedFileSize() 0341 { 0342 return d->maxSize; 0343 } 0344 0345 void FlickrTalker::maxAllowedFileSize() 0346 { 0347 if (d->reply) 0348 { 0349 d->reply->abort(); 0350 d->reply = nullptr; 0351 } 0352 0353 if (!d->o1->linked()) 0354 { 0355 return; 0356 } 0357 0358 QUrl url(d->apiUrl); 0359 QNetworkRequest netRequest(url); 0360 QList<O0RequestParameter> reqParams = QList<O0RequestParameter>(); 0361 0362 netRequest.setHeader(QNetworkRequest::ContentTypeHeader, QLatin1String(O2_MIME_TYPE_XFORM)); 0363 0364 reqParams << O0RequestParameter("method", "flickr.people.getLimits"); 0365 0366 QByteArray postData = O1::createQueryParameters(reqParams); 0367 0368 d->reply = d->requestor->post(netRequest, reqParams, postData); 0369 0370 d->state = FE_GETMAXSIZE; 0371 m_authProgressDlg->setLabelText(i18n("Getting the maximum allowed file size.")); 0372 m_authProgressDlg->setMaximum(4); 0373 m_authProgressDlg->setValue(1); 0374 0375 Q_EMIT signalBusy(true); 0376 } 0377 0378 void FlickrTalker::listPhotoSets() 0379 { 0380 if (d->reply) 0381 { 0382 d->reply->abort(); 0383 d->reply = nullptr; 0384 } 0385 0386 if (!d->o1->linked()) 0387 { 0388 return; 0389 } 0390 0391 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "List photoset invoked"; 0392 0393 QUrl url(d->apiUrl); 0394 QNetworkRequest netRequest(url); 0395 QList<O0RequestParameter> reqParams = QList<O0RequestParameter>(); 0396 0397 netRequest.setHeader(QNetworkRequest::ContentTypeHeader, QLatin1String(O2_MIME_TYPE_XFORM)); 0398 0399 reqParams << O0RequestParameter("method", "flickr.photosets.getList"); 0400 0401 QByteArray postData = O1::createQueryParameters(reqParams); 0402 0403 d->reply = d->requestor->post(netRequest, reqParams, postData); 0404 0405 d->state = FE_LISTPHOTOSETS; 0406 Q_EMIT signalBusy(true); 0407 } 0408 0409 void FlickrTalker::getPhotoProperty(const QString& method, const QStringList& argList) 0410 { 0411 if (d->reply) 0412 { 0413 d->reply->abort(); 0414 d->reply = nullptr; 0415 } 0416 0417 if (!d->o1->linked()) 0418 { 0419 return; 0420 } 0421 0422 QUrl url(d->apiUrl); 0423 QNetworkRequest netRequest(url); 0424 QList<O0RequestParameter> reqParams = QList<O0RequestParameter>(); 0425 0426 netRequest.setHeader(QNetworkRequest::ContentTypeHeader, QLatin1String(O2_MIME_TYPE_XFORM)); 0427 0428 reqParams << O0RequestParameter("method", method.toLatin1()); 0429 0430 for (QStringList::const_iterator it = argList.constBegin(); it != argList.constEnd(); ++it) 0431 { 0432 QStringList str = (*it).split(QLatin1Char('='), QT_SKIP_EMPTY_PARTS); 0433 reqParams << O0RequestParameter(str[0].toLatin1(), str[1].toLatin1()); 0434 } 0435 0436 QByteArray postData = O1::createQueryParameters(reqParams); 0437 0438 d->reply = d->requestor->post(netRequest, reqParams, postData); 0439 0440 d->state = FE_GETPHOTOPROPERTY; 0441 Q_EMIT signalBusy(true); 0442 } 0443 0444 void FlickrTalker::listPhotos(const QString& /*albumName*/) 0445 { 0446 // TODO 0447 } 0448 0449 void FlickrTalker::createPhotoSet(const QString& /*albumName*/, const QString& albumTitle, 0450 const QString& albumDescription, const QString& primaryPhotoId) 0451 { 0452 if (d->reply) 0453 { 0454 d->reply->abort(); 0455 d->reply = nullptr; 0456 } 0457 0458 if (!d->o1->linked()) 0459 { 0460 return; 0461 } 0462 0463 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Create photoset invoked"; 0464 0465 QUrl url(d->apiUrl); 0466 QNetworkRequest netRequest(url); 0467 QList<O0RequestParameter> reqParams = QList<O0RequestParameter>(); 0468 0469 netRequest.setHeader(QNetworkRequest::ContentTypeHeader, QLatin1String(O2_MIME_TYPE_XFORM)); 0470 0471 reqParams << O0RequestParameter("method", "flickr.photosets.create"); 0472 reqParams << O0RequestParameter("title", albumTitle.toLatin1()); 0473 reqParams << O0RequestParameter("description", albumDescription.toLatin1()); 0474 reqParams << O0RequestParameter("primary_photo_id", primaryPhotoId.toLatin1()); 0475 0476 QByteArray postData = O1::createQueryParameters(reqParams); 0477 0478 d->reply = d->requestor->post(netRequest, reqParams, postData); 0479 0480 d->state = FE_CREATEPHOTOSET; 0481 Q_EMIT signalBusy(true); 0482 } 0483 0484 void FlickrTalker::addPhotoToPhotoSet(const QString& photoId, 0485 const QString& photoSetId) 0486 { 0487 if (d->reply) 0488 { 0489 d->reply->abort(); 0490 d->reply = nullptr; 0491 } 0492 0493 if (!d->o1->linked()) 0494 { 0495 return; 0496 } 0497 0498 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "AddPhotoToPhotoSet invoked"; 0499 0500 /* 0501 * If the photoset id starts with the special string "UNDEFINED_", it means 0502 * it doesn't exist yet on Flickr and needs to be created. Note that it's 0503 * not necessary to subsequently add the photo to the photo set, as this 0504 * is done in the set creation call to Flickr. 0505 */ 0506 0507 if (photoSetId.startsWith(QLatin1String("UNDEFINED_"))) 0508 { 0509 createPhotoSet(QLatin1String(""), m_selectedPhotoSet.title, m_selectedPhotoSet.description, photoId); 0510 } 0511 else 0512 { 0513 QUrl url(d->apiUrl); 0514 QNetworkRequest netRequest(url); 0515 QList<O0RequestParameter> reqParams = QList<O0RequestParameter>(); 0516 0517 netRequest.setHeader(QNetworkRequest::ContentTypeHeader, QLatin1String(O2_MIME_TYPE_XFORM)); 0518 0519 reqParams << O0RequestParameter("method", "flickr.photosets.addPhoto"); 0520 reqParams << O0RequestParameter("photoset_id", photoSetId.toLatin1()); 0521 reqParams << O0RequestParameter("photo_id", photoId.toLatin1()); 0522 0523 QByteArray postData = O1::createQueryParameters(reqParams); 0524 0525 d->reply = d->requestor->post(netRequest, reqParams, postData); 0526 0527 d->state = FE_ADDPHOTOTOPHOTOSET; 0528 Q_EMIT signalBusy(true); 0529 } 0530 } 0531 0532 bool FlickrTalker::addPhoto(const QString& photoPath, const FPhotoInfo& info, 0533 bool original, bool rescale, int maxDim, int imageQuality) 0534 { 0535 if (d->reply) 0536 { 0537 d->reply->abort(); 0538 d->reply = nullptr; 0539 } 0540 0541 if (!d->o1->linked()) 0542 { 0543 return false; 0544 } 0545 0546 Q_EMIT signalBusy(true); 0547 0548 QUrl url(d->uploadUrl); 0549 QNetworkRequest netRequest(url); 0550 QList<O0RequestParameter> reqParams = QList<O0RequestParameter>(); 0551 0552 QString path = photoPath; 0553 FlickrMPForm form; 0554 0555 QString ispublic = (info.is_public == 1) ? QLatin1String("1") : QLatin1String("0"); 0556 form.addPair(QLatin1String("is_public"), ispublic, QLatin1String("text/plain")); 0557 reqParams << O0RequestParameter("is_public", ispublic.toLatin1()); 0558 0559 QString isfamily = (info.is_family == 1) ? QLatin1String("1") : QLatin1String("0"); 0560 form.addPair(QLatin1String("is_family"), isfamily, QLatin1String("text/plain")); 0561 reqParams << O0RequestParameter("is_family", isfamily.toLatin1()); 0562 0563 QString isfriend = (info.is_friend == 1) ? QLatin1String("1") : QLatin1String("0"); 0564 form.addPair(QLatin1String("is_friend"), isfriend, QLatin1String("text/plain")); 0565 reqParams << O0RequestParameter("is_friend", isfriend.toLatin1()); 0566 0567 QString safetyLevel = QString::number(static_cast<int>(info.safety_level)); 0568 form.addPair(QLatin1String("safety_level"), safetyLevel, QLatin1String("text/plain")); 0569 reqParams << O0RequestParameter("safety_level", safetyLevel.toLatin1()); 0570 0571 QString contentType = QString::number(static_cast<int>(info.content_type)); 0572 form.addPair(QLatin1String("content_type"), contentType, QLatin1String("text/plain")); 0573 reqParams << O0RequestParameter("content_type", contentType.toLatin1()); 0574 0575 QString tags = QLatin1Char('"') + info.tags.join(QLatin1String("\" \"")) + QLatin1Char('"'); 0576 0577 if (tags.length() > 0) 0578 { 0579 form.addPair(QLatin1String("tags"), tags, QLatin1String("text/plain")); 0580 reqParams << O0RequestParameter("tags", tags.toUtf8()); 0581 } 0582 0583 if (!info.title.isEmpty()) 0584 { 0585 form.addPair(QLatin1String("title"), info.title, QLatin1String("text/plain")); 0586 reqParams << O0RequestParameter("title", info.title.toUtf8()); 0587 } 0588 0589 if (!info.description.isEmpty()) 0590 { 0591 form.addPair(QLatin1String("description"), info.description, QLatin1String("text/plain")); 0592 reqParams << O0RequestParameter("description", info.description.toUtf8()); 0593 } 0594 0595 if (!original) 0596 { 0597 QImage image = PreviewLoadThread::loadHighQualitySynchronously(photoPath).copyQImage(); 0598 0599 if (image.isNull()) 0600 { 0601 image.load(photoPath); 0602 } 0603 0604 if (!image.isNull()) 0605 { 0606 if (!d->lastTmpFile.isEmpty()) 0607 { 0608 QFile::remove(d->lastTmpFile); 0609 } 0610 0611 path = WSToolUtils::makeTemporaryDir(d->serviceName.toLatin1().constData()).filePath(QFileInfo(photoPath) 0612 .baseName().trimmed() + QLatin1String(".jpg")); 0613 0614 if (rescale && (image.width() > maxDim || image.height() > maxDim)) 0615 { 0616 image = image.scaled(maxDim, maxDim, Qt::KeepAspectRatio, Qt::SmoothTransformation); 0617 } 0618 0619 image.save(path, "JPEG", imageQuality); 0620 d->lastTmpFile = path; 0621 0622 // Restore all metadata. 0623 0624 QScopedPointer<DMetadata> meta(new DMetadata); 0625 0626 if (meta->load(photoPath)) 0627 { 0628 meta->setItemDimensions(image.size()); 0629 meta->setItemOrientation(MetaEngine::ORIENTATION_NORMAL); 0630 0631 // NOTE: see bug #153207: Flickr use IPTC keywords to create Tags in web interface 0632 // As IPTC do not support UTF-8, we need to remove it. 0633 // This function call remove all Application2 Tags. 0634 0635 meta->removeIptcTags(QStringList() << QLatin1String("Application2")); 0636 0637 // NOTE: see bug # 384260: Flickr use Xmp.dc.subject to create Tags 0638 // in web interface, we need to remove it. 0639 // This function call remove all Dublin Core Tags. 0640 0641 meta->removeXmpTags(QStringList() << QLatin1String("dc")); 0642 0643 meta->setMetadataWritingMode((int)DMetadata::WRITE_TO_FILE_ONLY); 0644 meta->save(path, true); 0645 } 0646 else 0647 { 0648 qCWarning(DIGIKAM_WEBSERVICES_LOG) << "Flickr::Image do not have metadata"; 0649 } 0650 0651 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Resizing and saving to temp file: " << path; 0652 } 0653 } 0654 0655 QFileInfo tempFileInfo(path); 0656 0657 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "QUrl path is " << QUrl::fromLocalFile(path) << "Image size (in bytes) is "<< tempFileInfo.size(); 0658 0659 if (tempFileInfo.size() > (getMaxAllowedFileSize().toLongLong())) 0660 { 0661 Q_EMIT signalAddPhotoFailed(i18n("File Size exceeds maximum allowed file size.")); 0662 Q_EMIT signalBusy(false); 0663 0664 return false; 0665 } 0666 0667 if (!form.addFile(QLatin1String("photo"), path)) 0668 { 0669 Q_EMIT signalBusy(false); 0670 0671 return false; 0672 } 0673 0674 form.finish(); 0675 0676 netRequest.setHeader(QNetworkRequest::ContentTypeHeader, form.contentType()); 0677 0678 d->reply = d->requestor->post(netRequest, reqParams, form.formData()); 0679 d->state = FE_ADDPHOTO; 0680 0681 return true; 0682 } 0683 0684 void FlickrTalker::setGeoLocation(const QString& photoId, const QString& lat, const QString& lon) 0685 { 0686 if (d->reply) 0687 { 0688 d->reply->abort(); 0689 d->reply = nullptr; 0690 } 0691 0692 if (!d->o1->linked()) 0693 { 0694 return; 0695 } 0696 0697 QUrl url(d->apiUrl); 0698 QNetworkRequest netRequest(url); 0699 netRequest.setHeader(QNetworkRequest::ContentTypeHeader, QLatin1String(O2_MIME_TYPE_XFORM)); 0700 0701 QList<O0RequestParameter> reqParams = QList<O0RequestParameter>(); 0702 0703 reqParams << O0RequestParameter("method", "flickr.photos.geo.setLocation"); 0704 reqParams << O0RequestParameter("photo_id", photoId.toLatin1()); 0705 reqParams << O0RequestParameter("lat", lat.toLatin1()); 0706 reqParams << O0RequestParameter("lon", lon.toLatin1()); 0707 0708 QByteArray postData = O1::createQueryParameters(reqParams); 0709 d->reply = d->requestor->post(netRequest, reqParams, postData); 0710 d->state = FE_SETGEO; 0711 0712 Q_EMIT signalBusy(true); 0713 } 0714 0715 QString FlickrTalker::getUserName() const 0716 { 0717 return d->username; 0718 } 0719 0720 QString FlickrTalker::getUserId() const 0721 { 0722 return d->userId; 0723 } 0724 0725 void FlickrTalker::cancel() 0726 { 0727 if (d->reply) 0728 { 0729 d->reply->abort(); 0730 d->reply = nullptr; 0731 } 0732 0733 if (m_authProgressDlg && !m_authProgressDlg->isHidden()) 0734 { 0735 m_authProgressDlg->hide(); 0736 } 0737 } 0738 0739 void FlickrTalker::slotError(const QString& error) 0740 { 0741 QString transError; 0742 int errorNo = error.toInt(); 0743 0744 switch (errorNo) 0745 { 0746 case 2: 0747 transError = i18n("No photo specified"); 0748 break; 0749 0750 case 3: 0751 transError = i18n("General upload failure"); 0752 break; 0753 0754 case 4: 0755 transError = i18n("Filesize was zero"); 0756 break; 0757 0758 case 5: 0759 transError = i18n("Filetype was not recognized"); 0760 break; 0761 0762 case 6: 0763 transError = i18n("User exceeded upload limit"); 0764 break; 0765 0766 case 96: 0767 transError = i18n("Invalid signature"); 0768 break; 0769 0770 case 97: 0771 transError = i18n("Missing signature"); 0772 break; 0773 0774 case 98: 0775 transError = i18n("Login Failed / Invalid auth token"); 0776 break; 0777 0778 case 100: 0779 transError = i18n("Invalid API Key"); 0780 break; 0781 0782 case 105: 0783 transError = i18n("Service currently unavailable"); 0784 break; 0785 0786 case 108: 0787 transError = i18n("Invalid Frob"); 0788 break; 0789 0790 case 111: 0791 transError = i18n("Format \"xxx\" not found"); 0792 break; 0793 0794 case 112: 0795 transError = i18n("Method \"xxx\" not found"); 0796 break; 0797 0798 case 114: 0799 transError = i18n("Invalid SOAP envelope"); 0800 break; 0801 0802 case 115: 0803 transError = i18n("Invalid XML-RPC Method Call"); 0804 break; 0805 0806 case 116: 0807 transError = i18n("The POST method is now required for all setters"); 0808 break; 0809 0810 default: 0811 transError = i18n("Unknown error"); 0812 break; 0813 }; 0814 0815 QMessageBox::critical(QApplication::activeWindow(), 0816 i18nc("@title:window", "Error"), 0817 i18n("Error Occurred: %1\nCannot proceed any further.", transError)); 0818 } 0819 0820 void FlickrTalker::slotFinished(QNetworkReply* reply) 0821 { 0822 Q_EMIT signalBusy(false); 0823 0824 if (reply != d->reply) 0825 { 0826 return; 0827 } 0828 0829 d->reply = nullptr; 0830 0831 if (reply->error() != QNetworkReply::NoError) 0832 { 0833 if (d->state == FE_ADDPHOTO) 0834 { 0835 Q_EMIT signalAddPhotoFailed(reply->errorString()); 0836 } 0837 else 0838 { 0839 QMessageBox::critical(QApplication::activeWindow(), 0840 i18nc("@title:window", "Error"), reply->errorString()); 0841 } 0842 0843 reply->deleteLater(); 0844 0845 return; 0846 } 0847 0848 QByteArray buffer = reply->readAll(); 0849 0850 switch (d->state) 0851 { 0852 case (FE_LOGIN): 0853 /* 0854 parseResponseLogin(buffer); 0855 */ 0856 break; 0857 0858 case (FE_LISTPHOTOSETS): 0859 parseResponseListPhotoSets(buffer); 0860 break; 0861 0862 case (FE_LISTPHOTOS): 0863 parseResponseListPhotos(buffer); 0864 break; 0865 0866 case (FE_GETPHOTOPROPERTY): 0867 parseResponsePhotoProperty(buffer); 0868 break; 0869 0870 case (FE_ADDPHOTO): 0871 parseResponseAddPhoto(buffer); 0872 break; 0873 0874 case (FE_ADDPHOTOTOPHOTOSET): 0875 parseResponseAddPhotoToPhotoSet(buffer); 0876 break; 0877 0878 case (FE_CREATEPHOTOSET): 0879 parseResponseCreatePhotoSet(buffer); 0880 break; 0881 0882 case (FE_GETMAXSIZE): 0883 parseResponseMaxSize(buffer); 0884 break; 0885 0886 case (FE_SETGEO): 0887 parseResponseSetGeoLocation(buffer); 0888 break; 0889 0890 default: // FR_LOGOUT 0891 break; 0892 } 0893 0894 reply->deleteLater(); 0895 } 0896 0897 void FlickrTalker::parseResponseMaxSize(const QByteArray& data) 0898 { 0899 QString errorString; 0900 QDomDocument doc(QLatin1String("mydocument")); 0901 0902 if (!doc.setContent(data)) 0903 { 0904 return; 0905 } 0906 0907 QDomElement docElem = doc.documentElement(); 0908 QDomNode node = docElem.firstChild(); 0909 0910 QDomElement e; 0911 0912 while (!node.isNull()) 0913 { 0914 if (node.isElement() && (node.nodeName() == QLatin1String("person"))) 0915 { 0916 e = node.toElement(); 0917 QDomNode details = e.firstChild(); 0918 0919 while (!details.isNull()) 0920 { 0921 if (details.isElement()) 0922 { 0923 e = details.toElement(); 0924 0925 if (details.nodeName() == QLatin1String("videos")) 0926 { 0927 QDomAttr a = e.attributeNode(QLatin1String("maxupload")); 0928 d->maxSize = a.value(); 0929 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Max upload size is"<<d->maxSize; 0930 } 0931 } 0932 0933 details = details.nextSibling(); 0934 } 0935 } 0936 0937 if (node.isElement() && (node.nodeName() == QLatin1String("err"))) 0938 { 0939 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Checking Error in response"; 0940 errorString = node.toElement().attribute(QLatin1String("code")); 0941 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Error code=" << errorString; 0942 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Msg=" << node.toElement().attribute(QLatin1String("msg")); 0943 } 0944 0945 node = node.nextSibling(); 0946 } 0947 0948 m_authProgressDlg->hide(); 0949 } 0950 0951 void FlickrTalker::parseResponseCreatePhotoSet(const QByteArray& data) 0952 { 0953 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Parse response create photoset received " << data; 0954 0955 //bool success = false; 0956 0957 QDomDocument doc(QLatin1String("getListPhotoSets")); 0958 0959 if (!doc.setContent(data)) 0960 { 0961 return; 0962 } 0963 0964 QDomElement docElem = doc.documentElement(); 0965 QDomNode node = docElem.firstChild(); 0966 QDomElement e; 0967 0968 while (!node.isNull()) 0969 { 0970 if (node.isElement() && (node.nodeName() == QLatin1String("photoset"))) 0971 { 0972 // Parse the id from the response. 0973 0974 QString new_id = node.toElement().attribute(QLatin1String("id")); 0975 0976 // Set the new id in the photo sets list. 0977 0978 QList<FPhotoSet>::iterator it = m_photoSetsList->begin(); 0979 0980 while (it != m_photoSetsList->end()) 0981 { 0982 if (it->id == m_selectedPhotoSet.id) 0983 { 0984 it->id = new_id; 0985 break; 0986 } 0987 0988 ++it; 0989 } 0990 0991 // Set the new id in the selected photo set. 0992 0993 m_selectedPhotoSet.id = new_id; 0994 0995 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "PhotoSet created successfully with id" << new_id; 0996 Q_EMIT signalAddPhotoSetSucceeded(); 0997 } 0998 0999 if (node.isElement() && (node.nodeName() == QLatin1String("err"))) 1000 { 1001 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Checking Error in response"; 1002 QString code = node.toElement().attribute(QLatin1String("code")); 1003 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Error code=" << code; 1004 QString msg = node.toElement().attribute(QLatin1String("msg")); 1005 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Msg=" << msg; 1006 QMessageBox::critical(QApplication::activeWindow(), i18nc("@title:window", "Error"), i18n("PhotoSet creation failed: ") + msg); 1007 } 1008 1009 node = node.nextSibling(); 1010 } 1011 } 1012 1013 void FlickrTalker::parseResponseListPhotoSets(const QByteArray& data) 1014 { 1015 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "parseResponseListPhotosets" << data; 1016 bool success = false; 1017 QDomDocument doc(QLatin1String("getListPhotoSets")); 1018 1019 if (!doc.setContent(data)) 1020 { 1021 return; 1022 } 1023 1024 QDomElement docElem = doc.documentElement(); 1025 QDomNode node = docElem.firstChild(); 1026 QDomElement e; 1027 1028 QString photoSet_id, photoSet_title, photoSet_description; 1029 m_photoSetsList->clear(); 1030 1031 while (!node.isNull()) 1032 { 1033 if (node.isElement() && (node.nodeName() == QLatin1String("photosets"))) 1034 { 1035 e = node.toElement(); 1036 QDomNode details = e.firstChild(); 1037 FPhotoSet fps; 1038 QDomNode detailsNode = details; 1039 1040 while (!detailsNode.isNull()) 1041 { 1042 if (detailsNode.isElement()) 1043 { 1044 e = detailsNode.toElement(); 1045 1046 if (detailsNode.nodeName() == QLatin1String("photoset")) 1047 { 1048 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "id=" << e.attribute(QLatin1String("id")); 1049 photoSet_id = e.attribute(QLatin1String("id")); // this is what is obtained from data. 1050 fps.id = photoSet_id; 1051 QDomNode photoSetDetails = detailsNode.firstChild(); 1052 QDomElement e_detail; 1053 1054 while (!photoSetDetails.isNull()) 1055 { 1056 e_detail = photoSetDetails.toElement(); 1057 1058 if (photoSetDetails.nodeName() == QLatin1String("title")) 1059 { 1060 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Title=" << e_detail.text(); 1061 photoSet_title = e_detail.text(); 1062 fps.title = photoSet_title; 1063 } 1064 else if (photoSetDetails.nodeName() == QLatin1String("description")) 1065 { 1066 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Description =" << e_detail.text(); 1067 photoSet_description = e_detail.text(); 1068 fps.description = photoSet_description; 1069 } 1070 1071 photoSetDetails = photoSetDetails.nextSibling(); 1072 } 1073 1074 m_photoSetsList->append(fps); 1075 } 1076 } 1077 1078 detailsNode = detailsNode.nextSibling(); 1079 } 1080 1081 details = details.nextSibling(); 1082 success = true; 1083 } 1084 1085 if (node.isElement() && (node.nodeName() == QLatin1String("err"))) 1086 { 1087 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Checking Error in response"; 1088 QString code = node.toElement().attribute(QLatin1String("code")); 1089 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Error code=" << code; 1090 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Msg=" << node.toElement().attribute(QLatin1String("msg")); 1091 Q_EMIT signalError(code); 1092 } 1093 1094 node = node.nextSibling(); 1095 } 1096 1097 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "GetPhotoList finished"; 1098 1099 if (!success) 1100 { 1101 Q_EMIT signalListPhotoSetsFailed(i18n("Failed to fetch list of photo sets.")); 1102 } 1103 else 1104 { 1105 Q_EMIT signalListPhotoSetsSucceeded(); 1106 maxAllowedFileSize(); 1107 } 1108 } 1109 1110 void FlickrTalker::parseResponseListPhotos(const QByteArray& data) 1111 { 1112 QDomDocument doc(QLatin1String("getPhotosList")); 1113 1114 if (!doc.setContent(data)) 1115 { 1116 return; 1117 } 1118 1119 QDomElement docElem = doc.documentElement(); 1120 QDomNode node = docElem.firstChild(); 1121 1122 //QDomElement e; 1123 //TODO 1124 } 1125 1126 void FlickrTalker::parseResponseCreateAlbum(const QByteArray& data) 1127 { 1128 QDomDocument doc(QLatin1String("getCreateAlbum")); 1129 1130 if (!doc.setContent(data)) 1131 { 1132 return; 1133 } 1134 1135 QDomElement docElem = doc.documentElement(); 1136 QDomNode node = docElem.firstChild(); 1137 1138 //TODO 1139 } 1140 1141 void FlickrTalker::parseResponseAddPhoto(const QByteArray& data) 1142 { 1143 bool success = false; 1144 QString line; 1145 QDomDocument doc(QLatin1String("AddPhoto Response")); 1146 1147 if (!doc.setContent(data)) 1148 { 1149 return; 1150 } 1151 1152 QDomElement docElem = doc.documentElement(); 1153 QDomNode node = docElem.firstChild(); 1154 QDomElement e; 1155 QString photoId; 1156 1157 while (!node.isNull()) 1158 { 1159 if (node.isElement() && (node.nodeName() == QLatin1String("photoid"))) 1160 { 1161 e = node.toElement(); // try to convert the node to an element. 1162 QDomNode details = e.firstChild(); 1163 photoId = e.text(); 1164 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Photoid= " << photoId; 1165 success = true; 1166 } 1167 1168 if (node.isElement() && (node.nodeName() == QLatin1String("err"))) 1169 { 1170 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Checking Error in response"; 1171 QString code = node.toElement().attribute(QLatin1String("code")); 1172 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Error code=" << code; 1173 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Msg=" << node.toElement().attribute(QLatin1String("msg")); 1174 Q_EMIT signalError(code); 1175 } 1176 1177 node = node.nextSibling(); 1178 } 1179 1180 if (!success) 1181 { 1182 Q_EMIT signalAddPhotoFailed(i18n("Failed to upload photo")); 1183 } 1184 else 1185 { 1186 QString photoSetId = m_selectedPhotoSet.id; 1187 1188 if (photoSetId == QLatin1String("-1")) 1189 { 1190 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "PhotoSet Id not set, not adding the photo to any photoset"; 1191 Q_EMIT signalAddPhotoSucceeded(photoId); 1192 } 1193 else 1194 { 1195 addPhotoToPhotoSet(photoId, photoSetId); 1196 } 1197 } 1198 } 1199 1200 void FlickrTalker::parseResponsePhotoProperty(const QByteArray& data) 1201 { 1202 bool success = false; 1203 QString line; 1204 QDomDocument doc(QLatin1String("Photos Properties")); 1205 1206 if (!doc.setContent(data)) 1207 { 1208 return; 1209 } 1210 1211 QDomElement docElem = doc.documentElement(); 1212 QDomNode node = docElem.firstChild(); 1213 QDomElement e; 1214 1215 while (!node.isNull()) 1216 { 1217 if (node.isElement() && (node.nodeName() == QLatin1String("photoid"))) 1218 { 1219 e = node.toElement(); // try to convert the node to an element. 1220 QDomNode details = e.firstChild(); 1221 success = true; 1222 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Photoid=" << e.text(); 1223 } 1224 1225 if (node.isElement() && (node.nodeName() == QLatin1String("err"))) 1226 { 1227 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Checking Error in response"; 1228 QString code = node.toElement().attribute(QLatin1String("code")); 1229 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Error code=" << code; 1230 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "Msg=" << node.toElement().attribute(QLatin1String("msg")); 1231 Q_EMIT signalError(code); 1232 } 1233 1234 node = node.nextSibling(); 1235 } 1236 1237 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "GetToken finished"; 1238 1239 if (!success) 1240 { 1241 Q_EMIT signalAddPhotoFailed(i18n("Failed to query photo information")); 1242 } 1243 else 1244 { 1245 Q_EMIT signalAddPhotoSucceeded(QLatin1String("")); 1246 } 1247 } 1248 1249 void FlickrTalker::parseResponseAddPhotoToPhotoSet(const QByteArray& data) 1250 { 1251 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "parseResponseListPhotosets" << data; 1252 Q_EMIT signalAddPhotoSucceeded(QLatin1String("")); 1253 } 1254 1255 void FlickrTalker::parseResponseSetGeoLocation(const QByteArray& data) 1256 { 1257 qCDebug(DIGIKAM_WEBSERVICES_LOG) << "parseResponseSetGeoLocation" << data; 1258 Q_EMIT signalAddPhotoSucceeded(QLatin1String("")); 1259 } 1260 1261 } // namespace DigikamGenericFlickrPlugin 1262 1263 #include "moc_flickrtalker.cpp"