File indexing completed on 2024-05-12 04:57:44

0001 /*
0002     This file is part of Choqok, the KDE micro-blogging client
0003 
0004     SPDX-FileCopyrightText: 2010-2012 Andrey Esin <gmlastik@gmail.com>
0005 
0006     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0007 */
0008 
0009 #include "flickrconfig.h"
0010 
0011 #include <QCheckBox>
0012 #include <QCryptographicHash>
0013 #include <QDomDocument>
0014 #include <QDomElement>
0015 #include <QPushButton>
0016 #include <QRadioButton>
0017 #include <QVBoxLayout>
0018 
0019 #include <KAboutData>
0020 #include <KConfigGroup>
0021 #include <KIO/StoredTransferJob>
0022 #include <KLocalizedString>
0023 #include <KMessageBox>
0024 #include <KPluginFactory>
0025 #include <KSharedConfig>
0026 
0027 #include "choqoktools.h"
0028 #include "passwordmanager.h"
0029 
0030 #include "flickrsettings.h"
0031 
0032 K_PLUGIN_CLASS_WITH_JSON(FlickrConfig, "choqok_flickr_config.json")
0033 
0034 const QString apiKey = QLatin1String("13f602e6e705834d8cdd5dd2ccb19651");
0035 const QString apiSecret = QLatin1String("98c89dbe39ae3bea");
0036 const QString apiKeSec = apiSecret + QLatin1String("api_key") + apiKey;
0037 
0038 FlickrConfig::FlickrConfig(QWidget *parent, const QVariantList &)
0039     : KCModule(parent)
0040 {
0041     QVBoxLayout *layout = new QVBoxLayout(this);
0042     QWidget *wd = new QWidget(this);
0043     wd->setObjectName(QLatin1String("mFlickrCtl"));
0044     ui.setupUi(wd);
0045     addConfig(FlickrSettings::self(), wd);
0046     layout->addWidget(wd);
0047 
0048     connect(ui.authButton, &QPushButton::clicked, this, &FlickrConfig::slotAuthButton_clicked);
0049     connect(ui.cfg_shorturl, &QCheckBox::stateChanged, this, &FlickrConfig::emitChanged);
0050     connect(ui.cfg_forprivate, &QRadioButton::clicked, this, &FlickrConfig::emitChanged);
0051     connect(ui.cfg_forfriends, &QCheckBox::stateChanged, this, &FlickrConfig::emitChanged);
0052     connect(ui.cfg_forfamily, &QCheckBox::stateChanged, this, &FlickrConfig::emitChanged);
0053     connect(ui.cfg_forpublic, &QRadioButton::clicked, this, &FlickrConfig::emitChanged);
0054     connect(ui.cfg_safe, &QRadioButton::clicked, this, &FlickrConfig::emitChanged);
0055     connect(ui.cfg_moderate, &QRadioButton::clicked, this, &FlickrConfig::emitChanged);
0056     connect(ui.cfg_restricted, &QRadioButton::clicked, this, &FlickrConfig::emitChanged);
0057     connect(ui.cfg_hidefromsearch, &QCheckBox::stateChanged, this, &FlickrConfig::emitChanged);
0058 }
0059 
0060 FlickrConfig::~FlickrConfig()
0061 {
0062 }
0063 
0064 void FlickrConfig::load()
0065 {
0066     KCModule::load();
0067     KConfigGroup grp(KSharedConfig::openConfig(), "Flickr Uploader");
0068     m_nsid = grp.readEntry("nsid", "");
0069     m_username = grp.readEntry("username", "");
0070     m_fullname = grp.readEntry("fullname", "");
0071     ui.cfg_shorturl->setChecked(grp.readEntry("shorturl", true));
0072     ui.cfg_forprivate->setChecked(grp.readEntry("forprivate", false));
0073     ui.cfg_forfriends->setChecked(grp.readEntry("forfriends", false));
0074     ui.cfg_forfamily->setChecked(grp.readEntry("forfamily", false));
0075     ui.cfg_forpublic->setChecked(grp.readEntry("forpublic", true));
0076     ui.cfg_safe->setChecked(grp.readEntry("safe", true));
0077     ui.cfg_moderate->setChecked(grp.readEntry("moderate", false));
0078     ui.cfg_restricted->setChecked(grp.readEntry("restricted", false));
0079     ui.cfg_hidefromsearch->setChecked(grp.readEntry("hidefromsearch", false));
0080     m_token = Choqok::PasswordManager::self()->readPassword(QStringLiteral("flickr_%1")
0081               .arg(m_username));
0082     setAuthenticated(!m_token.isEmpty());
0083 }
0084 
0085 void FlickrConfig::save()
0086 {
0087     KCModule::save();
0088     KConfigGroup grp(KSharedConfig::openConfig(), "Flickr Uploader");
0089     grp.writeEntry("nsid", m_nsid);
0090     grp.writeEntry("username", m_username);
0091     grp.writeEntry("fullname", m_fullname);
0092     grp.writeEntry("shorturl", ui.cfg_shorturl->isChecked());
0093     grp.writeEntry("forprivate", ui.cfg_forprivate->isChecked());
0094     grp.writeEntry("forfriends", ui.cfg_forfriends->isChecked());
0095     grp.writeEntry("forfamily", ui.cfg_forfamily->isChecked());
0096     grp.writeEntry("forpublic", ui.cfg_forpublic->isChecked());
0097     grp.writeEntry("safe", ui.cfg_safe->isChecked());
0098     grp.writeEntry("moderate", ui.cfg_moderate->isChecked());
0099     grp.writeEntry("restricted", ui.cfg_restricted->isChecked());
0100     grp.writeEntry("hidefromsearch", ui.cfg_hidefromsearch->isChecked());
0101     Choqok::PasswordManager::self()->writePassword(QStringLiteral("flickr_%1").arg(m_username),
0102             m_token);
0103 }
0104 
0105 void FlickrConfig::emitChanged()
0106 {
0107     ui.cfg_forfamily->setEnabled(ui.cfg_forprivate->isChecked());
0108     ui.cfg_forfriends->setEnabled(ui.cfg_forprivate->isChecked());
0109     Q_EMIT changed(true);
0110 }
0111 
0112 void FlickrConfig::getFrob()
0113 {
0114     m_frob.clear();
0115     QUrl url(QLatin1String("https://flickr.com/services/rest/"));
0116     QUrlQuery urlQuery;
0117     urlQuery.addQueryItem(QLatin1String("method"), QLatin1String("flickr.auth.getFrob"));
0118     urlQuery.addQueryItem(QLatin1String("api_key"), QLatin1String(apiKey.toUtf8()));
0119     urlQuery.addQueryItem(QLatin1String("api_sig"),  QLatin1String(createSign("methodflickr.auth.getFrob")));
0120     url.setQuery(urlQuery);
0121 
0122     QString errMsg;
0123     KIO::StoredTransferJob *job = KIO::storedGet(url, KIO::Reload, KIO::HideProgressInfo);
0124     job->exec();
0125     if (!job->error()) {
0126         QDomDocument rep;
0127         rep.setContent(job->data());
0128         QDomElement element = rep.documentElement();
0129         if (element.tagName() == QLatin1String("rsp")) {
0130             QString res;
0131             res = element.attribute(QLatin1String("stat") , QLatin1String("fail"));
0132             QDomNode node = element.firstChild();
0133             while (!node.isNull()) {
0134                 QDomElement elem = node.toElement();
0135                 if (res == QLatin1String("ok")) {
0136                     if (elem.tagName() == QLatin1String("frob")) {
0137                         m_frob = elem.text();
0138                     }
0139                     return;
0140                 } else if (res == QLatin1String("fail")) {
0141                     if (elem.tagName() == QLatin1String("err")) {
0142                         errMsg = elem.text();
0143                         int errCode = elem.attribute(QLatin1String("code") , QLatin1String("0")).toInt();
0144                         switch (errCode) {
0145                         case 96:
0146                         case 97:
0147                             errMsg = i18n("Signature problem. Please try again later");
0148                             break;
0149                         case 105:
0150                             errMsg = i18n("The requested service is temporarily unavailable. Try again later");
0151                             break;
0152                         default:
0153                             errMsg = i18n("Unknown Error:%1. Please try again later", errCode);
0154                             break;
0155                         }
0156                     }
0157                 } else {
0158                     errMsg = i18n("Malformed response");
0159                 }
0160                 node = node.nextSibling();
0161             }
0162         } else {
0163             errMsg = i18n("Malformed response");
0164         }
0165     } else {
0166         errMsg = job->errorString();
0167     }
0168     if (!errMsg.isEmpty()) {
0169         KMessageBox::error(ui.gridLayout->widget(), errMsg, i18n("Flickr authorization"));
0170     }
0171 }
0172 
0173 void FlickrConfig::getToken()
0174 {
0175     m_token.clear();
0176     QUrl url(QLatin1String("https://flickr.com/services/rest/"));
0177     QUrlQuery urlQuery;
0178     urlQuery.addQueryItem(QLatin1String("method"), QLatin1String("flickr.auth.getToken"));
0179     urlQuery.addQueryItem(QLatin1String("api_key"), QLatin1String(apiKey.toUtf8()));
0180     urlQuery.addQueryItem(QLatin1String("frob"), QLatin1String(m_frob.toUtf8()));
0181     urlQuery.addQueryItem(QLatin1String("api_sig"),  QLatin1String(createSign("frob" + m_frob.toUtf8() + "methodflickr.auth.getToken")));
0182     url.setQuery(urlQuery);
0183 
0184     QString errMsg;
0185     KIO::StoredTransferJob *job = KIO::storedGet(url, KIO::Reload, KIO::HideProgressInfo);
0186     job->exec();
0187 
0188     if (!job->error()) {
0189         QDomDocument rep;
0190         rep.setContent(job->data());
0191         QDomElement element = rep.documentElement();
0192         if (element.tagName() == QLatin1String("rsp")) {
0193             QString res;
0194             res = element.attribute(QLatin1String("stat") , QLatin1String("fail"));
0195             QDomNode node = element.firstChild();
0196             while (!node.isNull()) {
0197                 QDomElement elem = node.toElement();
0198                 if (res == QLatin1String("ok")) {
0199                     QDomNode authNode = node.firstChild();
0200                     while (!authNode.isNull()) {
0201                         QDomElement elem = authNode.toElement();
0202                         if (elem.tagName() == QLatin1String("token")) {
0203                             m_token = elem.text();
0204                         }
0205 
0206                         if (elem.tagName() == QLatin1String("user")) {
0207                             m_nsid = elem.attribute(QLatin1String("nsid"));
0208                             m_username = elem.attribute(QLatin1String("username"));
0209                             m_fullname = elem.attribute(QLatin1String("fullname"));
0210                         }
0211                         authNode = authNode.nextSibling();
0212                     }
0213                 } else if (res == QLatin1String("fail")) {
0214                     if (elem.tagName() == QLatin1String("err")) {
0215                         errMsg = elem.text();
0216                         int errCode = elem.attribute(QLatin1String("code") , QLatin1String("0")).toInt();
0217                         switch (errCode) {
0218                         case 96:
0219                         case 97:
0220                         case 108:
0221                             errMsg = i18n("Something happens with signature. Please retry");
0222                             break;
0223                         case 105:
0224                             errMsg = i18n("The requested service is temporarily unavailable. Try again later");
0225                             break;
0226                         default:
0227                             errMsg = i18n("Something happens wrong. Error %1. Try again later", errCode);
0228                             break;
0229                         }
0230                     }
0231                 } else {
0232                     errMsg = i18n("Malformed response");
0233                 }
0234                 node = node.nextSibling();
0235             }
0236         } else {
0237             errMsg = i18n("Malformed response");
0238         }
0239     } else {
0240         errMsg = job->errorString();
0241     }
0242 
0243     if (!errMsg.isEmpty()) {
0244         KMessageBox::error(ui.gridLayout->widget(), errMsg, i18n("Flickr authorization"));
0245         return;
0246     }
0247 
0248     if (!m_token.isEmpty()) {
0249         setAuthenticated(true);
0250         FlickrConfig::save();
0251         ui.tabWidget->setCurrentIndex(1);
0252     } else {
0253         setAuthenticated(false);
0254     }
0255     ui.authButton->setEnabled(true);
0256 }
0257 
0258 void FlickrConfig::setAuthenticated(bool authenticated)
0259 {
0260     isAuthenticated = authenticated;
0261     if (authenticated) {
0262         ui.authButton->setIcon(QIcon::fromTheme(QLatin1String("object-unlocked")));
0263         ui.authLed->on();
0264         ui.authLabel->setText(i18n("Authorized as %1", m_username));
0265         if (!m_fullname.isEmpty()) {
0266             ui.authLabel->setText(ui.authLabel->text() + QStringLiteral(" (%1)").arg(m_fullname.toHtmlEscaped()));
0267         }
0268     } else {
0269         ui.authButton->setIcon(QIcon::fromTheme(QLatin1String("object-locked")));
0270         ui.authLed->off();
0271         ui.authLabel->setText(i18n("Not authorized"));
0272     }
0273 }
0274 
0275 void FlickrConfig::slotAuthButton_clicked()
0276 {
0277     getFrob();
0278     if (!m_frob.isEmpty()) {
0279         QUrl oUrl(QLatin1String("https://flickr.com/services/auth/?"));
0280         oUrl.setPath(oUrl.path() + QLatin1String("api_key=") + apiKey +
0281                      QLatin1String("&perms=write&frob=") + m_frob +
0282                      QLatin1String("&api_sig=") + QLatin1String(createSign("frob" + m_frob.toUtf8() + "permswrite")));
0283         Choqok::openUrl(oUrl);
0284 
0285         QPushButton *btn = new QPushButton(QIcon::fromTheme(QLatin1String("dialog-ok")), i18n("Click here when you authorized Choqok"), this);
0286         connect(btn, &QPushButton::clicked, this, &FlickrConfig::getToken);
0287         btn->setWindowFlags(Qt::Dialog);
0288         ui.authTab->layout()->addWidget(btn);
0289         ui.authButton->setEnabled(false);
0290     } else {
0291         return;
0292     }
0293 }
0294 
0295 QByteArray FlickrConfig::createSign(QByteArray req)
0296 {
0297     return QCryptographicHash::hash(apiKeSec.toUtf8().append(req), QCryptographicHash::Md5).toHex();
0298 }
0299 
0300 #include "flickrconfig.moc"
0301 #include "moc_flickrconfig.cpp"